Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/api/serialization_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,8 @@ func originFuzzer(t *testing.T, seed int64) *randfill.Filler {
scc.SupplementalGroups.Type = supGroupTypes[c.Rand.Intn(len(supGroupTypes))]
fsGroupTypes := []securityapi.FSGroupStrategyType{securityapi.FSGroupStrategyMustRunAs, securityapi.FSGroupStrategyRunAsAny}
scc.FSGroup.Type = fsGroupTypes[c.Rand.Intn(len(fsGroupTypes))]
runAsGroupTypes := []securityapi.RunAsGroupStrategyType{securityapi.RunAsGroupStrategyMustRunAs, securityapi.RunAsGroupStrategyMustRunAsRange, securityapi.RunAsGroupStrategyRunAsAny}
scc.RunAsGroup.Type = runAsGroupTypes[c.Rand.Intn(len(runAsGroupTypes))]
// avoid the defaulting logic for this field by making it never nil
allowPrivilegeEscalation := c.Bool()
scc.AllowPrivilegeEscalation = &allowPrivilegeEscalation
Expand Down
38 changes: 38 additions & 0 deletions pkg/security/apis/security/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ type SecurityContextConstraints struct {
SupplementalGroups SupplementalGroupsStrategyOptions
// FSGroup is the strategy that will dictate what fs group is used by the SecurityContext.
FSGroup FSGroupStrategyOptions
// RunAsGroup is the strategy that will dictate what RunAsGroup is used in the SecurityContext.
// +optional
RunAsGroup RunAsGroupStrategyOptions
// ReadOnlyRootFilesystem when set to true will force containers to run with a read only root file
// system. If the container specifically requests to run with a non-read only root file system
// the SCC should deny the pod.
Expand Down Expand Up @@ -177,6 +180,30 @@ type RunAsUserStrategyOptions struct {
UIDRangeMax *int64
}

// RunAsGroupStrategyOptions defines the strategy type and any options used to create the strategy.
type RunAsGroupStrategyOptions struct {
// Type is the strategy that will dictate what RunAsGroup is used in the SecurityContext.
Type RunAsGroupStrategyType
// GID is the group id that containers must run as. Required for the MustRunAs strategy if not using
// namespace/service account allocated gids.
GID *int64
// GIDRangeMin defines the min value for a strategy that allocates by range.
GIDRangeMin *int64
// GIDRangeMax defines the max value for a strategy that allocates by range.
GIDRangeMax *int64
// Ranges are the allowed ranges of gids. If you would like to force a single
// gid then supply a single range with the same start and end.
Ranges []RunAsGroupIDRange
}

// RunAsGroupIDRange provides a min/max of an allowed range of group IDs for RunAsGroup strategy.
type RunAsGroupIDRange struct {
// Min is the start of the range, inclusive.
Min *int64
// Max is the end of the range, inclusive.
Max *int64
}

// FSGroupStrategyOptions defines the strategy type and options used to create the strategy.
type FSGroupStrategyOptions struct {
// Type is the strategy that will dictate what FSGroup is used in the SecurityContext.
Expand Down Expand Up @@ -220,6 +247,10 @@ type SupplementalGroupsStrategyType string
// SecurityContext
type FSGroupStrategyType string

// RunAsGroupStrategyType denotes strategy types for generating RunAsGroup values for a
// SecurityContext
type RunAsGroupStrategyType string

const (
// container must have SELinux labels of X applied.
SELinuxStrategyMustRunAs SELinuxContextStrategyType = "MustRunAs"
Expand All @@ -235,6 +266,13 @@ const (
// container may make requests for any uid.
RunAsUserStrategyRunAsAny RunAsUserStrategyType = "RunAsAny"

// container must run as a particular gid.
RunAsGroupStrategyMustRunAs RunAsGroupStrategyType = "MustRunAs"
// container must run with a gid in a range.
RunAsGroupStrategyMustRunAsRange RunAsGroupStrategyType = "MustRunAsRange"
// container may make requests for any gid.
RunAsGroupStrategyRunAsAny RunAsGroupStrategyType = "RunAsAny"

// container must have FSGroup of X applied.
FSGroupStrategyMustRunAs FSGroupStrategyType = "MustRunAs"
// container may make requests for any FSGroup labels.
Expand Down
26 changes: 26 additions & 0 deletions pkg/security/apis/security/v1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ func Convert_v1_SecurityContextConstraints_To_security_SecurityContextConstraint
return autoConvert_v1_SecurityContextConstraints_To_security_SecurityContextConstraints(in, out, s)
}

func Convert_v1_RunAsGroupStrategyOptions_To_security_RunAsGroupStrategyOptions(in *v1.RunAsGroupStrategyOptions, out *securityapi.RunAsGroupStrategyOptions, s conversion.Scope) error {
return autoConvert_v1_RunAsGroupStrategyOptions_To_security_RunAsGroupStrategyOptions(in, out, s)
}

func Convert_security_RunAsGroupStrategyOptions_To_v1_RunAsGroupStrategyOptions(in *securityapi.RunAsGroupStrategyOptions, out *v1.RunAsGroupStrategyOptions, s conversion.Scope) error {
return autoConvert_security_RunAsGroupStrategyOptions_To_v1_RunAsGroupStrategyOptions(in, out, s)
}

func Convert_security_SecurityContextConstraints_To_v1_SecurityContextConstraints(in *securityapi.SecurityContextConstraints, out *v1.SecurityContextConstraints, s conversion.Scope) error {
if err := autoConvert_security_SecurityContextConstraints_To_v1_SecurityContextConstraints(in, out, s); err != nil {
return err
Expand All @@ -27,3 +35,21 @@ func Convert_security_SecurityContextConstraints_To_v1_SecurityContextConstraint
}
return nil
}

// Convert_v1_IDRange_To_security_RunAsGroupIDRange converts v1.IDRange to internal RunAsGroupIDRange
func Convert_v1_IDRange_To_security_RunAsGroupIDRange(in *v1.IDRange, out *securityapi.RunAsGroupIDRange, s conversion.Scope) error {
out.Min = &in.Min
out.Max = &in.Max
return nil
}

// Convert_security_RunAsGroupIDRange_To_v1_IDRange converts internal RunAsGroupIDRange to v1.IDRange
func Convert_security_RunAsGroupIDRange_To_v1_IDRange(in *securityapi.RunAsGroupIDRange, out *v1.IDRange, s conversion.Scope) error {
if in.Min != nil {
out.Min = *in.Min
}
if in.Max != nil {
out.Max = *in.Max
}
return nil
}
16 changes: 15 additions & 1 deletion pkg/security/apis/security/v1/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,21 @@ import (
func AddDefaultingFuncs(scheme *runtime.Scheme) error {
RegisterDefaults(scheme)
scheme.AddTypeDefaultingFunc(&v1.SecurityContextConstraints{}, func(obj interface{}) {
sccdefaults.SetDefaults_SCC(obj.(*v1.SecurityContextConstraints))
scc := obj.(*v1.SecurityContextConstraints)
sccdefaults.SetDefaults_SCC(scc)

// Default RunAsGroup to MustRunAs with ranges if not set
if len(scc.RunAsGroup.Type) == 0 {
min := int64(1000)
max := int64(65534)
scc.RunAsGroup.Type = v1.RunAsGroupStrategyMustRunAs
scc.RunAsGroup.Ranges = []v1.RunAsGroupIDRange{
{
Min: &min,
Max: &max,
},
}
}
})

return nil
Expand Down
76 changes: 76 additions & 0 deletions pkg/security/apis/security/v1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions pkg/security/apis/security/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,48 @@ func ValidateSecurityContextConstraints(scc *securityapi.SecurityContextConstrai
}
allErrs = append(allErrs, validateIDRanges(scc.SupplementalGroups.Ranges, field.NewPath("supplementalGroups"))...)

// validate runAsGroup if present
if scc.RunAsGroup.Type != "" {
runAsGroupPath := field.NewPath("runAsGroup")
switch scc.RunAsGroup.Type {
case securityapi.RunAsGroupStrategyMustRunAs, securityapi.RunAsGroupStrategyMustRunAsRange, securityapi.RunAsGroupStrategyRunAsAny:
// good types
default:
msg := fmt.Sprintf("invalid strategy type. Valid values are %s, %s, %s",
securityapi.RunAsGroupStrategyMustRunAs,
securityapi.RunAsGroupStrategyMustRunAsRange,
securityapi.RunAsGroupStrategyRunAsAny)
allErrs = append(allErrs, field.Invalid(runAsGroupPath.Child("type"), scc.RunAsGroup.Type, msg))
}

// if specified, gid cannot be negative
if scc.RunAsGroup.GID != nil {
if *scc.RunAsGroup.GID < 0 {
allErrs = append(allErrs, field.Invalid(runAsGroupPath.Child("gid"), *scc.RunAsGroup.GID, "gid cannot be negative"))
}
}

// validate GID range if specified
if scc.RunAsGroup.GIDRangeMin != nil {
if *scc.RunAsGroup.GIDRangeMin < 0 {
allErrs = append(allErrs, field.Invalid(runAsGroupPath.Child("gidRangeMin"), *scc.RunAsGroup.GIDRangeMin, "gidRangeMin cannot be negative"))
}
}
if scc.RunAsGroup.GIDRangeMax != nil {
if *scc.RunAsGroup.GIDRangeMax < 0 {
allErrs = append(allErrs, field.Invalid(runAsGroupPath.Child("gidRangeMax"), *scc.RunAsGroup.GIDRangeMax, "gidRangeMax cannot be negative"))
}
}
if scc.RunAsGroup.GIDRangeMin != nil && scc.RunAsGroup.GIDRangeMax != nil {
if *scc.RunAsGroup.GIDRangeMin > *scc.RunAsGroup.GIDRangeMax {
allErrs = append(allErrs, field.Invalid(runAsGroupPath.Child("gidRangeMin"), scc.RunAsGroup, "gidRangeMin cannot be greater than gidRangeMax"))
}
}

// validate ranges if specified
allErrs = append(allErrs, validateRunAsGroupIDRanges(scc.RunAsGroup.Ranges, runAsGroupPath)...)
}

// validate capabilities
allErrs = append(allErrs, validateSCCCapsAgainstDrops(scc.RequiredDropCapabilities, scc.DefaultAddCapabilities, field.NewPath("defaultAddCapabilities"))...)
allErrs = append(allErrs, validateSCCCapsAgainstDrops(scc.RequiredDropCapabilities, scc.AllowedCapabilities, field.NewPath("allowedCapabilities"))...)
Expand Down Expand Up @@ -270,6 +312,36 @@ func validateIDRanges(rng []securityapi.IDRange, fldPath *field.Path) field.Erro
return allErrs
}

// validateRunAsGroupIDRanges ensures the RunAsGroupIDRange is valid.
func validateRunAsGroupIDRanges(rng []securityapi.RunAsGroupIDRange, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}

for i, r := range rng {
// if 0 <= Min <= Max then we do not need to validate max. It is always greater than or
// equal to 0 and Min.
minPath := fldPath.Child("ranges").Index(i).Child("min")
maxPath := fldPath.Child("ranges").Index(i).Child("max")

if r.Min != nil {
if *r.Min < 0 {
allErrs = append(allErrs, field.Invalid(minPath, *r.Min, "min cannot be negative"))
}
}
if r.Max != nil {
if *r.Max < 0 {
allErrs = append(allErrs, field.Invalid(maxPath, *r.Max, "max cannot be negative"))
}
}
if r.Min != nil && r.Max != nil {
if *r.Min > *r.Max {
allErrs = append(allErrs, field.Invalid(minPath, r, "min cannot be greater than max"))
}
}
}

return allErrs
}

func ValidateSecurityContextConstraintsUpdate(newScc, oldScc *securityapi.SecurityContextConstraints) field.ErrorList {
allErrs := validation.ValidateObjectMetaUpdate(&newScc.ObjectMeta, &oldScc.ObjectMeta, field.NewPath("metadata"))
allErrs = append(allErrs, ValidateSecurityContextConstraints(newScc)...)
Expand Down
Loading