Wiki workshop · Αγγλικά

Security: Kubernetes

This document describes the full subject area of security in Kubernetes. It is intended for workshops, internal platform standards, security reviews, operational handovers, and architecture decisions.

Παραδείγματα workshop σε ZIP
Πρόοδος μάθησης στη web app

Σημειώστε κεφάλαια ως αναγνωσμένα, δείτε την πρόοδο ανάγνωσης και ολοκληρώστε πρακτικές ενότητες αφού ενεργοποιήσετε την προαιρετική web app. Η πρόοδος του workshop υπολογίζεται από τα κεφάλαια όλων των σελίδων τεκμηρίωσης. Οι επιλογές μένουν σε αυτή τη συσκευή· δεν υπάρχει λογαριασμός ή συγχρονισμός με server. Δεν απαιτείται εγκατάσταση. Η ανάκληση στις Ρυθμίσεις απορρήτου διαγράφει την πρόοδο.

Πρόοδος ανάγνωσης0%
0%
0 / 44 κεφάλαια που διαβάστηκαν

Δεν υπάρχει ακόμη ελληνική έκδοση αυτού του εγγράφου. Το περιεχόμενο εμφανίζεται στα αγγλικά.

Άλλη γλωσσική έκδοσηΓερμανικά ↗

Security: Kubernetes

Complete security documentation for Kubernetes workshops, platform design, operational reviews, and security assessments.

Version: June 13, 2026



1. Objective and Scope

This document describes the full subject area of security in Kubernetes. It is intended for workshops, internal platform standards, security reviews, operational handovers, and architecture decisions.

After working through this document, you should be able to:

  • structure Kubernetes security professionally;
  • assess risks by environment;
  • define secure defaults for workloads;
  • implement API, RBAC, pod, network, secret, node, and supply-chain controls;
  • classify security requirements for kind, minikube, k3d, WSL, local VMs, remote VMs, bare metal, kubeadm clusters, k3s, RKE2, k0s, Talos, EKS, AKS, GKE, OKE, DOKS, LKE, and OpenShift;
  • triage security findings;
  • handle incidents reproducibly;
  • translate compliance and audit requirements into technical controls.

1.1. What This Document Covers

Area Content
Cluster Security API Server, etcd, kubelet, controllers, scheduler, admission, audit
Identity users, groups, ServiceAccounts, OIDC, cloud workload identity
Authorization RBAC, least privilege, escalation paths, review commands
Workload Security Pod Security Standards, SecurityContext, capabilities, seccomp, AppArmor, SELinux
Network Security NetworkPolicies, CNI, DNS, Ingress, Gateway API, egress, service mesh
Secrets Kubernetes Secrets, encryption at rest, external secret systems, rotation
Supply Chain images, registries, SBOMs, signatures, scans, admission gates
Runtime Security Falco, Tetragon, audit logs, eBPF, behavior analysis
Node Security OS hardening, kubelet, runtime, SSH, patches, immutable nodes
Environments WSL, kind, minikube, k3d, VMs, bare metal, cloud, managed Kubernetes
Operations backup, restore, disaster recovery, patching, monitoring, logging, alerting
Compliance CIS, NSA/CISA, internal standards, audit reports

1.2. What This Document Does Not Replace

This document does not replace:

  • legal compliance assessment;
  • an organization-wide risk analysis;
  • vendor documentation for your provider;
  • penetration tests;
  • emergency exercises;
  • production approvals by security, privacy, or governance teams.

It provides the technical foundation needed to prepare these processes properly.

1.3. Terms

Term Meaning
Control Plane API Server, etcd, scheduler, controller manager, and other control components
Node machine running kubelet and a container runtime
Workload application or platform component running as a Pod
Admission validation or mutation of API requests before they are stored in etcd
Runtime Security detection and evaluation of behavior after a container has started
Supply Chain path from source code through build, image, registry, deployment, and runtime
Least Privilege granting only permissions that are objectively required
Break Glass emergency access for exceptional incidents with strong control and audit

01 / 44

2. Security Guiding Principles

Kubernetes security is not a single feature. It emerges from layered controls, clear responsibilities, and repeatability.

2.1. Principles

  1. Declarative instead of manual. Security controls belong in Git, IaC, Helm, Kustomize, or policy engines.
  2. Least privilege everywhere. Users, ServiceAccounts, nodes, cloud roles, registry access, and CI/CD tokens receive only the rights they need.
  3. Default deny before allow lists. Network, RBAC, admission, and egress should start with restrictive defaults.
  4. Identity instead of static secrets. Prefer OIDC, Workload Identity, Pod Identity, Managed Identity, or short-lived tokens.
  5. Immutable instead of repair. Replace compromised nodes and unsafe images instead of manually cleaning them up.
  6. Admission catches issues early. Anything that must not run should ideally never be stored in etcd.
  7. Observability is a security control. Without audit logs, metrics, runtime events, and centralized logs, security is blind.
  8. Restore is part of security. Backups without a tested restore are not a reliable control.
  9. The supply chain starts before Kubernetes. Images, dependencies, build runners, registries, and GitOps controllers are part of the threat model.
  10. Environment determines risk. A local kind lab needs different controls from a regulated multi-tenant production cluster.

2.2. Minimal Security Standard for Production-like Clusters

Control Minimum Standard
API access no open API from the internet; access through VPN, private endpoint, bastion, SSO, or IP allowlist
RBAC no broadly used cluster-admin bindings; review bind, escalate, impersonate, nodes/proxy
Pod Security namespace labels for baseline or restricted; exceptions documented
Secrets encryption at rest, strict RBAC, no real secrets in Git, defined rotation
Network default deny per tenant/namespace; DNS, monitoring, and required egress explicitly allowed
Images no latest tags in production; scans; digest pinning or signature verification for critical workloads
Nodes kubelet protected; SSH minimized; runtime current; OS patches planned
Audit API audit enabled or provider audit logs integrated; logs stored tamper-resistently
Backup etcd or cluster state, PV data, secrets, certificates, and IaC state backed up and restore-tested
Incident response runbooks for compromised pod, node, secret, registry, CI/CD, and API access

2.3. Security Maturity Levels

Maturity Description Typical Characteristics
0: Ad hoc manual clusters, few standards many cluster-admin users, no NetworkPolicies, no scans
1: Baseline basic controls introduced RBAC, PSS, basic scans, centralized logs
2: Standardized repeatable platform GitOps, policy as code, external secrets, backup/restore tested
3: Controlled audit and compliance capable CIS reviews, SIEM integration, runtime detection, cloud guardrails
4: Resilient security is an operations process tabletop exercises, automated rotation, multi-cluster DR, continuous improvement

02 / 44

3. Quick Start: Security Baseline

This section provides an immediately usable baseline for labs and production-like tests. For real production, adapt every control to your organization, regulatory context, network architecture, and provider constraints.

3.1. Namespace with Pod Security Admission

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: app-prod
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: latest
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest

Validation:

bash
kubectl apply -f namespace-app-prod.yaml
kubectl get ns app-prod --show-labels

3.2. Default Deny for Ingress and Egress

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: app-prod
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

This policy also blocks DNS egress unless DNS is explicitly allowed.

3.3. Allow DNS Egress

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: app-prod
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

Adjust the labels to your CoreDNS installation. Some distributions use different labels.

3.4. Secure ServiceAccount

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-runtime
  namespace: app-prod
automountServiceAccountToken: false

If your application does not need the Kubernetes API, do not mount a token. If it does need API access, grant exactly the required permissions and enable token mounting only for that workload.

3.5. Minimal RBAC for Read-Only Pod Access in the Namespace

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

3.6. Hardened Deployment

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
  namespace: app-prod
  labels:
    app.kubernetes.io/name: demo-app
    app.kubernetes.io/part-of: workshop
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: demo-app
  template:
    metadata:
      labels:
        app.kubernetes.io/name: demo-app
        app.kubernetes.io/part-of: workshop
    spec:
      serviceAccountName: app-runtime
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: app
          image: ghcr.io/example/demo-app@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 10001
            runAsGroup: 10001
            capabilities:
              drop:
                - ALL
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              memory: 256Mi
          livenessProbe:
            httpGet:
              path: /healthz
              port: http
            initialDelaySeconds: 20
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /readyz
              port: http
            initialDelaySeconds: 5
            periodSeconds: 5
          volumeMounts:
            - name: tmp
              mountPath: /tmp
      volumes:
        - name: tmp
          emptyDir: {}

3.7. Baseline Validation

bash
kubectl auth can-i list pods -n app-prod --as system:serviceaccount:app-prod:app-runtime
kubectl auth can-i get secrets -n app-prod --as system:serviceaccount:app-prod:app-runtime
kubectl get networkpolicy -n app-prod
kubectl get pods -n app-prod -o wide
kubectl describe pod -n app-prod -l app.kubernetes.io/name=demo-app

Expected result:

  • the ServiceAccount can read Pods but cannot read Secrets;
  • Pods run as non-root, without privilege escalation, and with RuntimeDefault seccomp;
  • networking is closed by default;
  • exceptions are explicitly documented.

03 / 44

4. Threat Model

Kubernetes has several attack surfaces. A useful security model considers not just Pods, but the full delivery and operations path.

4.1. Primary Attack Surfaces

Attack Surface Typical Risks Controls
API Server stolen kubeconfigs, open API, weak RBAC, missing audit logs OIDC, MFA, private API, RBAC, audit, admission
etcd unencrypted Secrets, leaked snapshots, control-plane access encryption at rest, TLS, backup protection, node isolation
kubelet anonymous access, nodes/proxy, exec into node workloads webhook authn/authz, network isolation, RBAC review
Workloads root containers, privileged Pods, HostPath, capabilities PSS, SecurityContext, admission, runtime detection
CNI and network open pod communication, uncontrolled egress, DNS abuse NetworkPolicies, egress gateway, DNS policy, optional service mesh
Ingress/Gateway missing TLS, unsafe headers, open admin endpoints TLS, WAF, rate limits, auth, Gateway role model
Registry tampered images, unsafe tags, CVEs scans, signatures, digest pinning, registry RBAC
CI/CD runner compromise, secret leak, supply-chain manipulation short-lived tokens, isolated runners, SBOM, provenance
GitOps overprivileged controller, drift, unreviewed manifests repo RBAC, branch protection, scoped ServiceAccounts, admission
Cloud IAM node roles with too many rights, metadata service abuse Pod Identity, Workload Identity, IMDS hardening, least privilege
Nodes SSH, unpatched OS, container escape, local credentials OS hardening, patches, immutable nodes, runtime detection
Add-ons overprivileged controllers, webhook outage, CRD misuse add-on review, versioning, RBAC, PDB, observability

4.2. Attacker Profiles

Profile Description Example
External attacker no initial cluster access exploitation of an application CVE through ingress
Malicious insider legitimate identity with malicious intent developer reads secrets outside their team
Compromised workload attacker controls a Pod shell in container, ServiceAccount token extraction
Compromised node attacker has host access container runtime, kubelet, Pod filesystems
Compromised pipeline build or deployment is manipulated image contains a backdoor, GitOps deploys malicious change
Compromised cloud account cloud IAM is abused node role can read Secrets Manager or broad storage

4.3. Typical Attack Chains

flowchart LR
    A[Public App CVE] --> B[Shell in Pod]
    B --> C[ServiceAccount Token]
    C --> D[Check RBAC]
    D --> E{Rights too broad?}
    E -- yes --> F[Read Secrets or create Pods]
    E -- no --> G[Explore node or network]
    F --> H[Cloud credentials or DB access]
    G --> I[Egress to C2 or lateral movement]
flowchart LR
    A[CI Runner compromised] --> B[Image manipulated]
    B --> C[Registry Push]
    C --> D[GitOps Rollout]
    D --> E[Pod starts in cluster]
    E --> F[Runtime Detection or Admission?]
    F -- no control --> G[Persistence and data access]
    F -- control active --> H[Deployment blocked or alert]

4.4. Threats by STRIDE

STRIDE Kubernetes Example Control
Spoofing stolen kubeconfig, fake ServiceAccount identity OIDC, MFA, short-lived tokens, audit
Tampering manipulated manifest, image, or admission webhook Git protection, signatures, admission, branch protection
Repudiation changes cannot be attributed audit logs, Git history, SIEM, change process
Information Disclosure Secrets, ConfigMaps, logs, or PV data exposed RBAC, encryption, log scrubbing, data classification
Denial of Service resource exhaustion, webhook outage, API overload quotas, LimitRanges, PDBs, HA, rate limits
Elevation of Privilege bind, escalate, impersonate, privileged Pods RBAC review, PSS, admission, separate admin groups

04 / 44

5. Defense-in-Depth Architecture

Security in Kubernetes is layered. A single policy is never enough.

5.1. Overview

