func accept(accepter rules.Accepter, imageResolutionType imagepolicyapi.ImageResolutionType, resolver imageResolver, m meta.ImageReferenceMutator, attr admission.Attributes, excludedRules sets.String) error { decisions := policyDecisions{} gr := attr.GetResource().GroupResource() errs := m.Mutate(func(ref *kapi.ObjectReference) error { // create the attribute set for this particular reference, if we have never seen the reference // before decision, ok := decisions[*ref] if !ok { if imagepolicyapi.RequestsResolution(imageResolutionType) { resolvedAttrs, err := resolver.ResolveObjectReference(ref, attr.GetNamespace()) switch { case err != nil && imagepolicyapi.FailOnResolutionFailure(imageResolutionType): // if we had a resolution error and we're supposed to fail, fail decision.err = err decision.tested = true decisions[*ref] = decision return err case err != nil: // if we had an error, but aren't supposed to fail, just don't do anything else and keep track of // the resolution failure decision.err = err case err == nil: // if we resolved properly, assign the attributes and rewrite the pull spec if we need to decision.attrs = resolvedAttrs if imagepolicyapi.RewriteImagePullSpec(imageResolutionType) { ref.Namespace = "" ref.Name = decision.attrs.Name.Exact() ref.Kind = "DockerImage" } } } // if we don't have any image policy attributes, attempt a best effort parse for the remaining tests if decision.attrs == nil { decision.attrs = &rules.ImagePolicyAttributes{} // an objectref that is DockerImage ref will have a name that corresponds to its pull spec. We can parse that // to a docker image ref if ref != nil && ref.Kind == "DockerImage" { decision.attrs.Name, _ = imageapi.ParseDockerImageReference(ref.Name) } } decision.attrs.Resource = gr decision.attrs.ExcludedRules = excludedRules } // we only need to test a given input once for acceptance if !decision.tested { accepted := accepter.Accepts(decision.attrs) glog.V(5).Infof("Made decision for %v (as: %v, err: %v): %t", ref, decision.attrs.Name, decision.err, accepted) decision.tested = true decisions[*ref] = decision if !accepted { // if the image is rejected, return the resolution error, if any if decision.err != nil { return decision.err } return errRejectByPolicy } } return nil }) for i := range errs { errs[i].Type = field.ErrorTypeForbidden if errs[i].Detail != errRejectByPolicy.Error() { errs[i].Detail = fmt.Sprintf("this image is prohibited by policy: %s", errs[i].Detail) } } if len(errs) > 0 { glog.V(5).Infof("failed to create: %v", errs) return apierrs.NewInvalid(attr.GetKind().GroupKind(), attr.GetName(), errs) } glog.V(5).Infof("allowed: %#v", attr) return nil }
func accept(accepter rules.Accepter, resolver imageResolver, m meta.ImageReferenceMutator, attr admission.Attributes, excludedRules sets.String) error { var decisions policyDecisions gr := attr.GetResource().GroupResource() requiresImage := accepter.RequiresImage(gr) resolvesImage := accepter.ResolvesImage(gr) errs := m.Mutate(func(ref *kapi.ObjectReference) error { // create the attribute set for this particular reference, if we have never seen the reference // before decision, ok := decisions[*ref] if !ok { var attrs *rules.ImagePolicyAttributes var err error if requiresImage || resolvesImage { // convert the incoming reference into attributes to pass to the accepter attrs, err = resolver.ResolveObjectReference(ref, attr.GetNamespace()) } // if the incoming reference is of a Kind that needed a lookup, but that lookup failed, // use the most generic policy rule here because we don't even know the image name if attrs == nil { attrs = &rules.ImagePolicyAttributes{} // an objectref that is DockerImage ref will have a name that corresponds to its pull spec. We can parse that // to a docker image ref if ref != nil && ref.Kind == "DockerImage" { attrs.Name, _ = imageapi.ParseDockerImageReference(ref.Name) } } attrs.Resource = gr attrs.ExcludedRules = excludedRules decision.attrs = attrs decision.err = err } // we only need to test a given input once for acceptance if !decision.tested { accepted := accepter.Accepts(decision.attrs) glog.V(5).Infof("Made decision for %v (as: %v, err: %v): %t", ref, decision.attrs.Name, decision.err, accepted) // remember this decision for any identical reference if decisions == nil { decisions = make(policyDecisions) } decision.tested = true decisions[*ref] = decision if !accepted { // if the image is rejected, return the resolution error, if any if decision.err != nil { return decision.err } return errRejectByPolicy } } // if resolution was requested, and no error was present, transform the // reference back into a string to a DockerImage if resolvesImage && decision.err == nil { ref.Namespace = "" ref.Name = decision.attrs.Name.Exact() ref.Kind = "DockerImage" } if decision.err != nil { glog.V(5).Infof("Ignored resolution error for %v: %v", ref, decision.err) } return nil }) for i := range errs { errs[i].Type = field.ErrorTypeForbidden if errs[i].Detail != errRejectByPolicy.Error() { errs[i].Detail = fmt.Sprintf("this image is prohibited by policy: %s", errs[i].Detail) } } if len(errs) > 0 { glog.V(5).Infof("failed to create: %v", errs) return apierrs.NewInvalid(attr.GetKind().GroupKind(), attr.GetName(), errs) } glog.V(5).Infof("allowed: %#v", attr) return nil }