Implement Kubernetes Pod Security Standards and admission controllers for policy enforcement

Advanced 45 min Apr 07, 2026 15 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Configure Pod Security Standards with baseline and restricted profiles, deploy OPA Gatekeeper admission controller with custom policies, and implement ValidatingAdmissionWebhooks for comprehensive security enforcement in production Kubernetes clusters.

Prerequisites

  • Existing Kubernetes cluster with admin access
  • kubectl configured
  • Basic understanding of Kubernetes RBAC
  • Prometheus monitoring stack (optional for alerting)

What this solves

Kubernetes Pod Security Standards provide a built-in framework for enforcing security policies at the namespace level, replacing deprecated Pod Security Policies. This tutorial shows you how to implement Pod Security Standards with baseline and restricted profiles, deploy OPA Gatekeeper for custom policy enforcement, and configure ValidatingAdmissionWebhooks to prevent insecure workloads from running in your cluster. You'll also set up comprehensive monitoring and alerting for security violations to maintain compliance in production environments.

Step-by-step configuration

Update system and install dependencies

Start by updating your system and installing necessary tools for Kubernetes security management.

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget git jq
sudo dnf update -y
sudo dnf install -y curl wget git jq

Install kubectl and helm

Install kubectl for cluster management and Helm for package management.

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

curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
sudo apt update
sudo apt install -y helm
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh

Create namespace labels for Pod Security Standards

Configure namespaces with appropriate Pod Security Standard labels for baseline and restricted security profiles.

# Create test namespaces
kubectl create namespace baseline-ns
kubectl create namespace restricted-ns
kubectl create namespace privileged-ns

Label namespaces with Pod Security Standards

kubectl label namespace baseline-ns \ pod-security.kubernetes.io/enforce=baseline \ pod-security.kubernetes.io/audit=baseline \ pod-security.kubernetes.io/warn=baseline kubectl label namespace restricted-ns \ pod-security.kubernetes.io/enforce=restricted \ pod-security.kubernetes.io/audit=restricted \ pod-security.kubernetes.io/warn=restricted kubectl label namespace privileged-ns \ pod-security.kubernetes.io/enforce=privileged \ pod-security.kubernetes.io/audit=privileged \ pod-security.kubernetes.io/warn=privileged

Configure cluster-wide Pod Security Standards

Set default Pod Security Standards at the cluster level by modifying the kube-apiserver configuration.

spec:
  containers:
  - command:
    - kube-apiserver
    - --admission-control-config-file=/etc/kubernetes/admission-control.yaml
    - --feature-gates=PodSecurity=true
    # Add other existing flags here
    volumeMounts:
    - mountPath: /etc/kubernetes/admission-control.yaml
      name: admission-control-config
      readOnly: true
  volumes:
  - hostPath:
      path: /etc/kubernetes/admission-control.yaml
      type: File
    name: admission-control-config

Create admission control configuration

Define the admission control configuration file for Pod Security Standards enforcement.

apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
  • name: PodSecurity
configuration: apiVersion: pod-security.admission.config.k8s.io/v1beta1 kind: PodSecurityConfiguration defaults: enforce: "baseline" enforce-version: "latest" audit: "baseline" audit-version: "latest" warn: "baseline" warn-version: "latest" exemptions: usernames: [] runtimeClasses: [] namespaces: ["kube-system", "kube-public", "kube-node-lease"]

Install OPA Gatekeeper

Deploy OPA Gatekeeper admission controller for custom policy enforcement using Helm.

helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update

Create gatekeeper-system namespace

kubectl create namespace gatekeeper-system

Install Gatekeeper with audit enabled

helm install gatekeeper gatekeeper/gatekeeper \ --namespace gatekeeper-system \ --set audit.replicas=2 \ --set replicas=3 \ --set audit.auditInterval=60 \ --set audit.logLevel=INFO \ --set logLevel=INFO

Create constraint templates for security policies