flowchart TB
    subgraph Supply[Supply Chain]
      Code[Code Review]
      Build[Build Runner]
      Scan[Scan and SBOM]
      Sign[Signature and Provenance]
      Registry[Registry]
    end

    subgraph Access[Access]
      User[Users / Groups]
      OIDC[OIDC / SSO / MFA]
      Kubeconfig[kubeconfig / Exec Plugin]
    end

    subgraph API[Kubernetes API]
      APIServer[API Server]
      Authn[Authentication]
      Authz[RBAC / Webhook Authz]
      Admission[Admission / Policy]
      Audit[Audit Logs]
      Etcd[etcd]
    end

    subgraph Runtime[Runtime]
      Node[Node]
      Kubelet[kubelet]
      RuntimeEngine[containerd / CRI-O]
      Pod[Pod]
      Net[NetworkPolicy / CNI]
      Detect[Runtime Detection]
    end

    Code --> Build --> Scan --> Sign --> Registry
    User --> OIDC --> Kubeconfig --> APIServer
    Registry --> Admission
    APIServer --> Authn --> Authz --> Admission --> Etcd
    APIServer --> Audit
    Etcd --> Kubelet
    Kubelet --> RuntimeEngine --> Pod
    Pod --> Net
    RuntimeEngine --> Detect
    Audit --> Detect

5.2. API Request Path

sequenceDiagram
    participant Client as kubectl / Controller / GitOps
    participant API as kube-apiserver
    participant Authn as Authentication
    participant Authz as Authorization
    participant Admission as Admission
    participant Etcd as etcd
    participant Audit as Audit Backend

    Client->>API: Request
    API->>Audit: RequestReceived
    API->>Authn: Who are you?
    Authn-->>API: user / groups / ServiceAccount
    API->>Authz: Are you allowed?
    Authz-->>API: allow / deny
    API->>Admission: validate / mutate
    Admission-->>API: allow / deny / patch
    API->>Etcd: persist
    API->>Audit: ResponseComplete
    API-->>Client: response

5.3. Control Matrix

Phase Preventive Detective Reactive
Code review, SAST, dependency pinning secret scanning revert, token rotation
Build isolated runners, SBOM, signature build audit, provenance verification rebuild runner
Registry RBAC, immutable tags, scans registry audit block image, stop pulls
Admission PSS, RBAC, Kyverno, Gatekeeper, CEL policy reports, audit fix policy, remove exception
Runtime SecurityContext, NetworkPolicy Falco, Tetragon, logs, metrics isolate Pod, rotate node
Data encryption, external secrets access logs, KMS logs rotate keys, restore
Operations change process, backup monitoring, SIEM incident response, DR

05 / 44

6. Environments and Responsibilities

Security controls vary significantly by environment. Always clarify who controls which layer.

6.1. Responsibility Model

Environment Control Plane Nodes Network Storage Typical Security Responsibility
WSL local / experimental Windows + WSL host NAT / mirrored local filesystem secure learning environment, no real secrets
kind containers on Docker/Podman local host Docker network local volumes quick tests, admission and manifest validation
minikube local single-node cluster local host/VM/container driver-dependent local storage labs, add-on behavior, ingress tests
k3d k3s in containers local host Docker network local volumes quick k3s-like tests
local VM you you you you OS, runtime, kubeadm, firewall, backup
remote VM you + provider you provider network + you provider disks + you cloud firewall, SSH, kubeadm, backup
bare metal you you you you full responsibility down to firmware/BMC
EKS AWS you or AWS depending on node type AWS + you AWS + you IAM, Pod Identity, Security Groups, logs, add-ons
AKS Microsoft you or Microsoft depending on mode Azure + you Azure + you Entra ID, Azure Policy, Defender, Key Vault
GKE Google you or Google depending on mode Google + you Google + you IAM/RBAC, Workload Identity, Binary Authorization
OpenShift platform team/provider platform team/provider platform team/provider platform team/provider SCC, operators, routes, projects, OAuth
Talos you declarative via Talos API you you immutable OS, API-secured node management

6.2. Decision Diagram

flowchart TD
    A[Which environment?] --> B{Learning or CI only?}
    B -- yes --> C[kind, minikube, k3d]
    B -- no --> D{Production-like operation?}
    D -- local --> E[VM, bare metal, kubeadm, k3s, RKE2, Talos]
    D -- cloud --> F[EKS, AKS, GKE, OKE, DOKS, LKE]
    D -- Enterprise PaaS --> G[OpenShift]
    C --> H[No real secrets, protect host, test policies]
    E --> I[Harden OS, runtime, API, etcd, CNI, storage]
    F --> J[Provider IAM, private endpoints, workload identity, logs]
    G --> K[SCC, OAuth, operators, projects, ClusterRoles]

6.3. Security Exceptions by Environment

Environment Acceptable Simplification Not Acceptable
local lab self-signed TLS, demo secrets, single node real customer data, production cloud tokens
CI cluster short-lived cluster, simplified ingress rules persistent admin tokens, unisolated runners with production access
dev cluster less strict availability missing RBAC separation, open secrets, no audit
staging production-like policies different images/policies than production without rationale
production controlled exceptions cluster-admin for apps, privileged Pods without review, open API

06 / 44

7. API Security

The API Server is the central control plane. Almost every security decision eventually reaches the Kubernetes API.

7.1. Risks

  • kubeconfig files with admin rights are shared.
  • API endpoints are publicly reachable.
  • old certificates or tokens do not expire.
  • users receive cluster-admin because RBAC design is missing.
  • audit logs are missing or not evaluated.
  • admission webhooks are operated insecurely or allow everything when they fail.

7.2. Securing API Access

Control Recommendation
Network access keep API private or restrict through IP allowlist, VPN, bastion, zero-trust access
Identity OIDC/SSO with MFA instead of static client certificates for humans
kubeconfig do not distribute admin kubeconfigs to laptops; prefer exec plugins
Break glass separate, time-limited, heavily audited, not for daily work
Audit enable API audit or integrate provider audit logs
Certificates monitor expiry, document rotation, protect CA material

7.3. Handling kubeconfig Securely

bash
kubectl config get-contexts
kubectl config view --minify
kubectl config current-context

Review regularly:

bash
find ~/.kube -maxdepth 2 -type f -print -exec ls -l {} \;

Minimum rules:

  • ~/.kube/config should be readable only by your user.
  • kubeconfigs do not belong in Git.
  • kubeconfigs do not belong in tickets, chat, wikis, or training material.
  • training uses demo clusters and demo credentials.
  • CI/CD uses short-lived OIDC flows or dedicated ServiceAccounts with minimal permissions.

7.4. API Server Flags in Self-Managed Clusters

In kubeadm clusters, API Server parameters usually live in the static Pod manifest:

bash
sudo grep -n "audit\|authorization\|admission\|encryption" /etc/kubernetes/manifests/kube-apiserver.yaml

Important topics:

Topic Goal
--authorization-mode Node,RBAC or organization-specific extension
--enable-admission-plugins enable required admission controllers
--audit-policy-file load audit policy
--audit-log-path or webhook persist audit events
--encryption-provider-config encrypt Secrets and other sensitive resources
--anonymous-auth avoid anonymous access unless strictly required
TLS flags use secure certificates and CAs

7.5. API Security Checks

bash
kubectl version
kubectl cluster-info
kubectl auth whoami
kubectl auth can-i --list
kubectl get --raw /readyz?verbose
kubectl get --raw /livez?verbose

For production environments, also check:

bash
kubectl get clusterrolebinding -o wide
kubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration
kubectl get validatingadmissionpolicy,validatingadmissionpolicybinding
kubectl get mutatingadmissionpolicy,mutatingadmissionpolicybinding

07 / 44

8. Authentication, Authorization, and Admission

Every API request goes through multiple stages.

flowchart LR
    Request[API Request] --> Authn[Authentication]
    Authn --> Authz[Authorization]
    Authz --> Admission[Admission]
    Admission --> Etcd[Persistence in etcd]
    Admission --> Audit[Audit]

8.1. Authentication

Kubernetes has no native User API for humans. User identities come from external mechanisms.

Method Usage
X.509 client certificates cluster admin, kubeadm, components, rarely humans in daily work
Bearer tokens ServiceAccounts, external systems, legacy flows
OIDC SSO for humans and CI/CD
Webhook token auth provider integration, for example EKS
Exec credential plugin cloud CLI creates short-lived tokens for kubeconfig

Recommendations:

  • humans use SSO/OIDC with MFA;
  • machines use short-lived, purpose-bound tokens;
  • legacy token Secrets are avoided;
  • certificate lifetimes are monitored.

8.2. Authorization

The most common authorization mechanism is RBAC. Kubernetes can use other modes, but RBAC is the primary control in most platforms.

Authorization questions:

bash
kubectl auth can-i get pods -n demo
kubectl auth can-i create deployments -n demo
kubectl auth can-i get secrets -A
kubectl auth can-i '*' '*' --all-namespaces
kubectl auth can-i get pods --as alice@example.com -n demo
kubectl auth can-i get secrets --as system:serviceaccount:demo:app -n demo

8.3. Admission

Admission controllers run after authentication and authorization but before persistence in etcd.

Control Purpose
Pod Security Admission enforce, warn, or audit Pod Security Standards
ResourceQuota limit resource consumption by namespace
LimitRanger set defaults and constraints for container resources
ValidatingAdmissionPolicy declarative CEL validation in the API Server
MutatingAdmissionPolicy declarative mutation in the API Server; stable as of Kubernetes v1.36
ValidatingWebhook external validation, for example Gatekeeper, Kyverno, custom webhooks
MutatingWebhook external mutation, for example sidecar injection

8.4. Handling Admission Failures Safely

Webhook outages are an operational and security risk.

Setting Meaning Recommendation
failurePolicy: Fail API request is blocked when webhook fails use for hard security controls
failurePolicy: Ignore API request proceeds despite failure only for non-critical controls
timeoutSeconds timeout per webhook keep short, measure, alert
namespaceSelector scope handle system namespaces deliberately
objectSelector object filter use sparingly, check bypasses

8.5. Admission Review Commands

bash
kubectl get validatingwebhookconfiguration -o wide
kubectl get mutatingwebhookconfiguration -o wide
kubectl describe validatingwebhookconfiguration <name>
kubectl describe mutatingwebhookconfiguration <name>
kubectl get validatingadmissionpolicy,validatingadmissionpolicybinding
kubectl get mutatingadmissionpolicy,mutatingadmissionpolicybinding
kubectl get events -A --sort-by=.lastTimestamp | grep -i admission

08 / 44

9. RBAC and Least Privilege

RBAC is one of the most important Kubernetes controls. Misconfigurations can lead directly to privilege escalation.

9.1. RBAC Objects

Object Scope Purpose
Role namespace define rights inside a namespace
ClusterRole cluster define cluster-wide or reusable rights
RoleBinding namespace bind Role or ClusterRole to subjects in a namespace
ClusterRoleBinding cluster bind ClusterRole to subjects cluster-wide

9.2. Subjects

RBAC can be bound to:

  • users;
  • groups;
  • ServiceAccounts.

Example:

yaml
subjects:
  - kind: User
    name: alice@example.com
  - kind: Group
    name: platform-admins
  - kind: ServiceAccount
    name: app
    namespace: demo

9.3. Dangerous Permissions

Permission Risk
cluster-admin full cluster access
* on * future resources and CRDs are included automatically
create pods can execute code in the cluster
create pods/exec direct shell access into containers
get/list/watch secrets access to sensitive data and tokens
create rolebindings can bind rights to self or others
bind bind roles even without already having their permissions
escalate create or modify roles with higher rights
impersonate act as another identity
nodes/proxy access kubelet APIs, potentially exec into containers on nodes
certificatesigningrequests/approval approve or issue certificates
update validatingwebhookconfigurations weaken admission protection
update mutatingwebhookconfigurations manipulate mutation
update namespaces remove Pod Security labels

9.4. RBAC Review

bash
kubectl get role,rolebinding -A
kubectl get clusterrole,clusterrolebinding
kubectl describe clusterrolebinding cluster-admin
kubectl get clusterrolebinding -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.roleRef.name}{"\t"}{range .subjects[*]}{.kind}:{.namespace}:{.name}{","}{end}{"\n"}{end}'

Search for wildcards:

bash
kubectl get clusterrole -o yaml | grep -n "\*"
kubectl get role -A -o yaml | grep -n "\*"

Check Secret access:

bash
kubectl get clusterrole,role -A -o yaml | grep -n -B5 -A10 "secrets"

Check impersonation, bind, and escalate:

bash
kubectl get clusterrole,role -A -o yaml | grep -n -B5 -A10 "impersonate\|bind\|escalate"

9.5. Designing Safe Roles

Process:

  1. Describe the use case.
  2. Identify required API resources.
  3. Use Role instead of ClusterRole when namespace scope is sufficient.
  4. Use only specific verbs.
  5. Avoid wildcards.
  6. Separate reading, writing, deploying, and administration.
  7. Test with kubectl auth can-i.
  8. Document owner, purpose, and expiry date.

9.6. Example: Developer Role in a Namespace

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer-workload-editor
  namespace: team-a
  labels:
    security.example.com/owner: platform
