Detailed Kubernetes RBAC, Pod Security Standards (PSS), ServiceAccount best practices, least-privilege access, audit logging, and security hardening for the cluster.
🔒 DevSecOps — Lesson 36
LESSON 36: RBAC & POD SECURITY STANDARDS
Deploy Microservices On-Premises with Kubernetes HA
Part 9: Security Hardening
xdev.asia
🎯 LESSON OBJECTIVE__HTMLTAG_66___
✅ Kubernetes RBAC (Role, ClusterRole, Binding)
✅ Pod Security Standards (Privileged, Baseline, Restricted)
✅ ServiceAccount best practices__HTMLTAG_73___
✅ Audit logging configuration
✅ Security hardening checklist
PART 1: KUBERNETES RBAC
RBAC Model:
User/ServiceAccount
│
▼
┌──────────────┐ ┌──────────────────┐
│ RoleBinding │────►│ Role │
│(namespace) │ │ (namespace) │
│ │ │ - get pods │
│ │ │ - list services │
└──────────────┘ └──────────────────┘
┌──────────────────┐ ┌──────────────────┐
│ClusterRoleBinding│─►│ ClusterRole │
│ (cluster-wide) │ │ (cluster-wide) │
│ │ │ - get nodes │
│ │ │ - list PVs │
└──────────────────┘ └──────────────────┘
# Role for app namespace (least privilege):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-developer
namespace: default
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "update", "patch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
# Explicitly deny secrets access (not listed)
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: default
subjects:
- kind: User
name: [email protected]
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: app-developer
apiGroup: rbac.authorization.k8s.io
# ClusterRole for read-only monitoring:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-reader
rules:
- apiGroups: [""]
resources: ["pods", "nodes", "services", "endpoints"]
verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"]
resources: ["pods", "nodes"]
verbs: ["get", "list"]
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
PART 2: SERVICEACCOUNT BEST PRACTICES__HTMLTAG_84___
# Dedicated ServiceAccount per workload:
apiVersion: v1
kind: ServiceAccount
metadata:
name: order-service
namespace: default
automountServiceAccountToken: false # Disable auto-mount
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
template:
spec:
serviceAccountName: order-service
automountServiceAccountToken: false # Double ensure
containers:
- name: app
image: registry.local/order-service:v1.0
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
PART 3: POD SECURITY STANDARDS
Level Description Use Case
Privileged No restrictions System-level (CNI, storage drivers)
Baseline_ Prevent known escalation Default for most workloads_
Restricted Hardened, all best practices Sensitive workloads_
# Apply PSS via namespace labels:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# Enforce restricted:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
# Warn on baseline violations:
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restricted
---
# Namespace for system workloads:
apiVersion: v1
kind: Namespace
metadata:
name: kube-system
labels:
pod-security.kubernetes.io/enforce: privileged
# Pod that complies with Restricted:
apiVersion: v1
kind: Pod
metadata:
name: secure-app
namespace: production
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.local/app:v1
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
PART 4: AUDIT LOGGING
# /etc/kubernetes/audit-policy.yaml:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Log all auth failures:
- level: Metadata
omitStages: ["RequestReceived"]
users: ["system:anonymous"]
# Log secret access:
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
# Log RBAC changes:
- level: RequestResponse
resources:
- group: "rbac.authorization.k8s.io"
resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
# Log pod exec/attach:
- level: RequestResponse
resources:
- group: ""
resources: ["pods/exec", "pods/attach"]
# Default: metadata only
- level: Metadata
omitStages: ["RequestReceived"]
# Enable in kube-apiserver:
# /etc/kubernetes/manifests/kube-apiserver.yaml
# Add flags:
# --audit-policy-file=/etc/kubernetes/audit-policy.yaml
# --audit-log-path=/var/log/kubernetes/audit.log
# --audit-log-maxage=30
# --audit-log-maxbackup=10
# --audit-log-maxsize=100
# Forward audit logs to Loki:
# Configure Promtail to scrape /var/log/kubernetes/audit.log
PART 5: SECURITY HARDENING CHECKLIST
# Item Status
1 RBAC enabled, no cluster-admin for apps ☐
2 Pod Security Standards enforced ☐
3 ServiceAccount token auto-mount disabled ☐
4 Network Policies deny-all default ☐
5 Audit logging enabled ☐
6 etcd encryption at rest ☐
7 API server on private network only ☐
8 Kubelet authn/authz enabled ☐
9 Container images signed/scanned ☐
10_ Secrets in Vault (not plain K8s secrets) ☐
💡 KEY TAKEAWAYS
RBAC : Least privilege — only grant needed verbs/resources
ServiceAccount : Per-workload, disable token auto-mount
PSS : Enforce Restricted for production namespaces
Audit : Log secret access, RBAC changes, pod exec
SecurityContext : runAsNonRoot, dropAll capabilities, readOnlyRootFilesystem
🎯 EXERCISE
Exercise 1: RBAC Setup__HTMLTAG_259___
Create developer/ops Roles with different permissions
Test access with kubectl --as=developer
Enable audit logging, verify secret access is logged__HTMLTAG_266___
Exercise 2: Pod Security
Label namespace with restricted PSS
Deploy a privileged pod → verify rejection
Fix pod to comply with restricted level
📚 NEXT POST
In Lesson 37: Kyverno Policy Engine , we will implement policy-as-code for the cluster.