Browse code

admission tests and swagger

Paul Weil authored on 2015/12/23 05:24:15
Showing 2 changed files
... ...
@@ -14743,6 +14743,8 @@
14743 14743
     "required": [
14744 14744
      "priority",
14745 14745
      "allowPrivilegedContainer",
14746
+     "defaultAddCapabilities",
14747
+     "requiredDropCapabilities",
14746 14748
      "allowedCapabilities",
14747 14749
      "allowHostDirVolumePlugin",
14748 14750
      "allowHostNetwork",
... ...
@@ -14771,6 +14773,20 @@
14771 14771
       "type": "boolean",
14772 14772
       "description": "allow containers to run as privileged"
14773 14773
      },
14774
+     "defaultAddCapabilities": {
14775
+      "type": "array",
14776
+      "items": {
14777
+       "$ref": "v1.Capability"
14778
+      },
14779
+      "description": "capabilities that are added by default but may be dropped"
14780
+     },
14781
+     "requiredDropCapabilities": {
14782
+      "type": "array",
14783
+      "items": {
14784
+       "$ref": "v1.Capability"
14785
+      },
14786
+      "description": "capabilities that will be dropped by default and may not be added"
14787
+     },
14774 14788
      "allowedCapabilities": {
14775 14789
       "type": "array",
14776 14790
       "items": {
... ...
@@ -27,6 +27,122 @@ func NewTestAdmission(store cache.Store, kclient client.Interface) kadmission.In
27 27
 	}
28 28
 }
29 29
 
