Skip to content

Commit

Permalink
customer verification (#281)
Browse files Browse the repository at this point in the history
* add TODOs with places to change

* add TODOs with places to change

* change accepted validation label values

* add support for namespaces system and user in webhook

* separate IsValidationEnabledForNS in validation package

* use one IsValidationEnabledForNS definition

* update linter excludes

* remove finished todo

* add factory for validation service

* add new mock for validation service factory

* use user validator during pod validation in defaulting webhook

* fix accidentaly commented code; rename validator fields in defaulting webhook

* remove not important calls of validation service factory in tests

* add support (partially) for annotation with notary url

* add support for namespace annotations with notary configuration

* cleanup creating user validation service

* add base for handleTimeout tests in defaulting webhook

* add next test cases for handleTimeout in defaulting webhook

* add test cases for unavaliable notary in defaulting webhook

* add support for strict mode in defaulting webhook for user validation

* add support for namespaces system and user in controller

* add TODO for namespace controller

* add support for changing namespace validation label value in controller

* add support for changing namespace user validation annotations value in controller

* fiv linter errors

* cleanup - rename variables

* cleanup - remove unimportant waits in tests

* shorten test notation

* shorten test notation

* shorten test notation

* improve namespace controller logging

---------

Co-authored-by: Piotr Halama <[email protected]>
  • Loading branch information
anoipm and halamix2 authored Oct 4, 2024
1 parent cf613d9 commit 1996eae
Show file tree
Hide file tree
Showing 22 changed files with 1,566 additions and 237 deletions.
3 changes: 3 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ linters:
issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude:
- "^SA1019: pkg.NamespaceValidationEnabled is deprecated:"
- "^SA1019: warden.NamespaceValidationEnabled is deprecated:"
21 changes: 8 additions & 13 deletions cmd/admission/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,20 @@ import (
"context"
"flag"
"fmt"
"os"

"github.com/kyma-project/warden/internal/env"
"github.com/kyma-project/warden/internal/logging"
"github.com/kyma-project/warden/internal/validate"
"github.com/kyma-project/warden/internal/webhook"
"go.uber.org/zap/zapcore"
"k8s.io/apimachinery/pkg/fields"
"os"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"

"github.com/go-logr/zapr"
"github.com/kyma-project/warden/internal/admission"
"github.com/kyma-project/warden/internal/config"
"github.com/kyma-project/warden/internal/validate"
"github.com/kyma-project/warden/internal/webhook/certs"
"go.uber.org/zap"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
Expand Down Expand Up @@ -151,15 +150,8 @@ func main() {
os.Exit(5)
}

repoFactory := validate.NotaryRepoFactory{Timeout: appConfig.Notary.Timeout}
allowedRegistries := validate.ParseAllowedRegistries(appConfig.Notary.AllowedRegistries)

validatorSvcConfig := validate.ServiceConfig{
NotaryConfig: validate.NotaryConfig{Url: appConfig.Notary.URL},
AllowedRegistries: allowedRegistries,
}
podValidatorSvc := validate.NewImageValidator(&validatorSvcConfig, repoFactory)
validatorSvc := validate.NewPodValidator(podValidatorSvc)
validatorSvc := validate.NewValidatorSvcFactory().NewValidatorSvc(
appConfig.Notary.URL, appConfig.Notary.AllowedRegistries, appConfig.Notary.Timeout)

logger.Info("setting up webhook server")
// webhook server setup
Expand All @@ -170,7 +162,10 @@ func main() {
})

whs.Register(admission.DefaultingPath, &ctrlwebhook.Admission{
Handler: admission.NewDefaultingWebhook(mgr.GetClient(), validatorSvc, appConfig.Admission.Timeout, appConfig.Admission.StrictMode, decoder, logger.With("webhook", "defaulting")),
Handler: admission.NewDefaultingWebhook(mgr.GetClient(),
validatorSvc, validate.NewValidatorSvcFactory(),
appConfig.Admission.Timeout, appConfig.Admission.StrictMode,
decoder, logger.With("webhook", "defaulting")),
})

logger.Info("starting the controller-manager")
Expand Down
1 change: 1 addition & 0 deletions cmd/operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func main() {
mgr.GetClient(),
mgr.GetScheme(),
podValidator,
validate.NewValidatorSvcFactory(),
controllers.PodReconcilerConfig{RequeueAfter: appConfig.Operator.PodReconcilerRequeueAfter},
logger.Named("pod-controller"),
)).SetupWithManager(mgr); err != nil {
Expand Down
76 changes: 52 additions & 24 deletions internal/admission/defaulting.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,27 @@ const (
const PodType = "Pod"

type DefaultingWebHook struct {
validationSvc validate.PodValidator
timeout time.Duration
client k8sclient.Client
decoder *admission.Decoder
baseLogger *zap.SugaredLogger
strictMode bool
systemValidator validate.PodValidator
userValidationSvcFactory validate.ValidatorSvcFactory
timeout time.Duration
client k8sclient.Client
decoder *admission.Decoder
baseLogger *zap.SugaredLogger
strictMode bool
}

func NewDefaultingWebhook(client k8sclient.Client, ValidationSvc validate.PodValidator, timeout time.Duration, strictMode bool, decoder *admission.Decoder, logger *zap.SugaredLogger) *DefaultingWebHook {
func NewDefaultingWebhook(client k8sclient.Client,
systemValidator validate.PodValidator, userValidationSvcFactory validate.ValidatorSvcFactory,
timeout time.Duration, strictMode bool,
decoder *admission.Decoder, logger *zap.SugaredLogger) *DefaultingWebHook {
return &DefaultingWebHook{
client: client,
validationSvc: ValidationSvc,
baseLogger: logger,
timeout: timeout,
strictMode: strictMode,
decoder: decoder,
client: client,
systemValidator: systemValidator,
userValidationSvcFactory: userValidationSvcFactory,
baseLogger: logger,
timeout: timeout,
strictMode: strictMode,
decoder: decoder,
}
}

Expand Down Expand Up @@ -76,19 +81,28 @@ func (w *DefaultingWebHook) handle(ctx context.Context, req admission.Request) a
return result
}

result, err := w.validationSvc.ValidatePod(ctx, pod, ns)
validator := w.systemValidator
if validate.IsUserValidationForNS(ns) {
var err error
validator, err = validate.NewUserValidationSvc(ns, w.userValidationSvcFactory)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
}

result, err := validator.ValidatePod(ctx, pod, ns)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
if result.Status == validate.NoAction {
return admission.Allowed("validation is not enabled for pod")
}
res := w.createResponse(ctx, req, result, pod, logger)
res := w.createResponse(ctx, req, result, pod, ns, logger)
return res
}

func cleanAnnotationIfNeeded(ctx context.Context, pod *corev1.Pod, ns *corev1.Namespace, req admission.Request) admission.Response {
if enabled := isValidationEnabledForNS(ns); !enabled {
if enabled := validate.IsValidationEnabledForNS(ns); !enabled {
return admission.Allowed("validation is not needed for pod")
}
if removed := removeInternalAnnotation(ctx, pod.ObjectMeta.Annotations); removed {
Expand All @@ -110,13 +124,31 @@ func (w DefaultingWebHook) handleTimeout(ctx context.Context, timeoutErr error,
msg := fmt.Sprintf("request exceeded desired timeout: %s, reason: %s", w.timeout.String(), timeoutErr.Error())
logger := helpers.LoggerFromCtx(ctx)
logger.Info(msg)
res := w.createResponse(ctx, req, validate.ValidationResult{Status: validate.ServiceUnavailable}, pod, logger)

ns := &corev1.Namespace{}
if err := w.client.Get(ctx, k8sclient.ObjectKey{Name: pod.Namespace}, ns); err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}

res := w.createResponse(ctx, req, validate.ValidationResult{Status: validate.ServiceUnavailable}, pod, ns, logger)
res.Result = &metav1.Status{Message: msg}
return res
}

func (w *DefaultingWebHook) createResponse(ctx context.Context, req admission.Request, result validate.ValidationResult, pod *corev1.Pod, logger *zap.SugaredLogger) admission.Response {
markedPod := markPod(ctx, result, pod, w.strictMode)
func (w *DefaultingWebHook) createResponse(ctx context.Context,
req admission.Request, result validate.ValidationResult,
pod *corev1.Pod, ns *corev1.Namespace, logger *zap.SugaredLogger) admission.Response {

strictMode := w.strictMode
if validate.IsUserValidationForNS(ns) {
var err error
strictMode, err = helpers.GetUserValidationStrictMode(ns)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
}
}

markedPod := markPod(ctx, result, pod, strictMode)
fBytes, err := json.Marshal(markedPod)
if err != nil {
return admission.Errored(http.StatusInternalServerError, err)
Expand All @@ -128,7 +160,7 @@ func (w *DefaultingWebHook) createResponse(ctx context.Context, req admission.Re

func isValidationNeeded(ctx context.Context, pod *corev1.Pod, ns *corev1.Namespace, operation admissionv1.Operation) bool {
logger := helpers.LoggerFromCtx(ctx)
if enabled := isValidationEnabledForNS(ns); !enabled {
if enabled := validate.IsValidationEnabledForNS(ns); !enabled {
logger.Debugw("pod validation skipped because validation for namespace is not enabled")
return false
}
Expand All @@ -146,10 +178,6 @@ func IsValidationNeededForOperation(operation admissionv1.Operation) bool {
return operation == admissionv1.Create
}

func isValidationEnabledForNS(ns *corev1.Namespace) bool {
return ns.GetLabels()[pkg.NamespaceValidationLabel] == pkg.NamespaceValidationEnabled
}

func isValidationEnabledForPodValidationLabel(pod *corev1.Pod) bool {
validationLabelValue := getPodValidationLabelValue(pod)
if validationLabelValue == pkg.ValidationStatusFailed || validationLabelValue == pkg.ValidationStatusPending {
Expand Down
Loading

0 comments on commit 1996eae

Please sign in to comment.