rules:
  - apiGroups: ["apps"]
    resources: ["deployments", "statefulsets", "daemonsets"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
  - apiGroups: [""]
    resources: ["pods", "pods/log", "services", "configmaps"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["batch"]
    resources: ["jobs", "cronjobs"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]

This role does not allow:

  • reading Secrets;
  • modifying RBAC;
  • direct pod exec;
  • modifying NetworkPolicies;
  • modifying namespace labels;
  • modifying cluster objects.

9.7. Break-Glass Model

Break-glass access is emergency access. It must not be daily access.

Minimum rules:

  • few people;
  • MFA;
  • separate accounts;
  • time-limited activation;
  • audit and alerting;
  • mandatory post-documentation;
  • regular test exercise;
  • immediate revocation when someone leaves or changes roles.

9.8. RBAC Anti-Patterns

Anti-Pattern Why It Is Critical
cluster-admin for CI/CD compromised pipeline owns the cluster
cluster-admin for Argo CD without scope Git repository becomes cluster root
wildcards in roles future CRDs are included automatically
get secrets for developer groups secrets become normal configuration data
broad pods/exec shell access becomes routine instead of exception
namespace admin can bind cluster-admin direct privilege escalation
ServiceAccount token automatically in every Pod unnecessary API credentials in compromisable Pods

09 / 44

10. ServiceAccounts and Workload Identities

ServiceAccounts are identities for processes in Pods. They are not user accounts for humans.

10.1. Risks

  • the default ServiceAccount is used everywhere;
  • tokens are automatically mounted into Pods;
  • ServiceAccounts have overly broad roles;
  • tokens appear in logs, debug dumps, or container filesystems;
  • cloud access runs through node roles instead of workload identities.

10.2. Standard Rules

Rule Recommendation
dedicated ServiceAccount per workload yes
use the default ServiceAccount no
automountServiceAccountToken: false default unless API access is required
role scope namespace instead of cluster
cloud access Workload Identity, Pod Identity, Managed Identity; not node role
token rotation prefer short-lived bound tokens

10.3. ServiceAccount Without Token Mount

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: frontend
  namespace: shop
automountServiceAccountToken: false
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
  namespace: shop
spec:
  selector:
    matchLabels:
      app: frontend
  template:
    metadata:
      labels:
        app: frontend
    spec:
      serviceAccountName: frontend
      automountServiceAccountToken: false
      containers:
        - name: app
          image: ghcr.io/example/frontend:1.0.0

10.4. ServiceAccount with Minimal API Access

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: config-reader
  namespace: shop
automountServiceAccountToken: true
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: read-configmaps
  namespace: shop
rules:
  - apiGroups: [""]
    resources: ["configmaps"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: config-reader-read-configmaps
  namespace: shop
subjects:
  - kind: ServiceAccount
    name: config-reader
    namespace: shop
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: read-configmaps

10.5. Cloud Workload Identities

flowchart LR
    Pod[Pod] --> SA[Kubernetes ServiceAccount]
    SA --> OIDC[Cluster OIDC Issuer]
    OIDC --> CloudIAM[Cloud IAM Trust]
    CloudIAM --> Resource[Cloud Resource]
Provider Mechanism Goal
AWS EKS EKS Pod Identity or IRSA Pod receives IAM role instead of node role
Azure AKS Microsoft Entra Workload ID / Managed Identity Pod uses Azure identity without static secret
Google GKE Workload Identity Federation for GKE Pod receives Google IAM access without JSON key
Oracle OKE Workload Identity / Instance Principal depending on design separate cloud access
generic OIDC federation short-lived, purpose-bound cloud tokens

10.6. Review Commands

bash
kubectl get serviceaccounts -A
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\t"}{.spec.automountServiceAccountToken}{"\n"}{end}'
kubectl auth can-i --as system:serviceaccount:shop:frontend --list -n shop
kubectl get rolebinding,clusterrolebinding -A -o yaml | grep -n "ServiceAccount"

10 / 44

11. Namespace and Tenant Isolation

Namespaces are not a hard security boundary like separate clusters. They are an administrative and policy boundary.

11.1. What Namespaces Are Suitable For

  • team separation;
  • RBAC scope;
  • ResourceQuota;
  • LimitRange;
  • NetworkPolicies;
  • Pod Security Admission;
  • Secret scope;
  • GitOps app boundaries;
  • cost and ownership labels.

11.2. What Namespaces Do Not Fully Isolate

Namespaces do not automatically separate:

  • node kernel;
  • container runtime;
  • CNI dataplane;
  • cluster-wide resources;
  • CRDs;
  • webhooks;
  • storage backends;
  • cloud IAM;
  • cluster-admin access.

For real tenant isolation, you need additional controls or separate clusters.

11.3. Namespace Baseline

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: team-a-prod
  labels:
    owner.example.com/team: team-a
    environment.example.com/stage: prod
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: team-a-prod
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.memory: 16Gi
    pods: "50"
    persistentvolumeclaims: "10"
---
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: team-a-prod
spec:
  limits:
    - type: Container
      defaultRequest:
        cpu: 100m
        memory: 128Mi
      default:
        memory: 512Mi
      max:
        memory: 2Gi

11.4. Multi-Tenancy Models

Model Description Suitable For
namespace per team multiple teams in one cluster internal platforms with moderate risk
namespace per app finer isolation GitOps and cost control
cluster per environment dev/stage/prod separated clear operational boundaries
cluster per tenant strong tenant separation regulated or external tenants
OpenShift project model namespace plus platform policies OpenShift environments
virtual cluster API isolation via vCluster/Kapsule development platforms; not always a hard security boundary

11.5. Namespace Review

bash
kubectl get ns --show-labels
kubectl get resourcequota,limitrange -A
kubectl get networkpolicy -A
kubectl get rolebinding -A
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.nodeName}{"\n"}{end}'

11 / 44

12. Pod Security Standards and Pod Security Admission

Pod Security Standards define three profiles:

Profile Purpose
Privileged mostly unrestricted, for highly trusted infrastructure workloads
Baseline prevents known privilege escalations while allowing many standard workloads
Restricted strongly hardened, target profile for many production application workloads

Pod Security Admission enforces these standards through namespace labels.

12.1. Modes

Mode Effect
enforce violating Pods are rejected
audit violations are written to audit logs
warn users receive warnings on API requests

12.2. Migrating from Baseline to Restricted

For existing platforms, usually proceed incrementally:

  1. set warn=restricted;
  2. evaluate warnings;
  3. set audit=restricted;
  4. document exceptions;
  5. adjust workloads;
  6. enable enforce=baseline or enforce=restricted;
  7. add regression tests in CI.

12.3. Namespace with Warning Instead of Immediate Blocking

yaml
apiVersion: v1
kind: Namespace
metadata:
  name: migration-test
  labels:
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: latest

12.4. Privileged Exceptions

Some platform components need more rights:

  • CNI agents;
  • CSI node plugins;
  • node-exporters with host mounts;
  • runtime security agents;
  • service mesh CNI;
  • kube-proxy or eBPF agents;
  • storage or backup agents.

Rules for exceptions:

  • dedicated namespace;
  • dedicated owner;
  • review date;
  • rationale;
  • minimal app-team write access;
  • enforce=privileged only for system namespaces;
  • no broad admission exceptions.

12.5. Test a Forbidden Pod

yaml
apiVersion: v1
kind: Pod
metadata:
  name: should-fail
  namespace: app-prod
spec:
  containers:
    - name: shell
      image: busybox
      command: ["sleep", "3600"]
      securityContext:
        privileged: true
bash
kubectl apply -f should-fail.yaml

Expected with enforce=restricted: the Pod is rejected.


12 / 44

13. SecurityContext, Linux Isolation, and Container Hardening

Pod Security Admission is only one layer. Workloads should declare secure runtime settings themselves.

yaml
securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  runAsNonRoot: true
  runAsUser: 10001
  runAsGroup: 10001
  capabilities:
    drop:
      - ALL
  seccompProfile:
    type: RuntimeDefault

seccompProfile can be set at Pod or container level. runAsNonRoot and runAsUser must match the image.

13.2. Pod SecurityContext

yaml
spec:
  securityContext:
    runAsNonRoot: true
    fsGroup: 10001
    fsGroupChangePolicy: OnRootMismatch
    seccompProfile:
      type: RuntimeDefault

13.3. Capabilities

Linux capabilities allow selected privileged actions without full root context. In Kubernetes, drop all capabilities by default and add only justified exceptions.

Capability Risk
NET_ADMIN manipulate networking, routing, interfaces
SYS_ADMIN very broad, often effectively privileged
SYS_PTRACE inspect processes
DAC_READ_SEARCH bypass filesystem permissions
CHOWN change ownership, sometimes required
NET_BIND_SERVICE bind ports below 1024, often avoidable

Example justified exception:

yaml
securityContext:
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]
    add: ["NET_BIND_SERVICE"]

Often better: make the application listen on port 8080 and map Service port 80 to it.

13.4. Read-only Root Filesystem

A read-only root filesystem reduces persistence and manipulation in the container.

yaml
securityContext:
  readOnlyRootFilesystem: true
volumeMounts:
  - name: tmp
    mountPath: /tmp
  - name: cache
    mountPath: /app/cache
volumes:
  - name: tmp
    emptyDir: {}
  - name: cache
    emptyDir: {}

13.5. Avoid Host Namespaces

Avoid in application workloads:

yaml
hostNetwork: true
hostPID: true
hostIPC: true

These options increase access and visibility on the node and are typically acceptable only for infrastructure components.

13.6. Avoid hostPath

hostPath connects containers directly to node filesystems. It is dangerous.

Problematic example:

yaml
volumes:
  - name: host-root
    hostPath:
      path: /
      type: Directory

Exceptions include DaemonSets for monitoring, CNI, CSI, runtime detection, or node agents. Every exception needs review.

13.7. User Namespaces

User namespaces can separate user IDs inside the container from user IDs on the host. This can make a process appear as root inside the container without being root on the host. Verify support in your Kubernetes version, runtime, distribution, and CNI before using this as a standard.

yaml
apiVersion: v1
kind: Pod
metadata:
  name: userns-demo
spec:
  hostUsers: false
  containers:
    - name: app
      image: busybox
      command: ["sleep", "3600"]

13.8. AppArmor, SELinux, and seccomp

Mechanism Purpose Notes
seccomp restrict system calls set RuntimeDefault by default
AppArmor program profiles for filesystem/network/capabilities mainly Ubuntu/Debian environments
SELinux mandatory access control relevant on RHEL, Fedora, OpenShift, RKE2 with SELinux

Example seccomp:

yaml
securityContext:
  seccompProfile:
    type: RuntimeDefault

13.9. Reviewing Workload Hardening

bash
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.securityContext.runAsNonRoot}{"\t"}{.spec.securityContext.seccompProfile.type}{"\n"}{end}'

More detail with jq:

