k8s.io/kubernetes@v1.29.3/pkg/securitycontext/accessors_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package securitycontext 18 19 import ( 20 "reflect" 21 "testing" 22 23 "k8s.io/apimachinery/pkg/util/diff" 24 api "k8s.io/kubernetes/pkg/apis/core" 25 "k8s.io/utils/pointer" 26 ) 27 28 func TestPodSecurityContextAccessor(t *testing.T) { 29 fsGroup := int64(2) 30 runAsUser := int64(1) 31 runAsGroup := int64(1) 32 runAsNonRoot := true 33 34 testcases := []*api.PodSecurityContext{ 35 nil, 36 {}, 37 {FSGroup: &fsGroup}, 38 {HostIPC: true}, 39 {HostNetwork: true}, 40 {HostPID: true}, 41 {RunAsNonRoot: &runAsNonRoot}, 42 {RunAsUser: &runAsUser}, 43 {RunAsGroup: &runAsGroup}, 44 {SELinuxOptions: &api.SELinuxOptions{User: "bob"}}, 45 {SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}}, 46 {SupplementalGroups: []int64{1, 2, 3}}, 47 } 48 49 for i, tc := range testcases { 50 expected := tc 51 if expected == nil { 52 expected = &api.PodSecurityContext{} 53 } 54 55 a := NewPodSecurityContextAccessor(tc) 56 57 if v := a.FSGroup(); !reflect.DeepEqual(expected.FSGroup, v) { 58 t.Errorf("%d: expected %#v, got %#v", i, expected.FSGroup, v) 59 } 60 if v := a.HostIPC(); !reflect.DeepEqual(expected.HostIPC, v) { 61 t.Errorf("%d: expected %#v, got %#v", i, expected.HostIPC, v) 62 } 63 if v := a.HostNetwork(); !reflect.DeepEqual(expected.HostNetwork, v) { 64 t.Errorf("%d: expected %#v, got %#v", i, expected.HostNetwork, v) 65 } 66 if v := a.HostPID(); !reflect.DeepEqual(expected.HostPID, v) { 67 t.Errorf("%d: expected %#v, got %#v", i, expected.HostPID, v) 68 } 69 if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) { 70 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v) 71 } 72 if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) { 73 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v) 74 } 75 if v := a.RunAsGroup(); !reflect.DeepEqual(expected.RunAsGroup, v) { 76 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsGroup, v) 77 } 78 if v := a.SeccompProfile(); !reflect.DeepEqual(expected.SeccompProfile, v) { 79 t.Errorf("%d: expected %#v, got %#v", i, expected.SeccompProfile, v) 80 } 81 if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) { 82 t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v) 83 } 84 if v := a.SupplementalGroups(); !reflect.DeepEqual(expected.SupplementalGroups, v) { 85 t.Errorf("%d: expected %#v, got %#v", i, expected.SupplementalGroups, v) 86 } 87 } 88 } 89 90 func TestPodSecurityContextMutator(t *testing.T) { 91 testcases := map[string]struct { 92 newSC func() *api.PodSecurityContext 93 }{ 94 "nil": { 95 newSC: func() *api.PodSecurityContext { return nil }, 96 }, 97 "zero": { 98 newSC: func() *api.PodSecurityContext { return &api.PodSecurityContext{} }, 99 }, 100 "populated": { 101 newSC: func() *api.PodSecurityContext { 102 return &api.PodSecurityContext{ 103 HostNetwork: true, 104 HostIPC: true, 105 HostPID: true, 106 SELinuxOptions: &api.SELinuxOptions{}, 107 RunAsUser: nil, 108 RunAsGroup: nil, 109 RunAsNonRoot: nil, 110 SeccompProfile: nil, 111 SupplementalGroups: nil, 112 FSGroup: nil, 113 } 114 }, 115 }, 116 } 117 118 nonNilSC := func(sc *api.PodSecurityContext) *api.PodSecurityContext { 119 if sc == nil { 120 return &api.PodSecurityContext{} 121 } 122 return sc 123 } 124 125 for k, tc := range testcases { 126 { 127 sc := tc.newSC() 128 originalSC := tc.newSC() 129 m := NewPodSecurityContextMutator(sc) 130 131 // no-op sets should not modify the object 132 m.SetFSGroup(m.FSGroup()) 133 m.SetHostNetwork(m.HostNetwork()) 134 m.SetHostIPC(m.HostIPC()) 135 m.SetHostPID(m.HostPID()) 136 m.SetRunAsNonRoot(m.RunAsNonRoot()) 137 m.SetRunAsUser(m.RunAsUser()) 138 m.SetRunAsGroup(m.RunAsGroup()) 139 m.SetSeccompProfile(m.SeccompProfile()) 140 m.SetSELinuxOptions(m.SELinuxOptions()) 141 m.SetSupplementalGroups(m.SupplementalGroups()) 142 if !reflect.DeepEqual(sc, originalSC) { 143 t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC) 144 } 145 if !reflect.DeepEqual(m.PodSecurityContext(), originalSC) { 146 t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.PodSecurityContext(), originalSC) 147 } 148 } 149 150 // FSGroup 151 { 152 modifiedSC := nonNilSC(tc.newSC()) 153 m := NewPodSecurityContextMutator(tc.newSC()) 154 i := int64(1123) 155 modifiedSC.FSGroup = &i 156 m.SetFSGroup(&i) 157 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 158 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 159 continue 160 } 161 } 162 163 // HostNetwork 164 { 165 modifiedSC := nonNilSC(tc.newSC()) 166 m := NewPodSecurityContextMutator(tc.newSC()) 167 modifiedSC.HostNetwork = !modifiedSC.HostNetwork 168 m.SetHostNetwork(!m.HostNetwork()) 169 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 170 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 171 continue 172 } 173 } 174 175 // HostIPC 176 { 177 modifiedSC := nonNilSC(tc.newSC()) 178 m := NewPodSecurityContextMutator(tc.newSC()) 179 modifiedSC.HostIPC = !modifiedSC.HostIPC 180 m.SetHostIPC(!m.HostIPC()) 181 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 182 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 183 continue 184 } 185 } 186 187 // HostPID 188 { 189 modifiedSC := nonNilSC(tc.newSC()) 190 m := NewPodSecurityContextMutator(tc.newSC()) 191 modifiedSC.HostPID = !modifiedSC.HostPID 192 m.SetHostPID(!m.HostPID()) 193 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 194 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 195 continue 196 } 197 } 198 199 // RunAsNonRoot 200 { 201 modifiedSC := nonNilSC(tc.newSC()) 202 m := NewPodSecurityContextMutator(tc.newSC()) 203 b := true 204 modifiedSC.RunAsNonRoot = &b 205 m.SetRunAsNonRoot(&b) 206 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 207 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 208 continue 209 } 210 } 211 212 // RunAsUser 213 { 214 modifiedSC := nonNilSC(tc.newSC()) 215 m := NewPodSecurityContextMutator(tc.newSC()) 216 i := int64(1123) 217 modifiedSC.RunAsUser = &i 218 m.SetRunAsUser(&i) 219 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 220 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 221 continue 222 } 223 } 224 225 // RunAsGroup 226 { 227 modifiedSC := nonNilSC(tc.newSC()) 228 m := NewPodSecurityContextMutator(tc.newSC()) 229 i := int64(1123) 230 modifiedSC.RunAsGroup = &i 231 m.SetRunAsGroup(&i) 232 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 233 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 234 continue 235 } 236 } 237 238 // SELinuxOptions 239 { 240 modifiedSC := nonNilSC(tc.newSC()) 241 m := NewPodSecurityContextMutator(tc.newSC()) 242 modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"} 243 m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"}) 244 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 245 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 246 continue 247 } 248 } 249 250 // SeccompProfile 251 { 252 modifiedSC := nonNilSC(tc.newSC()) 253 m := NewPodSecurityContextMutator(tc.newSC()) 254 modifiedSC.SeccompProfile = &api.SeccompProfile{Type: api.SeccompProfileTypeLocalhost, LocalhostProfile: pointer.String("verylocalhostey")} 255 m.SetSeccompProfile(&api.SeccompProfile{Type: api.SeccompProfileTypeLocalhost, LocalhostProfile: pointer.String("verylocalhostey")}) 256 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 257 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 258 continue 259 } 260 } 261 262 // SupplementalGroups 263 { 264 modifiedSC := nonNilSC(tc.newSC()) 265 m := NewPodSecurityContextMutator(tc.newSC()) 266 modifiedSC.SupplementalGroups = []int64{1, 1, 2, 3} 267 m.SetSupplementalGroups([]int64{1, 1, 2, 3}) 268 if !reflect.DeepEqual(m.PodSecurityContext(), modifiedSC) { 269 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.PodSecurityContext())) 270 continue 271 } 272 } 273 } 274 } 275 276 func TestContainerSecurityContextAccessor(t *testing.T) { 277 privileged := true 278 runAsUser := int64(1) 279 runAsGroup := int64(1) 280 runAsNonRoot := true 281 readOnlyRootFilesystem := true 282 allowPrivilegeEscalation := true 283 284 testcases := []*api.SecurityContext{ 285 nil, 286 {}, 287 {Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}}}, 288 {Privileged: &privileged}, 289 {SELinuxOptions: &api.SELinuxOptions{User: "bob"}}, 290 {RunAsUser: &runAsUser}, 291 {RunAsGroup: &runAsGroup}, 292 {RunAsNonRoot: &runAsNonRoot}, 293 {ReadOnlyRootFilesystem: &readOnlyRootFilesystem}, 294 {SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}}, 295 {AllowPrivilegeEscalation: &allowPrivilegeEscalation}, 296 } 297 298 for i, tc := range testcases { 299 expected := tc 300 if expected == nil { 301 expected = &api.SecurityContext{} 302 } 303 304 a := NewContainerSecurityContextAccessor(tc) 305 306 if v := a.Capabilities(); !reflect.DeepEqual(expected.Capabilities, v) { 307 t.Errorf("%d: expected %#v, got %#v", i, expected.Capabilities, v) 308 } 309 if v := a.Privileged(); !reflect.DeepEqual(expected.Privileged, v) { 310 t.Errorf("%d: expected %#v, got %#v", i, expected.Privileged, v) 311 } 312 if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) { 313 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v) 314 } 315 if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) { 316 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v) 317 } 318 if v := a.RunAsGroup(); !reflect.DeepEqual(expected.RunAsGroup, v) { 319 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsGroup, v) 320 } 321 if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) { 322 t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v) 323 } 324 if v := a.ReadOnlyRootFilesystem(); !reflect.DeepEqual(expected.ReadOnlyRootFilesystem, v) { 325 t.Errorf("%d: expected %#v, got %#v", i, expected.ReadOnlyRootFilesystem, v) 326 } 327 if v := a.SeccompProfile(); !reflect.DeepEqual(expected.SeccompProfile, v) { 328 t.Errorf("%d: expected %#v, got %#v", i, expected.SeccompProfile, v) 329 } 330 if v := a.AllowPrivilegeEscalation(); !reflect.DeepEqual(expected.AllowPrivilegeEscalation, v) { 331 t.Errorf("%d: expected %#v, got %#v", i, expected.AllowPrivilegeEscalation, v) 332 } 333 } 334 } 335 336 func TestContainerSecurityContextMutator(t *testing.T) { 337 testcases := map[string]struct { 338 newSC func() *api.SecurityContext 339 }{ 340 "nil": { 341 newSC: func() *api.SecurityContext { return nil }, 342 }, 343 "zero": { 344 newSC: func() *api.SecurityContext { return &api.SecurityContext{} }, 345 }, 346 "populated": { 347 newSC: func() *api.SecurityContext { 348 return &api.SecurityContext{ 349 Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}}, 350 SELinuxOptions: &api.SELinuxOptions{}, 351 SeccompProfile: &api.SeccompProfile{}, 352 } 353 }, 354 }, 355 } 356 357 nonNilSC := func(sc *api.SecurityContext) *api.SecurityContext { 358 if sc == nil { 359 return &api.SecurityContext{} 360 } 361 return sc 362 } 363 364 for k, tc := range testcases { 365 { 366 sc := tc.newSC() 367 originalSC := tc.newSC() 368 m := NewContainerSecurityContextMutator(sc) 369 370 // no-op sets should not modify the object 371 m.SetAllowPrivilegeEscalation(m.AllowPrivilegeEscalation()) 372 m.SetCapabilities(m.Capabilities()) 373 m.SetPrivileged(m.Privileged()) 374 m.SetReadOnlyRootFilesystem(m.ReadOnlyRootFilesystem()) 375 m.SetRunAsNonRoot(m.RunAsNonRoot()) 376 m.SetRunAsUser(m.RunAsUser()) 377 m.SetRunAsGroup(m.RunAsGroup()) 378 m.SetSELinuxOptions(m.SELinuxOptions()) 379 if !reflect.DeepEqual(sc, originalSC) { 380 t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC) 381 } 382 if !reflect.DeepEqual(m.ContainerSecurityContext(), originalSC) { 383 t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.ContainerSecurityContext(), originalSC) 384 } 385 } 386 387 // AllowPrivilegeEscalation 388 { 389 modifiedSC := nonNilSC(tc.newSC()) 390 m := NewContainerSecurityContextMutator(tc.newSC()) 391 b := true 392 modifiedSC.AllowPrivilegeEscalation = &b 393 m.SetAllowPrivilegeEscalation(&b) 394 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 395 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 396 continue 397 } 398 } 399 400 // Capabilities 401 { 402 modifiedSC := nonNilSC(tc.newSC()) 403 m := NewContainerSecurityContextMutator(tc.newSC()) 404 modifiedSC.Capabilities = &api.Capabilities{Drop: []api.Capability{"test2"}} 405 m.SetCapabilities(&api.Capabilities{Drop: []api.Capability{"test2"}}) 406 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 407 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 408 continue 409 } 410 } 411 412 // Privileged 413 { 414 modifiedSC := nonNilSC(tc.newSC()) 415 m := NewContainerSecurityContextMutator(tc.newSC()) 416 b := true 417 modifiedSC.Privileged = &b 418 m.SetPrivileged(&b) 419 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 420 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 421 continue 422 } 423 } 424 425 // ReadOnlyRootFilesystem 426 { 427 modifiedSC := nonNilSC(tc.newSC()) 428 m := NewContainerSecurityContextMutator(tc.newSC()) 429 b := true 430 modifiedSC.ReadOnlyRootFilesystem = &b 431 m.SetReadOnlyRootFilesystem(&b) 432 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 433 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 434 continue 435 } 436 } 437 438 // RunAsNonRoot 439 { 440 modifiedSC := nonNilSC(tc.newSC()) 441 m := NewContainerSecurityContextMutator(tc.newSC()) 442 b := true 443 modifiedSC.RunAsNonRoot = &b 444 m.SetRunAsNonRoot(&b) 445 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 446 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 447 continue 448 } 449 } 450 451 // RunAsUser 452 { 453 modifiedSC := nonNilSC(tc.newSC()) 454 m := NewContainerSecurityContextMutator(tc.newSC()) 455 i := int64(1123) 456 modifiedSC.RunAsUser = &i 457 m.SetRunAsUser(&i) 458 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 459 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 460 continue 461 } 462 } 463 464 // RunAsGroup 465 { 466 modifiedSC := nonNilSC(tc.newSC()) 467 m := NewContainerSecurityContextMutator(tc.newSC()) 468 i := int64(1123) 469 modifiedSC.RunAsGroup = &i 470 m.SetRunAsGroup(&i) 471 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 472 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 473 continue 474 } 475 } 476 477 // SeccompProfile 478 { 479 modifiedSC := nonNilSC(tc.newSC()) 480 m := NewContainerSecurityContextMutator(tc.newSC()) 481 modifiedSC.SeccompProfile = &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined} 482 m.SetSeccompProfile(&api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}) 483 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 484 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 485 continue 486 } 487 } 488 489 // SELinuxOptions 490 { 491 modifiedSC := nonNilSC(tc.newSC()) 492 m := NewContainerSecurityContextMutator(tc.newSC()) 493 modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"} 494 m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"}) 495 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 496 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 497 continue 498 } 499 } 500 } 501 } 502 503 func TestEffectiveContainerSecurityContextAccessor(t *testing.T) { 504 privileged := true 505 runAsUser := int64(1) 506 runAsUserPod := int64(12) 507 runAsGroup := int64(1) 508 runAsGroupPod := int64(12) 509 runAsNonRoot := true 510 runAsNonRootPod := false 511 readOnlyRootFilesystem := true 512 allowPrivilegeEscalation := true 513 514 testcases := []struct { 515 PodSC *api.PodSecurityContext 516 SC *api.SecurityContext 517 Effective *api.SecurityContext 518 }{ 519 { 520 PodSC: nil, 521 SC: nil, 522 Effective: nil, 523 }, 524 { 525 PodSC: &api.PodSecurityContext{}, 526 SC: &api.SecurityContext{}, 527 Effective: &api.SecurityContext{}, 528 }, 529 { 530 PodSC: &api.PodSecurityContext{ 531 SELinuxOptions: &api.SELinuxOptions{User: "bob"}, 532 SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}, 533 RunAsUser: &runAsUser, 534 RunAsNonRoot: &runAsNonRoot, 535 }, 536 SC: nil, 537 Effective: &api.SecurityContext{ 538 SELinuxOptions: &api.SELinuxOptions{User: "bob"}, 539 SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}, 540 RunAsUser: &runAsUser, 541 RunAsNonRoot: &runAsNonRoot, 542 }, 543 }, 544 { 545 PodSC: &api.PodSecurityContext{ 546 SELinuxOptions: &api.SELinuxOptions{User: "bob"}, 547 SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}, 548 RunAsUser: &runAsUserPod, 549 RunAsNonRoot: &runAsNonRootPod, 550 }, 551 SC: &api.SecurityContext{}, 552 Effective: &api.SecurityContext{ 553 SELinuxOptions: &api.SELinuxOptions{User: "bob"}, 554 SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}, 555 RunAsUser: &runAsUserPod, 556 RunAsNonRoot: &runAsNonRootPod, 557 }, 558 }, 559 { 560 PodSC: &api.PodSecurityContext{ 561 SELinuxOptions: &api.SELinuxOptions{User: "bob"}, 562 SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}, 563 RunAsUser: &runAsUserPod, 564 RunAsNonRoot: &runAsNonRootPod, 565 }, 566 SC: &api.SecurityContext{ 567 AllowPrivilegeEscalation: &allowPrivilegeEscalation, 568 Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}}, 569 Privileged: &privileged, 570 ReadOnlyRootFilesystem: &readOnlyRootFilesystem, 571 RunAsUser: &runAsUser, 572 RunAsNonRoot: &runAsNonRoot, 573 SELinuxOptions: &api.SELinuxOptions{User: "bob"}, 574 SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}, 575 }, 576 Effective: &api.SecurityContext{ 577 AllowPrivilegeEscalation: &allowPrivilegeEscalation, 578 Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}}, 579 Privileged: &privileged, 580 ReadOnlyRootFilesystem: &readOnlyRootFilesystem, 581 RunAsUser: &runAsUser, 582 RunAsNonRoot: &runAsNonRoot, 583 SELinuxOptions: &api.SELinuxOptions{User: "bob"}, 584 SeccompProfile: &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}, 585 }, 586 }, 587 { 588 PodSC: &api.PodSecurityContext{ 589 RunAsGroup: &runAsGroup, 590 }, 591 SC: nil, 592 Effective: &api.SecurityContext{ 593 RunAsGroup: &runAsGroup, 594 }, 595 }, 596 { 597 PodSC: &api.PodSecurityContext{ 598 RunAsGroup: &runAsGroupPod, 599 }, 600 SC: &api.SecurityContext{ 601 RunAsGroup: &runAsGroup, 602 }, 603 Effective: &api.SecurityContext{ 604 RunAsGroup: &runAsGroup, 605 }, 606 }, 607 } 608 609 for i, tc := range testcases { 610 expected := tc.Effective 611 if expected == nil { 612 expected = &api.SecurityContext{} 613 } 614 615 a := NewEffectiveContainerSecurityContextAccessor( 616 NewPodSecurityContextAccessor(tc.PodSC), 617 NewContainerSecurityContextMutator(tc.SC), 618 ) 619 620 if v := a.Capabilities(); !reflect.DeepEqual(expected.Capabilities, v) { 621 t.Errorf("%d: expected %#v, got %#v", i, expected.Capabilities, v) 622 } 623 if v := a.Privileged(); !reflect.DeepEqual(expected.Privileged, v) { 624 t.Errorf("%d: expected %#v, got %#v", i, expected.Privileged, v) 625 } 626 if v := a.RunAsNonRoot(); !reflect.DeepEqual(expected.RunAsNonRoot, v) { 627 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsNonRoot, v) 628 } 629 if v := a.RunAsUser(); !reflect.DeepEqual(expected.RunAsUser, v) { 630 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsUser, v) 631 } 632 if v := a.RunAsGroup(); !reflect.DeepEqual(expected.RunAsGroup, v) { 633 t.Errorf("%d: expected %#v, got %#v", i, expected.RunAsGroup, v) 634 } 635 if v := a.SELinuxOptions(); !reflect.DeepEqual(expected.SELinuxOptions, v) { 636 t.Errorf("%d: expected %#v, got %#v", i, expected.SELinuxOptions, v) 637 } 638 if v := a.ReadOnlyRootFilesystem(); !reflect.DeepEqual(expected.ReadOnlyRootFilesystem, v) { 639 t.Errorf("%d: expected %#v, got %#v", i, expected.ReadOnlyRootFilesystem, v) 640 } 641 if v := a.AllowPrivilegeEscalation(); !reflect.DeepEqual(expected.AllowPrivilegeEscalation, v) { 642 t.Errorf("%d: expected %#v, got %#v", i, expected.AllowPrivilegeEscalation, v) 643 } 644 } 645 } 646 647 func TestEffectiveContainerSecurityContextMutator(t *testing.T) { 648 runAsNonRootPod := false 649 runAsUserPod := int64(12) 650 651 testcases := map[string]struct { 652 newPodSC func() *api.PodSecurityContext 653 newSC func() *api.SecurityContext 654 }{ 655 "nil": { 656 newPodSC: func() *api.PodSecurityContext { return nil }, 657 newSC: func() *api.SecurityContext { return nil }, 658 }, 659 "zero": { 660 newPodSC: func() *api.PodSecurityContext { return &api.PodSecurityContext{} }, 661 newSC: func() *api.SecurityContext { return &api.SecurityContext{} }, 662 }, 663 "populated pod sc": { 664 newPodSC: func() *api.PodSecurityContext { 665 return &api.PodSecurityContext{ 666 SELinuxOptions: &api.SELinuxOptions{User: "poduser"}, 667 SeccompProfile: &api.SeccompProfile{}, 668 RunAsNonRoot: &runAsNonRootPod, 669 RunAsUser: &runAsUserPod, 670 } 671 }, 672 newSC: func() *api.SecurityContext { 673 return &api.SecurityContext{} 674 }, 675 }, 676 "populated sc": { 677 newPodSC: func() *api.PodSecurityContext { return nil }, 678 newSC: func() *api.SecurityContext { 679 return &api.SecurityContext{ 680 Capabilities: &api.Capabilities{Drop: []api.Capability{"test"}}, 681 SELinuxOptions: &api.SELinuxOptions{}, 682 SeccompProfile: &api.SeccompProfile{}, 683 } 684 }, 685 }, 686 } 687 688 nonNilSC := func(sc *api.SecurityContext) *api.SecurityContext { 689 if sc == nil { 690 return &api.SecurityContext{} 691 } 692 return sc 693 } 694 695 for k, tc := range testcases { 696 { 697 podSC := tc.newPodSC() 698 sc := tc.newSC() 699 originalPodSC := tc.newPodSC() 700 originalSC := tc.newSC() 701 m := NewEffectiveContainerSecurityContextMutator( 702 NewPodSecurityContextAccessor(podSC), 703 NewContainerSecurityContextMutator(sc), 704 ) 705 706 // no-op sets should not modify the object 707 m.SetAllowPrivilegeEscalation(m.AllowPrivilegeEscalation()) 708 m.SetCapabilities(m.Capabilities()) 709 m.SetPrivileged(m.Privileged()) 710 m.SetReadOnlyRootFilesystem(m.ReadOnlyRootFilesystem()) 711 m.SetRunAsNonRoot(m.RunAsNonRoot()) 712 m.SetRunAsUser(m.RunAsUser()) 713 m.SetRunAsGroup(m.RunAsGroup()) 714 m.SetSELinuxOptions(m.SELinuxOptions()) 715 m.SetSeccompProfile(m.SeccompProfile()) 716 if !reflect.DeepEqual(podSC, originalPodSC) { 717 t.Errorf("%s: unexpected mutation: %#v, %#v", k, podSC, originalPodSC) 718 } 719 if !reflect.DeepEqual(sc, originalSC) { 720 t.Errorf("%s: unexpected mutation: %#v, %#v", k, sc, originalSC) 721 } 722 if !reflect.DeepEqual(m.ContainerSecurityContext(), originalSC) { 723 t.Errorf("%s: unexpected mutation: %#v, %#v", k, m.ContainerSecurityContext(), originalSC) 724 } 725 } 726 727 // AllowPrivilegeEscalation 728 { 729 modifiedSC := nonNilSC(tc.newSC()) 730 m := NewEffectiveContainerSecurityContextMutator( 731 NewPodSecurityContextAccessor(tc.newPodSC()), 732 NewContainerSecurityContextMutator(tc.newSC()), 733 ) 734 b := true 735 modifiedSC.AllowPrivilegeEscalation = &b 736 m.SetAllowPrivilegeEscalation(&b) 737 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 738 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 739 continue 740 } 741 } 742 743 // Capabilities 744 { 745 modifiedSC := nonNilSC(tc.newSC()) 746 m := NewEffectiveContainerSecurityContextMutator( 747 NewPodSecurityContextAccessor(tc.newPodSC()), 748 NewContainerSecurityContextMutator(tc.newSC()), 749 ) 750 modifiedSC.Capabilities = &api.Capabilities{Drop: []api.Capability{"test2"}} 751 m.SetCapabilities(&api.Capabilities{Drop: []api.Capability{"test2"}}) 752 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 753 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 754 continue 755 } 756 } 757 758 // Privileged 759 { 760 modifiedSC := nonNilSC(tc.newSC()) 761 m := NewEffectiveContainerSecurityContextMutator( 762 NewPodSecurityContextAccessor(tc.newPodSC()), 763 NewContainerSecurityContextMutator(tc.newSC()), 764 ) 765 b := true 766 modifiedSC.Privileged = &b 767 m.SetPrivileged(&b) 768 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 769 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 770 continue 771 } 772 } 773 774 // ReadOnlyRootFilesystem 775 { 776 modifiedSC := nonNilSC(tc.newSC()) 777 m := NewEffectiveContainerSecurityContextMutator( 778 NewPodSecurityContextAccessor(tc.newPodSC()), 779 NewContainerSecurityContextMutator(tc.newSC()), 780 ) 781 b := true 782 modifiedSC.ReadOnlyRootFilesystem = &b 783 m.SetReadOnlyRootFilesystem(&b) 784 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 785 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 786 continue 787 } 788 } 789 790 // RunAsNonRoot 791 { 792 modifiedSC := nonNilSC(tc.newSC()) 793 m := NewEffectiveContainerSecurityContextMutator( 794 NewPodSecurityContextAccessor(tc.newPodSC()), 795 NewContainerSecurityContextMutator(tc.newSC()), 796 ) 797 b := true 798 modifiedSC.RunAsNonRoot = &b 799 m.SetRunAsNonRoot(&b) 800 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 801 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 802 continue 803 } 804 } 805 806 // RunAsUser 807 { 808 modifiedSC := nonNilSC(tc.newSC()) 809 m := NewEffectiveContainerSecurityContextMutator( 810 NewPodSecurityContextAccessor(tc.newPodSC()), 811 NewContainerSecurityContextMutator(tc.newSC()), 812 ) 813 i := int64(1123) 814 modifiedSC.RunAsUser = &i 815 m.SetRunAsUser(&i) 816 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 817 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 818 continue 819 } 820 } 821 822 // RunAsGroup 823 { 824 modifiedSC := nonNilSC(tc.newSC()) 825 m := NewEffectiveContainerSecurityContextMutator( 826 NewPodSecurityContextAccessor(tc.newPodSC()), 827 NewContainerSecurityContextMutator(tc.newSC()), 828 ) 829 i := int64(1123) 830 modifiedSC.RunAsGroup = &i 831 m.SetRunAsGroup(&i) 832 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 833 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 834 continue 835 } 836 } 837 838 // SeccompProfile 839 { 840 modifiedSC := nonNilSC(tc.newSC()) 841 m := NewContainerSecurityContextMutator(tc.newSC()) 842 modifiedSC.SeccompProfile = &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined} 843 m.SetSeccompProfile(&api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}) 844 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 845 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 846 continue 847 } 848 } 849 850 // SELinuxOptions 851 { 852 modifiedSC := nonNilSC(tc.newSC()) 853 m := NewEffectiveContainerSecurityContextMutator( 854 NewPodSecurityContextAccessor(tc.newPodSC()), 855 NewContainerSecurityContextMutator(tc.newSC()), 856 ) 857 modifiedSC.SELinuxOptions = &api.SELinuxOptions{User: "bob"} 858 m.SetSELinuxOptions(&api.SELinuxOptions{User: "bob"}) 859 if !reflect.DeepEqual(m.ContainerSecurityContext(), modifiedSC) { 860 t.Errorf("%s: unexpected object:\n%s", k, diff.ObjectGoPrintSideBySide(modifiedSC, m.ContainerSecurityContext())) 861 continue 862 } 863 } 864 } 865 }