} } return false, nil }) return ev, err } BeforeEach(func() { podClient = f.PodClient() }) It("should support sysctls", func() { pod := testPod() pod.Annotations[api.SysctlsPodAnnotationKey] = api.PodAnnotationsFromSysctls([]api.Sysctl{ { Name: "kernel.shm_rmid_forced", Value: "1", }, }) pod.Spec.Containers[0].Command = []string{"/bin/sysctl", "kernel.shm_rmid_forced"} By("Creating a pod with the kernel.shm_rmid_forced sysctl") pod = podClient.Create(pod) By("Watching for error events or started pod") // watch for events instead of termination of pod because the kubelet deletes // failed pods without running containers. This would create a race as the pod // might have already been deleted here. ev, err := waitForPodErrorEventOrStarted(pod) Expect(err).NotTo(HaveOccurred()) if ev != nil && ev.Reason == sysctl.UnsupportedReason { framework.Skipf("No sysctl support in Docker <1.12")
func TestValidate(t *testing.T) { tests := map[string]struct { patterns []string allowed []string disallowed []string }{ // no container requests "nil": { patterns: nil, allowed: []string{"foo"}, }, "empty": { patterns: []string{}, disallowed: []string{"foo"}, }, "without wildcard": { patterns: []string{"a", "a.b"}, allowed: []string{"a", "a.b"}, disallowed: []string{"b"}, }, "with catch-all wildcard": { patterns: []string{"*"}, allowed: []string{"a", "a.b"}, }, "with catch-all wildcard and non-wildcard": { patterns: []string{"a.b.c", "*"}, allowed: []string{"a", "a.b", "a.b.c", "b"}, }, "without catch-all wildcard": { patterns: []string{"a.*", "b.*", "c.d.e", "d.e.f.*"}, allowed: []string{"a.b", "b.c", "c.d.e", "d.e.f.g.h"}, disallowed: []string{"a", "b", "c", "c.d", "d.e", "d.e.f"}, }, } for k, v := range tests { strategy, err := NewMustMatchPatterns(v.patterns) if err != nil { t.Errorf("%s failed: %v", k, err) continue } pod := &api.Pod{} errs := strategy.Validate(pod) if len(errs) != 0 { t.Errorf("%s: unexpected validaton errors for empty sysctls: %v", k, errs) } sysctls := []api.Sysctl{} for _, s := range v.allowed { sysctls = append(sysctls, api.Sysctl{ Name: s, Value: "dummy", }) } testAllowed := func(key string, category string) { pod.Annotations = map[string]string{ key: api.PodAnnotationsFromSysctls(sysctls), } errs = strategy.Validate(pod) if len(errs) != 0 { t.Errorf("%s: unexpected validaton errors for %s sysctls: %v", k, category, errs) } } testDisallowed := func(key string, category string) { for _, s := range v.disallowed { pod.Annotations = map[string]string{ key: api.PodAnnotationsFromSysctls([]api.Sysctl{{s, "dummy"}}), } errs = strategy.Validate(pod) if len(errs) == 0 { t.Errorf("%s: expected error for %s sysctl %q", k, category, s) } } } testAllowed(api.SysctlsPodAnnotationKey, "safe") testAllowed(api.UnsafeSysctlsPodAnnotationKey, "unsafe") testDisallowed(api.SysctlsPodAnnotationKey, "safe") testDisallowed(api.UnsafeSysctlsPodAnnotationKey, "unsafe") } }
func TestAdmitSysctls(t *testing.T) { podWithSysctls := func(safeSysctls []string, unsafeSysctls []string) *kapi.Pod { pod := goodPod() dummySysctls := func(names []string) []kapi.Sysctl { sysctls := make([]kapi.Sysctl, len(names)) for i, n := range names { sysctls[i].Name = n sysctls[i].Value = "dummy" } return sysctls } pod.Annotations[kapi.SysctlsPodAnnotationKey] = kapi.PodAnnotationsFromSysctls(dummySysctls(safeSysctls)) pod.Annotations[kapi.UnsafeSysctlsPodAnnotationKey] = kapi.PodAnnotationsFromSysctls(dummySysctls(unsafeSysctls)) return pod } noSysctls := restrictivePSP() noSysctls.Name = "no sysctls" emptySysctls := restrictivePSP() emptySysctls.Name = "empty sysctls" emptySysctls.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "" mixedSysctls := restrictivePSP() mixedSysctls.Name = "wildcard sysctls" mixedSysctls.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "a.*,b.*,c,d.e.f" aSysctl := restrictivePSP() aSysctl.Name = "a sysctl" aSysctl.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "a" bSysctl := restrictivePSP() bSysctl.Name = "b sysctl" bSysctl.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "b" cSysctl := restrictivePSP() cSysctl.Name = "c sysctl" cSysctl.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "c" catchallSysctls := restrictivePSP() catchallSysctls.Name = "catchall sysctl" catchallSysctls.Annotations[extensions.SysctlsPodSecurityPolicyAnnotationKey] = "*" tests := map[string]struct { pod *kapi.Pod psps []*extensions.PodSecurityPolicy shouldPass bool expectedPSP string }{ "pod without unsafe sysctls request allowed under noSysctls PSP": { pod: goodPod(), psps: []*extensions.PodSecurityPolicy{noSysctls}, shouldPass: true, expectedPSP: noSysctls.Name, }, "pod without any sysctls request allowed under emptySysctls PSP": { pod: goodPod(), psps: []*extensions.PodSecurityPolicy{emptySysctls}, shouldPass: true, expectedPSP: emptySysctls.Name, }, "pod with safe sysctls request allowed under noSysctls PSP": { pod: podWithSysctls([]string{"a", "b"}, []string{}), psps: []*extensions.PodSecurityPolicy{noSysctls}, shouldPass: true, expectedPSP: noSysctls.Name, }, "pod with unsafe sysctls request allowed under noSysctls PSP": { pod: podWithSysctls([]string{}, []string{"a", "b"}), psps: []*extensions.PodSecurityPolicy{noSysctls}, shouldPass: true, expectedPSP: noSysctls.Name, }, "pod with safe sysctls request disallowed under emptySysctls PSP": { pod: podWithSysctls([]string{"a", "b"}, []string{}), psps: []*extensions.PodSecurityPolicy{emptySysctls}, shouldPass: false, }, "pod with unsafe sysctls request disallowed under emptySysctls PSP": { pod: podWithSysctls([]string{}, []string{"a", "b"}), psps: []*extensions.PodSecurityPolicy{emptySysctls}, shouldPass: false, }, "pod with matching sysctls request allowed under mixedSysctls PSP": { pod: podWithSysctls([]string{"a.b", "b.c"}, []string{"c", "d.e.f"}), psps: []*extensions.PodSecurityPolicy{mixedSysctls}, shouldPass: true, expectedPSP: mixedSysctls.Name, }, "pod with not-matching unsafe sysctls request allowed under mixedSysctls PSP": { pod: podWithSysctls([]string{"a.b", "b.c", "c", "d.e.f"}, []string{"e"}), psps: []*extensions.PodSecurityPolicy{mixedSysctls}, shouldPass: false, }, "pod with not-matching safe sysctls request allowed under mixedSysctls PSP": { pod: podWithSysctls([]string{"a.b", "b.c", "c", "d.e.f", "e"}, []string{}), psps: []*extensions.PodSecurityPolicy{mixedSysctls}, shouldPass: false, }, "pod with sysctls request allowed under catchallSysctls PSP": { pod: podWithSysctls([]string{"e"}, []string{"f"}), psps: []*extensions.PodSecurityPolicy{catchallSysctls}, shouldPass: true, expectedPSP: catchallSysctls.Name, }, "pod with sysctls request allowed under catchallSysctls PSP, not under mixedSysctls or emptySysctls PSP": { pod: podWithSysctls([]string{"e"}, []string{"f"}), psps: []*extensions.PodSecurityPolicy{mixedSysctls, catchallSysctls, emptySysctls}, shouldPass: true, expectedPSP: catchallSysctls.Name, }, "pod with safe c sysctl request allowed under cSysctl PSP, not under aSysctl or bSysctl PSP": { pod: podWithSysctls([]string{}, []string{"c"}), psps: []*extensions.PodSecurityPolicy{aSysctl, bSysctl, cSysctl}, shouldPass: true, expectedPSP: cSysctl.Name, }, "pod with unsafe c sysctl request allowed under cSysctl PSP, not under aSysctl or bSysctl PSP": { pod: podWithSysctls([]string{"c"}, []string{}), psps: []*extensions.PodSecurityPolicy{aSysctl, bSysctl, cSysctl}, shouldPass: true, expectedPSP: cSysctl.Name, }, } for k, v := range tests { origSafeSysctls, origUnsafeSysctls, err := kapi.SysctlsFromPodAnnotations(v.pod.Annotations) if err != nil { t.Fatalf("invalid sysctl annotation: %v", err) } testPSPAdmit(k, v.psps, v.pod, v.shouldPass, v.expectedPSP, t) if v.shouldPass { safeSysctls, unsafeSysctls, _ := kapi.SysctlsFromPodAnnotations(v.pod.Annotations) if !reflect.DeepEqual(safeSysctls, origSafeSysctls) { t.Errorf("%s: wrong safe sysctls: expected=%v, got=%v", k, origSafeSysctls, safeSysctls) } if !reflect.DeepEqual(unsafeSysctls, origUnsafeSysctls) { t.Errorf("%s: wrong unsafe sysctls: expected=%v, got=%v", k, origSafeSysctls, safeSysctls) } } } }