@@ -140,16 +140,17 @@ func TestAdmitCaps(t *testing.T) {
140
140
for i := 0 ; i < 2 ; i ++ {
141
141
for k , v := range tc {
142
142
v .pod .Spec .Containers , v .pod .Spec .InitContainers = v .pod .Spec .InitContainers , v .pod .Spec .Containers
143
+
144
+ testSCCAdmit (k , v .sccs , v .pod , v .shouldPass , t )
145
+
143
146
containers := v .pod .Spec .Containers
144
147
if i == 0 {
145
148
containers = v .pod .Spec .InitContainers
146
149
}
147
150
148
- testSCCAdmit (k , v .sccs , v .pod , v .shouldPass , t )
149
-
150
151
if v .expectedCapabilities != nil {
151
152
if ! reflect .DeepEqual (v .expectedCapabilities , containers [0 ].SecurityContext .Capabilities ) {
152
- t .Errorf ("%s resulted in caps that were not expected - expected: %v, received: %v" , k , v .expectedCapabilities , containers [0 ].SecurityContext .Capabilities )
153
+ t .Errorf ("%s resulted in caps that were not expected - expected: %# v, received: %# v" , k , v .expectedCapabilities , containers [0 ].SecurityContext .Capabilities )
153
154
}
154
155
}
155
156
}
@@ -239,43 +240,44 @@ func TestAdmitSuccess(t *testing.T) {
239
240
"specifyUIDInRange" : {
240
241
pod : specifyUIDInRange ,
241
242
expectedPodSC : podSC (seLinuxLevelFromNamespace , defaultGroup , defaultGroup ),
242
- expectedContainerSC : containerSC (seLinuxLevelFromNamespace , goodUID ),
243
+ expectedContainerSC : containerSC (nil , goodUID ),
243
244
},
244
245
"specifyLabels" : {
245
246
pod : specifyLabels ,
246
247
expectedPodSC : podSC (seLinuxLevelFromNamespace , defaultGroup , defaultGroup ),
247
- expectedContainerSC : containerSC (seLinuxLevelFromNamespace , 1 ),
248
+ expectedContainerSC : containerSC (& seLinuxLevelFromNamespace , 1 ),
248
249
},
249
250
"specifyFSGroup" : {
250
251
pod : specifyFSGroupInRange ,
251
252
expectedPodSC : podSC (seLinuxLevelFromNamespace , goodFSGroup , defaultGroup ),
252
- expectedContainerSC : containerSC (seLinuxLevelFromNamespace , 1 ),
253
+ expectedContainerSC : containerSC (nil , 1 ),
253
254
},
254
255
"specifySupGroup" : {
255
256
pod : specifySupGroup ,
256
257
expectedPodSC : podSC (seLinuxLevelFromNamespace , defaultGroup , 3 ),
257
- expectedContainerSC : containerSC (seLinuxLevelFromNamespace , 1 ),
258
+ expectedContainerSC : containerSC (nil , 1 ),
258
259
},
259
260
"specifyPodLevelSELinuxLevel" : {
260
261
pod : specifyPodLevelSELinux ,
261
262
expectedPodSC : podSC (seLinuxLevelFromNamespace , defaultGroup , defaultGroup ),
262
- expectedContainerSC : containerSC (seLinuxLevelFromNamespace , 1 ),
263
+ expectedContainerSC : containerSC (nil , 1 ),
263
264
},
264
265
}
265
266
266
267
for i := 0 ; i < 2 ; i ++ {
267
268
for k , v := range testCases {
268
269
v .pod .Spec .Containers , v .pod .Spec .InitContainers = v .pod .Spec .InitContainers , v .pod .Spec .Containers
269
- containers := v .pod .Spec .Containers
270
- if i == 0 {
271
- containers = v .pod .Spec .InitContainers
272
- }
273
270
274
271
hasErrors := testSCCAdmission (v .pod , p , saSCC .Name , k , t )
275
272
if hasErrors {
276
273
continue
277
274
}
278
275
276
+ containers := v .pod .Spec .Containers
277
+ if i == 0 {
278
+ containers = v .pod .Spec .InitContainers
279
+ }
280
+
279
281
if ! reflect .DeepEqual (v .expectedPodSC , v .pod .Spec .SecurityContext ) {
280
282
t .Errorf ("%s unexpected pod SecurityContext diff:\n %s" , k , diff .ObjectGoPrintSideBySide (v .expectedPodSC , v .pod .Spec .SecurityContext ))
281
283
}
@@ -934,6 +936,85 @@ func TestAdmitSeccomp(t *testing.T) {
934
936
935
937
}
936
938
939
+ func TestAdmitPreferNonmutatingWhenPossible (t * testing.T ) {
940
+
941
+ mutatingSCC := restrictiveSCC ()
942
+ mutatingSCC .Name = "mutating-scc"
943
+
944
+ nonMutatingSCC := laxSCC ()
945
+ nonMutatingSCC .Name = "non-mutating-scc"
946
+
947
+ simplePod := goodPod ()
948
+ simplePod .Spec .Containers [0 ].Name = "simple-pod"
949
+ simplePod .Spec .Containers [0 ].Image = "test-image:0.1"
950
+
951
+ modifiedPod := simplePod .DeepCopy ()
952
+ modifiedPod .Spec .Containers [0 ].Image = "test-image:0.2"
953
+
954
+ tests := map [string ]struct {
955
+ oldPod * kapi.Pod
956
+ newPod * kapi.Pod
957
+ operation kadmission.Operation
958
+ sccs []* securityapi.SecurityContextConstraints
959
+ shouldPass bool
960
+ expectedSCC string
961
+ }{
962
+ "creation: the first SCC (even if it mutates) should be used" : {
963
+ newPod : simplePod .DeepCopy (),
964
+ operation : kadmission .Create ,
965
+ sccs : []* securityapi.SecurityContextConstraints {mutatingSCC , nonMutatingSCC },
966
+ shouldPass : true ,
967
+ expectedSCC : mutatingSCC .Name ,
968
+ },
969
+ "updating: the first non-mutating SCC should be used" : {
970
+ oldPod : simplePod .DeepCopy (),
971
+ newPod : modifiedPod .DeepCopy (),
972
+ operation : kadmission .Update ,
973
+ sccs : []* securityapi.SecurityContextConstraints {mutatingSCC , nonMutatingSCC },
974
+ shouldPass : true ,
975
+ expectedSCC : nonMutatingSCC .Name ,
976
+ },
977
+ "updating: a pod should be rejected when there are only mutating SCCs" : {
978
+ oldPod : simplePod .DeepCopy (),
979
+ newPod : modifiedPod .DeepCopy (),
980
+ operation : kadmission .Update ,
981
+ sccs : []* securityapi.SecurityContextConstraints {mutatingSCC },
982
+ shouldPass : false ,
983
+ },
984
+ }
985
+
986
+ for testCaseName , testCase := range tests {
987
+ // We can't use testSCCAdmission() here because it doesn't support Update operation.
988
+ // We can't use testSCCAdmit() here because it doesn't support Update operation and doesn't check for the SCC annotation.
989
+
990
+ tc := setupClientSet ()
991
+ lister := createSCCLister (t , testCase .sccs )
992
+ plugin := NewTestAdmission (lister , tc )
993
+
994
+ attrs := kadmission .NewAttributesRecord (testCase .newPod , testCase .oldPod , kapi .Kind ("Pod" ).WithVersion ("version" ), testCase .newPod .Namespace , testCase .newPod .Name , kapi .Resource ("pods" ).WithVersion ("version" ), "" , testCase .operation , & user.DefaultInfo {})
995
+ err := plugin .(kadmission.MutationInterface ).Admit (attrs )
996
+
997
+ if testCase .shouldPass {
998
+ if err != nil {
999
+ t .Errorf ("%s expected no errors but received %v" , testCaseName , err )
1000
+ } else {
1001
+ validatedSCC , ok := testCase .newPod .Annotations [allocator .ValidatedSCCAnnotation ]
1002
+ if ! ok {
1003
+ t .Errorf ("expected %q to find the validated annotation on the pod for the scc but found none" , testCaseName )
1004
+
1005
+ } else if validatedSCC != testCase .expectedSCC {
1006
+ t .Errorf ("%q should have validated against %q but found %q" , testCaseName , testCase .expectedSCC , validatedSCC )
1007
+ }
1008
+ }
1009
+ } else {
1010
+ if err == nil {
1011
+ t .Errorf ("%s expected errors but received none" , testCaseName )
1012
+ }
1013
+ }
1014
+ }
1015
+
1016
+ }
1017
+
937
1018
// testSCCAdmission is a helper to admit the pod and ensure it was validated against the expected
938
1019
// SCC. Returns true when errors have been encountered.
939
1020
func testSCCAdmission (pod * kapi.Pod , plugin kadmission.Interface , expectedSCC , testName string , t * testing.T ) bool {
@@ -1087,15 +1168,16 @@ func goodPod() *kapi.Pod {
1087
1168
}
1088
1169
}
1089
1170
1090
- func containerSC (seLinuxLevel string , uid int64 ) * kapi.SecurityContext {
1091
- no := false
1092
- return & kapi. SecurityContext {
1093
- Privileged : & no ,
1094
- RunAsUser : & uid ,
1095
- SELinuxOptions : & kapi.SELinuxOptions {
1096
- Level : seLinuxLevel ,
1097
- },
1171
+ func containerSC (seLinuxLevel * string , uid int64 ) * kapi.SecurityContext {
1172
+ sc := & kapi. SecurityContext {
1173
+ RunAsUser : & uid ,
1174
+ }
1175
+ if seLinuxLevel != nil {
1176
+ sc . SELinuxOptions = & kapi.SELinuxOptions {
1177
+ Level : * seLinuxLevel ,
1178
+ }
1098
1179
}
1180
+ return sc
1099
1181
}
1100
1182
1101
1183
func podSC (seLinuxLevel string , fsGroup , supGroup int64 ) * kapi.PodSecurityContext {
0 commit comments