mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Merge pull request #65135 from stlaz/psp_group_mayrunas
Add "MayRunAs" value among other GroupStrategies
This commit is contained in:
commit
0b3a5cd64f
@ -48,12 +48,14 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
|
|
||||||
supplementalGroupsRules := []policy.SupplementalGroupsStrategyType{
|
supplementalGroupsRules := []policy.SupplementalGroupsStrategyType{
|
||||||
policy.SupplementalGroupsStrategyRunAsAny,
|
policy.SupplementalGroupsStrategyRunAsAny,
|
||||||
|
policy.SupplementalGroupsStrategyMayRunAs,
|
||||||
policy.SupplementalGroupsStrategyMustRunAs,
|
policy.SupplementalGroupsStrategyMustRunAs,
|
||||||
}
|
}
|
||||||
psp.SupplementalGroups.Rule = supplementalGroupsRules[c.Rand.Intn(len(supplementalGroupsRules))]
|
psp.SupplementalGroups.Rule = supplementalGroupsRules[c.Rand.Intn(len(supplementalGroupsRules))]
|
||||||
|
|
||||||
fsGroupRules := []policy.FSGroupStrategyType{
|
fsGroupRules := []policy.FSGroupStrategyType{
|
||||||
policy.FSGroupStrategyMustRunAs,
|
policy.FSGroupStrategyMustRunAs,
|
||||||
|
policy.FSGroupStrategyMayRunAs,
|
||||||
policy.FSGroupStrategyRunAsAny,
|
policy.FSGroupStrategyRunAsAny,
|
||||||
}
|
}
|
||||||
psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))]
|
psp.FSGroup.Rule = fsGroupRules[c.Rand.Intn(len(fsGroupRules))]
|
||||||
|
@ -372,6 +372,9 @@ type FSGroupStrategyOptions struct {
|
|||||||
type FSGroupStrategyType string
|
type FSGroupStrategyType string
|
||||||
|
|
||||||
const (
|
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 means that container must have FSGroup of X applied.
|
||||||
FSGroupStrategyMustRunAs FSGroupStrategyType = "MustRunAs"
|
FSGroupStrategyMustRunAs FSGroupStrategyType = "MustRunAs"
|
||||||
// FSGroupStrategyRunAsAny means that container may make requests for any FSGroup labels.
|
// FSGroupStrategyRunAsAny means that container may make requests for any FSGroup labels.
|
||||||
@ -394,6 +397,9 @@ type SupplementalGroupsStrategyOptions struct {
|
|||||||
type SupplementalGroupsStrategyType string
|
type SupplementalGroupsStrategyType string
|
||||||
|
|
||||||
const (
|
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 means that container must run as a particular gid.
|
||||||
SupplementalGroupsStrategyMustRunAs SupplementalGroupsStrategyType = "MustRunAs"
|
SupplementalGroupsStrategyMustRunAs SupplementalGroupsStrategyType = "MustRunAs"
|
||||||
// SupplementalGroupsStrategyRunAsAny means that container may make requests for any gid.
|
// SupplementalGroupsStrategyRunAsAny means that container may make requests for any gid.
|
||||||
|
@ -239,6 +239,7 @@ func validatePSPFSGroup(fldPath *field.Path, groupOptions *policy.FSGroupStrateg
|
|||||||
|
|
||||||
supportedRules := sets.NewString(
|
supportedRules := sets.NewString(
|
||||||
string(policy.FSGroupStrategyMustRunAs),
|
string(policy.FSGroupStrategyMustRunAs),
|
||||||
|
string(policy.FSGroupStrategyMayRunAs),
|
||||||
string(policy.FSGroupStrategyRunAsAny),
|
string(policy.FSGroupStrategyRunAsAny),
|
||||||
)
|
)
|
||||||
if !supportedRules.Has(string(groupOptions.Rule)) {
|
if !supportedRules.Has(string(groupOptions.Rule)) {
|
||||||
@ -257,6 +258,7 @@ func validatePSPSupplementalGroup(fldPath *field.Path, groupOptions *policy.Supp
|
|||||||
|
|
||||||
supportedRules := sets.NewString(
|
supportedRules := sets.NewString(
|
||||||
string(policy.SupplementalGroupsStrategyRunAsAny),
|
string(policy.SupplementalGroupsStrategyRunAsAny),
|
||||||
|
string(policy.SupplementalGroupsStrategyMayRunAs),
|
||||||
string(policy.SupplementalGroupsStrategyMustRunAs),
|
string(policy.SupplementalGroupsStrategyMustRunAs),
|
||||||
)
|
)
|
||||||
if !supportedRules.Has(string(groupOptions.Rule)) {
|
if !supportedRules.Has(string(groupOptions.Rule)) {
|
||||||
|
@ -390,12 +390,12 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
|
|||||||
"no fsgroup options": {
|
"no fsgroup options": {
|
||||||
psp: noFSGroupOptions,
|
psp: noFSGroupOptions,
|
||||||
errorType: field.ErrorTypeNotSupported,
|
errorType: field.ErrorTypeNotSupported,
|
||||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`,
|
||||||
},
|
},
|
||||||
"no sup group options": {
|
"no sup group options": {
|
||||||
psp: noSupplementalGroupsOptions,
|
psp: noSupplementalGroupsOptions,
|
||||||
errorType: field.ErrorTypeNotSupported,
|
errorType: field.ErrorTypeNotSupported,
|
||||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`,
|
||||||
},
|
},
|
||||||
"invalid user strategy type": {
|
"invalid user strategy type": {
|
||||||
psp: invalidUserStratType,
|
psp: invalidUserStratType,
|
||||||
@ -410,12 +410,12 @@ func TestValidatePodSecurityPolicy(t *testing.T) {
|
|||||||
"invalid sup group strategy type": {
|
"invalid sup group strategy type": {
|
||||||
psp: invalidSupGroupStratType,
|
psp: invalidSupGroupStratType,
|
||||||
errorType: field.ErrorTypeNotSupported,
|
errorType: field.ErrorTypeNotSupported,
|
||||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`,
|
||||||
},
|
},
|
||||||
"invalid fs group strategy type": {
|
"invalid fs group strategy type": {
|
||||||
psp: invalidFSGroupStratType,
|
psp: invalidFSGroupStratType,
|
||||||
errorType: field.ErrorTypeNotSupported,
|
errorType: field.ErrorTypeNotSupported,
|
||||||
errorDetail: `supported values: "MustRunAs", "RunAsAny"`,
|
errorDetail: `supported values: "MayRunAs", "MustRunAs", "RunAsAny"`,
|
||||||
},
|
},
|
||||||
"invalid uid": {
|
"invalid uid": {
|
||||||
psp: invalidUIDPSP,
|
psp: invalidUIDPSP,
|
||||||
|
@ -138,6 +138,8 @@ func createFSGroupStrategy(opts *policy.FSGroupStrategyOptions) (group.GroupStra
|
|||||||
switch opts.Rule {
|
switch opts.Rule {
|
||||||
case policy.FSGroupStrategyRunAsAny:
|
case policy.FSGroupStrategyRunAsAny:
|
||||||
return group.NewRunAsAny()
|
return group.NewRunAsAny()
|
||||||
|
case policy.FSGroupStrategyMayRunAs:
|
||||||
|
return group.NewMayRunAs(opts.Ranges)
|
||||||
case policy.FSGroupStrategyMustRunAs:
|
case policy.FSGroupStrategyMustRunAs:
|
||||||
return group.NewMustRunAs(opts.Ranges)
|
return group.NewMustRunAs(opts.Ranges)
|
||||||
default:
|
default:
|
||||||
@ -150,6 +152,8 @@ func createSupplementalGroupStrategy(opts *policy.SupplementalGroupsStrategyOpti
|
|||||||
switch opts.Rule {
|
switch opts.Rule {
|
||||||
case policy.SupplementalGroupsStrategyRunAsAny:
|
case policy.SupplementalGroupsStrategyRunAsAny:
|
||||||
return group.NewRunAsAny()
|
return group.NewRunAsAny()
|
||||||
|
case policy.SupplementalGroupsStrategyMayRunAs:
|
||||||
|
return group.NewMayRunAs(opts.Ranges)
|
||||||
case policy.SupplementalGroupsStrategyMustRunAs:
|
case policy.SupplementalGroupsStrategyMustRunAs:
|
||||||
return group.NewMustRunAs(opts.Ranges)
|
return group.NewMustRunAs(opts.Ranges)
|
||||||
default:
|
default:
|
||||||
|
@ -10,6 +10,8 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"doc.go",
|
"doc.go",
|
||||||
|
"helpers.go",
|
||||||
|
"mayrunas.go",
|
||||||
"mustrunas.go",
|
"mustrunas.go",
|
||||||
"runasany.go",
|
"runasany.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
@ -26,6 +28,7 @@ go_library(
|
|||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"mayrunas_test.go",
|
||||||
"mustrunas_test.go",
|
"mustrunas_test.go",
|
||||||
"runasany_test.go",
|
"runasany_test.go",
|
||||||
],
|
],
|
||||||
|
46
pkg/security/podsecuritypolicy/group/helpers.go
Normal file
46
pkg/security/podsecuritypolicy/group/helpers.go
Normal file
@ -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
|
||||||
|
}
|
59
pkg/security/podsecuritypolicy/group/mayrunas.go
Normal file
59
pkg/security/podsecuritypolicy/group/mayrunas.go
Normal file
@ -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)
|
||||||
|
}
|
185
pkg/security/podsecuritypolicy/group/mayrunas_test.go
Normal file
185
pkg/security/podsecuritypolicy/group/mayrunas_test.go
Normal file
@ -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
|
||||||
|
}
|
@ -22,7 +22,6 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/policy"
|
"k8s.io/kubernetes/pkg/apis/policy"
|
||||||
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// mustRunAs implements the GroupStrategy interface
|
// 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"))
|
allErrs = append(allErrs, field.Invalid(fldPath, groups, "unable to validate empty groups against required ranges"))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, group := range groups {
|
allErrs = append(allErrs, ValidateGroupsInRanges(fldPath, s.ranges, 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mustRunAs) isGroupValid(group int64) bool {
|
|
||||||
for _, rng := range s.ranges {
|
|
||||||
if psputil.GroupFallsInRange(group, rng) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -186,24 +186,41 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
|
|||||||
|
|
||||||
failSupplementalGroupPod := defaultPod()
|
failSupplementalGroupPod := defaultPod()
|
||||||
failSupplementalGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{999}
|
failSupplementalGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{999}
|
||||||
failSupplementalGroupPSP := defaultPSP()
|
failSupplementalGroupMustPSP := defaultPSP()
|
||||||
failSupplementalGroupPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{
|
failSupplementalGroupMustPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{
|
||||||
Rule: policy.SupplementalGroupsStrategyMustRunAs,
|
Rule: policy.SupplementalGroupsStrategyMustRunAs,
|
||||||
Ranges: []policy.IDRange{
|
Ranges: []policy.IDRange{
|
||||||
{Min: 1, Max: 1},
|
{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()
|
failFSGroupPod := defaultPod()
|
||||||
fsGroup := int64(999)
|
fsGroup := int64(999)
|
||||||
failFSGroupPod.Spec.SecurityContext.FSGroup = &fsGroup
|
failFSGroupPod.Spec.SecurityContext.FSGroup = &fsGroup
|
||||||
failFSGroupPSP := defaultPSP()
|
failFSGroupMustPSP := defaultPSP()
|
||||||
failFSGroupPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{
|
failFSGroupMustPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{
|
||||||
Rule: policy.FSGroupStrategyMustRunAs,
|
Rule: policy.FSGroupStrategyMustRunAs,
|
||||||
Ranges: []policy.IDRange{
|
Ranges: []policy.IDRange{
|
||||||
{Min: 1, Max: 1},
|
{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()
|
failNilSELinuxPod := defaultPod()
|
||||||
failSELinuxPSP := defaultPSP()
|
failSELinuxPSP := defaultPSP()
|
||||||
@ -334,24 +351,34 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
|
|||||||
psp: defaultPSP(),
|
psp: defaultPSP(),
|
||||||
expectedError: "Host IPC is not allowed to be used",
|
expectedError: "Host IPC is not allowed to be used",
|
||||||
},
|
},
|
||||||
"failSupplementalGroupOutOfRange": {
|
"failSupplementalGroupOutOfMustRange": {
|
||||||
pod: failSupplementalGroupPod,
|
pod: failSupplementalGroupPod,
|
||||||
psp: failSupplementalGroupPSP,
|
psp: failSupplementalGroupMustPSP,
|
||||||
expectedError: "group 999 must be in the ranges: [{1 1}]",
|
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(),
|
pod: defaultPod(),
|
||||||
psp: failSupplementalGroupPSP,
|
psp: failSupplementalGroupMustPSP,
|
||||||
expectedError: "unable to validate empty groups against required ranges",
|
expectedError: "unable to validate empty groups against required ranges",
|
||||||
},
|
},
|
||||||
"failFSGroupOutOfRange": {
|
"failFSGroupOutOfMustRange": {
|
||||||
pod: failFSGroupPod,
|
pod: failFSGroupPod,
|
||||||
psp: failFSGroupPSP,
|
psp: failFSGroupMustPSP,
|
||||||
expectedError: "group 999 must be in the ranges: [{1 1}]",
|
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(),
|
pod: defaultPod(),
|
||||||
psp: failFSGroupPSP,
|
psp: failFSGroupMustPSP,
|
||||||
expectedError: "unable to validate empty groups against required ranges",
|
expectedError: "unable to validate empty groups against required ranges",
|
||||||
},
|
},
|
||||||
"failNilSELinux": {
|
"failNilSELinux": {
|
||||||
@ -616,23 +643,37 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
|
|||||||
hostIPCPod := defaultPod()
|
hostIPCPod := defaultPod()
|
||||||
hostIPCPod.Spec.SecurityContext.HostIPC = true
|
hostIPCPod.Spec.SecurityContext.HostIPC = true
|
||||||
|
|
||||||
supGroupPSP := defaultPSP()
|
supGroupMustPSP := defaultPSP()
|
||||||
supGroupPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{
|
supGroupMustPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{
|
||||||
Rule: policy.SupplementalGroupsStrategyMustRunAs,
|
Rule: policy.SupplementalGroupsStrategyMustRunAs,
|
||||||
Ranges: []policy.IDRange{
|
Ranges: []policy.IDRange{
|
||||||
{Min: 1, Max: 5},
|
{Min: 1, Max: 5},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
supGroupMayPSP := defaultPSP()
|
||||||
|
supGroupMayPSP.Spec.SupplementalGroups = policy.SupplementalGroupsStrategyOptions{
|
||||||
|
Rule: policy.SupplementalGroupsStrategyMayRunAs,
|
||||||
|
Ranges: []policy.IDRange{
|
||||||
|
{Min: 1, Max: 5},
|
||||||
|
},
|
||||||
|
}
|
||||||
supGroupPod := defaultPod()
|
supGroupPod := defaultPod()
|
||||||
supGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{3}
|
supGroupPod.Spec.SecurityContext.SupplementalGroups = []int64{3}
|
||||||
|
|
||||||
fsGroupPSP := defaultPSP()
|
fsGroupMustPSP := defaultPSP()
|
||||||
fsGroupPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{
|
fsGroupMustPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{
|
||||||
Rule: policy.FSGroupStrategyMustRunAs,
|
Rule: policy.FSGroupStrategyMustRunAs,
|
||||||
Ranges: []policy.IDRange{
|
Ranges: []policy.IDRange{
|
||||||
{Min: 1, Max: 5},
|
{Min: 1, Max: 5},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
fsGroupMayPSP := defaultPSP()
|
||||||
|
fsGroupMayPSP.Spec.FSGroup = policy.FSGroupStrategyOptions{
|
||||||
|
Rule: policy.FSGroupStrategyMayRunAs,
|
||||||
|
Ranges: []policy.IDRange{
|
||||||
|
{Min: 1, Max: 5},
|
||||||
|
},
|
||||||
|
}
|
||||||
fsGroupPod := defaultPod()
|
fsGroupPod := defaultPod()
|
||||||
fsGroup := int64(3)
|
fsGroup := int64(3)
|
||||||
fsGroupPod.Spec.SecurityContext.FSGroup = &fsGroup
|
fsGroupPod.Spec.SecurityContext.FSGroup = &fsGroup
|
||||||
@ -793,13 +834,29 @@ func TestValidatePodSecurityContextSuccess(t *testing.T) {
|
|||||||
pod: hostIPCPod,
|
pod: hostIPCPod,
|
||||||
psp: hostIPCPSP,
|
psp: hostIPCPSP,
|
||||||
},
|
},
|
||||||
"pass supplemental group validating PSP": {
|
"pass required supplemental group validating PSP": {
|
||||||
pod: supGroupPod,
|
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,
|
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": {
|
"pass selinux validating PSP": {
|
||||||
pod: seLinuxPod,
|
pod: seLinuxPod,
|
||||||
|
Loading…
Reference in New Issue
Block a user