Define constraint templates for common security policies like required security contexts and resource limits.

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredsecuritycontext
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredSecurityContext
      validation:
        properties:
          runAsNonRoot:
            type: boolean
          runAsUser:
            type: integer
          fsGroup:
            type: integer
          allowPrivilegeEscalation:
            type: boolean
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredsecuritycontext
        
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.securityContext.runAsNonRoot
          msg := "Container must run as non-root user"
        }
        
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          container.securityContext.allowPrivilegeEscalation != false
          msg := "Container must not allow privilege escalation"
        }
        
        violation[{"msg": msg}] {
          container := input.review.object.spec.containers[_]
          not container.securityContext.runAsUser
          msg := "Container must specify runAsUser"
        }

Create resource limits constraint template

Define a constraint template to enforce resource limits on all containers.

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredresourcelimits
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredResourceLimits
      validation:
        properties:
          limits:
            type: array
            items:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredresourcelimits
        
        missing_limits[limit] {
          required := input.parameters.limits
          limit := required[_]
          not input.review.object.spec.containers[_].resources.limits[limit]
        }
        
        violation[{"msg": msg}] {
          limit := missing_limits[_]
          msg := sprintf("Container must specify resource limit: %v", [limit])
        }

Apply constraint templates

Deploy the constraint templates to your cluster.

kubectl apply -f required-security-context-template.yaml
kubectl apply -f resource-limits-template.yaml

Wait for templates to be established

kubectl wait --for=condition=Established crd/k8srequiredsecuritycontext.templates.gatekeeper.sh --timeout=60s kubectl wait --for=condition=Established crd/k8srequiredresourcelimits.templates.gatekeeper.sh --timeout=60s

Create security context constraints

Apply constraints using the templates to enforce security context requirements in specific namespaces.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredSecurityContext
metadata:
  name: must-have-security-context
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces: ["kube-system", "gatekeeper-system", "kube-public"]
  parameters:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 2000
    allowPrivilegeEscalation: false

Create resource limits constraints

Apply constraints to enforce resource limits on all containers.

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResourceLimits
metadata:
  name: must-have-resource-limits
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    excludedNamespaces: ["kube-system", "gatekeeper-system", "kube-public"]
  parameters:
    limits: ["memory", "cpu"]

Apply all constraints

Deploy the constraints to enforce security policies cluster-wide.

kubectl apply -f security-context-constraint.yaml
kubectl apply -f resource-limits-constraint.yaml

Check constraint status

kubectl get constraints kubectl describe K8sRequiredSecurityContext must-have-security-context

Create ValidatingAdmissionWebhook

Implement a custom ValidatingAdmissionWebhook for additional security checks beyond OPA Gatekeeper.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: security-webhook
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: security-webhook
  template:
    metadata:
      labels:
        app: security-webhook
    spec:
      containers:
      - name: webhook
        image: nginx:1.24
        ports:
        - containerPort: 8443
        volumeMounts:
        - name: certs
          mountPath: /etc/certs
          readOnly: true
        securityContext:
          runAsNonRoot: true
          runAsUser: 1000
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"
      volumes:
      - name: certs
        secret:
          secretName: webhook-certs

Create webhook certificates

Generate TLS certificates for the ValidatingAdmissionWebhook using OpenSSL.

# Create certificate authority
openssl genrsa -out ca-key.pem 2048
openssl req -new -x509 -key ca-key.pem -out ca-cert.pem -days 365 -subj "/CN=webhook-ca"

Create webhook certificate

openssl genrsa -out webhook-key.pem 2048 openssl req -new -key webhook-key.pem -out webhook-csr.pem -subj "/CN=security-webhook.default.svc" openssl x509 -req -in webhook-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out webhook-cert.pem -days 365

Create secret with certificates

kubectl create secret tls webhook-certs \ --cert=webhook-cert.pem \ --key=webhook-key.pem

Configure ValidatingAdmissionWebhook

Create the ValidatingAdmissionWebhook configuration to intercept pod creation requests.

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionWebhook
metadata:
  name: security-validator
webhooks:
  • name: pod-security-validator.example.com
