Skip to content

Commit

Permalink
SecurityContextConstraints: pass effective selinux options to validate.
Browse files Browse the repository at this point in the history
  • Loading branch information
php-coder committed Dec 18, 2017
1 parent abd601c commit b5a8497
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 46 deletions.
11 changes: 2 additions & 9 deletions pkg/security/securitycontextconstraints/provider.go
Expand Up @@ -241,14 +241,7 @@ func (s *simpleProvider) ValidatePodSecurityContext(pod *api.Pod, fldPath *field
allErrs = append(allErrs, s.supplementalGroupStrategy.Validate(pod, pod.Spec.SecurityContext.SupplementalGroups)...)
allErrs = append(allErrs, s.seccompStrategy.ValidatePod(pod)...)

// make a dummy container context to reuse the selinux strategies
container := &api.Container{
Name: pod.Name,
SecurityContext: &api.SecurityContext{
SELinuxOptions: pod.Spec.SecurityContext.SELinuxOptions,
},
}
allErrs = append(allErrs, s.seLinuxStrategy.Validate(pod, container)...)
allErrs = append(allErrs, s.seLinuxStrategy.Validate(fldPath.Child("seLinuxOptions"), pod, nil, pod.Spec.SecurityContext.SELinuxOptions)...)

if !s.scc.AllowHostNetwork && pod.Spec.SecurityContext.HostNetwork {
allErrs = append(allErrs, field.Invalid(fldPath.Child("hostNetwork"), pod.Spec.SecurityContext.HostNetwork, "Host network is not allowed to be used"))
Expand Down Expand Up @@ -317,7 +310,7 @@ func (s *simpleProvider) ValidateContainerSecurityContext(pod *api.Pod, containe

sc := container.SecurityContext
allErrs = append(allErrs, s.runAsUserStrategy.Validate(pod, container)...)
allErrs = append(allErrs, s.seLinuxStrategy.Validate(pod, container)...)
allErrs = append(allErrs, s.seLinuxStrategy.Validate(fldPath.Child("seLinuxOptions"), pod, container, sc.SELinuxOptions)...)
allErrs = append(allErrs, s.seccompStrategy.ValidateContainer(pod, container)...)

if !s.scc.AllowPrivilegedContainer && sc.Privileged != nil && *sc.Privileged {
Expand Down
6 changes: 3 additions & 3 deletions pkg/security/securitycontextconstraints/provider_test.go
Expand Up @@ -285,12 +285,12 @@ func TestValidatePodSecurityContextFailures(t *testing.T) {
"failNilSELinux": {
pod: failNilSELinuxPod,
scc: failSELinuxSCC,
expectedError: "unable to validate nil seLinuxOptions",
expectedError: "seLinuxOptions: Required",
},
"failInvalidSELinux": {
pod: failInvalidSELinuxPod,
scc: failSELinuxSCC,
expectedError: "does not match required level. Found bar, wanted foo",
expectedError: "seLinuxOptions.level: Invalid value",
},
"failNoSeccomp": {
pod: failNoSeccompAllowed,
Expand Down Expand Up @@ -421,7 +421,7 @@ func TestValidateContainerSecurityContextFailures(t *testing.T) {
"failSELinuxSCC": {
pod: failSELinuxPod,
scc: failSELinuxSCC,
expectedError: "does not match required level",
expectedError: "seLinuxOptions.level: Invalid value",
},
"failPrivSCC": {
pod: failPrivPod,
Expand Down
32 changes: 12 additions & 20 deletions pkg/security/securitycontextconstraints/selinux/mustrunas.go
Expand Up @@ -28,41 +28,33 @@ func NewMustRunAs(options *securityapi.SELinuxContextStrategyOptions) (SELinuxSe
}

// Generate creates the SELinuxOptions based on constraint rules.
func (s *mustRunAs) Generate(pod *api.Pod, container *api.Container) (*api.SELinuxOptions, error) {
func (s *mustRunAs) Generate(_ *api.Pod, _ *api.Container) (*api.SELinuxOptions, error) {
return s.opts.SELinuxOptions, nil
}

// Validate ensures that the specified values fall within the range of the strategy.
func (s *mustRunAs) Validate(pod *api.Pod, container *api.Container) field.ErrorList {
func (s *mustRunAs) Validate(fldPath *field.Path, _ *api.Pod, _ *api.Container, seLinux *api.SELinuxOptions) field.ErrorList {
allErrs := field.ErrorList{}

if container.SecurityContext == nil {
detail := fmt.Sprintf("unable to validate nil security context for %s", container.Name)
allErrs = append(allErrs, field.Invalid(field.NewPath("securityContext"), container.SecurityContext, detail))
if seLinux == nil {
allErrs = append(allErrs, field.Required(fldPath, ""))
return allErrs
}
if container.SecurityContext.SELinuxOptions == nil {
detail := fmt.Sprintf("unable to validate nil seLinuxOptions for %s", container.Name)
allErrs = append(allErrs, field.Invalid(field.NewPath("seLinuxOptions"), container.SecurityContext.SELinuxOptions, detail))
return allErrs
}
seLinuxOptionsPath := field.NewPath("seLinuxOptions")
seLinux := container.SecurityContext.SELinuxOptions
if seLinux.Level != s.opts.SELinuxOptions.Level {
detail := fmt.Sprintf("seLinuxOptions.level on %s does not match required level. Found %s, wanted %s", container.Name, seLinux.Level, s.opts.SELinuxOptions.Level)
allErrs = append(allErrs, field.Invalid(seLinuxOptionsPath.Child("level"), seLinux.Level, detail))
detail := fmt.Sprintf("must be %s", s.opts.SELinuxOptions.Level)
allErrs = append(allErrs, field.Invalid(fldPath.Child("level"), seLinux.Level, detail))
}
if seLinux.Role != s.opts.SELinuxOptions.Role {
detail := fmt.Sprintf("seLinuxOptions.role on %s does not match required role. Found %s, wanted %s", container.Name, seLinux.Role, s.opts.SELinuxOptions.Role)
allErrs = append(allErrs, field.Invalid(seLinuxOptionsPath.Child("role"), seLinux.Role, detail))
detail := fmt.Sprintf("must be %s", s.opts.SELinuxOptions.Role)
allErrs = append(allErrs, field.Invalid(fldPath.Child("role"), seLinux.Role, detail))
}
if seLinux.Type != s.opts.SELinuxOptions.Type {
detail := fmt.Sprintf("seLinuxOptions.type on %s does not match required type. Found %s, wanted %s", container.Name, seLinux.Type, s.opts.SELinuxOptions.Type)
allErrs = append(allErrs, field.Invalid(seLinuxOptionsPath.Child("type"), seLinux.Type, detail))
detail := fmt.Sprintf("must be %s", s.opts.SELinuxOptions.Type)
allErrs = append(allErrs, field.Invalid(fldPath.Child("type"), seLinux.Type, detail))
}
if seLinux.User != s.opts.SELinuxOptions.User {
detail := fmt.Sprintf("seLinuxOptions.user on %s does not match required user. Found %s, wanted %s", container.Name, seLinux.User, s.opts.SELinuxOptions.User)
allErrs = append(allErrs, field.Invalid(seLinuxOptionsPath.Child("user"), seLinux.User, detail))
detail := fmt.Sprintf("must be %s", s.opts.SELinuxOptions.User)
allErrs = append(allErrs, field.Invalid(fldPath.Child("user"), seLinux.User, detail))
}

return allErrs
Expand Down
15 changes: 5 additions & 10 deletions pkg/security/securitycontextconstraints/selinux/mustrunas_test.go
Expand Up @@ -85,19 +85,19 @@ func TestMustRunAsValidate(t *testing.T) {
}{
"invalid role": {
seLinux: role,
expectedMsg: "does not match required role",
expectedMsg: "role: Invalid value",
},
"invalid user": {
seLinux: user,
expectedMsg: "does not match required user",
expectedMsg: "user: Invalid value",
},
"invalid level": {
seLinux: level,
expectedMsg: "does not match required level",
expectedMsg: "level: Invalid value",
},
"invalid type": {
seLinux: seType,
expectedMsg: "does not match required type",
expectedMsg: "type: Invalid value",
},
"valid": {
seLinux: newValidOpts(),
Expand All @@ -115,13 +115,8 @@ func TestMustRunAsValidate(t *testing.T) {
t.Errorf("unexpected error initializing NewMustRunAs for testcase %s: %#v", name, err)
continue
}
container := &api.Container{
SecurityContext: &api.SecurityContext{
SELinuxOptions: tc.seLinux,
},
}

errs := mustRunAs.Validate(nil, container)
errs := mustRunAs.Validate(nil, nil, nil, tc.seLinux)
//should've passed but didn't
if len(tc.expectedMsg) == 0 && len(errs) > 0 {
t.Errorf("%s expected no errors but received %v", name, errs)
Expand Down
Expand Up @@ -23,6 +23,6 @@ func (s *runAsAny) Generate(pod *api.Pod, container *api.Container) (*api.SELinu
}

// Validate ensures that the specified values fall within the range of the strategy.
func (s *runAsAny) Validate(pod *api.Pod, container *api.Container) field.ErrorList {
func (s *runAsAny) Validate(fldPath *field.Path, _ *api.Pod, _ *api.Container, options *api.SELinuxOptions) field.ErrorList {
return field.ErrorList{}
}
Expand Up @@ -43,15 +43,15 @@ func TestRunAsAnyValidate(t *testing.T) {
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}
errs := s.Validate(nil, nil)
errs := s.Validate(nil, nil, nil, nil)
if len(errs) != 0 {
t.Errorf("unexpected errors validating with ")
}
s, err = NewRunAsAny(&securityapi.SELinuxContextStrategyOptions{})
if err != nil {
t.Fatalf("unexpected error initializing NewRunAsAny %v", err)
}
errs = s.Validate(nil, nil)
errs = s.Validate(nil, nil, nil, nil)
if len(errs) != 0 {
t.Errorf("unexpected errors validating %v", errs)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/security/securitycontextconstraints/selinux/types.go
Expand Up @@ -10,5 +10,5 @@ type SELinuxSecurityContextConstraintsStrategy interface {
// Generate creates the SELinuxOptions based on constraint rules.
Generate(pod *api.Pod, container *api.Container) (*api.SELinuxOptions, error)
// Validate ensures that the specified values fall within the range of the strategy.
Validate(pod *api.Pod, container *api.Container) field.ErrorList
Validate(fldPath *field.Path, pod *api.Pod, container *api.Container, options *api.SELinuxOptions) field.ErrorList
}

0 comments on commit b5a8497

Please sign in to comment.