mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-14 06:15:45 +00:00
deprecate ExperimentalHostUserNamespaceDefaulting
This commit is contained in:
parent
aa0fea6944
commit
eb60dce33b
@ -294,10 +294,9 @@ const (
|
|||||||
|
|
||||||
// owner: @pweil-
|
// owner: @pweil-
|
||||||
// alpha: v1.5
|
// alpha: v1.5
|
||||||
|
// deprecated: v1.28
|
||||||
//
|
//
|
||||||
// Default userns=host for containers that are using other host namespaces, host mounts, the pod
|
// This flag used to be needed for dockershim CRI and currently does nothing.
|
||||||
// contains a privileged container, or specific non-namespaced capabilities (MKNOD, SYS_MODULE,
|
|
||||||
// SYS_TIME). This should only be enabled if user namespace remapping is enabled in the docker daemon.
|
|
||||||
ExperimentalHostUserNamespaceDefaultingGate featuregate.Feature = "ExperimentalHostUserNamespaceDefaulting"
|
ExperimentalHostUserNamespaceDefaultingGate featuregate.Feature = "ExperimentalHostUserNamespaceDefaulting"
|
||||||
|
|
||||||
// owner: @yuzhiquan, @bowei, @PxyUp, @SergeyKanzhelev
|
// owner: @yuzhiquan, @bowei, @PxyUp, @SergeyKanzhelev
|
||||||
@ -998,7 +997,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
|
|
||||||
ExpandedDNSConfig: {Default: true, PreRelease: featuregate.Beta},
|
ExpandedDNSConfig: {Default: true, PreRelease: featuregate.Beta},
|
||||||
|
|
||||||
ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: featuregate.Beta},
|
ExperimentalHostUserNamespaceDefaultingGate: {Default: false, PreRelease: featuregate.Deprecated, LockToDefault: true}, // remove in 1.30
|
||||||
|
|
||||||
GRPCContainerProbe: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, //remove in 1.29
|
GRPCContainerProbe: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, //remove in 1.29
|
||||||
|
|
||||||
|
@ -480,12 +480,6 @@ type RunContainerOptions struct {
|
|||||||
ReadOnly bool
|
ReadOnly bool
|
||||||
// hostname for pod containers
|
// hostname for pod containers
|
||||||
Hostname string
|
Hostname string
|
||||||
// EnableHostUserNamespace sets userns=host when users request host namespaces (pid, ipc, net),
|
|
||||||
// are using non-namespaced capabilities (mknod, sys_time, sys_module), the pod contains a privileged container,
|
|
||||||
// or using host path volumes.
|
|
||||||
// This should only be enabled when the container runtime is performing user remapping AND if the
|
|
||||||
// experimental behavior is desired.
|
|
||||||
EnableHostUserNamespace bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumeInfo contains information about the volume.
|
// VolumeInfo contains information about the volume.
|
||||||
|
@ -517,56 +517,55 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
|||||||
tracer := kubeDeps.TracerProvider.Tracer(instrumentationScope)
|
tracer := kubeDeps.TracerProvider.Tracer(instrumentationScope)
|
||||||
|
|
||||||
klet := &Kubelet{
|
klet := &Kubelet{
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
hostnameOverridden: hostnameOverridden,
|
hostnameOverridden: hostnameOverridden,
|
||||||
nodeName: nodeName,
|
nodeName: nodeName,
|
||||||
kubeClient: kubeDeps.KubeClient,
|
kubeClient: kubeDeps.KubeClient,
|
||||||
heartbeatClient: kubeDeps.HeartbeatClient,
|
heartbeatClient: kubeDeps.HeartbeatClient,
|
||||||
onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure,
|
onRepeatedHeartbeatFailure: kubeDeps.OnHeartbeatFailure,
|
||||||
rootDirectory: filepath.Clean(rootDirectory),
|
rootDirectory: filepath.Clean(rootDirectory),
|
||||||
resyncInterval: kubeCfg.SyncFrequency.Duration,
|
resyncInterval: kubeCfg.SyncFrequency.Duration,
|
||||||
sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources),
|
sourcesReady: config.NewSourcesReady(kubeDeps.PodConfig.SeenAllSources),
|
||||||
registerNode: registerNode,
|
registerNode: registerNode,
|
||||||
registerWithTaints: registerWithTaints,
|
registerWithTaints: registerWithTaints,
|
||||||
registerSchedulable: registerSchedulable,
|
registerSchedulable: registerSchedulable,
|
||||||
dnsConfigurer: dns.NewConfigurer(kubeDeps.Recorder, nodeRef, nodeIPs, clusterDNS, kubeCfg.ClusterDomain, kubeCfg.ResolverConfig),
|
dnsConfigurer: dns.NewConfigurer(kubeDeps.Recorder, nodeRef, nodeIPs, clusterDNS, kubeCfg.ClusterDomain, kubeCfg.ResolverConfig),
|
||||||
serviceLister: serviceLister,
|
serviceLister: serviceLister,
|
||||||
serviceHasSynced: serviceHasSynced,
|
serviceHasSynced: serviceHasSynced,
|
||||||
nodeLister: nodeLister,
|
nodeLister: nodeLister,
|
||||||
nodeHasSynced: nodeHasSynced,
|
nodeHasSynced: nodeHasSynced,
|
||||||
streamingConnectionIdleTimeout: kubeCfg.StreamingConnectionIdleTimeout.Duration,
|
streamingConnectionIdleTimeout: kubeCfg.StreamingConnectionIdleTimeout.Duration,
|
||||||
recorder: kubeDeps.Recorder,
|
recorder: kubeDeps.Recorder,
|
||||||
cadvisor: kubeDeps.CAdvisorInterface,
|
cadvisor: kubeDeps.CAdvisorInterface,
|
||||||
cloud: kubeDeps.Cloud,
|
cloud: kubeDeps.Cloud,
|
||||||
externalCloudProvider: cloudprovider.IsExternal(cloudProvider),
|
externalCloudProvider: cloudprovider.IsExternal(cloudProvider),
|
||||||
providerID: providerID,
|
providerID: providerID,
|
||||||
nodeRef: nodeRef,
|
nodeRef: nodeRef,
|
||||||
nodeLabels: nodeLabels,
|
nodeLabels: nodeLabels,
|
||||||
nodeStatusUpdateFrequency: kubeCfg.NodeStatusUpdateFrequency.Duration,
|
nodeStatusUpdateFrequency: kubeCfg.NodeStatusUpdateFrequency.Duration,
|
||||||
nodeStatusReportFrequency: kubeCfg.NodeStatusReportFrequency.Duration,
|
nodeStatusReportFrequency: kubeCfg.NodeStatusReportFrequency.Duration,
|
||||||
os: kubeDeps.OSInterface,
|
os: kubeDeps.OSInterface,
|
||||||
oomWatcher: oomWatcher,
|
oomWatcher: oomWatcher,
|
||||||
cgroupsPerQOS: kubeCfg.CgroupsPerQOS,
|
cgroupsPerQOS: kubeCfg.CgroupsPerQOS,
|
||||||
cgroupRoot: kubeCfg.CgroupRoot,
|
cgroupRoot: kubeCfg.CgroupRoot,
|
||||||
mounter: kubeDeps.Mounter,
|
mounter: kubeDeps.Mounter,
|
||||||
hostutil: kubeDeps.HostUtil,
|
hostutil: kubeDeps.HostUtil,
|
||||||
subpather: kubeDeps.Subpather,
|
subpather: kubeDeps.Subpather,
|
||||||
maxPods: int(kubeCfg.MaxPods),
|
maxPods: int(kubeCfg.MaxPods),
|
||||||
podsPerCore: int(kubeCfg.PodsPerCore),
|
podsPerCore: int(kubeCfg.PodsPerCore),
|
||||||
syncLoopMonitor: atomic.Value{},
|
syncLoopMonitor: atomic.Value{},
|
||||||
daemonEndpoints: daemonEndpoints,
|
daemonEndpoints: daemonEndpoints,
|
||||||
containerManager: kubeDeps.ContainerManager,
|
containerManager: kubeDeps.ContainerManager,
|
||||||
nodeIPs: nodeIPs,
|
nodeIPs: nodeIPs,
|
||||||
nodeIPValidator: validateNodeIP,
|
nodeIPValidator: validateNodeIP,
|
||||||
clock: clock.RealClock{},
|
clock: clock.RealClock{},
|
||||||
enableControllerAttachDetach: kubeCfg.EnableControllerAttachDetach,
|
enableControllerAttachDetach: kubeCfg.EnableControllerAttachDetach,
|
||||||
makeIPTablesUtilChains: kubeCfg.MakeIPTablesUtilChains,
|
makeIPTablesUtilChains: kubeCfg.MakeIPTablesUtilChains,
|
||||||
iptablesMasqueradeBit: int(kubeCfg.IPTablesMasqueradeBit),
|
iptablesMasqueradeBit: int(kubeCfg.IPTablesMasqueradeBit),
|
||||||
iptablesDropBit: int(kubeCfg.IPTablesDropBit),
|
iptablesDropBit: int(kubeCfg.IPTablesDropBit),
|
||||||
experimentalHostUserNamespaceDefaulting: utilfeature.DefaultFeatureGate.Enabled(features.ExperimentalHostUserNamespaceDefaultingGate),
|
keepTerminatedPodVolumes: keepTerminatedPodVolumes,
|
||||||
keepTerminatedPodVolumes: keepTerminatedPodVolumes,
|
nodeStatusMaxImages: nodeStatusMaxImages,
|
||||||
nodeStatusMaxImages: nodeStatusMaxImages,
|
tracer: tracer,
|
||||||
tracer: tracer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if klet.cloud != nil {
|
if klet.cloud != nil {
|
||||||
@ -596,10 +595,6 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,
|
|||||||
klet.configMapManager = configMapManager
|
klet.configMapManager = configMapManager
|
||||||
}
|
}
|
||||||
|
|
||||||
if klet.experimentalHostUserNamespaceDefaulting {
|
|
||||||
klog.InfoS("Experimental host user namespace defaulting is enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
machineInfo, err := klet.cadvisor.MachineInfo()
|
machineInfo, err := klet.cadvisor.MachineInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1227,13 +1222,6 @@ type Kubelet struct {
|
|||||||
// The AppArmor validator for checking whether AppArmor is supported.
|
// The AppArmor validator for checking whether AppArmor is supported.
|
||||||
appArmorValidator apparmor.Validator
|
appArmorValidator apparmor.Validator
|
||||||
|
|
||||||
// experimentalHostUserNamespaceDefaulting sets userns=true when users request host namespaces (pid, ipc, net),
|
|
||||||
// are using non-namespaced capabilities (mknod, sys_time, sys_module), the pod contains a privileged container,
|
|
||||||
// or using host path volumes.
|
|
||||||
// This should only be enabled when the container runtime is performing user remapping AND if the
|
|
||||||
// experimental behavior is desired.
|
|
||||||
experimentalHostUserNamespaceDefaulting bool
|
|
||||||
|
|
||||||
// StatsProvider provides the node and the container stats.
|
// StatsProvider provides the node and the container stats.
|
||||||
StatsProvider *stats.Provider
|
StatsProvider *stats.Provider
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
|
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/component-helpers/storage/ephemeral"
|
|
||||||
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||||
@ -515,11 +514,6 @@ func (kl *Kubelet) GenerateRunContainerOptions(ctx context.Context, pod *v1.Pod,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// only do this check if the experimental behavior is enabled, otherwise allow it to default to false
|
|
||||||
if kl.experimentalHostUserNamespaceDefaulting {
|
|
||||||
opts.EnableHostUserNamespace = kl.enableHostUserNamespace(ctx, pod)
|
|
||||||
}
|
|
||||||
|
|
||||||
return opts, cleanupAction, nil
|
return opts, cleanupAction, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2166,82 +2160,3 @@ func (kl *Kubelet) cleanupOrphanedPodCgroups(pcm cm.PodContainerManager, cgroupP
|
|||||||
go pcm.Destroy(val)
|
go pcm.Destroy(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// enableHostUserNamespace determines if the host user namespace should be used by the container runtime.
|
|
||||||
// Returns true if the pod is using a host pid, pic, or network namespace, the pod is using a non-namespaced
|
|
||||||
// capability, the pod contains a privileged container, or the pod has a host path volume.
|
|
||||||
//
|
|
||||||
// NOTE: when if a container shares any namespace with another container it must also share the user namespace
|
|
||||||
// or it will not have the correct capabilities in the namespace. This means that host user namespace
|
|
||||||
// is enabled per pod, not per container.
|
|
||||||
func (kl *Kubelet) enableHostUserNamespace(ctx context.Context, pod *v1.Pod) bool {
|
|
||||||
if kubecontainer.HasPrivilegedContainer(pod) || hasHostNamespace(pod) ||
|
|
||||||
hasHostVolume(pod) || hasNonNamespacedCapability(pod) || kl.hasHostMountPVC(ctx, pod) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasNonNamespacedCapability returns true if MKNOD, SYS_TIME, or SYS_MODULE is requested for any container.
|
|
||||||
func hasNonNamespacedCapability(pod *v1.Pod) bool {
|
|
||||||
for _, c := range pod.Spec.Containers {
|
|
||||||
if c.SecurityContext != nil && c.SecurityContext.Capabilities != nil {
|
|
||||||
for _, cap := range c.SecurityContext.Capabilities.Add {
|
|
||||||
if cap == "MKNOD" || cap == "SYS_TIME" || cap == "SYS_MODULE" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasHostVolume returns true if the pod spec has a HostPath volume.
|
|
||||||
func hasHostVolume(pod *v1.Pod) bool {
|
|
||||||
for _, v := range pod.Spec.Volumes {
|
|
||||||
if v.HostPath != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasHostNamespace returns true if hostIPC, hostNetwork, or hostPID are set to true.
|
|
||||||
func hasHostNamespace(pod *v1.Pod) bool {
|
|
||||||
if pod.Spec.SecurityContext == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return pod.Spec.HostIPC || pod.Spec.HostNetwork || pod.Spec.HostPID
|
|
||||||
}
|
|
||||||
|
|
||||||
// hasHostMountPVC returns true if a PVC is referencing a HostPath volume.
|
|
||||||
func (kl *Kubelet) hasHostMountPVC(ctx context.Context, pod *v1.Pod) bool {
|
|
||||||
for _, volume := range pod.Spec.Volumes {
|
|
||||||
pvcName := ""
|
|
||||||
switch {
|
|
||||||
case volume.PersistentVolumeClaim != nil:
|
|
||||||
pvcName = volume.PersistentVolumeClaim.ClaimName
|
|
||||||
case volume.Ephemeral != nil:
|
|
||||||
pvcName = ephemeral.VolumeClaimName(pod, &volume)
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pvc, err := kl.kubeClient.CoreV1().PersistentVolumeClaims(pod.Namespace).Get(ctx, pvcName, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
klog.InfoS("Unable to retrieve pvc", "pvc", klog.KRef(pod.Namespace, pvcName), "err", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if pvc != nil {
|
|
||||||
referencedVolume, err := kl.kubeClient.CoreV1().PersistentVolumes().Get(ctx, pvc.Spec.VolumeName, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
klog.InfoS("Unable to retrieve pv", "pvName", pvc.Spec.VolumeName, "err", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if referencedVolume != nil && referencedVolume.Spec.HostPath != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -3437,222 +3437,6 @@ func TestGetPortForward(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHasHostMountPVC(t *testing.T) {
|
|
||||||
type testcase struct {
|
|
||||||
pvError error
|
|
||||||
pvcError error
|
|
||||||
expected bool
|
|
||||||
podHasPVC bool
|
|
||||||
pvcIsHostPath bool
|
|
||||||
podHasEphemeral bool
|
|
||||||
}
|
|
||||||
tests := map[string]testcase{
|
|
||||||
"no pvc": {podHasPVC: false, expected: false},
|
|
||||||
"error fetching pvc": {
|
|
||||||
podHasPVC: true,
|
|
||||||
pvcError: fmt.Errorf("foo"),
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
"error fetching pv": {
|
|
||||||
podHasPVC: true,
|
|
||||||
pvError: fmt.Errorf("foo"),
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
"host path pvc": {
|
|
||||||
podHasPVC: true,
|
|
||||||
pvcIsHostPath: true,
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
"enabled ephemeral host path": {
|
|
||||||
podHasEphemeral: true,
|
|
||||||
pvcIsHostPath: true,
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
"non host path pvc": {
|
|
||||||
podHasPVC: true,
|
|
||||||
pvcIsHostPath: false,
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
run := func(t *testing.T, v testcase) {
|
|
||||||
ctx := context.Background()
|
|
||||||
testKubelet := newTestKubelet(t, false)
|
|
||||||
defer testKubelet.Cleanup()
|
|
||||||
pod := &v1.Pod{
|
|
||||||
Spec: v1.PodSpec{},
|
|
||||||
}
|
|
||||||
|
|
||||||
volumeToReturn := &v1.PersistentVolume{
|
|
||||||
Spec: v1.PersistentVolumeSpec{},
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.podHasPVC {
|
|
||||||
pod.Spec.Volumes = []v1.Volume{
|
|
||||||
{
|
|
||||||
VolumeSource: v1.VolumeSource{
|
|
||||||
PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.podHasEphemeral {
|
|
||||||
pod.Spec.Volumes = []v1.Volume{
|
|
||||||
{
|
|
||||||
Name: "xyz",
|
|
||||||
VolumeSource: v1.VolumeSource{
|
|
||||||
Ephemeral: &v1.EphemeralVolumeSource{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v.podHasPVC || v.podHasEphemeral) && v.pvcIsHostPath {
|
|
||||||
volumeToReturn.Spec.PersistentVolumeSource = v1.PersistentVolumeSource{
|
|
||||||
HostPath: &v1.HostPathVolumeSource{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
testKubelet.fakeKubeClient.AddReactor("get", "persistentvolumeclaims", func(action core.Action) (bool, runtime.Object, error) {
|
|
||||||
return true, &v1.PersistentVolumeClaim{
|
|
||||||
Spec: v1.PersistentVolumeClaimSpec{
|
|
||||||
VolumeName: "foo",
|
|
||||||
},
|
|
||||||
}, v.pvcError
|
|
||||||
})
|
|
||||||
testKubelet.fakeKubeClient.AddReactor("get", "persistentvolumes", func(action core.Action) (bool, runtime.Object, error) {
|
|
||||||
return true, volumeToReturn, v.pvError
|
|
||||||
})
|
|
||||||
|
|
||||||
actual := testKubelet.kubelet.hasHostMountPVC(ctx, pod)
|
|
||||||
if actual != v.expected {
|
|
||||||
t.Errorf("expected %t but got %t", v.expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range tests {
|
|
||||||
t.Run(k, func(t *testing.T) {
|
|
||||||
run(t, v)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHasNonNamespacedCapability(t *testing.T) {
|
|
||||||
createPodWithCap := func(caps []v1.Capability) *v1.Pod {
|
|
||||||
pod := &v1.Pod{
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Containers: []v1.Container{{}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(caps) > 0 {
|
|
||||||
pod.Spec.Containers[0].SecurityContext = &v1.SecurityContext{
|
|
||||||
Capabilities: &v1.Capabilities{
|
|
||||||
Add: caps,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pod
|
|
||||||
}
|
|
||||||
|
|
||||||
nilCaps := createPodWithCap([]v1.Capability{v1.Capability("foo")})
|
|
||||||
nilCaps.Spec.Containers[0].SecurityContext = nil
|
|
||||||
|
|
||||||
tests := map[string]struct {
|
|
||||||
pod *v1.Pod
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
"nil security contxt": {createPodWithCap(nil), false},
|
|
||||||
"nil caps": {nilCaps, false},
|
|
||||||
"namespaced cap": {createPodWithCap([]v1.Capability{v1.Capability("foo")}), false},
|
|
||||||
"non-namespaced cap MKNOD": {createPodWithCap([]v1.Capability{v1.Capability("MKNOD")}), true},
|
|
||||||
"non-namespaced cap SYS_TIME": {createPodWithCap([]v1.Capability{v1.Capability("SYS_TIME")}), true},
|
|
||||||
"non-namespaced cap SYS_MODULE": {createPodWithCap([]v1.Capability{v1.Capability("SYS_MODULE")}), true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range tests {
|
|
||||||
actual := hasNonNamespacedCapability(v.pod)
|
|
||||||
if actual != v.expected {
|
|
||||||
t.Errorf("%s failed, expected %t but got %t", k, v.expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHasHostVolume(t *testing.T) {
|
|
||||||
pod := &v1.Pod{
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
Volumes: []v1.Volume{
|
|
||||||
{
|
|
||||||
VolumeSource: v1.VolumeSource{
|
|
||||||
HostPath: &v1.HostPathVolumeSource{},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
result := hasHostVolume(pod)
|
|
||||||
if !result {
|
|
||||||
t.Errorf("expected host volume to enable host user namespace")
|
|
||||||
}
|
|
||||||
|
|
||||||
pod.Spec.Volumes[0].VolumeSource.HostPath = nil
|
|
||||||
result = hasHostVolume(pod)
|
|
||||||
if result {
|
|
||||||
t.Errorf("expected nil host volume to not enable host user namespace")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHasHostNamespace(t *testing.T) {
|
|
||||||
tests := map[string]struct {
|
|
||||||
ps v1.PodSpec
|
|
||||||
expected bool
|
|
||||||
}{
|
|
||||||
"nil psc": {
|
|
||||||
ps: v1.PodSpec{},
|
|
||||||
expected: false},
|
|
||||||
|
|
||||||
"host pid true": {
|
|
||||||
ps: v1.PodSpec{
|
|
||||||
HostPID: true,
|
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
"host ipc true": {
|
|
||||||
ps: v1.PodSpec{
|
|
||||||
HostIPC: true,
|
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
"host net true": {
|
|
||||||
ps: v1.PodSpec{
|
|
||||||
HostNetwork: true,
|
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
|
||||||
},
|
|
||||||
expected: true,
|
|
||||||
},
|
|
||||||
"no host ns": {
|
|
||||||
ps: v1.PodSpec{
|
|
||||||
SecurityContext: &v1.PodSecurityContext{},
|
|
||||||
},
|
|
||||||
expected: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range tests {
|
|
||||||
pod := &v1.Pod{
|
|
||||||
Spec: v.ps,
|
|
||||||
}
|
|
||||||
actual := hasHostNamespace(pod)
|
|
||||||
if actual != v.expected {
|
|
||||||
t.Errorf("%s failed, expected %t but got %t", k, v.expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTruncatePodHostname(t *testing.T) {
|
func TestTruncatePodHostname(t *testing.T) {
|
||||||
for c, test := range map[string]struct {
|
for c, test := range map[string]struct {
|
||||||
input string
|
input string
|
||||||
|
Loading…
Reference in New Issue
Block a user