clientConfig: service: name: security-webhook-service namespace: default path: "/validate" caBundle: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t... # Base64 encoded CA cert rules: - operations: ["CREATE", "UPDATE"] apiGroups: [""] apiVersions: ["v1"] resources: ["pods"] admissionReviewVersions: ["v1", "v1beta1"] sideEffects: None failurePolicy: Fail

Set up monitoring and alerting

Configure Prometheus monitoring for Pod Security Standards and Gatekeeper violations. This requires an existing Prometheus setup.

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: gatekeeper-audit
  namespace: gatekeeper-system
spec:
  selector:
    matchLabels:
      gatekeeper.sh/operation: audit
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: pod-security-alerts
  namespace: gatekeeper-system
spec:
  groups:
  - name: gatekeeper.rules
    rules:
    - alert: GatekeeperViolation
      expr: increase(gatekeeper_violations_total[5m]) > 0
      for: 0m
      labels:
        severity: warning
      annotations:
        summary: "Gatekeeper policy violation detected"
        description: "Constraint {{ $labels.violation_kind }} has {{ $value }} violations in the last 5 minutes"
    - alert: HighGatekeeperViolationRate
      expr: rate(gatekeeper_violations_total[5m]) > 0.1
      for: 5m
      labels:
        severity: critical
      annotations:
        summary: "High rate of Gatekeeper violations"
        description: "Gatekeeper violation rate is {{ $value }} violations per second"

Create audit logging configuration

Configure audit logging to track Pod Security Standards violations and admission webhook activity.

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  • level: Metadata
namespaces: ["default", "baseline-ns", "restricted-ns"] resources: - group: "" resources: ["pods"] omitStages: - RequestReceived
  • level: Request
users: ["system:serviceaccount:gatekeeper-system:gatekeeper-admin"] resources: - group: "templates.gatekeeper.sh" - group: "constraints.gatekeeper.sh"
  • level: Violation
annotationAuditLevels: pod-security.kubernetes.io/enforce-policy: "Request" pod-security.kubernetes.io/audit-policy: "Metadata"

Test your security policies

Test Pod Security Standards enforcement

Create test pods to verify that Pod Security Standards are properly enforced.

apiVersion: v1
kind: Pod
metadata:
  name: insecure-pod
  namespace: restricted-ns
spec:
  containers:
  - name: test
    image: nginx:1.24
    securityContext:
      runAsUser: 0  # This should be rejected in restricted namespace
# This should fail in restricted namespace
kubectl apply -f test-insecure-pod.yaml

Create a compliant pod

cat <

Verify your setup

# Check Pod Security Standards labels
kubectl get namespaces --show-labels | grep pod-security

Verify Gatekeeper installation

kubectl get pods -n gatekeeper-system kubectl get constrainttemplates kubectl get constraints

Check constraint violations

kubectl get K8sRequiredSecurityContext must-have-security-context -o yaml kubectl get K8sRequiredResourceLimits must-have-resource-limits -o yaml

Review audit logs

sudo journalctl -u kubelet | grep -i "pod-security"

Check Gatekeeper metrics

kubectl port-forward -n gatekeeper-system svc/gatekeeper-webhook-service 8443:443 & curl -k https://localhost:8443/metrics

Common issues

SymptomCauseFix
Pod creation fails with "violates PodSecurity"Pod doesn't meet security standard requirementsAdd proper securityContext with runAsNonRoot, runAsUser, and drop capabilities
Gatekeeper constraints not enforcingTemplate not properly created or constraint misconfiguredCheck kubectl get constrainttemplates and verify Rego policy syntax
ValidatingAdmissionWebhook failsCertificate issues or webhook service unreachableVerify certificate validity and service endpoints with kubectl get svc
High violation rates in monitoringExisting workloads don't comply with new policiesGradually migrate workloads or use "warn" mode before "enforce"
System namespaces affected by policiesConstraints not properly excluding system namespacesAdd exclusions in constraint spec for kube-system, gatekeeper-system

Next steps

Automated install script

Run this to automate the entire setup

#kubernetes #pod-security-standards #admission-controllers #opa-gatekeeper #security-policy

Need help?

Don't want to manage this yourself?

We handle infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.

Talk to an engineer