diff --git a/pkg/internal/apis/certmanager/validation/plugins/plugins.go b/pkg/internal/apis/certmanager/validation/plugins/plugins.go index 876bb970a..d8b528cfc 100644 --- a/pkg/internal/apis/certmanager/validation/plugins/plugins.go +++ b/pkg/internal/apis/certmanager/validation/plugins/plugins.go @@ -23,6 +23,7 @@ import ( "k8s.io/client-go/kubernetes" ) +// Plugin is an admission plugin that will run during admission webhook events. type Plugin interface { Init(client kubernetes.Interface) Validate(admissionSpec *admissionv1.AdmissionRequest, oldObj, obj runtime.Object) *field.Error diff --git a/pkg/webhook/handlers/BUILD.bazel b/pkg/webhook/handlers/BUILD.bazel index 1a35fb3aa..8566ca754 100644 --- a/pkg/webhook/handlers/BUILD.bazel +++ b/pkg/webhook/handlers/BUILD.bazel @@ -13,6 +13,7 @@ go_library( deps = [ "//pkg/internal/api/mutation:go_default_library", "//pkg/internal/api/validation:go_default_library", + "//pkg/internal/apis/certmanager/validation/plugins:go_default_library", "//pkg/logs:go_default_library", "@com_github_go_logr_logr//:go_default_library", "@io_k8s_api//admission/v1:go_default_library", @@ -25,6 +26,7 @@ go_library( "@io_k8s_apimachinery//pkg/runtime/serializer/json:go_default_library", "@io_k8s_apimachinery//pkg/runtime/serializer/versioning:go_default_library", "@io_k8s_apimachinery//pkg/util/validation/field:go_default_library", + "@io_k8s_client_go//kubernetes:go_default_library", ], ) diff --git a/pkg/webhook/handlers/interfaces.go b/pkg/webhook/handlers/interfaces.go index 8805b430e..aba9a13bd 100644 --- a/pkg/webhook/handlers/interfaces.go +++ b/pkg/webhook/handlers/interfaces.go @@ -20,12 +20,17 @@ import ( admissionv1 "k8s.io/api/admission/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + "k8s.io/client-go/kubernetes" ) type ValidatingAdmissionHook interface { // Validate is called to decide whether to accept the admission request. The returned AdmissionResponse // must not use the Patch field. Validate(admissionSpec *admissionv1.AdmissionRequest) *admissionv1.AdmissionResponse + + // InitPlugins will initialise all plugins which are registered for this + // validating admission hook. + InitPlugins(client kubernetes.Interface) } type MutatingAdmissionHook interface { diff --git a/pkg/webhook/handlers/validation.go b/pkg/webhook/handlers/validation.go index faed4e0c1..5c14df010 100644 --- a/pkg/webhook/handlers/validation.go +++ b/pkg/webhook/handlers/validation.go @@ -26,14 +26,18 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/client-go/kubernetes" "github.com/jetstack/cert-manager/pkg/internal/api/validation" + "github.com/jetstack/cert-manager/pkg/internal/apis/certmanager/validation/plugins" ) type registryBackedValidator struct { log logr.Logger decoder runtime.Decoder registry *validation.Registry + + plugins []plugins.Plugin } func NewRegistryBackedValidator(log logr.Logger, scheme *runtime.Scheme, registry *validation.Registry) *registryBackedValidator { @@ -42,6 +46,13 @@ func NewRegistryBackedValidator(log logr.Logger, scheme *runtime.Scheme, registr log: log, decoder: factory.UniversalDecoder(), registry: registry, + plugins: plugins.All(scheme), + } +} + +func (r *registryBackedValidator) InitPlugins(client kubernetes.Interface) { + for _, plugin := range r.plugins { + plugin.Init(client) } } @@ -96,12 +107,17 @@ func (r *registryBackedValidator) Validate(admissionSpec *admissionv1.AdmissionR } else if admissionSpec.Operation == admissionv1.Update { // perform update validation on resource errs = append(errs, r.registry.ValidateUpdate(admissionSpec, oldObj, obj, gvk)...) + } - // If no validation errors occurred, perform SubjectAccessReview checks. - if len(errs) == 0 { - errs = append(errs, r.registry.SubjectAccessReview(admissionSpec, oldObj, obj, gvk)...) + // If no validation errors occurred, perform plugin checks. + if len(errs) == 0 { + for _, plugin := range r.plugins { + if err := plugin.Validate(admissionSpec, oldObj, obj); err != nil { + errs = append(errs, err) + } } } + // return with allowed = false if any errors occurred if err := errs.ToAggregate(); err != nil { status.Allowed = false