Most guides for OPA Gatekeeper are either vendor marketing or academic deep dives. I needed to get pod security policies enforced on a new cluster, fast. Here's the stripped-down, working procedure I used, clocked at 28 minutes from zero to blocking a privileged pod.
First, deploy Gatekeeper. The latest stable Helm chart is fine. No need for custom values yet.
```bash
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper gatekeeper/gatekeeper --namespace gatekeeper-system --create-namespace
```
While that settles, define your ConstraintTemplate. This is the reusable policy logic. We'll start with a basic "no privileged pods" template.
```yaml
apiVersion: templates.gatekeeper.io/v1
kind: ConstraintTemplate
metadata:
name: k8spspprivilegedcontainer
spec:
crd:
spec:
names:
kind: K8sPSPPrivilegedContainer
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8spspprivilegedcontainer
violation[{"msg": msg, "details": {}}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged
msg := sprintf("Privileged container is not allowed: %v", [container.name])
}
```
Apply that, then create the actual Constraint that enforces it across your chosen scope (e.g., all namespaces except `kube-system`).
```yaml
apiVersion: constraints.gatekeeper.io/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
name: psp-no-privileged
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces: ["kube-system"]
```
Test it by trying to launch a pod with `privileged: true`. You should get a clear rejection message. This is your foundation. From here, you can build out more constraints for host namespaces, capabilities, or volume types using the same pattern.
Key things I learned the hard way:
* The ConstraintTemplate defines the *rule*. The Constraint defines the *scope*.
* Audit functionality (checking existing resources) kicks in after a minute or two. Don't panic if it's not instant.
* Keep your Rego simple in these templates. This isn't the place for complex logic.
Total time spent: about 20 minutes for setup, 8 minutes for testing and refining the match/exclude clauses. It's a solid, auditable replacement for the deprecated PSP.
—JW
—JW
That's a solid start for getting something deployed quickly, but you're missing a critical step. After defining your ConstraintTemplate, you must create a Constraint object that actually applies it to the cluster. The template is just the rule definition; the Constraint is the enforcement.
Your rego snippet also cuts off. The full violation block needs to check both initContainers and containers, or you'll have a policy gap. Here's the complete block you'd want:
```rego
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
container.securityContext.privileged
msg := sprintf("Privileged container is not allowed: %v", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
container.securityContext.privileged
msg := sprintf("Privileged initContainer is not allowed: %v", [container.name])
}
```
Then you'd `kubectl apply` a Constraint of kind `K8sPSPPrivilegedContainer` to make it active. Without that, your 28-minute claim is for deployment only, not for a working policy.
-- bb42