[19/24] A is for Authentication and RBAC: Securing Your Cluster
This is Post #16 in the Kubernetes A-to-Z Series
Reading Order: Previous: Upgrades | Next: Federation
Series Progress: 19/24 complete | Difficulty: Advanced | Time: 35-40 min | Part 6/6: Security & Production
Welcome to the sixteenth post in our Kubernetes A-to-Z Series! Now that you understand testing, let’s explore Authentication and RBAC - the foundation of Kubernetes security that controls who can access your cluster and what they can do.
Kubernetes Security Model
┌─────────────────────────────────────────────────┐
│ Request Flow │
│ │
│ User/Service ──► API Server │
│ │ │
│ ▼ │
│ ┌──────────────┐ │
│ │Authentication│ Who are you? │
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ │
│ │Authorization │ What can you do? │
│ └──────┬───────┘ │
│ ▼ │
│ ┌──────────────┐ │
│ │ Admission │ Is it allowed? │
│ └──────┬───────┘ │
│ ▼ │
│ Execute │
└─────────────────────────────────────────────────┘
Authentication Methods
1. X.509 Client Certificates
# Generate user certificate
openssl genrsa -out developer.key 2048
openssl req -new -key developer.key \
-out developer.csr \
-subj "/CN=developer/O=dev-team"
# Sign with cluster CA
openssl x509 -req -in developer.csr \
-CA /etc/kubernetes/pki/ca.crt \
-CAkey /etc/kubernetes/pki/ca.key \
-CAcreateserial \
-out developer.crt \
-days 365
# Create kubeconfig
kubectl config set-credentials developer \
--client-certificate=developer.crt \
--client-key=developer.key
kubectl config set-context developer-context \
--cluster=kubernetes \
--user=developer \
--namespace=development
2. Service Accounts
# service-account.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: webapp-sa
namespace: production
---
apiVersion: v1
kind: Secret
metadata:
name: webapp-sa-token
namespace: production
annotations:
kubernetes.io/service-account.name: webapp-sa
type: kubernetes.io/service-account-token
# pod-with-sa.yaml
apiVersion: v1
kind: Pod
metadata:
name: webapp
namespace: production
spec:
serviceAccountName: webapp-sa
automountServiceAccountToken: true
containers:
- name: webapp
image: myapp:v1.0
3. OIDC Authentication
# API server configuration
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
spec:
containers:
- command:
- kube-apiserver
- --oidc-issuer-url=https://accounts.google.com
- --oidc-client-id=my-client-id
- --oidc-username-claim=email
- --oidc-groups-claim=groups
Role-Based Access Control (RBAC)
RBAC Components
┌─────────────────────────────────────────────────┐
│ RBAC Model │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Subject │ │ Resource │ │
│ │ (User/SA) │ │ (Pod/Svc) │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ │ ┌──────────┐ │ │
│ └───►│RoleBinding├─────┘ │
│ └─────┬────┘ │
│ │ │
│ ┌─────▼────┐ │
│ │ Role │ │
│ │ (Verbs) │ │
│ └──────────┘ │
└─────────────────────────────────────────────────┘
Roles and ClusterRoles
# role.yaml - Namespace-scoped
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
---
# clusterrole.yaml - Cluster-scoped
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch"]
RoleBindings and ClusterRoleBindings
# rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
- kind: User
name: [email protected]
apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount
name: webapp-sa
namespace: production
- kind: Group
name: dev-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
---
# clusterrolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-admin-binding
subjects:
- kind: User
name: [email protected]
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
Common Role Examples
# developer-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: development
name: developer
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["pods", "deployments", "services", "configmaps", "jobs"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["pods/log", "pods/exec"]
verbs: ["get", "create"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
---
# readonly-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: readonly
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["get", "list", "watch"]
---
# deployer-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: deployer
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: ["apps"]
resources: ["deployments/scale"]
verbs: ["update", "patch"]
Aggregated ClusterRoles
# aggregated-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-endpoints
labels:
rbac.example.com/aggregate-to-monitoring: "true"
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.example.com/aggregate-to-monitoring: "true"
rules: [] # Rules are automatically filled
Pod Security
Security Contexts
# secure-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: secure-webapp
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: webapp
image: myapp:v1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
Pod Security Standards
# namespace-with-pss.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
---
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
Network Policies
# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: webapp-network-policy
namespace: production
spec:
podSelector:
matchLabels:
app: webapp
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: production
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
Secrets Management
Encrypted Secrets at Rest
# encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
External Secrets Operator
# external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: database-credentials
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: db-credentials
creationPolicy: Owner
data:
- secretKey: username
remoteRef:
key: production/database
property: username
- secretKey: password
remoteRef:
key: production/database
property: password
Audit Logging
# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: ""
resources: ["endpoints", "services"]
- level: None
users: ["kubelet"]
verbs: ["get"]
resources:
- group: ""
resources: ["nodes"]
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: Request
verbs: ["create", "update", "patch", "delete"]
resources:
- group: ""
resources: ["pods", "services"]
- group: "apps"
resources: ["deployments"]
- level: RequestResponse
users: ["admin"]
verbs: ["create", "delete"]
Testing RBAC
# Check permissions
kubectl auth can-i create pods --namespace production
kubectl auth can-i create pods --namespace production --as [email protected]
kubectl auth can-i '*' '*' --as system:serviceaccount:production:webapp-sa
# List permissions
kubectl auth can-i --list --namespace production
kubectl auth can-i --list --as [email protected]
# Verify role bindings
kubectl get rolebindings -n production
kubectl describe rolebinding read-pods -n production
# Check who can perform action
kubectl auth who-can create pods -n production
Security Best Practices
# secure-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-webapp
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
spec:
serviceAccountName: webapp-sa
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: webapp
image: myapp:v1.0@sha256:abc123...
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "100m"
memory: "128Mi"
Commands Reference
# Service Accounts
kubectl create serviceaccount webapp-sa -n production
kubectl get serviceaccounts -n production
# Roles
kubectl create role pod-reader --verb=get,list,watch --resource=pods -n production
kubectl get roles -n production
# ClusterRoles
kubectl create clusterrole secret-reader --verb=get,list --resource=secrets
kubectl get clusterroles
# RoleBindings
kubectl create rolebinding read-pods --role=pod-reader --user=developer -n production
kubectl get rolebindings -n production
# ClusterRoleBindings
kubectl create clusterrolebinding admin-binding --clusterrole=cluster-admin --user=admin
kubectl get clusterrolebindings
# Testing
kubectl auth can-i create pods -n production
kubectl auth can-i --list -n production
kubectl auth who-can delete pods -n production
Key Takeaways
- Authentication verifies identity (certificates, tokens, OIDC)
- Authorization (RBAC) controls what authenticated users can do
- Roles are namespace-scoped; ClusterRoles are cluster-wide
- Security contexts restrict container capabilities
- Pod Security Standards enforce security baselines
- Network policies control pod-to-pod communication
- Principle of least privilege: Grant minimum required permissions
Next Steps
Now that you understand security, you’re ready to explore Federation in the next post for multi-cluster management strategies.
Resources for Further Learning
Series Navigation:
- Previous: U is for Upgrades
- Next: F is for Federation: Multi-Cluster Management
Complete Series: Kubernetes A-to-Z Series Overview