100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
YAML

Kubernetes Security Basics

Learn defensive Kubernetes security fundamentals: RBAC, NetworkPolicies, Pod security context, secrets handling, and image scanning.

Kubernetes OperationsIntermediate11 min readJul 8, 2026
Analogies

Defense in Depth for Kubernetes

Securing a cluster means layering controls: who can call the API (authentication/authorization), what traffic Pods can send or receive (network policy), what a container is allowed to do at runtime (Pod security context), and how sensitive data and images are handled before they ever run. No single control is sufficient on its own — they combine to reduce blast radius when something goes wrong.

🏏

Cricket analogy: Securing a cluster is like a franchise layering checks: who can enter the dressing room (authentication), what messages fielders can pass to each other (network policy), what a player is allowed to do on the pitch (security context), and how the trophy and player contracts are handled before the tournament even starts.

RBAC: Roles and RoleBindings

Role-Based Access Control governs who can perform which verbs (get, list, create, delete, etc.) on which resources. A Role (namespace-scoped) or ClusterRole (cluster-scoped) defines permissions; a RoleBinding or ClusterRoleBinding grants those permissions to a user, group, or ServiceAccount. Follow least privilege: grant only the verbs and resources actually needed, avoid binding cluster-admin to application or CI ServiceAccounts, and audit wildcard rules (resources: ["*"], verbs: ["*"]) closely.

🏏

Cricket analogy: RBAC is like a club's committee granting specific powers: a groundskeeper role can only water and mow (get, list), never sign new players (create, delete); avoid handing the tea-boy the chairman's full authority (cluster-admin), and audit any role with blanket powers over everything.

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: prod
  name: pod-reader
rules:
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-ci
  namespace: prod
subjects:
  - kind: ServiceAccount
    name: ci-runner
    namespace: prod
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

NetworkPolicies: restricting pod-to-pod traffic

By default, all Pods in a cluster can reach all other Pods on any port — there is no network isolation unless the CNI plugin enforces NetworkPolicy resources (Calico, Cilium, and others support this; some CNIs do not). A NetworkPolicy selects Pods by label and defines allowed ingress/egress rules; once any policy selects a Pod, all traffic not explicitly allowed is denied by default for that direction. A good baseline is a default-deny policy per namespace plus explicit allow rules for required paths only. This is combined with Pod-level securityContext hardening (covered next) to shrink the container's attack surface at both the network and OS-process layers.

🏏

Cricket analogy: By default all Pods reaching each other is like every player from every team having free access to every dressing room; a NetworkPolicy is like security enforcing that only registered squad members enter their own room, with a default-deny stance requiring explicit accreditation for any other access.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: prod
spec:
  podSelector:
    matchLabels: { app: api }
  policyTypes: ["Ingress"]
  ingress:
    - from:
        - podSelector:
            matchLabels: { app: frontend }
      ports:
        - protocol: TCP
          port: 8080

Pod Security: securityContext and Pod Security Standards

securityContext (at the Pod or container level) restricts what a container process can do on the host: runAsNonRoot/runAsUser avoid running as root, readOnlyRootFilesystem prevents writes to the container filesystem (mount a writable emptyDir at specific paths that need it, rather than disabling the setting), allowPrivilegeEscalation: false blocks gaining more privileges than the parent process, and capabilities.drop: ["ALL"] removes all Linux capabilities by default. Kubernetes also defines Pod Security Standards (Privileged, Baseline, Restricted) enforceable per-namespace via the built-in Pod Security Admission controller using namespace labels.

🏏

Cricket analogy: securityContext hardening is like a player's kit restrictions: runAsNonRoot means no one plays as the untouchable captain by default, readOnlyRootFilesystem means you can't rewrite the official rulebook (only scribble on a scratchpad), and capabilities.drop ALL strips every special privilege unless explicitly re-granted.

yaml
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    fsGroup: 10001
  containers:
    - name: web
      image: registry.example.com/web:1.5.0
      securityContext:
        readOnlyRootFilesystem: true
        allowPrivilegeEscalation: false
        capabilities:
          drop: ["ALL"]
---
# Enforce the Restricted Pod Security Standard on a namespace
apiVersion: v1
kind: Namespace
metadata:
  name: prod
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/warn: restricted

Kubernetes Secrets are base64-encoded, not encrypted, by default — treat base64 as encoding, not security. Enable encryption at rest for the etcd datastore, restrict RBAC access to Secret objects tightly (get on secrets is effectively read access to credentials), avoid mounting Secrets as environment variables when possible (volume mounts are generally preferred), and consider an external secrets manager (Vault, AWS/GCP/Azure secret stores) synced in via a controller for rotation and auditing. Separately, scan container images for known CVEs before deployment (tools like Trivy or Grype), pin images by digest rather than a mutable tag like latest in production, and use admission control (OPA Gatekeeper or Kyverno) to block images that fail a scan or lack a required provenance attestation.

🏏

Cricket analogy: Base64-encoded Secrets are like a scorecard written in a simple substitution code anyone can decode — not real security; encrypt the archive at rest, restrict who can view player contracts (RBAC on Secrets), prefer sealed envelopes over open memos (volume mounts over env vars), and use an external vault for player medical records with rotation and audit trails, while scanning new equipment for defects (image CVEs) and pinning the exact model used (digest) rather than 'latest gear'.

bash
kubectl create secret generic db-creds \
  --from-literal=username=app \
  --from-literal=password='REDACTED' \
  -n prod

# Prefer least-privilege RBAC: only specific ServiceAccounts should get/list secrets
kubectl auth can-i get secrets -n prod --as=system:serviceaccount:prod:ci-runner

trivy image registry.example.com/web:1.5.0
# Scans for OS package and application-dependency CVEs, reports by severity
  • RBAC Roles/ClusterRoles define permissions; RoleBindings/ClusterRoleBindings grant them — always apply least privilege.
  • NetworkPolicies are deny-by-default only once a policy selects a Pod, and require a CNI that supports them.
  • securityContext settings like runAsNonRoot, readOnlyRootFilesystem, and dropped capabilities shrink the container's attack surface.
  • Pod Security Admission enforces Privileged/Baseline/Restricted standards per namespace via labels.
  • Kubernetes Secrets are base64-encoded, not encrypted — enable etcd encryption at rest and restrict RBAC on secrets.
  • Scan images for CVEs (e.g. Trivy) and pin by digest; use admission policies to enforce scanning before deploy.

Practice what you learned

Was this page helpful?

Topics covered

#YAML#DockerKubernetesStudyNotes#DevOps#KubernetesSecurityBasics#Kubernetes#Security#Defense#Depth#StudyNotes#SkillVeris