Kubernetes Security Best Practices
Secure your Kubernetes clusters and workloads with comprehensive security measures
Security is a critical aspect of running Kubernetes in production environments. As Kubernetes adoption grows, it has become an increasingly attractive target for attackers. In this section, we'll explore comprehensive security measures to protect your clusters, workloads, and data.
Security Fundamentals in Kubernetes
Kubernetes security should be approached from multiple angles:
- Cluster security: Securing the Kubernetes control plane and nodes
- Container security: Securing the container images and runtime
- Application security: Securing the workloads running in your cluster
- Network security: Controlling traffic within and outside the cluster
- Data security: Protecting sensitive information
Let's explore each of these dimensions.
Securing the Kubernetes Cluster
Control Plane Security
The Kubernetes control plane is a critical security component. Protect it with these measures:
Use TLS for all API communications:
apiVersion: v1 kind: Pod metadata: name: kube-apiserver spec: containers: - name: kube-apiserver command: - kube-apiserver - --secure-port=6443 - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key - --client-ca-file=/etc/kubernetes/pki/ca.crt
Enable API server admission controllers:
apiVersion: v1 kind: Pod metadata: name: kube-apiserver spec: containers: - name: kube-apiserver command: - kube-apiserver - --enable-admission-plugins=NodeRestriction,PodSecurityPolicy,AlwaysPullImages
Restrict access to etcd:
- Use TLS for etcd client and peer communication
- Firewall etcd ports from unnecessary access
- Run etcd on dedicated nodes when possible
Implement network policies for the control plane:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: control-plane-protection namespace: kube-system spec: podSelector: matchLabels: tier: control-plane policyTypes: - Ingress ingress: - from: - ipBlock: cidr: 10.0.0.0/24 # Admin workstations ports: - protocol: TCP port: 6443 # API server
Node Security
Secure your worker nodes with these practices:
Keep nodes updated:
- Apply security patches promptly
- Use minimal, hardened OS images
- Consider immutable infrastructure patterns
Secure kubelet configuration:
# /var/lib/kubelet/config.yaml apiVersion: kubelet.config.k8s.io/v1beta1 kind: KubeletConfiguration authentication: anonymous: enabled: false webhook: enabled: true x509: clientCAFile: /etc/kubernetes/pki/ca.crt authorization: mode: Webhook readOnlyPort: 0 protectKernelDefaults: true
Node isolation and segmentation:
- Use separate node pools for different workload types
- Isolate nodes for sensitive workloads
- Apply appropriate node taints and labels
Authentication and Authorization
Implement proper access controls:
Use strong authentication methods:
- X.509 client certificates
- OpenID Connect (OIDC) with an identity provider
- Service accounts for applications
Role-Based Access Control (RBAC):
Define roles with specific permissions:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: default name: pod-reader rules: - apiGroups: [''] resources: ['pods'] verbs: ['get', 'watch', 'list']
Bind roles to users or groups:
apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: read-pods namespace: default subjects: - kind: User name: jane apiGroup: rbac.authorization.k8s.io roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
Follow the principle of least privilege:
- Grant minimal permissions needed for each role
- Regularly audit and review RBAC permissions
- Use namespaces to enforce separation
Container and Image Security
Image Security
Secure your container images:
Use minimal base images:
- Alpine Linux or distroless images
- Remove unnecessary packages and tools
Scan images for vulnerabilities:
# Using Trivy trivy image nginx:1.21 # Or in CI/CD pipeline trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:latest
Implement a secure image registry:
- Use private registries
- Enable authentication and authorization
- Enforce image signing and verification with Docker Content Trust or Cosign:
# Sign an image with Cosign cosign sign --key cosign.key registry.example.com/myapp:latest # Verify an image cosign verify --key cosign.pub registry.example.com/myapp:latest
Create and enforce image policies:
# Using OPA Gatekeeper apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sAllowedRepos metadata: name: require-trusted-repos spec: match: kinds: - apiGroups: [''] kinds: ['Pod'] parameters: repos: - 'registry.example.com/' - 'docker.io/bitnami/'
Container Runtime Security
Secure the container runtime:
Use container-optimized operating systems:
- Container-Optimized OS (Google)
- Bottlerocket (AWS)
- RancherOS or K3OS
Configure seccomp profiles:
apiVersion: v1 kind: Pod metadata: name: secure-pod spec: securityContext: seccompProfile: type: Localhost localhostProfile: profiles/restricted.json containers: - name: app image: myapp:1.0
Use container runtime sandboxes:
- gVisor
- Kata Containers
- Firecracker
Implement runtime security monitoring:
- Falco for runtime threat detection
- Sysdig for container visibility
- Aqua Security or Twistlock for comprehensive protection
Workload Security
Pod Security
Apply security measures to your pods:
Use Pod Security Standards:
Since Kubernetes 1.25, Pod Security Admission provides built-in enforcement of the Pod Security Standards, replacing the deprecated Pod Security Policies:
# Namespace-level enforcement apiVersion: v1 kind: Namespace metadata: name: secure-namespace labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/warn: restricted pod-security.kubernetes.io/audit: restricted
Configure security contexts:
apiVersion: v1 kind: Pod metadata: name: secure-pod spec: securityContext: runAsNonRoot: true runAsUser: 1000 runAsGroup: 3000 fsGroup: 2000 seccompProfile: type: RuntimeDefault containers: - name: app image: myapp:1.0 securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL readOnlyRootFilesystem: true
Limit container capabilities:
- Drop all capabilities by default
- Add only required capabilities
Configure resource limits:
resources: requests: memory: '64Mi' cpu: '250m' limits: memory: '128Mi' cpu: '500m'
Service Account Security
Secure your service accounts:
Disable automounting of service account tokens:
apiVersion: v1 kind: ServiceAccount metadata: name: restricted-sa automountServiceAccountToken: false
Create and use minimal service accounts:
apiVersion: v1 kind: ServiceAccount metadata: name: app-sa --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: app-role rules: - apiGroups: [''] resources: ['configmaps'] verbs: ['get'] resourceNames: ['app-config'] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: app-rb subjects: - kind: ServiceAccount name: app-sa roleRef: kind: Role name: app-role apiGroup: rbac.authorization.k8s.io
Use projected service account tokens:
apiVersion: v1 kind: Pod metadata: name: token-projected-pod spec: containers: - name: app image: myapp:1.0 volumeMounts: - name: token mountPath: /var/run/secrets/tokens volumes: - name: token projected: sources: - serviceAccountToken: path: token expirationSeconds: 3600 audience: api
Secret Management
Properly manage sensitive information:
Use external secret management systems:
- HashiCorp Vault
- AWS Secrets Manager
- Google Secret Manager
- Azure Key Vault
Using External Secrets Operator:
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: database-credentials spec: refreshInterval: '15m' secretStoreRef: name: vault-backend kind: SecretStore target: name: database-credentials data: - secretKey: username remoteRef: key: databases/mysql/credentials property: username - secretKey: password remoteRef: key: databases/mysql/credentials property: password
Encrypt etcd data:
apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: <base64-encoded-key> - identity: {}
Use sealed secrets for GitOps workflows:
# Encrypt a secret kubectl create secret generic db-creds \ --from-literal=username=admin \ --from-literal=password=secretpassword \ --dry-run=client -o yaml | \ kubeseal --format yaml > sealed-db-creds.yaml
Network Security
Network Policies
Implement network segmentation:
Default deny policy:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all spec: podSelector: {} policyTypes: - Ingress - Egress
Allow specific communication:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: api-allow spec: podSelector: matchLabels: app: api policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080 egress: - to: - podSelector: matchLabels: app: database ports: - protocol: TCP port: 5432
Namespace isolation:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: namespace-isolation namespace: production spec: podSelector: {} policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: purpose: production
Secure Ingress
Protect external access:
TLS termination:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: secure-ingress spec: tls: - hosts: - api.example.com secretName: api-tls rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: api-service port: number: 80
Authentication with OAuth2 Proxy:
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: oauth-ingress annotations: nginx.ingress.kubernetes.io/auth-url: 'https://$host/oauth2/auth' nginx.ingress.kubernetes.io/auth-signin: 'https://$host/oauth2/start' spec: # ...
Web Application Firewall (WAF):
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: waf-protected-ingress annotations: nginx.ingress.kubernetes.io/enable-modsecurity: 'true' nginx.ingress.kubernetes.io/modsecurity-transaction-id: '$request_id' spec: # ...
Service Mesh Security
Implement a service mesh for enhanced security:
Istio with mTLS:
apiVersion: security.istio.io/v1beta1 kind: PeerAuthentication metadata: name: default namespace: istio-system spec: mtls: mode: STRICT
Authentication and authorization policies:
apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: frontend-to-backend namespace: default spec: selector: matchLabels: app: backend rules: - from: - source: principals: ['cluster.local/ns/default/sa/frontend-sa'] to: - operation: methods: ['GET'] paths: ['/api/v1/*']
Compliance and Auditing
Audit Logging
Enable and configure audit logging:
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-log-maxage=30
- --audit-log-maxbackup=10
- --audit-log-maxsize=100
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
With a policy like:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log pod changes at RequestResponse level
- level: RequestResponse
resources:
- group: ''
resources: ['pods']
# Log configmaps and secrets at Metadata level
- level: Metadata
resources:
- group: ''
resources: ['secrets', 'configmaps']
# Log nothing else
- level: None
Security Scanning and Benchmarking
Regularly scan your cluster:
CIS Kubernetes Benchmark:
# Using kube-bench kubectl run kube-bench --image=aquasec/kube-bench:latest
Kubernetes Security Posture Management (KSPM):
- Kubescape
- Falco
- Prisma Cloud
Configuration scanning:
# Using Trivy for configuration scanning trivy config --severity HIGH,CRITICAL ./kubernetes/
Compliance Frameworks
Align with industry standards:
Map controls to standards:
- PCI DSS
- HIPAA
- SOC 2
- ISO 27001
Implement compliance as code:
# OPA Gatekeeper constraint for PCI requirement 2.2 apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sRequiredLabels metadata: name: required-compliance-labels spec: match: kinds: - apiGroups: [''] kinds: ['Pod'] parameters: labels: - key: 'compliance' allowedRegex: 'pci|hipaa|sox'
Security Response
Incident Response
Prepare for security incidents:
Create an incident response plan:
- Detection procedures
- Containment strategies
- Eradication processes
- Recovery steps
Implement detection mechanisms:
- Runtime security monitoring
- Anomaly detection
- Alert correlation
Practice containment strategies:
# Isolate a compromised node kubectl cordon <node-name> kubectl drain <node-name> --ignore-daemonsets # Isolate a namespace with network policies kubectl apply -f quarantine-policy.yaml
Automated Remediation
Set up automated responses:
Pod restart on suspicious activity:
# Falco response using falco-sidekick spec: alertOutput: webhooks: - url: 'http://falco-sidekick:2801'
Network quarantine:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: quarantine spec: podSelector: matchLabels: security.kubernetes.io/quarantine: 'true' policyTypes: - Ingress - Egress
Security Hardening in DigitalOcean Kubernetes
DigitalOcean Kubernetes Service (DOKS) provides several security features:
Control plane security:
- Managed and secured by DigitalOcean
- Automatic security patching
- Private networking for nodes
Node security:
- Regular security updates
- Minimal images
Network security:
- Support for NetworkPolicies
- Private networking
- VPC integration
Sign up with DigitalOcean to get $200 in free credits and deploy your applications on a secure Kubernetes platform.
Securing the CI/CD Pipeline
Protect your deployment pipeline:
Secure the build environment:
- Use isolated build environments
- Implement least privilege for CI systems
- Scan dependencies during builds
Implement GitOps security:
- Require signed commits
- Enforce code reviews
- Use protected branches
Secure deployment credentials:
- Use short-lived credentials
- Implement specific deployment service accounts
- Restrict deployment to specific namespaces
Example secure CI/CD workflow:
# GitHub Actions workflow
name: Secure Kubernetes Deployment
on:
push:
branches: [main]
jobs:
scan-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Verify commit signature
run: git verify-commit HEAD
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.REGISTRY }}
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ secrets.REGISTRY }}/app:${{ github.sha }}
- name: Scan image
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ secrets.REGISTRY }}/app:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
exit-code: '1'
severity: 'CRITICAL'
- name: Deploy to Kubernetes
uses: Azure/k8s-deploy@v1
with:
manifests: |
kubernetes/deployment.yaml
kubernetes/service.yaml
images: |
${{ secrets.REGISTRY }}/app:${{ github.sha }}
namespace: production
Security Best Practices Checklist
Use this checklist to ensure comprehensive security:
Cluster Security
- TLS encryption for all control plane communication
- RBAC properly configured
- API server admission controllers enabled
- etcd encrypted and secured
- Nodes regularly updated and hardened
- Kubelet configured securely
Container Security
- Images scanned for vulnerabilities
- Base images minimized
- Images signed and verified
- Container registry secured
- Runtime security monitoring implemented
- Security contexts configured
Workload Security
- Pod Security Standards enforced
- Service accounts properly managed
- Secrets stored securely
- Resource limits defined
- Non-root users configured
- ReadOnly file systems where possible
Network Security
- Network policies implemented
- Default deny policies applied
- Ingress traffic secured with TLS
- Service mesh with mTLS (if applicable)
- Egress traffic controlled
Monitoring and Audit
- Audit logging enabled
- Security scanning automated
- Compliance checks implemented
- Monitoring for suspicious activity
- Incident response plan documented
Conclusion
Kubernetes security requires a defense-in-depth approach, addressing multiple layers of the stack. By implementing the practices outlined in this guide, you can significantly improve your cluster's security posture.
Remember that security is not a one-time task but an ongoing process. Stay updated with security best practices and vulnerabilities that affect Kubernetes and its ecosystem.
For production deployments, consider using a managed Kubernetes service like DigitalOcean Kubernetes, which handles many security aspects for you while giving you the flexibility to implement additional security measures for your specific needs.
In this comprehensive guide, we've covered the fundamentals of Kubernetes, from architecture to security. You now have the knowledge to deploy, manage, and secure Kubernetes applications in various environments. Continue exploring and experimenting to deepen your expertise in this powerful container orchestration platform.
Found an issue?