bash
kubectl get pods -A -o json | jq -r '
  .items[] |
  [.metadata.namespace,
   .metadata.name,
   (.spec.containers[]?.securityContext.privileged // false),
   (.spec.containers[]?.securityContext.allowPrivilegeEscalation // "unset"),
   (.spec.containers[]?.securityContext.readOnlyRootFilesystem // "unset")]
  | @tsv'

13 / 44

14. Admission Policy, Policy as Code, and Governance

Admission is the technical place where unsafe resources can be blocked before they start.

14.1. Policy Options

Option Type Strengths Limits
Pod Security Admission built-in simple, standardized only Pod security fields
ValidatingAdmissionPolicy built-in, CEL no external webhook, fast validation, no complex external logic
MutatingAdmissionPolicy built-in, CEL declarative mutation in API Server version-dependent, not for everything
Kyverno Kubernetes-native policy engine YAML-oriented, validate/mutate/generate/verifyImages additional controller/webhook
OPA Gatekeeper Rego/OPA powerful, auditable, many libraries requires Rego expertise
custom webhooks arbitrary maximum flexibility operational effort, outage risk
cloud policy provider central governance provider-specific

14.2. ValidatingAdmissionPolicy: Disallow latest Tags

yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: disallow-latest-image-tag
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
  validations:
    - expression: "object.spec.containers.all(c, !c.image.endsWith(':latest'))"
      message: "Container images must not use the latest tag. Use a versioned tag or digest."
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: disallow-latest-image-tag-binding
spec:
  policyName: disallow-latest-image-tag
  validationActions:
    - Deny
  matchResources:
    namespaceSelector:
      matchExpressions:
        - key: kubernetes.io/metadata.name
          operator: NotIn
          values:
            - kube-system

14.3. Kyverno Example: Enforce runAsNonRoot

yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-run-as-non-root
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: require-run-as-non-root
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Pods must set runAsNonRoot=true."
        pattern:
          spec:
            securityContext:
              runAsNonRoot: true

14.4. Kyverno Example: Approved Registries

yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-image-registries
spec:
  validationFailureAction: Enforce
  background: true
  rules:
    - name: only-approved-registries
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Images must come from approved registries."
        pattern:
          spec:
            containers:
              - image: "ghcr.io/my-org/* | registry.example.com/*"

Adjust syntax and version to your Kyverno version. Always test policies in audit or warning mode first.

14.5. Gatekeeper Example: ConstraintTemplate

yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        violation[{"msg": msg}] {
          required := input.parameters.labels[_]
          not input.review.object.metadata.labels[required]
          msg := sprintf("Label %v is missing", [required])
        }
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-owner-and-env
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels:
      - owner.example.com/team
      - environment.example.com/stage

14.6. Policy Lifecycle

flowchart LR
    Draft[Policy draft] --> Audit[Audit/warn mode]
    Audit --> Report[Evaluate policy reports]
    Report --> Fix[Adjust workloads]
    Fix --> Enforce[Enable enforce]
    Enforce --> Monitor[Monitor]
    Monitor --> Review[Regular review]
    Review --> Draft

14.7. Governance Rules

  • Every policy has an owner, purpose, severity, and exception process.
  • Policies are versioned and tested.
  • System namespaces are handled separately.
  • failurePolicy is chosen deliberately.
  • Policies are validated before cluster upgrades.
  • Admission controllers have PDBs, monitoring, and resource limits.
  • Policy exceptions are time-bound.

14 / 44

15. Secrets, Keys, and Confidential Data

Kubernetes Secrets are intended for confidential data, but they are not automatically sufficiently protected. Base64 is encoding, not encryption.

15.1. Secret Risks

Risk Example Control
Secrets in Git password: supersecret in manifest SOPS, Sealed Secrets, External Secrets, secret scanning
Secrets in logs app logs env vars log scrubbing, app review, avoid secrets as env where possible
broad RBAC developers can read all Secrets namespace-specific roles, no list secrets
etcd unencrypted snapshot contains plaintext encryption at rest, snapshot protection
static cloud keys JSON key in Secret Workload Identity / Pod Identity
missing rotation DB password valid for years rotation, short TTLs, dynamic secrets

15.2. Secret Usage Patterns

Method Advantage Risk
Env var simple often appears in dumps, harder to rotate
Volume mount better rotation options file permissions and app reload matter
CSI Secret Store external source, no permanent Kubernetes Secret required provider/driver complexity
External Secrets Operator sync from external secret manager controller needs access to backend
SOPS/Sealed Secrets GitOps-friendly key management is critical
Vault Agent / Injector dynamic secrets additional platform component

15.3. Kubernetes Secret with Demo Value

bash
kubectl create secret generic demo-secret \
  -n app-prod \
  --from-literal=username=demo \
  --from-literal=password='not-for-production' \
  --dry-run=client -o yaml

15.4. Do Not Print Secrets

Avoid in training:

bash
kubectl get secret app-secret -o yaml
kubectl get secret app-secret -o jsonpath='{.data.password}' | base64 -d

If you must demonstrate it, use dummy values deliberately and clear shell history in lab environments.

15.5. Encryption at Rest

Example encryption configuration for self-managed clusters:

yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
      - configmaps
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-32-byte-key>
      - identity: {}

API Server integration:

yaml
- --encryption-provider-config=/etc/kubernetes/encryption/encryption-config.yaml

After enabling encryption, rewrite existing objects so they are stored encrypted:

bash
kubectl get secrets -A -o json | kubectl replace -f -

In production, prefer KMS providers or provider-specific key-management integrations where available.

15.6. External Secret Systems

System Typical Use
HashiCorp Vault dynamic secrets, PKI, database credentials, Kubernetes auth
AWS Secrets Manager EKS workloads with Pod Identity/IRSA
AWS SSM Parameter Store configuration and simple secrets
Azure Key Vault AKS with Workload Identity or CSI driver
Google Secret Manager GKE with Workload Identity Federation
External Secrets Operator Kubernetes-native sync from external backends
Secrets Store CSI Driver secrets as volumes from external backends
Mozilla SOPS encrypted GitOps manifests
Bitnami Sealed Secrets public-key Secret encryption for Git

15.7. Secret Rotation

Rotation includes:

  1. create a new secret;
  2. make the application compatible;
  3. roll out the secret;
  4. reload or restart the workload;
  5. invalidate the old secret;
  6. check access and logs;
  7. update documentation.

Example restart after a Secret change:

bash
kubectl rollout restart deployment/app -n app-prod
kubectl rollout status deployment/app -n app-prod

15.8. Short Secret Leak Runbook

  1. Treat the secret as compromised.
  2. Disable or rotate the password/API key.
  3. Review logs and audit.
  4. Redeploy affected workloads.
  5. Clean Git history and artifacts if the secret appeared there.
  6. Fix the root cause.
  7. Improve detection.

15 / 44

16. etcd and Control Plane Protection

etcd stores cluster state. Anyone who can read or manipulate etcd effectively controls the cluster.

16.1. etcd Risks

  • plaintext Secrets when encryption at rest is missing;
  • unprotected snapshots;
  • access to etcd certificates;
  • missing TLS protection;
  • no restore test;
  • insecure control-plane nodes;
  • missing monitoring for leader, latency, disk, and quorum.

16.2. Self-Managed Clusters

Check:

bash
sudo ls -l /etc/kubernetes/pki/etcd
sudo crictl ps | grep etcd
sudo grep -n "etcd" /etc/kubernetes/manifests/etcd.yaml

etcd snapshot:

bash
sudo ETCDCTL_API=3 etcdctl snapshot save /var/backups/etcd/etcd-$(date +%F-%H%M).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Snapshot status:

bash
ETCDCTL_API=3 etcdctl snapshot status /var/backups/etcd/<snapshot>.db -w table

Security rules:

  • encrypt snapshots;
  • do not keep snapshots only on control-plane nodes;
  • test restores regularly;
  • restrict access to etcd certificates;
  • do not run normal workloads on control-plane nodes;
  • do not expose API Server or etcd publicly.

16.3. Managed Kubernetes

For EKS, AKS, GKE, and similar services, the provider manages the control plane. You still control:

  • API endpoint reachability;
  • cloud IAM;
  • audit/control-plane logs;
  • Secrets encryption/KMS options;
  • add-ons;
  • nodes;
  • workload identities;
  • NetworkPolicies;
  • RBAC;
  • backups of Kubernetes resources and PV data.

16.4. Control Plane Hardening in kubeadm

bash
sudo ls -l /etc/kubernetes/manifests
sudo grep -n "authorization-mode\|admission\|audit\|encryption" /etc/kubernetes/manifests/kube-apiserver.yaml
sudo grep -n "profiling\|bind-address" /etc/kubernetes/manifests/kube-controller-manager.yaml
sudo grep -n "profiling\|bind-address" /etc/kubernetes/manifests/kube-scheduler.yaml

Typical goals:

  • RBAC enabled;
  • NodeAuthorizer enabled;
  • suitable admission plugins;
  • audit enabled;
  • profiling disabled or isolated;
  • bind-address not unnecessarily open;
  • certificates checked regularly.

16 / 44

17. Node, Host, and Runtime Hardening

A node is a critical security boundary. If an attacker gets node access, all Pods on that node are at risk.

17.1. Node Baseline

Area Control
OS supported version, automatic security updates or patch windows
SSH minimal, MFA/bastion, no password authentication
Firewall only required ports; kubelet not public
Runtime current containerd or CRI-O; no Docker socket mounts
kubelet anonymous auth disabled, webhook authorization, certificates protected
Kernel enable LSM, control sysctl, avoid unnecessary modules
Filesystem separate partitions where needed, log rotation, protect sensitive paths
Monitoring node exporter, runtime logs, kubelet logs, disk/memory/pressure
Lifecycle drain and replace nodes instead of manual repair

17.2. kubelet Protection

kubelet exposes an HTTPS API. This API can disclose sensitive information and may allow powerful actions depending on permissions.

Check:

bash
sudo cat /var/lib/kubelet/config.yaml | grep -E "anonymous|authorization|authentication" -n
sudo ss -lntp | grep kubelet

Target values:

yaml
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
authorization:
  mode: Webhook

Review RBAC for nodes/proxy strictly:

bash
kubectl get clusterrole -o yaml | grep -n -B5 -A15 "nodes/proxy"
kubectl get clusterrolebinding -o yaml | grep -n -B5 -A15 "nodes"

17.3. Container Runtime

Check runtime:

bash
kubectl get nodes -o wide
crictl info
crictl ps
systemctl status containerd --no-pager
systemctl status crio --no-pager

Recommendations:

  • no Docker socket mounts in Pods;
  • patch runtime regularly;
  • no insecure registries unless explicitly isolated;
  • registry mirrors with TLS;
  • cgroup driver consistent with kubelet;
  • centralize runtime logs.

17.4. Docker Socket Anti-Pattern

Very critical:

yaml
volumeMounts:
  - name: docker-sock
    mountPath: /var/run/docker.sock
volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock

Anyone who controls the Docker or container runtime socket can often compromise the host. Use instead:

  • rootless build tools;
  • BuildKit in an isolated environment;
  • Kaniko with restrictions;
  • cloud build services;
  • dedicated build clusters;
  • separate runners without production access.

17.5. Node Isolation

Separate nodes by risk:

Node Pool Workloads
system CoreDNS, CNI, CSI, Ingress, monitoring
default normal apps
high-security sensitive workloads
privileged CNI/CSI/runtime agents with host access
gpu GPU workloads
edge edge-specific workloads

Example taint:

bash
kubectl taint nodes node-a dedicated=system:NoSchedule

Example toleration:

yaml
tolerations:
  - key: dedicated
    operator: Equal
    value: system
    effect: NoSchedule

17 / 44

18. Network Security

Without NetworkPolicies, pod communication is open in many clusters. NetworkPolicies work only if the CNI plugin enforces them.

18.1. Network Zones

flowchart TB
    Internet[Internet] --> Edge[Load Balancer / WAF]
    Edge --> Ingress[Ingress Controller / Gateway]
    Ingress --> App[App Namespace]
    App --> DB[Database Namespace]
    App --> DNS[CoreDNS]
    App --> Egress[Egress Gateway / NAT]
    Egress --> External[External APIs]
    Monitor[Monitoring] --> App
    Security[Runtime Security] --> App

18.2. NetworkPolicy Basics

NetworkPolicies select Pods by labels. Once a policy applies to a Pod for ingress or egress, that Pod is isolated in that direction and only explicitly allowed traffic works.

18.3. Default Deny per Namespace

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress-egress
  namespace: team-a
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

18.4. Allow Ingress from Ingress Controller

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-controller-to-web
  namespace: team-a
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: ingress-nginx
          podSelector:
            matchLabels:
              app.kubernetes.io/name: ingress-nginx
      ports:
        - protocol: TCP
          port: 8080

18.5. Allow App to Database

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api-to-postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
    - Ingress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              owner.example.com/team: team-a
          podSelector:
            matchLabels:
              app: api
      ports:
        - protocol: TCP
          port: 5432

18.6. Egress to External API

The standard Kubernetes NetworkPolicy model can match IP blocks, but not FQDNs. FQDN-based egress control requires CNI extensions, an egress gateway, proxy, or service mesh.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-egress-payment-provider
  namespace: team-a
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Egress
  egress:
    - to:
        - ipBlock:
            cidr: 203.0.113.0/24
      ports:
        - protocol: TCP
          port: 443

18.7. CNI-Specific Extensions

CNI Security-Relevant Capabilities
Calico NetworkPolicy, GlobalNetworkPolicy, HostEndpoint, egress rules depending on edition
Cilium eBPF, CiliumNetworkPolicy, DNS/FQDN policies, Hubble, L7 policies
Antrea NetworkPolicy, ClusterNetworkPolicy, flow visibility
Flannel simple Pod network, no NetworkPolicy without additional components
Weave Net NetworkPolicy support, historically common

18.8. Egress Strategies

Strategy Advantage Disadvantage
NAT gateway simple no app-level control
HTTP proxy FQDN/URL control app configuration required
egress gateway central exit point CNI/service-mesh dependency
Cilium FQDN policy Kubernetes-native Cilium-specific
service mesh mTLS, L7 policies complexity, sidecars or ambient mode
cloud firewall good provider integration limited pod identity depending on implementation

18.9. Network Troubleshooting

bash
kubectl get networkpolicy -A
kubectl describe networkpolicy -n team-a
kubectl run netshoot -n team-a --rm -it --image=nicolaka/netshoot --restart=Never -- bash
nslookup kubernetes.default.svc.cluster.local
curl -v http://service.namespace.svc.cluster.local:8080

Always check:

  • Pod labels;
  • namespace labels;
  • CNI support;
  • DNS egress;
  • ingress-controller namespace;
  • Service port versus targetPort;
  • node firewalls;
  • cloud security groups.

18 / 44

19. Ingress, Gateway, TLS, and External Exposure

Ingress and Gateway API are central attack surfaces because they expose internal workloads externally.

19.1. Ingress Risks

  • TLS missing or misconfigured;
  • wildcard hosts route unexpectedly;
  • admin endpoints are public;
  • ingress controller has overly broad RBAC;
  • unsafe annotations allow snippet injection;
  • rate limits and body limits are missing;
  • authentication is missing for internal tools.

19.2. Gateway API Role Model

flowchart LR
    Infra[Infrastructure team] --> GatewayClass[GatewayClass]
    Platform[Platform team] --> Gateway[Gateway]
    AppTeam[App team] --> HTTPRoute[HTTPRoute]
    GatewayClass --> Gateway
    Gateway --> HTTPRoute
    HTTPRoute --> Service[Service]

19.3. TLS Standard

  • redirect HTTP to HTTPS;
  • issue and renew TLS certificates automatically;
  • wildcard certificates only after review;
  • do not route private services publicly;
  • enable HSTS only deliberately;
  • alert on certificate expiry.

19.4. cert-manager Example

yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: app-example-com
  namespace: app-prod
spec:
  secretName: app-example-com-tls
  dnsNames:
    - app.example.com
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer

19.5. Gateway API Example

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: public-gateway
  namespace: gateways
spec:
  gatewayClassName: nginx
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "*.example.com"
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-example-com
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app
  namespace: app-prod
spec:
  parentRefs:
    - name: public-gateway
      namespace: gateways
  hostnames:
    - app.example.com
  rules:
    - backendRefs:
        - name: app
          port: 8080

19.6. External Endpoints in Local Environments

Environment Access Security Note
WSL Windows browser through localhost, hosts file, or port-forward modify Windows hosts file only for demo domains
kind extraPortMappings, ingress controller, host port restrict ports deliberately
minikube minikube tunnel, service, ingress add-on admin rights may be needed for tunnel
k3d load-balancer port mappings avoid conflicts with local ports
local VM bridged/host-only/NAT prefer host-only for labs
remote VM public IP, firewall, reverse proxy open only 80/443, restrict SSH

19 / 44

20. Image, Registry, and Supply Chain Security

Kubernetes can only run what you give it. Unsafe images are one of the most common causes of cluster compromise.

20.1. Supply Chain Flow

flowchart LR
    Dev[Developer] --> Repo[Git Repository]
    Repo --> CI[CI Runner]
    CI --> Build[Image Build]
    Build --> Scan[Vulnerability Scan]
    Build --> SBOM[SBOM]
    Build --> Sign[Signature]
    Sign --> Registry[Registry]
    Registry --> Admission[Admission Verification]
    Admission --> Cluster[Kubernetes Cluster]
    Cluster --> Runtime[Runtime Detection]

20.2. Image Baseline

Control Recommendation
Base images minimal, maintained, defined origin
Tags no latest in production
Digests pin for critical workloads
CVE scans build time and registry time
Secrets no secrets in image or build args
SBOM generate, store, link to release
Signatures Cosign/Sigstore or registry-native signing
Provenance document build origin, SLSA-oriented
Registry RBAC, immutable tags, retention, malware scan

20.3. Use Image with Digest

yaml
containers:
  - name: app
    image: registry.example.com/team/app@sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

20.4. Trivy Scan

bash
trivy image registry.example.com/team/app:1.2.3
trivy image --severity HIGH,CRITICAL --exit-code 1 registry.example.com/team/app:1.2.3
trivy fs .
trivy config ./k8s

20.5. SBOM with Syft

bash
syft registry.example.com/team/app:1.2.3 -o spdx-json > sbom.spdx.json
syft registry.example.com/team/app:1.2.3 -o cyclonedx-json > sbom.cyclonedx.json

20.6. Sign and Verify with Cosign

bash
cosign sign registry.example.com/team/app:1.2.3
cosign verify registry.example.com/team/app:1.2.3
cosign verify-attestation registry.example.com/team/app:1.2.3

20.7. Admission for Signed Images

Possible approaches:

  • Kyverno verifyImages;
  • Sigstore policy-controller;
  • Connaisseur;
  • cloud-native Binary Authorization;
  • custom Validating Webhooks.

20.8. Registry RBAC

Role Rights
Build Runner push into specific repositories
Deployment Controller pull, no push
Developer pull dev images, no direct prod push
Security Scanner pull and read metadata
Admin rare, break-glass, audited

20.9. Unsafe Image Patterns

  • latest;
  • unversioned base images;
  • root user in image;
  • package manager and shell in runtime image without need;
  • SSH server in container;
  • debug tools in production;
  • secrets in layers;
  • non-reproducible builds;
  • pull from public registries without mirror and verification.

20 / 44

21. CI/CD and GitOps Security

CI/CD and GitOps are part of the Kubernetes attack surface. A compromised deployment controller can change production clusters.

21.1. CI/CD Risks

  • runner has access to production secrets;
  • pull requests can run untrusted code with secrets;
  • deployment tokens are static and long-lived;
  • build images are not hardened;
  • artifacts are not signed;
  • branch protection is missing.

21.2. CI/CD Baseline

Control Recommendation
Branch protection required reviews, status checks, optionally signed commits
Secrets no secrets for untrusted pull requests
Runner isolated, ephemeral, minimally privileged
Deployment OIDC or short-lived tokens instead of static kubeconfigs
Scans SAST, IaC, container, dependency, secret scanning
Provenance store build attestations
Logs mask secrets, define retention and access

21.3. GitOps Risks

Risk Control
GitOps controller has cluster-admin limit rights to target namespaces
app can deploy cluster resources restrict AppProject/policy
drift is automatically overwritten monitor drift deliberately, block manual changes
secrets in Git SOPS, External Secrets, Sealed Secrets
webhook secret leaked rotation and IP allowlist
supply chain manipulation signatures, reviews, branch protection

21.4. Argo CD Baseline

  • enable SSO;
  • disable or strongly protect local admin accounts;
  • use AppProjects;
  • restrict target namespaces;
  • restrict cluster-scoped resources;
  • grant minimal repository access;
  • review sync windows for critical environments;
  • integrate notifications and audit.

21.5. Flux Baseline

  • limit Git access with deploy keys;
  • use SOPS or External Secrets;
  • review Kustomization scope;
  • minimize controller RBAC;
  • use image automation only with a review process;
  • monitor drift and reconciliation events.

21 / 44

22. Storage and Data Security

Storage is not only availability. It affects data classification, encryption, access, backup, and deletion.

22.1. Storage Risks

  • PV contains personal or secret data;
  • StorageClass provisions unencrypted volumes;
  • ReclaimPolicy deletes data unexpectedly or retains it too long;
  • backup contains secrets or customer data;
  • snapshot permissions are too broad;
  • Pods mount PVCs they should not access;
  • hostPath bypasses storage controls.

22.2. StorageClass Security

bash
kubectl get storageclass -o yaml
kubectl get pv,pvc -A
kubectl get volumesnapshotclass

Check:

Topic Question
Encryption are volumes encrypted by default?
KMS is a customer-managed key used?
ReclaimPolicy is Delete or Retain chosen deliberately?
VolumeBindingMode WaitForFirstConsumer for topology?
AccessModes is RWX used only when needed?
Snapshots who can create and read snapshots?
Backup are backups encrypted and tested?

22.3. Minimize PVC Access

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
  namespace: app-prod
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: encrypted-standard

22.4. Limit Snapshot RBAC

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: snapshot-reader
  namespace: app-prod
rules:
  - apiGroups: ["snapshot.storage.k8s.io"]
    resources: ["volumesnapshots"]
    verbs: ["get", "list", "watch"]

22.5. Data Classification

Class Examples Requirements
Public demo data, static assets standard controls
Internal configuration data, internal logs RBAC, backup, retention
Confidential customer data, tokens, business secrets encryption, access control, audit
Highly sensitive key material, payment data, health data strong isolation, KMS, special compliance, minimized access

22 / 44

23. Observability, Audit, Detection, and Forensics

Security without visibility is not reliable. You need metrics, logs, audit events, and runtime signals.

23.1. Signal Types

Signal Source Security Value
Metrics kube-state-metrics, node-exporter, cAdvisor anomalies, resource abuse
Logs Pod logs, kubelet, API Server, controllers errors, indicators of attack
Audit logs kube-apiserver or provider who did what and when?
Events Kubernetes Events scheduling, pull, admission, crashes
Runtime events Falco, Tetragon, eBPF shells, suspicious files, network
Cloud logs CloudTrail, Azure Activity, GCP Audit Logs cloud IAM and provider actions
Network flow logs CNI, cloud VPC flow logs, Hubble lateral movement, egress

23.2. Audit Policy Example

yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets", "configmaps"]
  - level: RequestResponse
    verbs: ["create", "update", "patch", "delete"]
    resources:
      - group: "rbac.authorization.k8s.io"
        resources: ["roles", "rolebindings", "clusterroles", "clusterrolebindings"]
  - level: Request
    verbs: ["create", "update", "patch", "delete"]
    resources:
      - group: "admissionregistration.k8s.io"
        resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"]
  - level: Metadata
    omitStages:
      - RequestReceived

Do not unnecessarily log Secret values. Audit level RequestResponse can contain sensitive content.

23.3. Alert Categories

Category Example
API misuse cluster-admin binding created
RBAC escalation bind, escalate, impersonate used
Secret access unusually many Secret reads
Admission bypass webhook deleted or failurePolicy changed
Pod risk privileged Pod started
Runtime shell in container, new binary, access to /etc/shadow
Network unusual egress, DNS tunneling indicators
Node kubelet unreachable, Node NotReady, kernel alerts
Registry critical CVE in production image
Backup backup failed or restore test overdue

23.4. PrometheusRule Examples

yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: kubernetes-security-alerts
  namespace: monitoring
spec:
  groups:
    - name: kubernetes-security
      rules:
        - alert: KubeAPIServerAuditErrorsHigh
          expr: increase(apiserver_audit_event_total{stage="Panic"}[5m]) > 0
          for: 2m
          labels:
            severity: critical
          annotations:
            summary: "API Server audit panic events"
            description: "The API Server has produced audit events in panic stage."
        - alert: TooManyPodsPending
          expr: count(kube_pod_status_phase{phase="Pending"}) > 20
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Many Pods are Pending"
            description: "This can indicate quota, scheduling, CNI, or policy issues."

23.5. Forensic Principles

  • Change as little state as possible.
  • Preserve logs, events, manifests, and image digests.
  • Record time ranges and time zones.
  • Rotate credentials only after preserving necessary evidence, if risk allows.
  • Isolate and replace compromised nodes.
  • Use snapshots only after privacy and approval processes.

23.6. Evidence Collection for a Suspicious Pod

bash
NS=app-prod
POD=demo-app-abc123
mkdir -p incident-$NS-$POD
kubectl get pod "$POD" -n "$NS" -o yaml > incident-$NS-$POD/pod.yaml
kubectl describe pod "$POD" -n "$NS" > incident-$NS-$POD/describe.txt
kubectl logs "$POD" -n "$NS" --all-containers > incident-$NS-$POD/logs-current.txt
kubectl logs "$POD" -n "$NS" --all-containers --previous > incident-$NS-$POD/logs-previous.txt || true
kubectl get events -n "$NS" --sort-by=.lastTimestamp > incident-$NS-$POD/events.txt

23 / 44

24. Runtime Security

Runtime security detects suspicious behavior after a workload has started.

24.1. What Runtime Security Detects

  • shell in a container;
  • new executable files;
  • access to sensitive paths;
  • unusual network connections;
  • process starts outside the expected profile;
  • privilege escalation attempts;
  • container escape indicators;
  • Kubernetes API misuse;
  • suspicious cloud API calls.

24.2. Falco Baseline

Falco observes kernel events and other sources and generates alerts using rules.

Example rule:

yaml
- rule: Shell spawned in container
  desc: A shell was started in a container
  condition: container.id != host and proc.name in (bash, sh, zsh, csh)
  output: Shell started in container (user=%user.name command=%proc.cmdline container=%container.name image=%container.image.repository)
  priority: WARNING
  tags: [container, shell, mitre_execution]

24.3. Tetragon and eBPF

Tetragon is especially relevant in Cilium environments. It can collect process, network, and security events using eBPF and add Kubernetes context.

Typical use cases:

  • process execution in Pods;
  • network connections;
  • file or syscall-adjacent detection;
  • policy-adjacent runtime enforcement depending on setup.

24.4. Runtime Detection Architecture

flowchart LR
    Kernel[Linux Kernel Events] --> Agent[Runtime Agent: Falco/Tetragon]
    K8s[Kubernetes API Context] --> Agent
    Runtime[Container Runtime] --> Agent
    Agent --> Alerts[Alerts]
    Alerts --> SIEM[SIEM / Log Backend]
    Alerts --> IR[Incident Response]

24.5. Runtime Alert Triage

Alert First Questions
Shell in container Was this allowed debugging? Who used exec?
Write below /etc application behavior or compromise? read-only root FS active?
Connection to unknown IP legitimate egress or C2? Check DNS query.
Privileged container system component or app exception? Should admission have blocked it?
Sensitive file read which file, process, and user?
Crypto miner indicator image, process, egress, CPU spike

24 / 44

25. Backup, Restore, and Disaster Recovery Security

Backups are security-critical. They often contain the most complete data set.

25.1. What Must Be Backed Up

Artifact Why It Matters
Git repositories desired state, manifests, IaC
IaC state cloud resources, IDs, outputs
etcd cluster state for self-managed clusters
Kubernetes resources Namespaces, RBAC, CRDs, Deployments, Services
PV data application data
Secrets recovery, but must be strongly protected
certificates API, etcd, Ingress, mTLS
registry images rebuild if registry fails
KMS keys decrypt Secrets and volumes
observability data forensics and compliance

25.2. Backup Security Rules

  • Encrypt backups.
  • Strongly restrict backup access.
  • Test restores regularly.
  • Define backup retention.
  • Use offsite copies or a separate region.
  • Verify backup integrity.
  • Enable ransomware protection for backup buckets where available.
  • Treat Secrets and KMS keys separately.

25.3. Velero Backup Example

yaml
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: daily-prod
  namespace: velero
spec:
  schedule: "0 2 * * *"
  template:
    includedNamespaces:
      - app-prod
    ttl: 720h0m0s
    storageLocation: default
    snapshotVolumes: true

25.4. Restore Test

bash
velero backup create app-prod-manual --include-namespaces app-prod
velero backup describe app-prod-manual
velero restore create app-prod-restore-test --from-backup app-prod-manual --namespace-mappings app-prod:app-prod-restore
velero restore describe app-prod-restore-test
kubectl get all,pvc,secret,configmap -n app-prod-restore

25.5. DR Security Questions

  • Who may trigger restore?
  • Could a restore reintroduce old vulnerable images?
  • Is secret rotation required after restore?
  • Is RBAC restored?
  • Are old admission policies restored?
  • Is there an isolated restore test cluster?
  • Are backups available after a region/provider outage?

25 / 44

26. Patch, Update, and Vulnerability Management

Security is a lifecycle topic. Kubernetes versions, node images, add-ons, and application images must be maintained.

26.1. Patch Layers

Layer Examples
OS Ubuntu, RHEL, Bottlerocket, COS, Azure Linux, Talos
Kernel CVEs, eBPF, filesystem, container escape
Container Runtime containerd, CRI-O, runc
Kubernetes API Server, kubelet, kube-proxy, controllers, scheduler
Add-ons CNI, CSI, Ingress, cert-manager, External Secrets, monitoring
Workloads app images, dependencies, base images
Cloud resources load balancer, IAM, KMS, firewall, registry
CI/CD runner images, actions, plugins, tokens

26.2. Vulnerability Workflow

flowchart LR
    Detect[CVE or advisory] --> Assess[Check exposure]
    Assess --> Risk[Assess severity and exposure]
    Risk --> Plan[Patch plan]
    Plan --> Test[Test cluster / staging]
    Test --> Rollout[Production rollout]
    Rollout --> Verify[Validation]
    Verify --> Document[Documentation]

26.3. Kubernetes Upgrade Security

Before upgrade:

bash
kubectl version
kubectl get nodes -o wide
kubectl get apiservices
kubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration
kubectl get crd
kubectl get events -A --sort-by=.lastTimestamp | tail -100

Check:

  • version skew;
  • deprecated APIs;
  • admission compatibility;
  • CNI/CSI compatibility;
  • backup and restore;
  • node drain behavior;
  • PodDisruptionBudgets;
  • Cluster Autoscaler compatibility;
  • security-relevant release notes.

26.4. Image CVE Triage

Not every CVE is equally critical. Evaluate:

  • Is the vulnerable library actually used?
  • Is the code path reachable?
  • Is the Pod publicly reachable?
  • Does the container run as root?
  • Are NetworkPolicy and egress controls in place?
  • Is runtime detection active?
  • Is there a fix or only mitigation?
  • Can you rebuild with a newer base image?

26.5. Example Patch SLAs

Severity Target Time
Critical, exploitable, exposed 24 to 72 hours
High 7 to 14 days
Medium 30 days
Low regular maintenance cycle
Not applicable documented exception

26 / 44

27. Security by Kubernetes Variant

27.1. kubeadm

kubeadm gives you a lot of control and a lot of responsibility.

Important controls:

  • OS hardening;
  • secure containerd/CRI-O configuration;
  • kubelet webhook authn/authz;
  • API audit;
  • Secrets encryption at rest;
  • etcd snapshots;
  • CNI with NetworkPolicy;
  • secure control-plane endpoint;
  • certificate rotation;
  • upgrade discipline.

Review commands:

bash
kubeadm version
kubeadm certs check-expiration
kubectl get nodes -o wide
sudo ls /etc/kubernetes/manifests
sudo journalctl -u kubelet --no-pager | tail -100

27.2. k3s

k3s is lightweight and often suitable for edge, labs, and smaller clusters.

Security focus:

  • protect server token;
  • secure embedded etcd or external DB;
  • consciously enable or disable Traefik/ServiceLB;
  • configure local registry mirrors securely;
  • minimize node access;
  • check Secret encryption;
  • review systemd unit and install scripts.
bash
sudo systemctl status k3s
sudo cat /etc/rancher/k3s/config.yaml
kubectl get nodes -o wide
kubectl get pods -A

27.3. RKE2

RKE2 is more oriented toward production-like and hardened environments.

Security focus:

  • review CIS profile;
  • use SELinux where appropriate;
  • version static Pod manifests and add-ons;
  • protect server and agent tokens;
  • encrypt and store etcd snapshots safely;
  • separate system namespaces.

27.4. k0s

k0s is a lean Kubernetes distribution with its own cluster configuration.

Security focus:

  • separate controller and worker roles;
  • version k0s configuration;
  • handle join tokens as short-lived;
  • choose CNI and storage deliberately;
  • check kubelet and runtime;
  • test backup/restore of cluster state.

27.5. Talos Linux

Talos is an immutable OS for Kubernetes. Management is through the Talos API, not SSH.

Security focus:

  • treat MachineConfig as sensitive desired state;
  • protect talosconfig;
  • no classic SSH management;
  • restrict API access;
  • evaluate disk encryption;
  • store cluster and machine secrets securely;
  • run upgrades declaratively and reproducibly.

27.6. Docker Desktop Kubernetes

Suitable for local development, not production security exercises with real secrets.

Security focus:

  • do not use production kubeconfigs or tokens in Docker Desktop;
  • clean up local images and volumes regularly;
  • name Kubernetes contexts clearly;
  • do not expose demo ingresses with real data.

27.7. MicroK8s

MicroK8s is practical for local labs, edge, and Ubuntu-oriented environments.

Security focus:

  • enable add-ons deliberately;
  • review local user groups;
  • control snap updates;
  • secure registry and ingress;
  • check host firewall.

27 / 44

28. Security by Environment

28.1. WSL on Windows 11

WSL is a strong learning and CLI environment, but not a complete production substitute.

Risks:

  • Windows host and WSL share attack surfaces;
  • files under /mnt/c have different permissions and performance characteristics;
  • Docker Desktop integration extends the trust boundary;
  • Windows hosts file can affect local name resolution;
  • real cloud credentials can easily sit in the home directory.

Recommendations:

  • no real production secrets in WSL labs;
  • name kubeconfig contexts clearly;
  • do not bypass Windows Defender/EDR;
  • clearly mark local demo domains, for example *.127.0.0.1.nip.io or *.localtest.me;
  • modify the Windows hosts file only deliberately and with documentation;
  • do not fill Git repositories with real secrets.

Back up the Windows hosts file from WSL:

bash
sudo cp /mnt/c/Windows/System32/drivers/etc/hosts /mnt/c/Windows/System32/drivers/etc/hosts.k8s-backup

Add entry if you have elevated rights:

bash
printf "127.0.0.1 app.local\n" | sudo tee -a /mnt/c/Windows/System32/drivers/etc/hosts

Rollback:

bash
sudo cp /mnt/c/Windows/System32/drivers/etc/hosts.k8s-backup /mnt/c/Windows/System32/drivers/etc/hosts

28.2. kind

kind runs Kubernetes nodes as containers. It is ideal for policy, admission, CI, and manifest tests.

Security notes:

  • the host Docker/Podman environment is the real security boundary;
  • no real secrets;
  • set extraPortMappings deliberately;
  • use local registry only with demo images;
  • delete clusters after tests.
yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
    extraPortMappings:
      - containerPort: 80
        hostPort: 8080
        protocol: TCP
      - containerPort: 443
        hostPort: 8443
        protocol: TCP

28.3. minikube

minikube is suitable for local development and labs.

Security notes:

  • driver determines risk: Docker, VirtualBox, VMware, Hyper-V, SSH;
  • minikube tunnel may need elevated rights;
  • add-ons add components with RBAC;
  • clean up local images and secrets regularly.
bash
minikube start --driver=docker
minikube addons enable ingress
minikube addons enable metrics-server
minikube status

28.4. k3d

k3d runs k3s in Docker containers.

Security notes:

  • protect Docker host;
  • set port mappings deliberately;
  • choose Traefik or your own ingress solution deliberately;
  • delete clusters after tests.
bash
k3d cluster create lab \
  --servers 1 \
  --agents 2 \
  -p "8080:80@loadbalancer" \
  -p "8443:443@loadbalancer"

28.5. Local VM

Security focus:

  • VM snapshots before risky labs;
  • host-only network for private labs;
  • NAT/bridged only when needed;
  • SSH key instead of password;
  • firewall active;
  • no private cloud credentials in snapshots.

28.6. Remote VM

Security focus:

  • cloud firewall first, host firewall additionally;
  • SSH only from known IPs;
  • do not open API Server publicly;
  • do not expose Kubernetes Dashboard publicly;
  • protect local kubeconfigs;
  • encrypt disks;
  • restrict snapshot access.

28.7. Bare Metal

Security focus:

  • secure firmware/BIOS/UEFI and BMC;
  • isolate management network;
  • protect PXE/provisioning network;
  • evaluate disk encryption;
  • consider physical access;
  • evaluate hardware supply chain;
  • audit out-of-band access.

28 / 44

29. Cloud-Specific Security

Managed Kubernetes reduces control-plane operations but not your platform responsibility.

29.1. AWS EKS

Important controls:

  • private or restricted API endpoints;
  • model IAM Identity Center or IAM-based authentication cleanly;
  • review EKS Access Entries instead of relying on historically grown aws-auth disorder;
  • use EKS Pod Identity or IRSA for workloads;
  • keep node IAM role minimal;
  • review Security Groups and NACLs;
  • enable control plane logs;
  • use KMS for Secrets encryption;
  • evaluate GuardDuty EKS Protection;
  • ECR scanning and image signatures;
  • evaluate managed node groups or Fargate by risk.

Review commands:

bash
aws eks describe-cluster --name <cluster>
aws eks list-access-entries --cluster-name <cluster>
aws eks list-pod-identity-associations --cluster-name <cluster>
aws eks update-kubeconfig --name <cluster> --region <region>
kubectl get nodes -o wide

29.2. Azure AKS

Important controls:

  • Microsoft Entra ID integration;
  • deliberately choose Azure RBAC for Kubernetes Authorization;
  • private cluster or API authorized IP ranges;
  • AKS Workload Identity;
  • Azure Policy for Kubernetes;
  • Microsoft Defender for Containers;
  • Azure Key Vault CSI Driver or External Secrets;
  • NetworkPolicies with Azure CNI/Cilium/Calico depending on setup;
  • node OS upgrades and maintenance windows;
  • Container Registry scans and RBAC.

Review commands:

bash
az aks show -g <resource-group> -n <cluster>
az aks get-credentials -g <resource-group> -n <cluster>
az aks update -g <resource-group> -n <cluster> --enable-oidc-issuer --enable-workload-identity
kubectl get nodes -o wide

29.3. Google GKE

Important controls:

  • separate IAM and Kubernetes RBAC clearly;
  • use Workload Identity Federation for GKE;
  • evaluate Autopilot for stronger managed defaults;
  • private clusters and Master Authorized Networks;
  • Shielded GKE Nodes;
  • Binary Authorization;
  • Artifact Registry scans;
  • Cloud KMS for Secrets and storage;
  • Cloud Audit Logs and Security Command Center;
  • GKE release channels and maintenance windows.

Review commands:

bash
gcloud container clusters describe <cluster> --region <region>
gcloud container clusters get-credentials <cluster> --region <region>
kubectl get nodes -o wide

29.4. Oracle OKE

Important controls:

  • review private API endpoints;
  • keep OCI IAM policies minimal;
  • worker nodes in private subnets;
  • Network Security Groups;
  • Vault/KMS integration;
  • enable logging and audit;
  • check image scanning in OCIR.

29.5. DigitalOcean DOKS

Important controls:

  • restrict kubeconfig access;
  • review API access and team permissions;
  • Container Registry RBAC;
  • Load Balancer and firewall rules;
  • manage secrets externally;
  • verify NetworkPolicies with supported CNI.

29.6. Linode/Akamai LKE

Important controls:

  • Cloud Firewall;
  • node pool access;
  • API and kubeconfig protection;
  • Longhorn/CSI storage security;
  • registry and secret management;
  • add provider monitoring and audit options.

29.7. Multi-Cloud

Multi-cloud does not automatically improve security. It increases complexity.

Required standards:

  • consistent RBAC role models;
  • consistent labels and namespaces;
  • central policy library;
  • secret backend per provider or federated;
  • centralized audit-log collection;
  • identical admission gates;
  • clear cluster inventory;
  • provider-specific exceptions documented.

29 / 44

30. OpenShift, OKD, and SCC

OpenShift adds its own platform concepts to Kubernetes. Security Context Constraints, Routes, Operators, Projects, and OAuth are especially relevant.

30.1. SCC Instead of Only Pod Security Admission

Security Context Constraints control under which security conditions Pods are allowed to run. They are OpenShift-specific and historically central to Pod security.

Review:

bash
oc get scc
oc describe scc restricted-v2
oc adm policy who-can use scc restricted-v2

30.2. OpenShift Security Baseline

Area Control
OAuth IdP, groups, MFA through IdP
Projects team and app boundaries
SCC restrictive SCCs, exceptions documented
Routes TLS, HSTS, public exposure
Operators OperatorHub sources, subscription channels, RBAC
ImageStreams registry trust and import policies
Builds review BuildConfigs and secrets
MachineConfig declaratively manage node hardening

30.3. OpenShift Anti-Patterns

  • broadly granting anyuid;
  • privileged SCC for app namespaces;
  • ClusterRoleBindings without a group model;
  • operators without lifecycle plan;
  • routes without TLS;
  • build secrets in the wrong namespace;
  • local admin accounts without audit.

30 / 44

31. Compliance, Benchmarks, and Audits

Compliance is not a substitute for security engineering. It helps make controls measurable.

31.1. CIS Kubernetes Benchmark

The CIS Kubernetes Benchmark contains concrete configuration recommendations for Kubernetes and provider variants.

Typical areas:

  • API Server;
  • Controller Manager;
  • Scheduler;
  • etcd;
  • kubelet;
  • policies;
  • RBAC;
  • NetworkPolicies;
  • Secrets;
  • Pod Security.

31.2. kube-bench

bash
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl get pods -n default
kubectl logs job/kube-bench

For production, review manifests before applying, pin image versions, and control scope.

31.3. NSA/CISA-Hardening-Oriented Controls

Typical topics:

  • scan containers and Pods for vulnerabilities and misconfiguration;
  • least privilege for containers and Pods;
  • network segmentation;
  • strong authentication;
  • audit logging;
  • protect Secrets;
  • avoid dangerous workload options;
  • harden nodes.

31.4. Audit Artifacts

Artifact Purpose
Cluster inventory prove scope and responsibility
RBAC export review permissions
Policy reports verify admission compliance
NetworkPolicy list prove segmentation
Pod Security labels review namespace hardening
Secret access analysis evaluate access to confidential data
Backup logs prove DR capability
Restore test report prove recovery
Patch status prove vulnerability management
Audit logs reconstruct changes

31.5. Audit Export

bash
mkdir -p audit-export
kubectl get ns --show-labels > audit-export/namespaces.txt
kubectl get role,rolebinding -A -o yaml > audit-export/rbac-namespaced.yaml
kubectl get clusterrole,clusterrolebinding -o yaml > audit-export/rbac-cluster.yaml
kubectl get networkpolicy -A -o yaml > audit-export/networkpolicies.yaml
kubectl get pods -A -o yaml > audit-export/pods.yaml
kubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration -o yaml > audit-export/webhooks.yaml
kubectl get validatingadmissionpolicy,validatingadmissionpolicybinding -o yaml > audit-export/validating-admission-policies.yaml || true
kubectl get resourcequota,limitrange -A -o yaml > audit-export/quotas-limits.yaml

Protect these exports. They can contain Secrets, internal names, images, and architecture details.


31 / 44

32. Tooling Matrix

Category Tools Purpose
RBAC Review kubectl auth can-i, rbac-tool, rakkess review permissions
CIS kube-bench, Kubescape benchmark checks
Manifest Security kube-score, Polaris, Checkov, KICS, Datree YAML/IaC checks
Policy Kyverno, Gatekeeper, ValidatingAdmissionPolicy admission/governance
Image Scan Trivy, Grype, Clair, registry-native scanners CVEs and misconfigurations
SBOM Syft, Trivy, CycloneDX tools capture software inventory
Signature Cosign, Sigstore policy-controller, Notary v2 image trust
Secrets SOPS, Sealed Secrets, External Secrets, Vault, CSI Driver secret management
Runtime Falco, Tetragon, Tracee runtime detection
Network Cilium Hubble, Calico tools, tcpdump, netshoot network visibility
Cloud Security GuardDuty, Defender, Security Command Center provider security
GitOps Argo CD, Flux declarative deployments
Audit/SIEM Loki, OpenSearch, Splunk, Sentinel, Chronicle centralized analysis

32.1. Kubescape Example

bash
kubescape scan framework nsa
kubescape scan framework cis
kubescape scan --submit=false

32.2. Polaris Example

bash
polaris audit --audit-path ./manifests --format=pretty

32.3. Checkov Example

bash
checkov -d ./manifests --framework kubernetes
checkov -d ./terraform --framework terraform

32.4. Conftest Example

bash
conftest test deployment.yaml

32 / 44

33. Standard Runbooks

33.1. Runbook: Compromised Pod

Goal: limit damage, preserve evidence, fix root cause.

  1. Validate the alert.
  2. Capture namespace, Pod, node, image, ServiceAccount.
  3. Preserve logs, events, and manifest.
  4. Restrict network access.
  5. Do not blindly delete the Pod if forensics are required.
  6. Review ServiceAccount permissions.
  7. Rotate Secrets if access was possible.
  8. Check image digest and registry history.
  9. Roll out workload with fixed image and policy.
  10. Improve admission and runtime rules.

Commands:

bash
NS=<namespace>
POD=<pod>
kubectl get pod "$POD" -n "$NS" -o wide
kubectl describe pod "$POD" -n "$NS"
kubectl logs "$POD" -n "$NS" --all-containers --previous
kubectl get pod "$POD" -n "$NS" -o jsonpath='{.spec.serviceAccountName}{"\n"}'
kubectl auth can-i --as system:serviceaccount:$NS:$(kubectl get pod "$POD" -n "$NS" -o jsonpath='{.spec.serviceAccountName}') --list -n "$NS"

Containment via NetworkPolicy:

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: isolate-suspect-workload
  namespace: app-prod
spec:
  podSelector:
    matchLabels:
      incident.example.com/isolate: "true"
  policyTypes:
    - Ingress
    - Egress

33.2. Runbook: Compromised Node

  1. Cordon node.
  2. Stop scheduling.
  3. Evacuate or preserve workloads depending on criticality and forensics.
  4. Restrict cloud/host network access.
  5. Remove node from load balancers.
  6. Preserve node logs and runtime information.
  7. Rotate affected Pod Secrets.
  8. Rebuild or replace node.
  9. Review cluster and cloud audit.
bash
NODE=<node>
kubectl cordon "$NODE"
kubectl get pods -A --field-selector spec.nodeName="$NODE" -o wide
kubectl drain "$NODE" --ignore-daemonsets --delete-emptydir-data

For serious compromise, rebuild is safer than repair.

33.3. Runbook: Secret Leak

  1. Identify the secret.
  2. Capture affected systems and permissions.
  3. Rotate or disable the secret immediately.
  4. Find usages.
  5. Restart workloads.
  6. Review Git history, artifacts, and logs.
  7. Check audit for misuse.
  8. Improve prevention.
bash
kubectl get secret -A | grep <name>
kubectl get pods -A -o yaml | grep -n "secretName: <name>"
kubectl rollout restart deployment -n <namespace> <deployment>

33.4. Runbook: Unauthorized cluster-admin Binding

bash
kubectl describe clusterrolebinding cluster-admin
kubectl get clusterrolebinding -o yaml | grep -n -B5 -A20 "cluster-admin"

Procedure:

  1. Identify binding.
  2. Check change source in audit logs.
  3. Remove binding if not approved.
  4. Disable or rotate affected identity.
  5. Close RBAC escalation path.
  6. Improve alerts.

33.5. Runbook: Admission Webhook Down

  1. Check error message.
  2. Check webhook Service and Endpoints.
  3. Check certificates.
  4. Evaluate failurePolicy.
  5. Freeze critical changes if policy protection is inactive.
  6. Stabilize webhook.
  7. Run drift check after recovery.
bash
kubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration
kubectl get pods,svc,endpoints -A | grep -i webhook
kubectl get events -A --sort-by=.lastTimestamp | grep -i webhook

33.6. Runbook: Suspicious Egress

  1. Identify affected Pod IP.
  2. Map Pod, namespace, node, and ServiceAccount.
  3. Check DNS logs and flow logs.
  4. Temporarily block egress.
  5. Review image and processes.
  6. Rotate credentials if C2 was possible.
  7. Improve egress policy.
bash
kubectl get pods -A -o wide | grep <pod-ip>
kubectl describe pod -n <namespace> <pod>
kubectl get networkpolicy -n <namespace>

33 / 44

34. Security Checklists

34.1. Cluster Baseline

  • API access is not open to the internet.
  • Users use SSO/OIDC and MFA.
  • Break-glass is separate, audited, and tested.
  • RBAC does not use unnecessary wildcards.
  • cluster-admin is strongly limited.
  • nodes/proxy is tightly controlled.
  • Audit logs are active and centrally stored.
  • Secrets encryption at rest is enabled or provider-equivalent is implemented.
  • etcd backups are encrypted and restore-tested.
  • CNI supports NetworkPolicies.
  • Critical add-ons have monitoring and PDBs.
  • Upgrade process and version skew are documented.

34.2. Namespace Baseline

  • Namespace has owner labels.
  • Pod Security Admission is set.
  • ResourceQuota is set.
  • LimitRange is set.
  • Default-deny NetworkPolicy is set.
  • DNS egress is explicitly handled.
  • RBAC is namespaced and minimal.
  • Secrets are external or managed under control.
  • GitOps scope is limited.

34.3. Workload Baseline

  • dedicated ServiceAccount.
  • automountServiceAccountToken: false when API access is not required.
  • runAsNonRoot: true.
  • allowPrivilegeEscalation: false.
  • capabilities.drop: [ALL].
  • seccompProfile: RuntimeDefault.
  • no privileged: true.
  • no hostNetwork, hostPID, hostIPC.
  • no hostPath, except documented platform exception.
  • read-only root filesystem where possible.
  • image is versioned or pinned by digest.
  • resource requests and memory limits are set.
  • probes are meaningful.
  • logs contain no secrets.

34.4. Supply Chain Baseline

  • branch protection active.
  • CI runner isolated.
  • secret scanning active.
  • dependency scanning active.
  • image scanning active.
  • SBOM generated.
  • signature or provenance for critical images.
  • registry RBAC minimal.
  • no latest tags in production.
  • admission gate for critical minimum requirements.

34.5. Cloud Baseline

  • API endpoint private or restricted.
  • Workload Identity instead of static cloud keys.
  • node roles minimal.
  • cloud audit logs active.
  • KMS used for Secrets/storage.
  • security groups/firewalls minimal.
  • container registry scans active.
  • provider security services evaluated.
  • maintenance windows and automatic updates documented.

34 / 44

35. Workshop Labs

35.1. Lab 1: RBAC Least Privilege

Goal: build a role that can read Pods but cannot read Secrets.

Steps:

  1. Create namespace.
  2. Create ServiceAccount.
  3. Create Role and RoleBinding.
  4. Test kubectl auth can-i.
  5. Deliberately deny access to Secrets.

Acceptance:

bash
kubectl auth can-i get pods -n lab-rbac --as system:serviceaccount:lab-rbac:reader
kubectl auth can-i get secrets -n lab-rbac --as system:serviceaccount:lab-rbac:reader

35.2. Lab 2: Pod Security Admission

Goal: block a privileged Pod.

Steps:

  1. Create namespace with warn=restricted.
  2. Apply privileged Pod and observe warning.
  3. Set namespace to enforce=restricted.
  4. Apply privileged Pod again.
  5. Deploy hardened Pod.

35.3. Lab 3: NetworkPolicy Default Deny

Goal: isolate a namespace and allow only defined communication.

Steps:

  1. Deploy app and test Pod.
  2. Test connectivity before policy.
  3. Apply default deny.
  4. Allow DNS egress.
  5. Allow targeted Service access.

35.4. Lab 4: Use Secrets Safely

Goal: compare Secret as env var, volume, and external secret model.

Steps:

  1. Create demo Secret.
  2. Mount Secret as volume.
  3. Test rollout on Secret change.
  4. Check RBAC for Secrets.
  5. Run secret scan against repository.

35.5. Lab 5: Image Security

Goal: scan, sign, and verify an image.

Steps:

  1. Build image.
  2. Run Trivy scan.
  3. Generate SBOM.
  4. Sign with Cosign.
  5. Discuss admission policy.

35.6. Lab 6: Audit and Incident Response

Goal: simulate suspicious API access and collect evidence.

Steps:

  1. Create ServiceAccount with wrong role.
  2. Test access.
  3. Review audit/events.
  4. Fix role.
  5. Write post-incident review.

35.7. Lab 7: Cloud Workload Identity

Goal: replace static cloud secrets with Workload Identity.

Variants:

  • EKS Pod Identity or IRSA;
  • AKS Workload Identity;
  • GKE Workload Identity Federation.

Acceptance:

  • Pod can reach exactly one allowed cloud resource.
  • Node role has no broad app rights.
  • No static cloud key exists as a Kubernetes Secret.

35 / 44

36. Common Anti-Patterns

Anti-Pattern Problem Better
cluster-admin for apps full cluster takeover after Pod compromise namespaced RBAC
default ServiceAccount no clear identity dedicated ServiceAccount per workload
automatic token mounts unnecessary API credentials automountServiceAccountToken: false
no NetworkPolicies lateral movement is easy default deny + allowlist
privileged: true container isolation heavily reduced only system exceptions
hostPath / host filesystem exposed avoid, use isolated volumes
Docker socket mount possible host takeover isolated build environment
Secrets in Git persistent compromise SOPS, External Secrets, Vault
latest tag not reproducible versioned tag or digest
no audit logs no accountability API audit and SIEM
webhook without monitoring admission failures unnoticed metrics, alerts, PDB
open Kubernetes API direct attack path private API, VPN, IP allowlist
node SSH for daily work bypasses Kubernetes controls declarative maintenance, drain/replace
debug container in prod without process uncontrolled access time-limited break-glass

36 / 44

37. Example Repository Structure

text
kubernetes-security/
├── README.md
├── clusters/
│   ├── dev/
│   ├── stage/
│   └── prod/
├── namespaces/
│   ├── base/
│   │   ├── namespace.yaml
│   │   ├── resourcequota.yaml
│   │   ├── limitrange.yaml
│   │   └── networkpolicy-default-deny.yaml
│   └── overlays/
├── policies/
│   ├── pod-security/
│   ├── kyverno/
│   ├── gatekeeper/
│   └── validating-admission-policy/
├── rbac/
│   ├── roles/
│   ├── rolebindings/
│   └── reviews/
├── workloads/
│   ├── secure-deployment.yaml
│   └── examples/
├── secrets/
│   ├── external-secrets/
│   ├── sops/
│   └── sealed-secrets/
├── observability/
│   ├── audit-policy.yaml
│   ├── prometheus-rules.yaml
│   └── falco-rules.yaml
├── scripts/
│   ├── audit-export.sh
│   ├── rbac-review.sh
│   ├── policy-test.sh
│   └── incident-collect.sh
└── docs/
    ├── threat-model.md
    ├── exceptions.md
    ├── runbooks.md
    └── audit-evidence.md

37.1. Exception Process as File

yaml
apiVersion: security.example.com/v1
kind: SecurityException
metadata:
  name: allow-privileged-csi-node
spec:
  owner: platform-storage
  namespace: storage-system
  control: pod-security-restricted
  reason: CSI Node Plugin requires host access for volume mounts.
  compensatingControls:
    - dedicated namespace
    - only platform team has write access
    - image signed
    - runtime detection active
    - NetworkPolicy active
  expires: "2026-12-31"
  reviewCycle: quarterly

37 / 44

38. Security Command Reference

38.1. Cluster Overview

bash
kubectl version
kubectl cluster-info
kubectl get nodes -o wide
kubectl get ns --show-labels
kubectl get pods -A -o wide

38.2. RBAC

bash
kubectl auth can-i --list
kubectl auth can-i get secrets -A
kubectl auth can-i get pods --as system:serviceaccount:demo:app -n demo
kubectl get role,rolebinding -A
kubectl get clusterrole,clusterrolebinding
kubectl describe clusterrolebinding cluster-admin

38.3. ServiceAccounts

bash
kubectl get serviceaccounts -A
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\t"}{.spec.automountServiceAccountToken}{"\n"}{end}'

38.4. Pod Security

bash
kubectl get ns --show-labels | grep pod-security
kubectl label ns demo pod-security.kubernetes.io/warn=restricted --overwrite
kubectl label ns demo pod-security.kubernetes.io/audit=restricted --overwrite
kubectl label ns demo pod-security.kubernetes.io/enforce=restricted --overwrite

38.5. Check SecurityContext

bash
kubectl get pods -A -o json | jq -r '
.items[] as $pod |
$pod.spec.containers[]? |
[$pod.metadata.namespace, $pod.metadata.name, .name,
 (.securityContext.privileged // false),
 (.securityContext.allowPrivilegeEscalation // "unset"),
 (.securityContext.readOnlyRootFilesystem // "unset")]
| @tsv'

38.6. NetworkPolicies

bash
kubectl get networkpolicy -A
kubectl describe networkpolicy -n <namespace> <policy>
kubectl run netshoot -n <namespace> --rm -it --restart=Never --image=nicolaka/netshoot -- bash

38.7. Secrets

bash
kubectl get secrets -A
kubectl auth can-i get secrets -n <namespace> --as <identity>
kubectl get pods -A -o yaml | grep -n "secretName"

38.8. Admission

bash
kubectl get validatingwebhookconfiguration,mutatingwebhookconfiguration
kubectl get validatingadmissionpolicy,validatingadmissionpolicybinding
kubectl get mutatingadmissionpolicy,mutatingadmissionpolicybinding
kubectl get events -A --sort-by=.lastTimestamp | grep -i admission

38.9. Images

bash
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.image}{","}{end}{"\n"}{end}'
trivy image <image>
cosign verify <image>
syft <image> -o spdx-json

38.10. Node and Runtime

bash
kubectl get nodes -o wide
kubectl describe node <node>
kubectl top nodes
sudo journalctl -u kubelet --no-pager | tail -100
crictl info
crictl ps

38.11. Events and Logs

bash
kubectl get events -A --sort-by=.lastTimestamp | tail -100
kubectl logs -n <namespace> <pod> --all-containers
kubectl logs -n <namespace> <pod> --all-containers --previous

38.12. Cloud

bash
# AWS EKS
aws eks describe-cluster --name <cluster>
aws eks list-access-entries --cluster-name <cluster>
aws eks list-pod-identity-associations --cluster-name <cluster>

# Azure AKS
az aks show -g <resource-group> -n <cluster>
az aks get-credentials -g <resource-group> -n <cluster>

# Google GKE
gcloud container clusters describe <cluster> --region <region>
gcloud container clusters get-credentials <cluster> --region <region>

38 / 44

39. Decision Questions for Architecture Reviews

39.1. Cluster and Environment

  • Which environment is affected: local, VM, bare metal, cloud, managed, OpenShift?
  • Who operates control plane, nodes, network, and storage?
  • What data classification does the workload have?
  • Is this tenant isolation or only team separation?
  • Which compliance requirements apply?

39.2. Identity and Access

  • How do humans authenticate?
  • Is MFA used?
  • Which groups receive which roles?
  • How does break-glass work?
  • Are there static kubeconfigs?
  • Which ServiceAccounts exist?
  • Which workloads need API access?

39.3. Workload Security

  • Does the container run as non-root?
  • Are capabilities dropped?
  • Is privilege escalation disabled?
  • Are host namespaces or hostPath used?
  • Are resource limits and requests set?
  • Is the image scanned, signed, or pinned by digest?

39.4. Network

  • Is default deny in place?
  • Is DNS explicitly allowed?
  • Which ingress paths are public?
  • How is egress controlled?
  • Is service-to-service mTLS used?
  • Are admin endpoints internal?

39.5. Secrets and Data

  • Where are secrets authoritative?
  • Are secrets excluded from Git?
  • Is encryption at rest active?
  • How does rotation work?
  • Who may read secrets?
  • Are backups encrypted?

39.6. Operations and Detection

  • Are audit logs active?
  • Are runtime events collected?
  • Which alerts exist?
  • Are runbooks available?
  • Has restore been tested?
  • How quickly are critical CVEs patched?

39 / 44

40. Sources and Further References

40.1. Kubernetes Primary Documentation

  • Kubernetes Security Overview: https://kubernetes.io/docs/concepts/security/
  • Kubernetes Security Checklist: https://kubernetes.io/docs/concepts/security/security-checklist/
  • Controlling Access to the Kubernetes API: https://kubernetes.io/docs/concepts/security/controlling-access/
  • RBAC: https://kubernetes.io/docs/reference/access-authn-authz/rbac/
  • RBAC Good Practices: https://kubernetes.io/docs/concepts/security/rbac-good-practices/
  • ServiceAccounts: https://kubernetes.io/docs/concepts/security/service-accounts/
  • Managing ServiceAccounts: https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/
  • Pod Security Standards: https://kubernetes.io/docs/concepts/security/pod-security-standards/
  • Pod Security Admission: https://kubernetes.io/docs/concepts/security/pod-security-admission/
  • SecurityContext: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
  • NetworkPolicies: https://kubernetes.io/docs/concepts/services-networking/network-policies/
  • Good Practices for Secrets: https://kubernetes.io/docs/concepts/security/secrets-good-practices/
  • Encrypting Confidential Data at Rest: https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
  • Auditing: https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/
  • Admission Controllers: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/
  • ValidatingAdmissionPolicy: https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/
  • MutatingAdmissionPolicy: https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/
  • Kubelet Authentication and Authorization: https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/

40.2. Benchmarks and Hardening

  • CIS Kubernetes Benchmark: https://www.cisecurity.org/benchmark/kubernetes
  • NSA/CISA Kubernetes Hardening Guidance: https://www.cisa.gov/news-events/alerts/2022/03/15/updated-kubernetes-hardening-guide
  • kube-bench: https://github.com/aquasecurity/kube-bench
  • Kubescape: https://kubescape.io/

40.3. Policy, Supply Chain, and Runtime

  • Kyverno: https://kyverno.io/
  • OPA Gatekeeper: https://open-policy-agent.github.io/gatekeeper/
  • Sigstore Cosign: https://docs.sigstore.dev/cosign/
  • Sigstore Policy Controller: https://docs.sigstore.dev/policy-controller/overview/
  • Falco: https://falco.org/docs/
  • Cilium Tetragon: https://tetragon.io/
  • Trivy: https://trivy.dev/
  • Syft: https://github.com/anchore/syft
  • Grype: https://github.com/anchore/grype

40.4. Cloud Providers

  • AWS EKS Best Practices Guide: https://docs.aws.amazon.com/eks/latest/best-practices/
  • AKS Security Concepts: https://learn.microsoft.com/en-us/azure/aks/concepts-security
  • GKE Hardening Guide: https://cloud.google.com/kubernetes-engine/docs/how-to/hardening-your-cluster
  • GKE Autopilot Security: https://cloud.google.com/kubernetes-engine/docs/concepts/autopilot-security
  • OpenShift Security Context Constraints: https://docs.redhat.com/

40 / 44

Appendix A: Minimal Secure Workload Template

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: app-prod
  labels:
    app.kubernetes.io/name: secure-app
    app.kubernetes.io/managed-by: gitops
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: secure-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0
      maxSurge: 1
  template:
    metadata:
      labels:
        app.kubernetes.io/name: secure-app
    spec:
      serviceAccountName: secure-app
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: app
          image: registry.example.com/team/secure-app@sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
          ports:
            - name: http
              containerPort: 8080
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            runAsUser: 10001
            runAsGroup: 10001
            capabilities:
              drop: ["ALL"]
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              memory: 256Mi
          readinessProbe:
            httpGet:
              path: /readyz
              port: http
          livenessProbe:
            httpGet:
              path: /healthz
              port: http
          volumeMounts:
            - name: tmp
              mountPath: /tmp
      volumes:
        - name: tmp
          emptyDir: {}

41 / 44

Appendix B: Evaluating Security Exceptions

Question Assessment
Which policy is violated? name the exact control
Why is the exception required? technical reason, not convenience
Which alternative was evaluated? for example non-root, different ports, avoid sidecar
What scope is affected? namespace, app, node pool
How long does the exception apply? expiry date
Which compensating controls exist? NetworkPolicy, runtime detection, separate nodes
Who approves? platform + security + owner
How will it be removed? concrete plan

42 / 44

Appendix C: Security Review Protocol

markdown
# Kubernetes Security Review

## Metadata

- Cluster:
- Environment:
- Namespace:
- Application:
- Owner:
- Date:
- Reviewer:

## Result

- Risk level:
- Approval:
- Open items:

## Identity and RBAC

- User access reviewed:
- ServiceAccount reviewed:
- Secret access reviewed:
- ClusterRoleBindings reviewed:

## Workload Security

- Pod Security Admission:
- SecurityContext:
- Privileged/hostPath/hostNetwork:
- Resources:

## Network

- Default deny:
- Ingress:
- Egress:
- DNS:

## Secrets and Data

- Secret source:
- Encryption:
- Rotation:
- Backup:

## Supply Chain

- Image:
- Scan:
- SBOM:
- Signature:

## Observability

- Logs:
- Audit:
- Alerts:
- Runtime Detection:

## Exceptions

| Exception | Reason | Expiry Date | Compensation |
|---|---|---|---|

## Actions

| Action | Owner | Due | Status |
|---|---|---|---|

43 / 44

Appendix D: Security Mindset for Workshops

In the workshop:

  • You do not use real secrets.
  • You do not use real customer data.
  • You keep lab contexts separate from production contexts.
  • You check which context you are using before every kubectl apply.
  • You use dry-run, diff, and review.
  • You document every exception.
  • You include teardown and cleanup.

Context protection:

bash
kubectl config current-context
kubectl config get-contexts

Optional prompt protection:

bash
export KUBE_PS1_ENABLED=on

Or use tools such as kubectx, kubens, and shell prompt integrations so that cluster and namespace are always visible.

44 / 44

K8S · Orthevs Academy

31 modules ως ενιαία διαδρομή μάθησης.

Η σειρά παραμένει αμετάβλητη: από τη βασική δομή του lab μέσω τεχνικών θεμελίων και λειτουργικών μοντέλων έως το τελικό troubleshooting. Τα τεχνικά ονόματα καταλόγων διατηρούνται σκόπιμα.

Orthevs – Η μηχανική ως βάση για όσα ακολουθούν.

Το Orthevs ως εφαρμογή

Εγκατάσταση του Orthevs

Η web app του Orthevs μπορεί να εγκατασταθεί σε υποστηριζόμενες κινητές συσκευές και browsers υπολογιστή.

iPhone και iPad

Ανοίξτε το Orthevs στο Safari. Πατήστε Κοινή χρήση και μετά Προσθήκη στην οθόνη αφετηρίας. Ενεργοποιήστε το Άνοιγμα ως web app, αν εμφανίζεται, και πατήστε Προσθήκη.

Android

Για τη web app, ανοίξτε το μενού του browser και επιλέξτε Εγκατάσταση εφαρμογής ή Προσθήκη στην αρχική οθόνη. Επιβεβαιώστε την εγκατάσταση.

Browser υπολογιστή

Ανοίξτε το μενού του browser ή το εικονίδιο εγκατάστασης στη γραμμή διευθύνσεων και επιλέξτε Εγκατάσταση εφαρμογής ή Προσθήκη στο Dock.

Η εγκατάσταση της web app εξαρτάται από τον browser. Αν δεν εμφανιστεί διάλογος εγκατάστασης, ακολουθήστε τα βήματα του browser που αναφέρονται παραπάνω.