From a577b50012bc9df2212f83678bca2c3b11c759d6 Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka Date: Fri, 15 Jun 2018 12:49:19 +0200 Subject: [PATCH] Add "MayRunAs" value among other GroupStrategies Adds "MayRunAs" value among other group strategies. This strategy allows to define a certain range of GIDs for FSGroupStrategy and SupplementalGroupStrategy in a PSP. This new strategy works similarly to the "MustRunAs" one, except that when no GID is specified in a pod/container security context then no GID is generated for the respective containers. Resolves #56173 --- pkg/apis/policy/fuzzer/fuzzer.go | 2 + pkg/apis/policy/types.go | 6 + pkg/apis/policy/validation/validation.go | 2 + pkg/apis/policy/validation/validation_test.go | 8 +- pkg/security/podsecuritypolicy/factory.go | 4 + pkg/security/podsecuritypolicy/group/BUILD | 3 + .../podsecuritypolicy/group/helpers.go | 46 +++++ .../podsecuritypolicy/group/mayrunas.go | 59 ++++++ .../podsecuritypolicy/group/mayrunas_test.go | 185 ++++++++++++++++++ .../podsecuritypolicy/group/mustrunas.go | 17 +- .../podsecuritypolicy/provider_test.go | 97 +++++++-- 11 files changed, 389 insertions(+), 40 deletions(-) create mode 100644 pkg/security/podsecuritypolicy/group/helpers.go create mode 100644 pkg/security/podsecuritypolicy/group/mayrunas.go create mode 100644 pkg/security/podsecuritypolicy/group/mayrunas_test.go diff --git a/pkg/apis/policy/fuzzer/fuzzer.go b/pkg/apis/policy/fuzzer/fuzzer.go index 184004fed14..1e01120005a 100644 --- a/pkg/apis/policy/fuzzer/fuzzer.go +++ b/pkg/apis/policy/fuzzer/fuzzer.go @@ -48,12 +48,14 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { supplementalGroupsRules := []policy.SupplementalGroupsStrategyType{ policy.SupplementalGroupsStrategyRunAsAny, + policy.SupplementalGroupsStrategyMayRunAs, policy.SupplementalGroupsStrategyMustRunAs, } psp.SupplementalGroups.Rule = supplementalGroupsRules[c.Rand.Intn(len(supplementalGroupsRules))] fsGroupRules := []policy.FSGroupStrategyType{ policy.FSGroupStrategyMustRunAs, + policy.FSGroupStrategyMayRunAs, policy.FSGroupStrategyRunAsAny, } psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))] diff --git a/pkg/apis/policy/types.go b/pkg/apis/policy/types.go index 7b9628657f1..d570059609e 100644 --- a/pkg/apis/policy/types.go +++ b/pkg/apis/policy/types.go @@ -372,6 +372,9 @@ type FSGroupStrategyOptions struct { type FSGroupStrategyType string const ( + // FSGroupStrategyMayRunAs means that container does not need to have FSGroup of X applied. + // However, when FSGroups are specified, they have to fall in the defined range. + FSGroupStrategyMayRunAs FSGroupStrategyType = "MayRunAs" // FSGroupStrategyMustRunAs means that container must have FSGroup of X applied. FSGroupStrategyMustRunAs FSGroupStrategyType = "MustRunAs" // FSGroupStrategyRunAsAny means that container may make requests for any FSGroup labels. @@ -394,6 +397,9 @@ type SupplementalGroupsStrategyOptions struct { type SupplementalGroupsStrategyType string const ( + // SupplementalGroupsStrategyMayRunAs means that container does not need to run with a particular gid. + // However, when gids are specified, they have to fall in the defined range. + SupplementalGroupsStrategyMayRunAs SupplementalGroupsStrategyType = "MayRunAs" // SupplementalGroupsStrategyMustRunAs means that container must run as a particular gid. SupplementalGroupsStrategyMustRunAs SupplementalGroupsStrategyType = "MustRunAs" // SupplementalGroupsStrategyRunAsAny means that container may make requests for any gid. diff --git a/pkg/apis/policy/validation/validation.go b/pkg/apis/policy/validation/validation.go index 54db7bc88df..424bebc0035 100644 --- a/pkg/apis/policy/validation/validation.go +++ b/pkg/apis/policy/validation/validation.go @@ -239,6 +239,7 @@ func validatePSPFSGroup(fldPath *field.Path, groupOptions *policy.FSGroupStrateg supportedRules := sets.NewString( string(policy.FSGroupStrategyMustRunAs), + string(policy.FSGroupStrategyMayRunAs), string(policy.FSGroupStrategyRunAsAny), ) if !supportedRules.Has(string(groupOptions.Rule)) { @@ -257,6 +258,7 @@ func validatePSPSupplementalGroup(fldPath *field.Path, groupOptions *policy.Supp supportedRules := sets.NewString( string(policy.SupplementalGroupsStrategyRunAsAny), + string(policy.SupplementalGroupsStrategyMayRunAs), string(policy.SupplementalGroupsStrategyMustRunAs), ) if !supportedRules.Has(string(groupOptions.Rule)) { diff --git a/pkg/apis/policy/validation/validation_test.go b/pkg/apis/policy/validation/validation_test.go index 552fd8cecab..37cf6670715 100644 --- a/pkg/apis/policy/validation/validation_test.go +++ b/pkg/apis/policy/validation/validation_test.go @@ -390,12 +390,12 @@ func TestValidatePodSecurityPolicy(t *testing.T) { "no fsgroup options": { psp: noFSGroupOptions, errorType: field.ErrorTypeNotSupported, - errorDetail: `supported values: "MustRunAs", "RunAsAny"`, + errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`, }, "no sup group options": { psp: noSupplementalGroupsOptions, errorType: field.ErrorTypeNotSupported, - errorDetail: `supported values: "MustRunAs", "RunAsAny"`, + errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`, }, "invalid user strategy type": { psp: invalidUserStratType, @@ -410,12 +410,12 @@ func TestValidatePodSecurityPolicy(t *testing.T) { "invalid sup group strategy type": { psp: invalidSupGroupStratType, errorType: field.ErrorTypeNotSupported, - errorDetail: `supported values: "MustRunAs", "RunAsAny"`, + errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`, }, "invalid fs group strategy type": { psp: invalidFSGroupStratType, errorType: field.ErrorTypeNotSupported, - errorDetail: `supported values: "MustRunAs", "RunAsAny"`, + errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`, }, "invalid uid": { psp: invalidUIDPSP, diff --git a/pkg/security/podsecuritypolicy/factory.go b/pkg/security/podsecuritypolicy/factory.go index cfa13ee10c9..c429eaf6c89 100644 --- a/pkg/security/podsecuritypolicy/factory.go +++ b/pkg/security/podsecuritypolicy/factory.go @@ -138,6 +138,8 @@ func createFSGroupStrategy(opts *policy.FSGroupStrategyOptions) (group.GroupStra switch opts.Rule { case policy.FSGroupStrategyRunAsAny: return group.NewRunAsAny() + case policy.FSGroupStrategyMayRunAs: + return group.NewMayRunAs(opts.Ranges) case policy.FSGroupStrategyMustRunAs: return group.NewMustRunAs(opts.Ranges) default: @@ -150,6 +152,8 @@ func createSupplementalGroupStrategy(opts *policy.SupplementalGroupsStrategyOpti switch opts.Rule { case policy.SupplementalGroupsStrategyRunAsAny: return group.NewRunAsAny() + case policy.SupplementalGroupsStrategyMayRunAs: + return group.NewMayRunAs(opts.Ranges) case policy.SupplementalGroupsStrategyMustRunAs: return group.NewMustRunAs(opts.Ranges) default: diff --git a/pkg/security/podsecuritypolicy/group/BUILD b/pkg/security/podsecuritypolicy/group/BUILD index 20f49accde5..ba98f7a6105 100644 --- a/pkg/security/podsecuritypolicy/group/BUILD +++ b/pkg/security/podsecuritypolicy/group/BUILD @@ -10,6 +10,8 @@ go_library( name = "go_default_library", srcs = [ "doc.go", + "helpers.go", + "mayrunas.go", "mustrunas.go", "runasany.go", "types.go", @@ -26,6 +28,7 @@ go_library( go_test( name = "go_default_test", srcs = [ + "mayrunas_test.go", "mustrunas_test.go", "runasany_test.go", ], diff --git a/pkg/security/podsecuritypolicy/group/helpers.go b/pkg/security/podsecuritypolicy/group/helpers.go new file mode 100644 index 00000000000..1fa2ecad0d0 --- /dev/null +++ b/pkg/security/podsecuritypolicy/group/helpers.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package group + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/kubernetes/pkg/apis/policy" + psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" +) + +func ValidateGroupsInRanges(fldPath *field.Path, ranges []policy.IDRange, groups []int64) field.ErrorList { + allErrs := field.ErrorList{} + + for _, group := range groups { + if !isGroupInRanges(group, ranges) { + detail := fmt.Sprintf("group %d must be in the ranges: %v", group, ranges) + allErrs = append(allErrs, field.Invalid(fldPath, groups, detail)) + } + } + return allErrs +} + +func isGroupInRanges(group int64, ranges []policy.IDRange) bool { + for _, rng := range ranges { + if psputil.GroupFallsInRange(group, rng) { + return true + } + } + return false +} diff --git a/pkg/security/podsecuritypolicy/group/mayrunas.go b/pkg/security/podsecuritypolicy/group/mayrunas.go new file mode 100644 index 00000000000..086f0c80928 --- /dev/null +++ b/pkg/security/podsecuritypolicy/group/mayrunas.go @@ -0,0 +1,59 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package group + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/util/validation/field" + api "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/apis/policy" +) + +// mayRunAs implements the GroupStrategy interface. +type mayRunAs struct { + ranges []policy.IDRange +} + +var _ GroupStrategy = &mayRunAs{} + +// NewMayRunAs provides a new MayRunAs strategy. +func NewMayRunAs(ranges []policy.IDRange) (GroupStrategy, error) { + if len(ranges) == 0 { + return nil, fmt.Errorf("ranges must be supplied for MayRunAs") + } + return &mayRunAs{ + ranges: ranges, + }, nil +} + +// Generate creates the group based on policy rules. This strategy returns an empty slice. +func (s *mayRunAs) Generate(_ *api.Pod) ([]int64, error) { + return nil, nil +} + +// Generate a single value to be applied. This is used for FSGroup. This strategy returns nil. +func (s *mayRunAs) GenerateSingle(_ *api.Pod) (*int64, error) { + return nil, nil +} + +// Validate ensures that the specified values fall within the range of the strategy. +// Groups are passed in here to allow this strategy to support multiple group fields (fsgroup and +// supplemental groups). +func (s *mayRunAs) Validate(fldPath *field.Path, _ *api.Pod, groups []int64) field.ErrorList { + return ValidateGroupsInRanges(fldPath, s.ranges, groups) +} diff --git a/pkg/security/podsecuritypolicy/group/mayrunas_test.go b/pkg/security/podsecuritypolicy/group/mayrunas_test.go new file mode 100644 index 00000000000..04288efee2c --- /dev/null +++ b/pkg/security/podsecuritypolicy/group/mayrunas_test.go @@ -0,0 +1,185 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package group + +import ( + "fmt" + "strings" + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/kubernetes/pkg/apis/policy" +) + +func TestMayRunAsOptions(t *testing.T) { + tests := map[string]struct { + ranges []policy.IDRange + pass bool + }{ + "empty": { + ranges: []policy.IDRange{}, + }, + "ranges": { + ranges: []policy.IDRange{ + {Min: 1, Max: 1}, + }, + pass: true, + }, + } + + for k, v := range tests { + _, err := NewMayRunAs(v.ranges) + if v.pass && err != nil { + t.Errorf("error creating strategy for %s: %v", k, err) + } + if !v.pass && err == nil { + t.Errorf("expected error for %s but got none", k) + } + } +} + +func TestMayRunAsValidate(t *testing.T) { + tests := map[string]struct { + ranges []policy.IDRange + groups []int64 + expectedErrors []string + }{ + "empty groups": { + ranges: []policy.IDRange{ + {Min: 1, Max: 3}, + }, + }, + "not in range": { + groups: []int64{5}, + ranges: []policy.IDRange{ + {Min: 1, Max: 3}, + {Min: 4, Max: 4}, + }, + expectedErrors: []string{"group 5 must be in the ranges: [{1 3} {4 4}]"}, + }, + "not in ranges - multiple groups": { + groups: []int64{5, 10, 2020}, + ranges: []policy.IDRange{ + {Min: 1, Max: 3}, + {Min: 15, Max: 70}, + }, + expectedErrors: []string{ + "group 5 must be in the ranges: [{1 3} {15 70}]", + "group 10 must be in the ranges: [{1 3} {15 70}]", + "group 2020 must be in the ranges: [{1 3} {15 70}]", + }, + }, + "not in ranges - one of multiple groups does not match": { + groups: []int64{5, 10, 2020}, + ranges: []policy.IDRange{ + {Min: 1, Max: 5}, + {Min: 8, Max: 12}, + {Min: 15, Max: 70}, + }, + expectedErrors: []string{ + "group 2020 must be in the ranges: [{1 5} {8 12} {15 70}]", + }, + }, + "in range 1": { + groups: []int64{2}, + ranges: []policy.IDRange{ + {Min: 1, Max: 3}, + }, + }, + "in range boundary min": { + groups: []int64{1}, + ranges: []policy.IDRange{ + {Min: 1, Max: 3}, + }, + }, + "in range boundary max": { + groups: []int64{3}, + ranges: []policy.IDRange{ + {Min: 1, Max: 3}, + }, + }, + "singular range": { + groups: []int64{4}, + ranges: []policy.IDRange{ + {Min: 4, Max: 4}, + }, + }, + "in one of multiple ranges": { + groups: []int64{4}, + ranges: []policy.IDRange{ + {Min: 1, Max: 4}, + {Min: 10, Max: 15}, + }, + }, + "multiple groups matches one range": { + groups: []int64{4, 8, 12}, + ranges: []policy.IDRange{ + {Min: 1, Max: 20}, + }, + }, + "multiple groups match multiple ranges": { + groups: []int64{4, 8, 12}, + ranges: []policy.IDRange{ + {Min: 1, Max: 4}, + {Min: 200, Max: 2000}, + {Min: 7, Max: 11}, + {Min: 5, Max: 7}, + {Min: 17, Max: 53}, + {Min: 12, Max: 71}, + }, + }, + } + + for k, v := range tests { + s, err := NewMayRunAs(v.ranges) + if err != nil { + t.Errorf("error creating strategy for %s: %v", k, err) + } + errs := s.Validate(field.NewPath(""), nil, v.groups) + if len(v.expectedErrors) != len(errs) { + // number of expected errors is different from actual, includes cases when we expected errors and they appeared or vice versa + t.Errorf("number of expected errors for '%s' does not match with errors received:\n"+ + "expected:\n%s\nbut got:\n%s", + k, concatenateStrings(v.expectedErrors), concatenateErrors(errs)) + } else if len(v.expectedErrors) > 0 { + // check that the errors received match the expectations + for i, s := range v.expectedErrors { + if !strings.Contains(errs[i].Error(), s) { + t.Errorf("expected errors in particular order for '%s':\n%s\nbut got:\n%s", + k, concatenateStrings(v.expectedErrors), concatenateErrors(errs)) + break + } + } + } + } +} + +func concatenateErrors(errs field.ErrorList) string { + var errStrings []string + for _, e := range errs { + errStrings = append(errStrings, e.Error()) + } + return concatenateStrings(errStrings) +} + +func concatenateStrings(ss []string) string { + var ret string + for i, v := range ss { + ret += fmt.Sprintf("%d: %s\n", i+1, v) + } + return ret +} diff --git a/pkg/security/podsecuritypolicy/group/mustrunas.go b/pkg/security/podsecuritypolicy/group/mustrunas.go index 544f473424c..2c83ae0973c 100644 --- a/pkg/security/podsecuritypolicy/group/mustrunas.go +++ b/pkg/security/podsecuritypolicy/group/mustrunas.go @@ -22,7 +22,6 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/policy" - psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" ) // mustRunAs implements the GroupStrategy interface @@ -66,21 +65,7 @@ func (s *mustRunAs) Validate(fldPath *field.Path, _ *api.Pod, groups []int64) fi allErrs = append(allErrs, field.Invalid(fldPath, groups, "unable to validate empty groups against required ranges")) } - for _, group := range groups { - if !s.isGroupValid(group) { - detail := fmt.Sprintf("group %d must be in the ranges: %v", group, s.ranges) - allErrs = append(allErrs, field.Invalid(fldPath, groups, detail)) - } - } + allErrs = append(allErrs, ValidateGroupsInRanges(fldPath, s.ranges, groups)...) return allErrs } - -func (s *mustRunAs) isGroupValid(group int64) bool { - for _, rng := range s.ranges { - if psputil.GroupFallsInRange(group, rng) { - return true - } - } - return false -} diff --git a/pkg/security/podsecuritypolicy/provider_test.go b/pkg/security/podsecuritypolicy/provider_test.go index c246e7b5296..90049f460a5 100644 --- a/pkg/security/podsecuritypolicy/provider_test.go +++ b/pkg/security/podsecuritypolicy/provider_test.go @@ -186,24 +186,41 @@ func TestValidatePodSecurityContextFailures(t *testing.T) { failSupplementalGroupPod := defaultPod() failSupplementalGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{999} - failSupplementalGroupPSP := defaultPSP() - failSupplementalGroupPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{ + failSupplementalGroupMustPSP := defaultPSP() + failSupplementalGroupMustPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{ Rule: policy.SupplementalGroupsStrategyMustRunAs, Ranges: []policy.IDRange{ {Min: 1, Max: 1}, }, } + failSupplementalGroupMayPSP := defaultPSP() + failSupplementalGroupMayPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{ + Rule: policy.SupplementalGroupsStrategyMayRunAs, + Ranges: []policy.IDRange{ + {Min: 50, Max: 50}, + {Min: 55, Max: 998}, + {Min: 1000, Max: 1000}, + }, + } failFSGroupPod := defaultPod() fsGroup := int64(999) failFSGroupPod.Spec.SecurityContext.FSGroup = &fsGroup - failFSGroupPSP := defaultPSP() - failFSGroupPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{ + failFSGroupMustPSP := defaultPSP() + failFSGroupMustPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{ Rule: policy.FSGroupStrategyMustRunAs, Ranges: []policy.IDRange{ {Min: 1, Max: 1}, }, } + failFSGroupMayPSP := defaultPSP() + failFSGroupMayPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{ + Rule: policy.FSGroupStrategyMayRunAs, + Ranges: []policy.IDRange{ + {Min: 10, Max: 20}, + {Min: 1000, Max: 1001}, + }, + } failNilSELinuxPod := defaultPod() failSELinuxPSP := defaultPSP() @@ -334,24 +351,34 @@ func TestValidatePodSecurityContextFailures(t *testing.T) { psp: defaultPSP(), expectedError: "Host IPC is not allowed to be used", }, - "failSupplementalGroupOutOfRange": { + "failSupplementalGroupOutOfMustRange": { pod: failSupplementalGroupPod, - psp: failSupplementalGroupPSP, + psp: failSupplementalGroupMustPSP, expectedError: "group 999 must be in the ranges: [{1 1}]", }, - "failSupplementalGroupEmpty": { + "failSupplementalGroupOutOfMayRange": { + pod: failSupplementalGroupPod, + psp: failSupplementalGroupMayPSP, + expectedError: "group 999 must be in the ranges: [{50 50} {55 998} {1000 1000}]", + }, + "failSupplementalGroupMustEmpty": { pod: defaultPod(), - psp: failSupplementalGroupPSP, + psp: failSupplementalGroupMustPSP, expectedError: "unable to validate empty groups against required ranges", }, - "failFSGroupOutOfRange": { + "failFSGroupOutOfMustRange": { pod: failFSGroupPod, - psp: failFSGroupPSP, + psp: failFSGroupMustPSP, expectedError: "group 999 must be in the ranges: [{1 1}]", }, - "failFSGroupEmpty": { + "failFSGroupOutOfMayRange": { + pod: failFSGroupPod, + psp: failFSGroupMayPSP, + expectedError: "group 999 must be in the ranges: [{10 20} {1000 1001}]", + }, + "failFSGroupMustEmpty": { pod: defaultPod(), - psp: failFSGroupPSP, + psp: failFSGroupMustPSP, expectedError: "unable to validate empty groups against required ranges", }, "failNilSELinux": { @@ -616,23 +643,37 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) { hostIPCPod := defaultPod() hostIPCPod.Spec.SecurityContext.HostIPC = true - supGroupPSP := defaultPSP() - supGroupPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{ + supGroupMustPSP := defaultPSP() + supGroupMustPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{ Rule: policy.SupplementalGroupsStrategyMustRunAs, Ranges: []policy.IDRange{ {Min: 1, Max: 5}, }, } + supGroupMayPSP := defaultPSP() + supGroupMayPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{ + Rule: policy.SupplementalGroupsStrategyMayRunAs, + Ranges: []policy.IDRange{ + {Min: 1, Max: 5}, + }, + } supGroupPod := defaultPod() supGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{3} - fsGroupPSP := defaultPSP() - fsGroupPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{ + fsGroupMustPSP := defaultPSP() + fsGroupMustPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{ Rule: policy.FSGroupStrategyMustRunAs, Ranges: []policy.IDRange{ {Min: 1, Max: 5}, }, } + fsGroupMayPSP := defaultPSP() + fsGroupMayPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{ + Rule: policy.FSGroupStrategyMayRunAs, + Ranges: []policy.IDRange{ + {Min: 1, Max: 5}, + }, + } fsGroupPod := defaultPod() fsGroup := int64(3) fsGroupPod.Spec.SecurityContext.FSGroup = &fsGroup @@ -793,13 +834,29 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) { pod: hostIPCPod, psp: hostIPCPSP, }, - "pass supplemental group validating PSP": { + "pass required supplemental group validating PSP": { pod: supGroupPod, - psp: supGroupPSP, + psp: supGroupMustPSP, }, - "pass fs group validating PSP": { + "pass optional supplemental group validation PSP": { + pod: supGroupPod, + psp: supGroupMayPSP, + }, + "pass optional supplemental group validation PSP - no pod group specified": { + pod: defaultPod(), + psp: supGroupMayPSP, + }, + "pass required fs group validating PSP": { pod: fsGroupPod, - psp: fsGroupPSP, + psp: fsGroupMustPSP, + }, + "pass optional fs group validating PSP": { + pod: fsGroupPod, + psp: fsGroupMayPSP, + }, + "pass optional fs group validating PSP - no pod group specified": { + pod: defaultPod(), + psp: fsGroupMayPSP, }, "pass selinux validating PSP": { pod: seLinuxPod,