9.7 Security and RBAC
Securing Kubernetes Clusters and Applications
Kubernetes security involves multiple layers: cluster security, pod security, network security, and access control.
Pod Security Standards
Modern Pod Security (Replacing Pod Security Policies)
Pod Security Standards provide three predefined security profiles: Privileged, Baseline, and Restricted.
Pod Security Standard Levels
Privileged: Unrestricted policy (no restrictions)
Baseline: Minimally restrictive policy (prevents known privilege escalations)
Restricted: Heavily restricted policy (follows security best practices)
Namespace-Level Pod Security
# Enforce restricted pod security at namespace level
apiVersion: v1
kind: Namespace
metadata:
name: secure-namespace
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/enforce-version: v1.28
Secure Pod Configuration
# Pod following restricted security standards
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
namespace: secure-namespace
spec:
serviceAccountName: restricted-sa
securityContext:
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
fsGroup: 65534
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:1.21-alpine
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65534
runAsGroup: 65534
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
volumeMounts:
- name: tmp-volume
mountPath: /tmp
- name: var-cache-nginx
mountPath: /var/cache/nginx
- name: var-run
mountPath: /var/run
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
volumes:
- name: tmp-volume
emptyDir: {}
- name: var-cache-nginx
emptyDir: {}
- name: var-run
emptyDir: {}
Pod Security Policy Migration
# Check current PSP usage
kubectl get psp
kubectl get podsecuritypolicy
# Validate pods against new standards
kubectl label --dry-run=server --overwrite ns production \
pod-security.kubernetes.io/enforce=restricted
# Gradual migration approach
kubectl label ns production pod-security.kubernetes.io/warn=restricted
kubectl label ns production pod-security.kubernetes.io/audit=restricted
# After validation, enforce
kubectl label ns production pod-security.kubernetes.io/enforce=restricted
Runtime Security with Falco
Falco for Runtime Threat Detection
Falco detects unexpected behavior and security threats in real-time using kernel-level monitoring.
Falco Installation
# Install Falco using Helm
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm repo update
# Install with default configuration
helm install falco falcosecurity/falco \
--namespace falco-system \
--create-namespace \
--set falco.grpc.enabled=true \
--set falco.grpcOutput.enabled=true
Falco Rules Configuration
# Custom Falco rules
apiVersion: v1
kind: ConfigMap
metadata:
name: falco-rules
namespace: falco-system
data:
custom-rules.yaml: |
- rule: Unauthorized Process in Container
desc: Detect unauthorized processes in containers
condition: >
spawned_process and container and
not proc.name in (nginx, apache2, httpd, node, python, java)
output: >
Unauthorized process spawned in container
(user=%user.name command=%proc.cmdline container=%container.name
image=%container.image.repository:%container.image.tag)
priority: WARNING
tags: [process, container]
- rule: Sensitive File Access
desc: Detect access to sensitive files
condition: >
open_read and sensitive_files and
not proc.name in (systemd, kubelet, dockerd)
output: >
Sensitive file opened for reading
(user=%user.name command=%proc.cmdline file=%fd.name
container=%container.name)
priority: WARNING
tags: [filesystem, container]
- macro: sensitive_files
condition: >
fd.name startswith /etc/passwd or
fd.name startswith /etc/shadow or
fd.name startswith /etc/ssh/ or
fd.name startswith /root/.ssh/
Falco Integration with External Systems
# Falco with Slack notifications
apiVersion: v1
kind: ConfigMap
metadata:
name: falco-config
namespace: falco-system
data:
falco.yaml: |
outputs:
rate: 1
max_burst: 1000
outputs_file:
enabled: true
keep_alive: false
filename: /var/log/falco.log
http_output:
enabled: true
url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
user_agent: "falco/0.34.1"
program_output:
enabled: true
keep_alive: false
program: 'curl -X POST -H "Content-Type: application/json" -d @- https://your-webhook-url.com/falco'
Image Scanning Security
Trivy Image Scanning
# Install Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin
# Scan container image
trivy image nginx:latest
# Scan with specific severity
trivy image --severity HIGH,CRITICAL nginx:latest
# Output as JSON for automation
trivy image --format json --output results.json nginx:latest
Trivy Operator for Kubernetes
# Install Trivy Operator
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/trivy-operator/main/deploy/static/trivy-operator.yaml
# Trivy scan configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: trivy-operator
namespace: trivy-system
data:
config.yaml: |
vulnerabilityReports:
scanner: Trivy
configAuditReports:
scanner: Trivy
compliance:
cron: "0 */6 * * *"
trivy:
severity: CRITICAL,HIGH,MEDIUM
ignoreUnfixed: true
timeout: 5m
Admission Controller for Image Scanning
# ValidatingAdmissionWebhook for image scanning
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionWebhook
metadata:
name: image-security-webhook
webhooks:
- name: image-scan.security.io
clientConfig:
service:
name: image-scanner
namespace: security-system
path: "/scan"
rules:
- operations: ["CREATE", "UPDATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
- operations: ["CREATE", "UPDATE"]
apiGroups: ["apps"]
apiVersions: ["v1"]
resources: ["deployments", "replicasets"]
RBAC (Role-Based Access Control)
Fine-Grained Access Control
RBAC controls what users and services can do in the cluster.
Role and RoleBinding
# Role for reading pods
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
# Bind role to user
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
ClusterRole and ClusterRoleBinding
# Cluster-wide role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-reader
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
Service Account RBAC
# Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-service-account
namespace: production
# Role for service account
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: configmap-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
Network Security
Network Policies
Control traffic between pods and external sources.
# Default deny all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
# Allow specific communication
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
Secrets Management
Secure Secret Handling
# Encrypted secret at rest
apiVersion: v1
kind: Secret
metadata:
name: secure-secret
type: Opaque
data:
api-key: <base64-encoded-value>
Using secrets securely:
# Pod with secret volume
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: secure-secret
defaultMode: 0400 # Read-only for owner
Image Security
Secure Container Images
# Pod with image security
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
containers:
- name: app
image: myregistry.com/myapp:v1.2.3@sha256:abc123...
imagePullPolicy: Always
imagePullSecrets:
- name: registry-secret
Essential Commands
# RBAC
kubectl get roles,rolebindings
kubectl get clusterroles,clusterrolebindings
kubectl auth can-i get pods --as=jane
kubectl auth can-i create deployments --as=system:serviceaccount:default:app-sa
# Security contexts
kubectl get pod secure-pod -o jsonpath='{.spec.securityContext}'
# Network policies
kubectl get networkpolicies
kubectl describe networkpolicy default-deny-all
# Secrets
kubectl get secrets
kubectl create secret docker-registry registry-secret \
--docker-server=myregistry.com \
--docker-username=user \
--docker-password=pass
What’s Next?
Next, we’ll explore Observability and Monitoring to gain visibility into your applications and cluster.