[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:

Complete Series: Kubernetes A-to-Z Series Overview