Skip to content

Commit

Permalink
feat(kuma-cp) Secrets validation on K8S
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubdyszkiewicz committed Apr 27, 2020
1 parent dbc4b5e commit af91abc
Show file tree
Hide file tree
Showing 12 changed files with 514 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4680,3 +4680,21 @@ webhooks:
- UPDATE
resources:
- services
- name: secret.validator.kuma-admission.kuma.io
failurePolicy: Fail
clientConfig:
caBundle: Q0VSVA==
service:
namespace: kuma-system
name: kuma-control-plane
path: /validate-v1-secret
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- secrets
Original file line number Diff line number Diff line change
Expand Up @@ -4534,3 +4534,21 @@ webhooks:
- UPDATE
resources:
- services
- name: secret.validator.kuma-admission.kuma.io
failurePolicy: Fail
clientConfig:
caBundle: Q0VSVA==
service:
namespace: kuma-system
name: kuma-control-plane
path: /validate-v1-secret
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- secrets
Original file line number Diff line number Diff line change
Expand Up @@ -4535,3 +4535,21 @@ webhooks:
- UPDATE
resources:
- services
- name: secret.validator.kuma-admission.kuma.io
failurePolicy: Fail
clientConfig:
caBundle: QWRtaXNzaW9uQ2VydA==
service:
namespace: kuma
name: kuma-ctrl-plane
path: /validate-v1-secret
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- secrets
18 changes: 18 additions & 0 deletions app/kumactl/data/install/k8s/control-plane/kuma-cp/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,21 @@ webhooks:
- UPDATE
resources:
- services
- name: secret.validator.kuma-admission.kuma.io
failurePolicy: Fail
clientConfig:
caBundle: {{ .AdmissionServerTlsCert | b64enc }}
service:
namespace: {{ .Namespace }}
name: {{ .ControlPlaneServiceName }}
path: /validate-v1-secret
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- secrets
42 changes: 21 additions & 21 deletions app/kumactl/pkg/install/k8s/control-plane/templates_vfsdata.go

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions pkg/plugins/runtime/k8s/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,11 @@ func addValidators(mgr kube_ctrl.Manager, rt core_runtime.Runtime) error {
mgr.GetWebhookServer().Register("/validate-v1-service", &kuba_webhook.Admission{Handler: &k8s_webhooks.ServiceValidator{}})
log.Info("Registering a validation webhook for v1/Service", "path", "/validate-v1-service")

secretValidator := &k8s_webhooks.SecretValidator{
Client: mgr.GetClient(),
}
mgr.GetWebhookServer().Register("/validate-v1-secret", &kuba_webhook.Admission{Handler: secretValidator})
log.Info("Registering a validation webhook for v1/Secret", "path", "/validate-v1-secret")

return nil
}
4 changes: 2 additions & 2 deletions pkg/plugins/runtime/k8s/webhooks/mesh_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (h *MeshValidator) ValidateCreate(ctx context.Context, req admission.Reques
}
if err := h.validator.ValidateCreate(ctx, req.Name, coreRes); err != nil {
if kumaErr, ok := err.(*validators.ValidationError); ok {
return convertValidationError(kumaErr, k8sRes)
return convertSpecValidationError(kumaErr, k8sRes)
}
return admission.Denied(err.Error())
}
Expand Down Expand Up @@ -82,7 +82,7 @@ func (h *MeshValidator) ValidateUpdate(ctx context.Context, req admission.Reques

if err := h.validator.ValidateUpdate(ctx, oldCoreRes, coreRes); err != nil {
if kumaErr, ok := err.(*validators.ValidationError); ok {
return convertValidationError(kumaErr, k8sRes)
return convertSpecValidationError(kumaErr, k8sRes)
}
return admission.Denied(err.Error())
}
Expand Down
104 changes: 104 additions & 0 deletions pkg/plugins/runtime/k8s/webhooks/secret_validator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package webhooks

import (
"context"
"net/http"

"github.com/pkg/errors"

"github.com/Kong/kuma/pkg/core/validators"
mesh_k8s "github.com/Kong/kuma/pkg/plugins/resources/k8s/native/api/v1alpha1"

kube_core "k8s.io/api/core/v1"
kube_apierrs "k8s.io/apimachinery/pkg/api/errors"
kube_types "k8s.io/apimachinery/pkg/types"
kube_client "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
)

const (
meshLabel = "kuma.io/mesh"
)

type SecretValidator struct {
Decoder *admission.Decoder
Client kube_client.Client
}

func (v *SecretValidator) Handle(ctx context.Context, req admission.Request) admission.Response {
secret := &kube_core.Secret{}

err := v.Decoder.Decode(req, secret)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}

oldSecret := &kube_core.Secret{}
if len(req.OldObject.Raw) != 0 {
err := v.Decoder.DecodeRaw(req.OldObject, oldSecret)
if err != nil {
return admission.Errored(http.StatusBadRequest, err)
}
} else {
oldSecret = nil
}

if err := v.validate(ctx, secret, oldSecret); err != nil {
if verr, ok := err.(*validators.ValidationError); ok {
return convertValidationErrorOf(*verr, secret, secret)
}
return admission.Denied(err.Error())
}

return admission.Allowed("")
}

func (v *SecretValidator) validate(ctx context.Context, secret *kube_core.Secret, oldSecret *kube_core.Secret) error {
verr := &validators.ValidationError{}
if !isKumaSecret(secret) {
return nil
}

// validate mesh exists
mesh := mesh_k8s.Mesh{}
key := kube_types.NamespacedName{
Name: meshOfSecret(secret),
}
if err := v.Client.Get(ctx, key, &mesh); err != nil {
if kube_apierrs.IsNotFound(err) {
verr.AddViolationAt(validators.RootedAt("metadata").Field("labels").Key(meshLabel), "mesh does not exist")
} else {
return errors.Wrap(err, "could not fetch mesh")
}
}

// block change of the mesh on the secret
if oldSecret != nil {
if meshOfSecret(secret) != meshOfSecret(oldSecret) {
verr.AddViolationAt(validators.RootedAt("metadata").Field("labels").Key(meshLabel), "cannot change mesh of the Secret. Delete the Secret first and apply it again.")
}
}

// validate convention of the secret
if len(secret.Data["value"]) == 0 {
verr.AddViolationAt(validators.RootedAt("data").Field("value"), "cannot be empty.")
}
return verr.OrNil()
}

func isKumaSecret(secret *kube_core.Secret) bool {
return secret.Type == "system.kuma.io/secret"
}

func meshOfSecret(secret *kube_core.Secret) string {
meshName := secret.GetLabels()[meshLabel]
if meshName == "" {
return "default"
}
return meshName
}

func (v *SecretValidator) InjectDecoder(d *admission.Decoder) error {
v.Decoder = d
return nil
}
Loading

0 comments on commit af91abc

Please sign in to comment.