Set up OPA Gatekeeper admission controllers to enforce security policies, resource governance, and compliance rules across your Kubernetes cluster with custom constraint templates.
Prerequisites
- Kubernetes cluster with admin access
- kubectl installed and configured
- Basic understanding of YAML and Kubernetes resources
What this solves
OPA Gatekeeper provides policy-as-code enforcement for Kubernetes clusters through admission controllers that validate and mutate resources before they're created. This tutorial shows you how to implement comprehensive policy enforcement including security controls, resource limits, and compliance requirements using constraint templates and custom policies.
Step-by-step installation
Update system packages and install kubectl
Start by ensuring your system has the latest packages and kubectl installed for cluster management.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget apt-transport-https ca-certificates gnupg
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
Verify Kubernetes cluster access
Confirm you have administrative access to your Kubernetes cluster before installing Gatekeeper.
kubectl cluster-info
kubectl auth can-i '' '' --all-namespaces
Install OPA Gatekeeper
Deploy Gatekeeper using the official release manifests which include all necessary CRDs, RBAC, and admission controller components.
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.14/deploy/gatekeeper.yaml
Wait for Gatekeeper components to start
Monitor the deployment until all Gatekeeper pods are running and the admission controller webhook is ready.
kubectl wait --for=condition=ready pod -l gatekeeper.sh/operation=webhook -n gatekeeper-system --timeout=120s
kubectl get pods -n gatekeeper-system
kubectl get validatingadmissionwebhooks.admissionregistration.k8s.io
Create constraint template for required labels
Define a reusable constraint template that enforces required labels on resources. This template uses Rego language for policy logic.
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
required := input.parameters.labels
provided := input.review.object.metadata.labels
missing := required[_]
not provided[missing]
msg := sprintf("Missing required label: %v", [missing])
}
Apply the constraint template
Install the constraint template to make it available for creating specific policy constraints.
kubectl apply -f required-labels-template.yaml
kubectl get constrainttemplates
Create a constraint for environment labeling
Use the template to create a specific constraint that requires pods to have environment and team labels.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-must-have-env
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces: ["kube-system", "gatekeeper-system", "kube-public", "kube-node-lease"]
parameters:
labels: ["environment", "team"]
Apply the pod labeling constraint
Install the constraint to start enforcing required labels on new pod deployments.
kubectl apply -f require-pod-labels.yaml
kubectl get k8srequiredlabels
Create security policy constraint template
Define a template for container security policies that prevents privileged containers and enforces security contexts.
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8ssecuritypolicy
spec:
crd:
spec:
names:
kind: K8sSecurityPolicy
validation:
type: object
properties:
allowPrivileged:
type: boolean
requiredSecurityContext:
type: boolean
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8ssecuritypolicy
violation[{"msg": msg}] {
not input.parameters.allowPrivileged
container := input.review.object.spec.containers[_]
container.securityContext.privileged == true
msg := "Privileged containers are not allowed"
}
violation[{"msg": msg}] {
input.parameters.requiredSecurityContext
container := input.review.object.spec.containers[_]
not container.securityContext
msg := "Containers must define securityContext"
}
violation[{"msg": msg}] {
input.parameters.requiredSecurityContext
container := input.review.object.spec.containers[_]
not container.securityContext.runAsNonRoot
msg := "Containers must run as non-root user"
}
Apply security policy template and constraint
Install the security template and create a constraint that enforces container security best practices.
kubectl apply -f security-policy-template.yaml
cat << 'EOF' > security-constraint.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sSecurityPolicy
metadata:
name: container-security-policy
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
- apiGroups: ["apps"]
kinds: ["Deployment"]
excludedNamespaces: ["kube-system", "gatekeeper-system"]
parameters:
allowPrivileged: false
requiredSecurityContext: true
EOF
kubectl apply -f security-constraint.yaml
Create resource limits constraint template
Define a template that enforces CPU and memory limits on containers to prevent resource starvation.
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8sresourcelimits
spec:
crd:
spec:
names:
kind: K8sResourceLimits
validation:
type: object
properties:
maxCpu:
type: string
maxMemory:
type: string
requireLimits:
type: boolean
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sresourcelimits
violation[{"msg": msg}] {
input.parameters.requireLimits
container := input.review.object.spec.containers[_]
not container.resources.limits
msg := sprintf("Container %v missing resource limits", [container.name])
}
violation[{"msg": msg}] {
input.parameters.requireLimits
container := input.review.object.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("Container %v missing CPU limit", [container.name])
}
violation[{"msg": msg}] {
input.parameters.requireLimits
container := input.review.object.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("Container %v missing memory limit", [container.name])
}
Apply resource limits policies
Install the resource template and create constraints that enforce resource limits on all workloads.
kubectl apply -f resource-limits-template.yaml
cat << 'EOF' > resource-limits-constraint.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sResourceLimits
metadata:
name: container-resource-limits
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
- apiGroups: ["apps"]
kinds: ["Deployment", "StatefulSet", "DaemonSet"]
excludedNamespaces: ["kube-system", "gatekeeper-system"]
parameters:
maxCpu: "2"
maxMemory: "4Gi"
requireLimits: true
EOF
kubectl apply -f resource-limits-constraint.yaml
Configure constraint violation monitoring
Set up monitoring for policy violations to track compliance and identify problematic deployments.
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: gatekeeper-system
spec:
match:
- excludedNamespaces: ["kube-system", "gatekeeper-system"]
processes: ["*"]
validation:
traces:
- user:
kind:
group: "*"
version: "*"
kind: "*"
readiness:
statsEnabled: true
Apply monitoring configuration
Enable violation tracking and readiness monitoring to observe Gatekeeper's policy enforcement.
kubectl apply -f monitoring-config.yaml
kubectl get config -n gatekeeper-system
Verify your setup
Test your Gatekeeper installation by attempting to create pods that violate the configured policies.
# Check Gatekeeper status
kubectl get pods -n gatekeeper-system
kubectl get constrainttemplates
kubectl get constraints
Test label enforcement (this should fail)
kubectl run test-pod --image=nginx --restart=Never
Test with required labels (this should succeed)
kubectl run test-pod-labeled --image=nginx --restart=Never --labels="environment=test,team=platform"
Test security policy (this should fail)
kubectl run privileged-test --image=nginx --restart=Never --labels="environment=test,team=platform" -- /bin/sh -c "sleep 3600" --privileged
Check constraint violations
kubectl get k8srequiredlabels pod-must-have-env -o yaml
kubectl get k8ssecuritypolicy container-security-policy -o yaml
Monitor and troubleshoot policy violations
View constraint status and violations
Monitor policy enforcement by checking constraint status and violation details.
# Check all constraint violations
kubectl get constraints -o json | jq '.items[] | {name: .metadata.name, violations: .status.violations}'
View specific constraint details
kubectl describe k8srequiredlabels pod-must-have-env
Check Gatekeeper audit logs
kubectl logs -n gatekeeper-system -l control-plane=audit-controller
kubectl logs -n gatekeeper-system -l control-plane=controller-manager
Set up Prometheus monitoring integration
Configure Prometheus to scrape Gatekeeper metrics for comprehensive policy monitoring.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: gatekeeper-controller-manager-metrics
namespace: gatekeeper-system
spec:
endpoints:
- path: /metrics
port: metrics
interval: 30s
selector:
matchLabels:
control-plane: controller-manager
gatekeeper.sh/operation: webhook
Create policy exception configurations
Configure exceptions for system namespaces or specific workloads that need policy exemptions.
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-labels-with-exceptions
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces: ["kube-system", "gatekeeper-system", "monitoring"]
parameters:
labels: ["environment", "team"]
exemptions:
- name: "system-pods"
subjects:
- kind: "Pod"
name: "coredns-*"
namespace: "kube-system"
For comprehensive cluster monitoring including Gatekeeper metrics, check our Prometheus and Grafana monitoring guide. You can also integrate with service mesh security using Istio security policies.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Webhook timeout errors | Gatekeeper pods not ready | kubectl wait --for=condition=ready pod -l gatekeeper.sh/operation=webhook -n gatekeeper-system |
| Constraint template validation fails | Invalid Rego syntax | Test Rego policy at play.openpolicyagent.org before applying |
| Policies blocking system pods | Missing namespace exclusions | Add excludedNamespaces: ["kube-system", "gatekeeper-system"] to constraints |
| No violation data in constraint status | Audit disabled | Check Config resource and enable audit: kubectl get config -n gatekeeper-system |
| Deployment blocked by security policy | Missing securityContext | Add securityContext: {runAsNonRoot: true, runAsUser: 1000} to container specs |
Next steps
- Implement Cilium Tetragon runtime security for comprehensive eBPF-based threat detection
- Configure Pod Security Standards for additional built-in security controls
- Integrate Gatekeeper with ArgoCD for GitOps-based policy management
- Implement network policies to complement admission control with runtime network security
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Configuration
GATEKEEPER_VERSION="release-3.14"
TIMEOUT_SECONDS=300
# Functions
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
cleanup_on_error() {
log_error "Installation failed. Cleaning up..."
kubectl delete -f "https://raw.githubusercontent.com/open-policy-agent/gatekeeper/${GATEKEEPER_VERSION}/deploy/gatekeeper.yaml" 2>/dev/null || true
rm -f kubectl required-labels-template.yaml require-pod-labels.yaml security-policy-template.yaml pod-security-constraint.yaml
}
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo "Install OPA Gatekeeper for Kubernetes policy enforcement"
echo ""
echo "Options:"
echo " -v, --version VERSION Gatekeeper version (default: ${GATEKEEPER_VERSION})"
echo " -t, --timeout SECONDS Timeout for pod readiness (default: ${TIMEOUT_SECONDS})"
echo " -h, --help Show this help message"
}
check_prerequisites() {
if [[ $EUID -eq 0 ]]; then
log_error "This script should not be run as root for kubectl operations"
exit 1
fi
if ! command -v sudo &> /dev/null; then
log_error "sudo is required but not installed"
exit 1
fi
}
detect_distro() {
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="sudo apt update && sudo apt upgrade -y"
PKG_INSTALL="sudo apt install -y"
EXTRA_PACKAGES="apt-transport-https ca-certificates gnupg"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="sudo dnf update -y"
PKG_INSTALL="sudo dnf install -y"
EXTRA_PACKAGES="ca-certificates"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="sudo yum update -y"
PKG_INSTALL="sudo yum install -y"
EXTRA_PACKAGES="ca-certificates"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect Linux distribution"
exit 1
fi
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-v|--version)
GATEKEEPER_VERSION="$2"
shift 2
;;
-t|--timeout)
TIMEOUT_SECONDS="$2"
shift 2
;;
-h|--help)
show_usage
exit 0
;;
*)
log_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Set up error handling
trap cleanup_on_error ERR
log_info "Starting OPA Gatekeeper installation..."
check_prerequisites
detect_distro
echo "[1/8] Updating system packages and installing dependencies..."
eval "$PKG_UPDATE"
eval "$PKG_INSTALL curl wget $EXTRA_PACKAGES"
echo "[2/8] Installing kubectl..."
if ! command -v kubectl &> /dev/null; then
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod 755 kubectl
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
rm -f kubectl
else
log_info "kubectl already installed"
fi
echo "[3/8] Verifying Kubernetes cluster access..."
if ! kubectl cluster-info &> /dev/null; then
log_error "Cannot connect to Kubernetes cluster. Check your kubeconfig."
exit 1
fi
if ! kubectl auth can-i '*' '*' --all-namespaces &> /dev/null; then
log_error "Insufficient permissions. Cluster admin privileges required."
exit 1
fi
echo "[4/8] Installing OPA Gatekeeper..."
kubectl apply -f "https://raw.githubusercontent.com/open-policy-agent/gatekeeper/${GATEKEEPER_VERSION}/deploy/gatekeeper.yaml"
echo "[5/8] Waiting for Gatekeeper components to start..."
kubectl wait --for=condition=ready pod -l gatekeeper.sh/operation=webhook -n gatekeeper-system --timeout=${TIMEOUT_SECONDS}s
echo "[6/8] Creating constraint template for required labels..."
cat > required-labels-template.yaml << 'EOF'
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
required := input.parameters.labels
provided := input.review.object.metadata.labels
missing := required[_]
not provided[missing]
msg := sprintf("Missing required label: %v", [missing])
}
EOF
kubectl apply -f required-labels-template.yaml
echo "[7/8] Creating pod labeling constraint..."
cat > require-pod-labels.yaml << 'EOF'
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-must-have-env
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces: ["kube-system", "gatekeeper-system", "kube-public", "kube-node-lease"]
parameters:
labels: ["environment", "team"]
EOF
kubectl apply -f require-pod-labels.yaml
echo "[8/8] Verifying installation..."
kubectl get pods -n gatekeeper-system
kubectl get constrainttemplates
kubectl get k8srequiredlabels
log_info "Testing policy enforcement..."
if kubectl run test-pod --image=nginx --dry-run=server -o yaml 2>&1 | grep -q "Missing required label"; then
log_info "Policy enforcement is working correctly!"
else
log_warn "Policy enforcement test inconclusive"
fi
# Cleanup temporary files
rm -f required-labels-template.yaml require-pod-labels.yaml
log_info "OPA Gatekeeper installation completed successfully!"
log_info "Constraint templates and policies are now active"
log_info "Use 'kubectl get constraints' to view active policies"
Review the script before running. Execute with: bash install.sh