Chuyển đến nội dung chính

LESSON 25: SECURITY BEST PRACTICES KUBERNETES 2026

SecurityContext (non-root, read-only filesystem, drop capabilities), supply chain security with Cosign/Sigstore, SBOM, secrets encryption at rest, network isolation best practices.

🔒 DevSecOps — Lesson 25 LESSON 25: SECURITY BEST PRACTICES KUBERNETES 2026

KUBERNETES: FROM BASIC TO ADVANCED

Module 6: Security

xdev.asia

🎯 Lesson objectives

Master security best practices for Kubernetes 2026: SecurityContext hardening, supply chain security with Cosign, SBOM generation, and secure secrets management.

1. SecurityContext — Container Hardening

SecurityContext defines the security settings for the Pod or container. Apply defense-in-depth:

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      # Pod-level security context
      securityContext:
        runAsNonRoot: true          # không chạy với root user
        runAsUser: 1000             # UID cụ thể
        runAsGroup: 3000            # GID cụ thể
        fsGroup: 2000               # group owner của mounted volumes
        fsGroupChangePolicy: OnRootMismatch  # hiệu quả hơn Always
        seccompProfile:
          type: RuntimeDefault      # syscall filtering mặc định của container runtime
        supplementalGroups: [4000]  # additional groups
      containers:
      - name: app
        image: myapp:1.2.3          # không dùng :latest
        # Container-level security context (override pod level)
        securityContext:
          allowPrivilegeEscalation: false   # không cho phép setuid/setgid
          readOnlyRootFilesystem: true      # filesystem read-only
          capabilities:
            drop: ["ALL"]           # drop tất cả Linux capabilities
            add: ["NET_BIND_SERVICE"]  # chỉ add nếu thực sự cần

readOnlyRootFilesystem: if the app needs to write files, use emptyDir volume:

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

2. Supply Chain Security — Cosign/Sigstore

Verify that container images are built and signed by a trusted source.

2.1 Sign Image with Cosign

# Cài cosign
brew install cosign
# hoặc
curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
chmod +x /usr/local/bin/cosign

Keyless signing (dùng OIDC identity — không cần quản lý keys)

Chỉ hoạt động trong CI/CD environment có OIDC token

COSIGN_EXPERIMENTAL=1 cosign sign myregistry.io/myapp:v1.2.3

Key-based signing

cosign generate-key-pair # tạo cosign.key và cosign.pub cosign sign --key cosign.key myregistry.io/myapp:v1.2.3

Verify image

cosign verify --key cosign.pub myregistry.io/myapp:v1.2.3

2.2 Sigstore Policy Controller

# Cài Policy Controller để enforce image signing
helm repo add sigstore https://sigstore.github.io/helm-charts
helm install policy-controller sigstore/policy-controller \
  --namespace cosign-system \
  --create-namespace
# ClusterImagePolicy: yêu cầu image phải được ký
apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: require-signed-images
spec:
  images:
  - glob: "myregistry.io/**"     # áp dụng cho images từ registry của bạn
  authorities:
  - key:
      secretRef:
        name: cosign-public-key
        namespace: cosign-system

3. SBOM — Software Bill of Materials

SBOM lists all packages and dependencies in the container image, helping to track vulnerabilities.

# Tạo SBOM với Syft
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh

Generate SBOM cho image

syft myapp:v1.2.3 -o spdx-json > sbom.json

Scan vulnerabilities với Grype

curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh

grype myapp:v1.2.3 # scan image trực tiếp grype sbom:sbom.json # scan từ SBOM file grype myapp:v1.2.3 --fail-on critical # fail nếu có critical vulnerabilities

4. Secrets Management Best Practices

4.1 Secrets Encryption at Rest

# /etc/kubernetes/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
  - secrets
  providers:
  - aescbc:
      keys:
      - name: key1
        secret: <base64-encoded-32-byte-key>
  - identity: {}   # fallback: plaintext (cho secrets chưa encrypt)
# Bật trong kube-apiserver
kube-apiserver \
  --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

Verify encryption

kubectl get secret mysecret -n production -o yaml

data.password phải là opaque ciphertext

Encrypt tất cả existing secrets

kubectl get secrets --all-namespaces -o json | kubectl replace -f -

4.2 External Secrets Management

Instead of storing secrets in Kubernetes etcd, use the External Secrets Operator to sync from:

  • AWS Secrets Manager
  • HashiCorp Vault
  • GCP Secret Manager
  • Azure Key Vault
# ExternalSecret: định nghĩa secret cần sync
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: production
spec:
  refreshInterval: 1h    # sync mỗi 1 giờ
  secretStoreRef:
    name: aws-secret-store
    kind: ClusterSecretStore
  target:
    name: db-credentials   # tên Kubernetes Secret sẽ được tạo
  data:
  - secretKey: POSTGRES_PASSWORD
    remoteRef:
      key: production/database
      property: password
  - secretKey: POSTGRES_USER
    remoteRef:
      key: production/database
      property: username

5. Image Security Best Practices

# Chỉ pull từ private registry đã được quét
spec:
  containers:
  - name: app
    image: myregistry.io/myapp:v1.2.3  # không dùng Docker Hub trực tiếp
    imagePullPolicy: Always             # luôn verify với registry

imagePullSecrets:

  • name: registry-credentials

Sử dụng digest thay tag để immutable reference

image: myregistry.io/myapp@sha256:abc123...

6. Network Security

# Default deny + allow specific
# 1. Default deny all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]
---
# 2. Allow DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes: [Egress]
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53

7. Audit Logging

# Audit policy
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse     # log request + response body
  resources:
  - group: ""
    resources: ["secrets"]  # log mọi thao tác với Secrets
- level: Request             # log request body
  resources:
  - group: "apps"
    resources: ["deployments"]
  verbs: ["create", "update", "delete"]
- level: Metadata            # log metadata only (no body)
  omitStages: [RequestReceived]

Summary — Security Checklist 2026

  • ✅ SecurityContext: non-root, readOnlyRootFilesystem, dropAll caps, seccomp RuntimeDefault
  • ✅ Pod Security Admission: Restricted mode for production namespaces
  • ✅ Sign images with Cosign, enforce with Policy Controller
  • ✅ Generate SBOM, scan with Grype
  • ✅ Secrets encryption at rest or External Secrets Operator
  • ✅ Network Policies: default-deny
  • ✅ RBAC: least privilege ServiceAccounts
  • ✅ Audit logging for Secrets and critical resources__HTMLTAG_135___
  • ✅ Specific image tags (do not use :latest), pulled from private registry