Kubernetes Security

A comprehensive guide to Kubernetes security covering RBAC, security contexts, pod security policies, OPA/Gatekeeper, secrets management, and practical implementation strategies for securing production clusters.

RBAC Security Contexts OPA/Gatekeeper Secrets Management
Kubernetes Security: A Multi-Layered Approach

Kubernetes security requires a defense-in-depth strategy with multiple layers of protection. Key security areas include:

  • Authentication & Authorization: Who can access the cluster and what they can do
  • Pod Security: What containers can do at runtime
  • Network Security: What can communicate with what
  • Data Security: Protecting secrets and sensitive data
  • Policy Enforcement: Ensuring compliance with security policies
  • Image Security: Ensuring only trusted images are deployed
Security Principle: Always use the principle of least privilege. Grant only the minimum permissions required for users, pods, and services to function. Regularly audit and review permissions.
RBAC: Role-Based Access Control

RBAC is the primary mechanism for controlling access to Kubernetes resources. It defines who can do what to which resources in the cluster.

# Role (namespace-scoped) apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: pod-reader namespace: default rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["pods/log"] verbs: ["get", "list"] # ClusterRole (cluster-scoped) apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cluster-admin-readonly rules: - apiGroups: ["*"] resources: ["*"] verbs: ["get", "list", "watch"] # RoleBinding (bind role to subjects) apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: read-pods namespace: default subjects: - kind: User name: developer@example.com apiGroup: rbac.authorization.k8s.io - kind: ServiceAccount name: my-sa namespace: default roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io # ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: view-all subjects: - kind: Group name: developers apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: cluster-admin-readonly apiGroup: rbac.authorization.k8s.io # Check RBAC permissions kubectl auth can-i get pods --namespace default kubectl auth can-i create deployments --namespace production kubectl auth can-i delete secrets --as=developer@example.com # View RBAC resources kubectl get roles --all-namespaces kubectl get clusterroles kubectl get rolebindings --all-namespaces kubectl get clusterrolebindings
RBAC Best Practices:
  • Use the principle of least privilege
  • Prefer namespaced Roles over ClusterRoles
  • Use Groups for managing multiple users
  • Regularly audit RBAC permissions
  • Use ServiceAccounts for pods needing API access
  • Avoid using the default ServiceAccount
Security Contexts: Pod and Container Security

Security Contexts define privilege and access control settings for pods and containers. They are essential for running containers securely.

# Pod Security Context apiVersion: v1 kind: Pod metadata: name: secure-pod spec: securityContext: runAsUser: 1000 # Run as non-root user runAsGroup: 3000 fsGroup: 2000 runAsNonRoot: true # Prevent root execution seccompProfile: type: RuntimeDefault containers: - name: app image: nginx securityContext: capabilities: drop: ["ALL"] # Drop all capabilities add: ["NET_BIND_SERVICE"] # Only add required readOnlyRootFilesystem: true allowPrivilegeEscalation: false volumeMounts: - name: data mountPath: /data # Security Context for Pod (user namespace) apiVersion: v1 kind: Pod metadata: name: isolated-pod spec: securityContext: runAsUser: 1000 seccompProfile: type: Localhost localhostProfile: profiles/my-seccomp.json supplementalGroups: [2000, 3000] # Common security settings # - runAsNonRoot: true (prevent root) # - readOnlyRootFilesystem: true (prevent writes) # - allowPrivilegeEscalation: false (prevent priv escalation) # - drop capabilities (remove unnecessary privileges) # - seccomp profile (restrict syscalls)
Security Context Critical: Always set runAsNonRoot: true and allowPrivilegeEscalation: false in production. Drop all unnecessary capabilities (capabilities.drop: ["ALL"]) and only add what's needed (capabilities.add: ["NET_BIND_SERVICE"]).
Pod Security Standards and Admission

Pod Security Standards define three security profiles that can be enforced at the namespace level: Privileged, Baseline, and Restricted.

