// Create registers a given new PodSecurityPolicyReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { pspr, ok := obj.(*securityapi.PodSecurityPolicyReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicyReview: %#v", obj)) } if errs := securityvalidation.ValidatePodSecurityPolicyReview(pspr); len(errs) > 0 { return nil, kapierrors.NewInvalid(kapi.Kind("PodSecurityPolicyReview"), "", errs) } ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("namespace parameter required.") } serviceAccounts, err := getServiceAccounts(pspr.Spec, r.saCache, ns) if err != nil { return nil, kapierrors.NewBadRequest(err.Error()) } if len(serviceAccounts) == 0 { glog.Errorf("No service accounts for namespace %s", ns) return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find ServiceAccount for namespace: %s", ns)) } errs := []error{} newStatus := securityapi.PodSecurityPolicyReviewStatus{} for _, sa := range serviceAccounts { userInfo := serviceaccount.UserInfo(ns, sa.Name, "") saConstraints, err := r.sccMatcher.FindApplicableSCCs(userInfo) if err != nil { errs = append(errs, fmt.Errorf("unable to find SecurityContextConstraints for ServiceAccount %s: %v", sa.Name, err)) continue } oscc.DeduplicateSecurityContextConstraints(saConstraints) sort.Sort(oscc.ByPriority(saConstraints)) var namespace *kapi.Namespace for _, constraint := range saConstraints { var ( provider kscc.SecurityContextConstraintsProvider err error ) pspsrs := securityapi.PodSecurityPolicySubjectReviewStatus{} if provider, namespace, err = oscc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil { errs = append(errs, fmt.Errorf("unable to create provider for service account %s: %v", sa.Name, err)) continue } _, err = podsecuritypolicysubjectreview.FillPodSecurityPolicySubjectReviewStatus(&pspsrs, provider, pspr.Spec.Template.Spec, constraint) if err != nil { glog.Errorf("unable to fill PodSecurityPolicyReviewStatus from constraint %v", err) continue } sapsprs := securityapi.ServiceAccountPodSecurityPolicyReviewStatus{pspsrs, sa.Name} newStatus.AllowedServiceAccounts = append(newStatus.AllowedServiceAccounts, sapsprs) } } if len(errs) > 0 { return nil, kapierrors.NewBadRequest(fmt.Sprintf("%s", kerrors.NewAggregate(errs))) } pspr.Status = newStatus return pspr, nil }
// Create registers a given new PodSecurityPolicySubjectReview instance to r.registry. func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { pspsr, ok := obj.(*securityapi.PodSecurityPolicySubjectReview) if !ok { return nil, kapierrors.NewBadRequest(fmt.Sprintf("not a PodSecurityPolicySubjectReview: %#v", obj)) } ns, ok := kapi.NamespaceFrom(ctx) if !ok { return nil, kapierrors.NewBadRequest("namespace parameter required.") } if errs := securityvalidation.ValidatePodSecurityPolicySubjectReview(pspsr); len(errs) > 0 { return nil, kapierrors.NewInvalid(kapi.Kind("PodSecurityPolicySubjectReview"), "", errs) } userInfo := &user.DefaultInfo{Name: pspsr.Spec.User, Groups: pspsr.Spec.Groups} matchedConstraints, err := r.sccMatcher.FindApplicableSCCs(userInfo) if err != nil { return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find SecurityContextConstraints: %v", err)) } saName := pspsr.Spec.Template.Spec.ServiceAccountName if len(saName) > 0 { saUserInfo := serviceaccount.UserInfo(ns, saName, "") saConstraints, err := r.sccMatcher.FindApplicableSCCs(saUserInfo) if err != nil { return nil, kapierrors.NewBadRequest(fmt.Sprintf("unable to find SecurityContextConstraints: %v", err)) } matchedConstraints = append(matchedConstraints, saConstraints...) } oscc.DeduplicateSecurityContextConstraints(matchedConstraints) sort.Sort(oscc.ByPriority(matchedConstraints)) var namespace *kapi.Namespace for _, constraint := range matchedConstraints { var ( provider kscc.SecurityContextConstraintsProvider err error ) if provider, namespace, err = oscc.CreateProviderFromConstraint(ns, namespace, constraint, r.client); err != nil { glog.Errorf("Unable to create provider for constraint: %v", err) continue } filled, err := FillPodSecurityPolicySubjectReviewStatus(&pspsr.Status, provider, pspsr.Spec.Template.Spec, constraint) if err != nil { glog.Errorf("unable to fill PodSecurityPolicySubjectReviewStatus from constraint %v", err) continue } if filled { return pspsr, nil } } return pspsr, nil }
// Admit determines if the pod should be admitted based on the requested security context // and the available SCCs. // // 1. Find SCCs for the user. // 2. Find SCCs for the SA. If there is an error retrieving SA SCCs it is not fatal. // 3. Remove duplicates between the user/SA SCCs. // 4. Create the providers, includes setting pre-allocated values if necessary. // 5. Try to generate and validate an SCC with providers. If we find one then admit the pod // with the validated SCC. If we don't find any reject the pod and give all errors from the // failed attempts. // On updates, the BeforeUpdate of the pod strategy only zeroes out the status. That means that // any change that claims the pod is no longer privileged will be removed. That should hold until // we get a true old/new set of objects in. func (c *constraint) Admit(a kadmission.Attributes) error { if a.GetResource().GroupResource() != kapi.Resource("pods") { return nil } if len(a.GetSubresource()) != 0 { return nil } pod, ok := a.GetObject().(*kapi.Pod) // if we can't convert then we don't handle this object so just return if !ok { return nil } // get all constraints that are usable by the user glog.V(4).Infof("getting security context constraints for pod %s (generate: %s) in namespace %s with user info %v", pod.Name, pod.GenerateName, a.GetNamespace(), a.GetUserInfo()) sccMatcher := oscc.NewDefaultSCCMatcher(c.sccLister) matchedConstraints, err := sccMatcher.FindApplicableSCCs(a.GetUserInfo()) if err != nil { return kadmission.NewForbidden(a, err) } // get all constraints that are usable by the SA if len(pod.Spec.ServiceAccountName) > 0 { userInfo := serviceaccount.UserInfo(a.GetNamespace(), pod.Spec.ServiceAccountName, "") glog.V(4).Infof("getting security context constraints for pod %s (generate: %s) with service account info %v", pod.Name, pod.GenerateName, userInfo) saConstraints, err := sccMatcher.FindApplicableSCCs(userInfo) if err != nil { return kadmission.NewForbidden(a, err) } matchedConstraints = append(matchedConstraints, saConstraints...) } // remove duplicate constraints and sort matchedConstraints = oscc.DeduplicateSecurityContextConstraints(matchedConstraints) sort.Sort(oscc.ByPriority(matchedConstraints)) providers, errs := oscc.CreateProvidersFromConstraints(a.GetNamespace(), matchedConstraints, c.client) logProviders(pod, providers, errs) if len(providers) == 0 { return kadmission.NewForbidden(a, fmt.Errorf("no providers available to validate pod request")) } // all containers in a single pod must validate under a single provider or we will reject the request validationErrs := field.ErrorList{} for _, provider := range providers { if errs := oscc.AssignSecurityContext(provider, pod, field.NewPath(fmt.Sprintf("provider %s: ", provider.GetSCCName()))); len(errs) > 0 { validationErrs = append(validationErrs, errs...) continue } // the entire pod validated, annotate and accept the pod glog.V(4).Infof("pod %s (generate: %s) validated against provider %s", pod.Name, pod.GenerateName, provider.GetSCCName()) if pod.ObjectMeta.Annotations == nil { pod.ObjectMeta.Annotations = map[string]string{} } pod.ObjectMeta.Annotations[allocator.ValidatedSCCAnnotation] = provider.GetSCCName() return nil } // we didn't validate against any security context constraint provider, reject the pod and give the errors for each attempt glog.V(4).Infof("unable to validate pod %s (generate: %s) against any security context constraint: %v", pod.Name, pod.GenerateName, validationErrs) return kadmission.NewForbidden(a, fmt.Errorf("unable to validate against any security context constraint: %v", validationErrs)) }