Add alpha annotations support to the PodSecurityPolicy provider

This commit is contained in:
Tim St. Clair 2016-08-17 10:14:23 -07:00
parent d4ea444277
commit c99d7fddc1
No known key found for this signature in database
GPG Key ID: 434D16BCEF479EAB
4 changed files with 32 additions and 20 deletions

View File

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
"k8s.io/kubernetes/pkg/util/maps"
"k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/util/validation/field"
) )
@ -67,7 +68,7 @@ func NewSimpleProvider(psp *extensions.PodSecurityPolicy, namespace string, stra
// //
// NOTE: this method works on a copy of the PodSecurityContext. It is up to the caller to // NOTE: this method works on a copy of the PodSecurityContext. It is up to the caller to
// apply the PSC if validation passes. // apply the PSC if validation passes.
func (s *simpleProvider) CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurityContext, error) { func (s *simpleProvider) CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurityContext, map[string]string, error) {
var sc *api.PodSecurityContext = nil var sc *api.PodSecurityContext = nil
if pod.Spec.SecurityContext != nil { if pod.Spec.SecurityContext != nil {
// work with a copy // work with a copy
@ -76,11 +77,12 @@ func (s *simpleProvider) CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurit
} else { } else {
sc = &api.PodSecurityContext{} sc = &api.PodSecurityContext{}
} }
annotations := maps.CopySS(pod.Annotations)
if len(sc.SupplementalGroups) == 0 { if len(sc.SupplementalGroups) == 0 {
supGroups, err := s.strategies.SupplementalGroupStrategy.Generate(pod) supGroups, err := s.strategies.SupplementalGroupStrategy.Generate(pod)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
sc.SupplementalGroups = supGroups sc.SupplementalGroups = supGroups
} }
@ -88,7 +90,7 @@ func (s *simpleProvider) CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurit
if sc.FSGroup == nil { if sc.FSGroup == nil {
fsGroup, err := s.strategies.FSGroupStrategy.GenerateSingle(pod) fsGroup, err := s.strategies.FSGroupStrategy.GenerateSingle(pod)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
sc.FSGroup = fsGroup sc.FSGroup = fsGroup
} }
@ -96,12 +98,12 @@ func (s *simpleProvider) CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurit
if sc.SELinuxOptions == nil { if sc.SELinuxOptions == nil {
seLinux, err := s.strategies.SELinuxStrategy.Generate(pod, nil) seLinux, err := s.strategies.SELinuxStrategy.Generate(pod, nil)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
sc.SELinuxOptions = seLinux sc.SELinuxOptions = seLinux
} }
return sc, nil return sc, annotations, nil
} }
// Create a SecurityContext based on the given constraints. If a setting is already set on the // Create a SecurityContext based on the given constraints. If a setting is already set on the
@ -110,7 +112,7 @@ func (s *simpleProvider) CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurit
// //
// NOTE: this method works on a copy of the SC of the container. It is up to the caller to apply // NOTE: this method works on a copy of the SC of the container. It is up to the caller to apply
// the SC if validation passes. // the SC if validation passes.
func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container *api.Container) (*api.SecurityContext, error) { func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container *api.Container) (*api.SecurityContext, map[string]string, error) {
var sc *api.SecurityContext = nil var sc *api.SecurityContext = nil
if container.SecurityContext != nil { if container.SecurityContext != nil {
// work with a copy of the original // work with a copy of the original
@ -119,10 +121,12 @@ func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container
} else { } else {
sc = &api.SecurityContext{} sc = &api.SecurityContext{}
} }
annotations := maps.CopySS(pod.Annotations)
if sc.RunAsUser == nil { if sc.RunAsUser == nil {
uid, err := s.strategies.RunAsUserStrategy.Generate(pod, container) uid, err := s.strategies.RunAsUserStrategy.Generate(pod, container)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
sc.RunAsUser = uid sc.RunAsUser = uid
} }
@ -130,7 +134,7 @@ func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container
if sc.SELinuxOptions == nil { if sc.SELinuxOptions == nil {
seLinux, err := s.strategies.SELinuxStrategy.Generate(pod, container) seLinux, err := s.strategies.SELinuxStrategy.Generate(pod, container)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
sc.SELinuxOptions = seLinux sc.SELinuxOptions = seLinux
} }
@ -150,7 +154,7 @@ func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container
caps, err := s.strategies.CapabilitiesStrategy.Generate(pod, container) caps, err := s.strategies.CapabilitiesStrategy.Generate(pod, container)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
sc.Capabilities = caps sc.Capabilities = caps
@ -161,7 +165,7 @@ func (s *simpleProvider) CreateContainerSecurityContext(pod *api.Pod, container
sc.ReadOnlyRootFilesystem = &readOnlyRootFS sc.ReadOnlyRootFilesystem = &readOnlyRootFS
} }
return sc, nil return sc, annotations, nil
} }
// Ensure a pod's SecurityContext is in compliance with the given constraints. // Ensure a pod's SecurityContext is in compliance with the given constraints.