# Enable Pod Security Admission (built-in) # Kubernetes v1.23+ supports Pod Security Admission controller # Label namespace with security profile kubectl label namespace default pod-security.kubernetes.io/enforce=baseline kubectl label namespace default pod-security.kubernetes.io/audit=restricted kubectl label namespace default pod-security.kubernetes.io/warn=restricted # Enforce Restricted profile (strictest) kubectl label namespace production pod-security.kubernetes.io/enforce=restricted # Pod Security Standards levels: # - Privileged: Unrestricted (default) # - Baseline: Minimally restrictive, prevents known privilege escalations # - Restricted: Heavily restricted, follows Pod Security best practices # Pod that violates Restricted profile apiVersion: v1 kind: Pod metadata: name: problematic-pod spec: containers: - name: app image: nginx securityContext: runAsUser: 0 # root user - violates Restricted allowPrivilegeEscalation: true # violates Restricted # Pod that complies with Restricted profile apiVersion: v1 kind: Pod metadata: name: compliant-pod spec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: app image: nginx securityContext: capabilities: drop: ["ALL"] add: ["NET_BIND_SERVICE"] readOnlyRootFilesystem: true allowPrivilegeEscalation: false
Pod Security Profiles:
  • Privileged: No restrictions (use sparingly)
  • Baseline: Prevents known privilege escalations
  • Restricted: Enforces pod security best practices

Start with warn and audit modes before enforcing to avoid breaking existing workloads.

OPA & Gatekeeper: Policy as Code

Open Policy Agent (OPA) with Gatekeeper provides policy-as-code capabilities for Kubernetes. It enables fine-grained policy enforcement beyond what's possible with built-in admission controllers.

# Install Gatekeeper kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.12/deploy/gatekeeper.yaml # Verify Gatekeeper installation kubectl get pods -n gatekeeper-system # ConstraintTemplate (defines policy logic) apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata: name: k8srequiredlabels spec: crd: spec: names: kind: K8sRequiredLabels validation: # Schema for the constraint parameters openAPIV3Schema: type: object 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]) } # Constraint (enforces the policy) apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sRequiredLabels metadata: name: require-security-labels spec: match: kinds: - apiGroups: [""] kinds: ["Pod"] namespaces: - "production" - "staging" parameters: labels: - "security-tier" - "owner" # Another ConstraintTemplate: prevent privilege escalation apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata: name: k8sprivilegeescalation spec: crd: spec: names: kind: K8sPrivilegeEscalation targets: - target: admission.k8s.gatekeeper.sh rego: | package k8sprivilegeescalation violation[{"msg": msg}] { container := input.review.object.spec.containers[_] container.securityContext.allowPrivilegeEscalation == true msg := sprintf("Container %v allows privilege escalation", [container.name]) } # Constraint: disallow privilege escalation apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sPrivilegeEscalation metadata: name: no-privilege-escalation spec: match: kinds: - apiGroups: [""] kinds: ["Pod"]
OPA/Gatekeeper Benefits:
  • Enforce custom policies beyond built-in admission controllers
  • Audit existing resources for policy violations
  • Dry-run mode for testing policies
  • Policy-as-code with version control
  • Reusable policy templates
Secrets Management

Secrets management is critical for Kubernetes security. Secrets contain sensitive data like passwords, API keys, and certificates. Use proper secret management to protect this data.

# Create a secret kubectl create secret generic db-credentials \ --from-literal=username=admin \ --from-literal=password=supersecret # Secret from file kubectl create secret generic tls-cert \ --from-file=cert.pem=/path/to/cert.pem \ --from-file=key.pem=/path/to/key.pem # Secret YAML (base64 encoded) apiVersion: v1 kind: Secret metadata: name: db-credentials type: Opaque data: username: YWRtaW4= # base64 of "admin" password: c3VwZXJzZWNyZXQ= # base64 of "supersecret" # Use secret in pod (environment variable) apiVersion: v1 kind: Pod metadata: name: app-pod spec: containers: - name: app image: myapp env: - name: DB_USER valueFrom: secretKeyRef: name: db-credentials key: username - name: DB_PASS valueFrom: secretKeyRef: name: db-credentials key: password # Use secret as volume mount volumes: - name: secrets secret: secretName: db-credentials mode: 0400 containers: - name: app volumeMounts: - name: secrets mountPath: /etc/secrets readOnly: true # Sealed Secrets (GitOps safe) # Install Sealed Secrets kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/latest/download/controller.yaml # Create sealed secret kubeseal --format yaml < secret.yaml > sealed-secret.yaml # Sealed Secret YAML (safe to commit to Git) apiVersion: bitnami.com/v1alpha1 kind: SealedSecret metadata: name: db-credentials spec: encryptedData: username: AgBy... # Encrypted data password: AgBy... # Encrypted data # External Secrets (using HashiCorp Vault) apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: vault-store spec: provider: vault: server: "https://vault.example.com" path: "secret" auth: kubernetes: role: "app-role" apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: db-credentials spec: secretStoreRef: name: vault-store target: name: db-credentials data: - secretKey: username remoteRef: key: app/db property: username
Secrets Security:
  • Never store raw secrets in Git
  • Enable etcd encryption for secrets
  • Use Sealed Secrets or SOPS for GitOps
  • Use External Secrets Operator for Vault integration
  • Regularly rotate secrets
  • Limit secret access with RBAC
