OPA / Gatekeeper Notes
First, we have to understand the admission controller:
An admission controller is a piece of code that intercepts requests to the Kubernetes API server prior to persistence of the resource, but after the request is authenticated and authorized.
Admission control mechanisms may be validating, mutating, or both. Mutating controllers may modify the data for the resource being modified; validating controllers may not.
There are a bunch of admission controller plugins! Here are some of the default ones in k8s 1.34:
CertificateApproval, CertificateSigning, CertificateSubjectRestriction, DefaultIngressClass, DefaultStorageClass, DefaultTolerationSeconds, LimitRanger, MutatingAdmissionWebhook, NamespaceLifecycle, PersistentVolumeClaimResize, PodSecurity, Priority, ResourceQuota, RuntimeClass, ServiceAccount, StorageObjectInUseProtection, TaintNodesByCondition, ValidatingAdmissionPolicy, ValidatingAdmissionWebhook
With that being said, Gatekeeper is an Admission Controller that enforces constraints using OPA (open policy agent).
"constraints" and "policies" is a matter of semantics.
Gatekeeper looks at its user-defined constraints and checks if resources can be created/modified before allowing them.
Users create constraints by creating ConstraintTemplates.
ConstraintTemplates define a way to validate some set of Kubernetes objects in Gatekeeper's Kubernetes admission controller. They are made of two main elements:
- Rego code that defines a policy violation
- The schema of the accompanying Constraint object, which represents an instantiation of a ConstraintTemplate
ConstraintTemplates create a new CRD when they are installed (kubectl apply -f my-constraint-template.yaml
).
Here's an example that will enforce all resources to have labels:
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
# Schema for the `parameters` field
openAPIV3Schema:
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("you must provide labels: %v", [missing])
}
and then you could create a k8srequiredlabels
constraint by applying something like this:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-gk
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["gatekeeper"]
which would require all namespaces to include the label: gatekeeper