View File

@ -78,7 +78,7 @@ func TestCreatePodSecurityContextNonmutating(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to create provider %v", err) t.Fatalf("unable to create provider %v", err)
} }
sc, err := provider.CreatePodSecurityContext(pod) sc, _, err := provider.CreatePodSecurityContext(pod)
if err != nil { if err != nil {
t.Fatalf("unable to create psc %v", err) t.Fatalf("unable to create psc %v", err)
} }
@ -148,7 +148,7 @@ func TestCreateContainerSecurityContextNonmutating(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("unable to create provider %v", err) t.Fatalf("unable to create provider %v", err)
} }
sc, err := provider.CreateContainerSecurityContext(pod, &pod.Spec.Containers[0]) sc, _, err := provider.CreateContainerSecurityContext(pod, &pod.Spec.Containers[0])
if err != nil { if err != nil {
t.Fatalf("unable to create container security context %v", err) t.Fatalf("unable to create container security context %v", err)
} }
@ -698,7 +698,7 @@ func TestGenerateContainerSecurityContextReadOnlyRootFS(t *testing.T) {
t.Errorf("%s unable to create provider %v", k, err) t.Errorf("%s unable to create provider %v", k, err)
continue continue
} }
sc, err := provider.CreateContainerSecurityContext(v.pod, &v.pod.Spec.Containers[0]) sc, _, err := provider.CreateContainerSecurityContext(v.pod, &v.pod.Spec.Containers[0])
if err != nil { if err != nil {
t.Errorf("%s unable to create container security context %v", k, err) t.Errorf("%s unable to create container security context %v", k, err)
continue continue

View File

@ -29,10 +29,12 @@ import (
// Provider provides the implementation to generate a new security // Provider provides the implementation to generate a new security
// context based on constraints or validate an existing security context against constraints. // context based on constraints or validate an existing security context against constraints.
type Provider interface { type Provider interface {
// Create a PodSecurityContext based on the given constraints. // Create a PodSecurityContext based on the given constraints. Also returns an updated set
CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurityContext, error) // of Pod annotations for alpha feature support.
// Create a container SecurityContext based on the given constraints CreatePodSecurityContext(pod *api.Pod) (*api.PodSecurityContext, map[string]string, error)
CreateContainerSecurityContext(pod *api.Pod, container *api.Container) (*api.SecurityContext, error) // Create a container SecurityContext based on the given constraints. Also returns an updated set
// of Pod annotations for alpha feature support.
CreateContainerSecurityContext(pod *api.Pod, container *api.Container) (*api.SecurityContext, map[string]string, error)
// Ensure a pod's SecurityContext is in compliance with the given constraints. // Ensure a pod's SecurityContext is in compliance with the given constraints.
ValidatePodSecurityContext(pod *api.Pod, fldPath *field.Path) field.ErrorList ValidatePodSecurityContext(pod *api.Pod, fldPath *field.Path) field.ErrorList
// Ensure a container's SecurityContext is in compliance with the given constraints // Ensure a container's SecurityContext is in compliance with the given constraints

View File

@ -35,6 +35,7 @@ import (
psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util"
sc "k8s.io/kubernetes/pkg/securitycontext" sc "k8s.io/kubernetes/pkg/securitycontext"
"k8s.io/kubernetes/pkg/serviceaccount" "k8s.io/kubernetes/pkg/serviceaccount"
"k8s.io/kubernetes/pkg/util/maps"
"k8s.io/kubernetes/pkg/util/validation/field" "k8s.io/kubernetes/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/pkg/watch"
) )
@ -190,7 +191,7 @@ func assignSecurityContext(provider psp.Provider, pod *api.Pod, fldPath *field.P
errs := field.ErrorList{} errs := field.ErrorList{}
psc, err := provider.CreatePodSecurityContext(pod) psc, pscAnnotations, err := provider.CreatePodSecurityContext(pod)
if err != nil { if err != nil {
errs = append(errs, field.Invalid(field.NewPath("spec", "securityContext"), pod.Spec.SecurityContext, err.Error())) errs = append(errs, field.Invalid(field.NewPath("spec", "securityContext"), pod.Spec.SecurityContext, err.Error()))
} }
@ -200,6 +201,8 @@ func assignSecurityContext(provider psp.Provider, pod *api.Pod, fldPath *field.P
// validation. // validation.
originalPSC := pod.Spec.SecurityContext originalPSC := pod.Spec.SecurityContext
pod.Spec.SecurityContext = psc pod.Spec.SecurityContext = psc
originalAnnotations := maps.CopySS(pod.Annotations)
pod.Annotations = pscAnnotations
errs = append(errs, provider.ValidatePodSecurityContext(pod, field.NewPath("spec", "securityContext"))...) errs = append(errs, provider.ValidatePodSecurityContext(pod, field.NewPath("spec", "securityContext"))...)
// Note: this is not changing the original container, we will set container SCs later so long // Note: this is not changing the original container, we will set container SCs later so long
@ -211,7 +214,7 @@ func assignSecurityContext(provider psp.Provider, pod *api.Pod, fldPath *field.P
// overriding pod level settings. // overriding pod level settings.
containerCopy.SecurityContext = sc.DetermineEffectiveSecurityContext(pod, &containerCopy) containerCopy.SecurityContext = sc.DetermineEffectiveSecurityContext(pod, &containerCopy)
sc, err := provider.CreateContainerSecurityContext(pod, &containerCopy) sc, scAnnotations, err := provider.CreateContainerSecurityContext(pod, &containerCopy)
if err != nil { if err != nil {
errs = append(errs, field.Invalid(field.NewPath("spec", "initContainers").Index(i).Child("securityContext"), "", err.Error())) errs = append(errs, field.Invalid(field.NewPath("spec", "initContainers").Index(i).Child("securityContext"), "", err.Error()))
continue continue
@ -219,6 +222,7 @@ func assignSecurityContext(provider psp.Provider, pod *api.Pod, fldPath *field.P
generatedInitSCs = append(generatedInitSCs, sc) generatedInitSCs = append(generatedInitSCs, sc)
containerCopy.SecurityContext = sc containerCopy.SecurityContext = sc
pod.Annotations = scAnnotations
errs = append(errs, provider.ValidateContainerSecurityContext(pod, &containerCopy, field.NewPath("spec", "initContainers").Index(i).Child("securityContext"))...) errs = append(errs, provider.ValidateContainerSecurityContext(pod, &containerCopy, field.NewPath("spec", "initContainers").Index(i).Child("securityContext"))...)
} }
@ -231,7 +235,7 @@ func assignSecurityContext(provider psp.Provider, pod *api.Pod, fldPath *field.P
// overriding pod level settings. // overriding pod level settings.
containerCopy.SecurityContext = sc.DetermineEffectiveSecurityContext(pod, &containerCopy) containerCopy.SecurityContext = sc.DetermineEffectiveSecurityContext(pod, &containerCopy)
sc, err := provider.CreateContainerSecurityContext(pod, &containerCopy) sc, scAnnotations, err := provider.CreateContainerSecurityContext(pod, &containerCopy)
if err != nil { if err != nil {
errs = append(errs, field.Invalid(field.NewPath("spec", "containers").Index(i).Child("securityContext"), "", err.Error())) errs = append(errs, field.Invalid(field.NewPath("spec", "containers").Index(i).Child("securityContext"), "", err.Error()))
continue continue
@ -239,12 +243,14 @@ func assignSecurityContext(provider psp.Provider, pod *api.Pod, fldPath *field.P
generatedSCs[i] = sc generatedSCs[i] = sc
containerCopy.SecurityContext = sc containerCopy.SecurityContext = sc
pod.Annotations = scAnnotations
errs = append(errs, provider.ValidateContainerSecurityContext(pod, &containerCopy, field.NewPath("spec", "containers").Index(i).Child("securityContext"))...) errs = append(errs, provider.ValidateContainerSecurityContext(pod, &containerCopy, field.NewPath("spec", "containers").Index(i).Child("securityContext"))...)
} }
if len(errs) > 0 { if len(errs) > 0 {
// ensure psc is not mutated if there are errors // ensure psc is not mutated if there are errors
pod.Spec.SecurityContext = originalPSC pod.Spec.SecurityContext = originalPSC
pod.Annotations = originalAnnotations
return errs return errs
} }