Network Security: Policies and Segmentation

Network policies provide security at the network level, controlling which pods can communicate with each other.

# Default deny all ingress apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: deny-all-ingress spec: podSelector: {} policyTypes: - Ingress # Allow specific namespace apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-from-monitoring spec: podSelector: matchLabels: app: my-app ingress: - from: - namespaceSelector: matchLabels: name: monitoring policyTypes: - Ingress # Allow specific pods apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend spec: podSelector: matchLabels: app: backend ingress: - from: - podSelector: matchLabels: app: frontend ports: - port: 8080 policyTypes: - Ingress # Allow egress to external database apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-db spec: podSelector: matchLabels: app: my-app egress: - to: - ipBlock: cidr: 10.0.0.0/24 ports: - port: 5432 protocol: TCP policyTypes: - Egress
Network Policy Best Practices:
  • Start with default deny all policies
  • Gradually allow specific traffic
  • Use namespace isolation
  • Implement egress policies for external access
  • Test policies with network policy verification tools
  • Requires a CNI that supports NetworkPolicy (Calico, Cilium, etc.)
Kubernetes Security Checklist

RBAC

✓ Use least privilege principle
✓ Regular audit of permissions
✓ Use ServiceAccounts with minimal permissions

Pod Security

✓ Run as non-root
✓ Drop unnecessary capabilities
✓ Enable seccomp profiles
✓ Set read-only root filesystem

Network

✓ Use NetworkPolicy for segmentation
✓ Encrypt traffic with mTLS
✓ Use service mesh for advanced security

Secrets

✓ Enable etcd encryption
✓ Use Sealed Secrets or External Secrets
✓ Regularly rotate secrets

Policies

✓ Use OPA/Gatekeeper for policy enforcement
✓ Implement Pod Security Standards
✓ Audit policies regularly

Images

✓ Scan images for vulnerabilities
✓ Sign images with Cosign
✓ Use trusted base images
✓ Implement image allowlists
Security is Continuous: Regularly review and update your security posture. Conduct security audits, scan for vulnerabilities, and stay informed about new security best practices.
Frequently Asked Questions
What is the difference between Role and ClusterRole?
Role is namespace-scoped and grants permissions within a specific namespace. ClusterRole is cluster-scoped and grants permissions across the entire cluster. Use Roles for namespace-specific permissions and ClusterRoles for cluster-wide permissions.
Why should I avoid running containers as root?
Running as root gives containers elevated privileges that can lead to privilege escalation and container escapes. Use runAsNonRoot: true and set a specific user ID. This reduces the attack surface and limits the impact of container compromises.
What are Pod Security Standards?
Pod Security Standards are three security profiles: Privileged (unrestricted), Baseline (prevent known privilege escalations), and Restricted (heavily restricted). They provide a consistent security baseline for pods across the cluster.
What is OPA and how does it relate to Gatekeeper?
OPA (Open Policy Agent) is a general-purpose policy engine. Gatekeeper is a Kubernetes implementation of OPA that acts as an admission controller. Gatekeeper enables policy-as-code for Kubernetes with declarative policies enforced at the Kubernetes API level.
How do I secure secrets in Kubernetes?
Use etcd encryption, Sealed Secrets for GitOps, External Secrets Operator for Vault integration, and implement RBAC for secret access. Never store raw secrets in Git. Regularly rotate secrets and monitor access.
What is NetworkPolicy and why is it important?
NetworkPolicy defines which pods can communicate with each other. It provides network segmentation and enforces zero-trust networking. It's essential for limiting the blast radius of security breaches and implementing defense-in-depth.
How do I perform a security audit on my cluster?
Use tools like kube-bench (CIS benchmark), kube-hunter (security scanning), and kubescape. Review RBAC permissions, check for vulnerable configurations, scan images, and audit network policies. Regular security audits are essential for maintaining a secure cluster.
What is the principle of least privilege?
The principle of least privilege means granting only the minimum permissions required for a user, pod, or service to function. This limits the potential damage from security breaches and reduces the attack surface. Apply it to RBAC, security contexts, and network policies.
Previous: Backup & Restore Next: RBAC Best Practices

Kubernetes security is a journey, not a destination. Implement defense-in-depth, regularly audit your security posture, and stay updated on emerging threats and best practices.