mutatingwebhookconfiguration-hardening
A webhook that fails open is bypassed by anyone who can make it unreachable, and an external URL endpoint sends every intercepted object off-cluster and lets whoever runs it rewrite workloads at admission time.
!has(object.webhooks) || object.webhooks.all(w,
w.?failurePolicy.orValue('Fail') != 'Ignore'
)
MutatingWebhookConfigurations must not set failurePolicy to Ignore.
!has(object.webhooks) || object.webhooks.all(w,
!has(w.clientConfig.url)
)
MutatingWebhookConfigurations must not use an external clientConfig.url; back the webhook with an in-cluster service.
Set failurePolicy to Fail on every webhook and point clientConfig at an in-cluster service rather than a url. Fields: webhooks[*].failurePolicy, webhooks[*].clientConfig.url.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: mutatingwebhookconfiguration-hardening
annotations:
kubeapt.io/uuid: "065baa8b-6120-4ac7-9433-7ed2fe5ffda5"
security.kubeapt.io/displayName: "Fails Open or Uses an Off-Cluster Endpoint"
security.kubeapt.io/description: "A webhook that fails open is bypassed by anyone who can make it unreachable, and an external URL endpoint sends every intercepted object off-cluster and lets whoever runs it rewrite workloads at admission time."
security.kubeapt.io/resource: "MutatingWebhookConfigurations"
security.kubeapt.io/severity: "Moderate"
security.kubeapt.io/remediation: "Set failurePolicy to Fail on every webhook and point clientConfig at an in-cluster service rather than a url. Fields: webhooks[*].failurePolicy, webhooks[*].clientConfig.url."
security.kubeapt.io/product: "Kubernetes"
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups:
- admissionregistration.k8s.io
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- mutatingwebhookconfigurations
validations:
- expression: |
!has(object.webhooks) || object.webhooks.all(w,
w.?failurePolicy.orValue('Fail') != 'Ignore'
)
message: |
MutatingWebhookConfigurations must not set failurePolicy to Ignore.
- expression: |
!has(object.webhooks) || object.webhooks.all(w,
!has(w.clientConfig.url)
)
message: |
MutatingWebhookConfigurations must not use an external clientConfig.url; back the webhook with an in-cluster service.Save it as mutatingwebhookconfiguration-hardening.yaml — the commands below assume that name.
Check a workload against this one policy, before anything is installed on a cluster.
$ kubeapt validate -p ./mutatingwebhookconfiguration-hardening.yaml -r ./workload.yamlOr without the file, from the published policy set — -r takes a directory too:
$ kubeapt policies download && kubeapt validate --policy-name mutatingwebhookconfiguration-hardening -r ./manifestsOr against every namespace in the cluster your kubeconfig points at:
$ kubeapt validate --policy-name mutatingwebhookconfiguration-hardening -A