30
+func TestAdmitCaps(t *testing.T) {
31
+	createPodWithCaps := func(caps *kapi.Capabilities) *kapi.Pod {
32
+		pod := goodPod()
33
+		pod.Spec.Containers[0].SecurityContext.Capabilities = caps
34
+		return pod
35
+	}
36
+
37
+	restricted := restrictiveSCC()
38
+
39
+	allowsFooInAllowed := restrictiveSCC()
40
+	allowsFooInAllowed.Name = "allowCapInAllowed"
41
+	allowsFooInAllowed.AllowedCapabilities = []kapi.Capability{"foo"}
42
+
43
+	allowsFooInRequired := restrictiveSCC()
44
+	allowsFooInRequired.Name = "allowCapInRequired"
45
+	allowsFooInRequired.DefaultAddCapabilities = []kapi.Capability{"foo"}
46
+
47
+	requiresFooToBeDropped := restrictiveSCC()
48
+	requiresFooToBeDropped.Name = "requireDrop"
49
+	requiresFooToBeDropped.RequiredDropCapabilities = []kapi.Capability{"foo"}
50
+
51
+	tc := map[string]struct {
52
+		pod                  *kapi.Pod
53
+		sccs                 []*kapi.SecurityContextConstraints
54
+		shouldPass           bool
55
+		expectedCapabilities *kapi.Capabilities
56
+	}{
57
+		// UC 1: if an SCC does not define allowed or required caps then a pod requesting a cap
58
+		// should be rejected.
59
+		"should reject cap add when not allowed or required": {
60
+			pod:        createPodWithCaps(&kapi.Capabilities{Add: []kapi.Capability{"foo"}}),
61
+			sccs:       []*kapi.SecurityContextConstraints{restricted},
62
+			shouldPass: false,
63
+		},
64
+		// UC 2: if an SCC allows a cap in the allowed field it should accept the pod request
65
+		// to add the cap.
66
+		"should accept cap add when in allowed": {
67
+			pod:        createPodWithCaps(&kapi.Capabilities{Add: []kapi.Capability{"foo"}}),
68
+			sccs:       []*kapi.SecurityContextConstraints{restricted, allowsFooInAllowed},
69
+			shouldPass: true,
70
+		},
71
+		// UC 3: if an SCC requires a cap then it should accept the pod request
72
+		// to add the cap.
73
+		"should accept cap add when in required": {
74
+			pod:        createPodWithCaps(&kapi.Capabilities{Add: []kapi.Capability{"foo"}}),
75
+			sccs:       []*kapi.SecurityContextConstraints{restricted, allowsFooInRequired},
76
+			shouldPass: true,
77
+		},
78
+		// UC 4: if an SCC requires a cap to be dropped then it should fail both
79
+		// in the verification of adds and verification of drops
80
+		"should reject cap add when requested cap is required to be dropped": {
81
+			pod:        createPodWithCaps(&kapi.Capabilities{Add: []kapi.Capability{"foo"}}),
82
+			sccs:       []*kapi.SecurityContextConstraints{restricted, requiresFooToBeDropped},
83
+			shouldPass: false,
84
+		},
85
+		// UC 5: if an SCC requires a cap to be dropped it should accept
86
+		// a manual request to drop the cap.
87
+		"should accept cap drop when cap is required to be dropped": {
88
+			pod:        createPodWithCaps(&kapi.Capabilities{Drop: []kapi.Capability{"foo"}}),
89
+			sccs:       []*kapi.SecurityContextConstraints{restricted, requiresFooToBeDropped},
90
+			shouldPass: true,
91
+		},
92
+		// UC 6: required add is defaulted
93
+		"required add is defaulted": {
94
+			pod:        goodPod(),
95
+			sccs:       []*kapi.SecurityContextConstraints{allowsFooInRequired},
96
+			shouldPass: true,
97
+			expectedCapabilities: &kapi.Capabilities{
98
+				Add: []kapi.Capability{"foo"},
99
+			},
100
+		},
101
+		// UC 7: required drop is defaulted
102
+		"required drop is defaulted": {
103
+			pod:        goodPod(),
104
+			sccs:       []*kapi.SecurityContextConstraints{requiresFooToBeDropped},
105
+			shouldPass: true,
106
+			expectedCapabilities: &kapi.Capabilities{
107
+				Drop: []kapi.Capability{"foo"},
108
+			},
109
+		},
110
+	}
111
+
112
+	for k, v := range tc {
113
+		testSCCAdmit(k, v.sccs, v.pod, v.shouldPass, t)
114
+
115
+		if v.expectedCapabilities != nil {
116
+			if !reflect.DeepEqual(v.expectedCapabilities, v.pod.Spec.Containers[0].SecurityContext.Capabilities) {
117
+				t.Errorf("%s resulted in caps that were not expected - expected: %v, received: %v", k, v.expectedCapabilities, v.pod.Spec.Containers[0].SecurityContext.Capabilities)
118
+			}
119
+		}
120
+	}
121
+}
122
+
123
+func testSCCAdmit(testCaseName string, sccs []*kapi.SecurityContextConstraints, pod *kapi.Pod, shouldPass bool, t *testing.T) {
124
+	namespace := createNamespaceForTest()
125
+	serviceAccount := createSAForTest()
126
+	tc := testclient.NewSimpleFake(namespace, serviceAccount)
127
+	store := cache.NewStore(cache.MetaNamespaceKeyFunc)
128
+
129
+	for _, scc := range sccs {
130
+		store.Add(scc)
131
+	}
132
+
133
+	plugin := NewTestAdmission(store, tc)
134
+
135
+	attrs := kadmission.NewAttributesRecord(pod, "Pod", "namespace", "", string(kapi.ResourcePods), "", kadmission.Create, &user.DefaultInfo{})
136
+	err := plugin.Admit(attrs)
137
+
138
+	if shouldPass && err != nil {
139
+		t.Errorf("%s expected no errors but received %v", testCaseName, err)
140
+	}
141
+	if !shouldPass && err == nil {
142
+		t.Errorf("%s expected errors but received none", testCaseName)
143
+	}
144
+}
145
+
30 146
 func TestAdmit(t *testing.T) {
31 147
 	// create the annotated namespace and add it to the fake client
32 148
 	namespace := createNamespaceForTest()