Learning Platform
Глоссарий Troubleshooting
Урок 15.04 · 22 мин
Продвинутый
Pod Security StandardsPSABaselineRestrictedadmission control

Pod Security Standards и Admission

Pod Security Admission (PSA) — это built-in admission controller, который проверяет каждый создаваемый Pod на соответствие одному из трёх стандартов: Privileged, Baseline, Restricted. PSA включён по умолчанию с v1.23, GA c v1.25, и полностью заменил PodSecurityPolicy (PSP) — последний удалён в v1.25. На v1.35 это единственный официальный mechanism для namespace-level security policy в core K8s. Применение — через labels на Namespace. На CKAD это знание концептуальное: понять три уровня, mode-флаги, и какие поля SecurityContext нужны для каждого уровня.


Rootless Docker и user namespaces

Три уровня (Pod Security Standards)

Три уровня Pod Security Standards
PrivilegedПолностью unrestricted. Любые SecurityContext settings, hostPID, hostNetwork, privileged: true, hostPath volumes, любые capabilities. Для системных компонентов кластера: CNI агенты, monitoring DaemonSets, kube-proxy, csi-drivers.
BaselineМинимальные ограничения для типичных приложений. Запрещены: privileged, hostNetwork, hostPID, hostIPC, hostPath, hostPort, добавление опасных capabilities (NET_ADMIN, SYS_ADMIN, ...). Большинство публичных images проходят baseline без модификаций.
RestrictedЖёсткие ограничения для security-conscious apps. Требует: runAsNonRoot, allowPrivilegeEscalation false, capabilities drop ALL (можно add только NET_BIND_SERVICE), seccompProfile RuntimeDefault или Localhost. Это уровень для production multi-tenant.

Стандарты определены документом Kubernetes Pod Security Standards и фиксированы версией кластера (можно ссылаться на latest или конкретный v1.34, v1.35).


Что Restricted требует от SecurityContext

Самый детализированный уровень. Pod проходит, если соблюдены все правила:

apiVersion: v1
kind: Pod
metadata:
  name: restricted-ok
spec:
  securityContext:
    runAsNonRoot: true          # либо на Pod-level, либо на всех containers
    seccompProfile:
      type: RuntimeDefault       # либо RuntimeDefault либо Localhost
  containers:
  - name: app
    image: app:1.0
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: [ALL]
        add: [NET_BIND_SERVICE]  # единственный allowed add
    # readOnlyRootFilesystem НЕ обязательно в restricted v1.35
Restricted required fields
runAsNonRoot trueОбязательно. Либо на Pod-level, либо на КАЖДОМ container. Если хотя бы один container не имеет runAsNonRoot true (и Pod не имеет) — admission deny.
allowPrivilegeEscalation falseНа КАЖДОМ container (включая init и ephemeral). Если хоть один отсутствует или true — deny.
capabilities drop ALLНа КАЖДОМ container в capabilities.drop должен быть ALL. Add allowed только NET_BIND_SERVICE.
seccompProfiletype должен быть RuntimeDefault или Localhost (с указанием профиля). Можно на Pod-level — наследуется. На container-level override.
никаких host* volumesЗапрещены hostPath, hostNetwork, hostPID, hostIPC, hostPort. Любой emptyDir, persistentVolumeClaim, configMap, secret, projected, csi — разрешены.
никаких privilegedprivileged: true, никаких опасных capabilities кроме NET_BIND_SERVICE. procMount только Default. AppArmor profile должен быть RuntimeDefault или Localhost.

Применение через namespace labels

PSA не имеет собственного API-объекта в обычном случае — конфигурируется через labels на Namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    # Mode: enforce — block non-compliant Pods
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    # Mode: audit — log violations to audit log
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: latest
    # Mode: warn — print warning к kubectl при создании
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest

Прикладной императивный паттерн:

kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest

Проверить:

kubectl get namespace production -o jsonpath='{.metadata.labels}' | jq

Three modes: enforce, audit, warn

PSA modes
enforceAdmission deny. Если Pod нарушает уровень — apiserver отвергнет создание с ошибкой. kubectl apply вернёт error. Самый строгий mode — нужен для production.
auditPod создаётся, но в audit log apiserver пишется violations annotation. Не влияет на runtime. Используется для discovery: что в кластере уже нарушает policy.
warnПри создании Pod kubectl выводит warning с описанием нарушения. Pod создаётся, behavior работает. Полезно при rollout policy — пользователи видят что не так до enforcement.
migration patternProduction rollout: 1) audit + warn на restricted, чтобы найти все нарушающие workloads и предупредить разработчиков. 2) После исправлений включить enforce на baseline. 3) После полной готовности — enforce restricted.

Каждый mode — независимый. Можно поставить enforce=baseline, audit=restricted, warn=restricted — это значит «блокирую baseline нарушения, логирую и предупреждаю о restricted нарушениях». Это типичный pattern: enforce baseline (минимум), audit restricted (видеть прогресс к более жёсткому уровню).


Killer-момент: enforce на existing namespace

DANGER

PSA проверяет только при создании / обновлении Pod. Уже запущенные Pods не аффектятся новым label. Но при их rolling restart (новый ReplicaSet, deployment update, scaling, node drain → reschedule) — kubelet попробует создать новые Pods, apiserver их отвергнет, deployment останется без healthy replicas.

Production playbook применения restricted к существующему namespace:

  1. Поставить warn=restricted + audit=restricted. Сделать deployment apps — увидеть violations в kubectl и audit log.
  2. Исправить SecurityContext во всех manifests.
  3. Дождаться полного rollout — проверить что новых violations нет.
  4. Только потом включить enforce=restricted.

Альтернатива при неотложности — поставить enforce=baseline, который много легче, и потом мигрировать к restricted.


Privileged Pods для system needs

Системные DaemonSets (CNI, monitoring agents) часто требуют privileged: true или hostNetwork. Они НЕ должны жить в restricted namespace. Стандартные подходы:

  • Запускать их в kube-system namespace с enforce=privileged (или вообще без label — equivalent to privileged).
  • Если нужен dedicated namespace (например, monitoring), пометить его enforce=privileged.
# Promtail DaemonSet, читающий /var/log/containers на хосте
apiVersion: v1
kind: Namespace
metadata:
  name: logging
  labels:
    pod-security.kubernetes.io/enforce: privileged

PSA vs admission webhooks vs OPA/Kyverno

PSA покрывает базовые сценарии. Для более сложных — например, «запретить images не из нашего registry» или «требовать lab team» — нужны:

  • OPA Gatekeeper — admission webhook на основе Rego policies.
  • Kyverno — admission и mutation на основе YAML policies (proще чем Rego).
  • Custom ValidatingAdmissionWebhook — собственный сервис.
  • ValidatingAdmissionPolicy (v1.30+ GA) — CEL expressions без external webhook.

На CKAD они не требуются — экзамен ограничен built-in PSA. Но знать что PSA — не единственный механизм admission, полезно для рассуждения в production.


Команды для quick reference

# Применить enforce restricted к namespace
kubectl label ns production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=latest

# Применить warn для discovery
kubectl label ns dev \
  pod-security.kubernetes.io/warn=restricted

# Снять label (вернуть к privileged по умолчанию)
kubectl label ns production \
  pod-security.kubernetes.io/enforce-

# Создать Pod и увидеть warning (с warn label)
kubectl apply -f pod.yaml -n dev
# Warning: would violate "latest" version of "restricted" PodSecurity profile:
# allowPrivilegeEscalation != false (container "app"), ...

Проверка знанийKnowledge check
Namespace помечен enforce=restricted. Pod создаётся с runAsNonRoot: true и capabilities drop ALL, но без allowPrivilegeEscalation: false. Что произойдёт?
ОтветAnswer
Admission deny — kubectl apply вернёт ошибку. Restricted требует ВСЕ четыре поля: runAsNonRoot, allowPrivilegeEscalation false, capabilities drop ALL, seccompProfile RuntimeDefault. Отсутствие любого — нарушение. Pod не создастся, deployment останется без healthy replicas.
Проверка знанийKnowledge check
Какой режим PSA правильно использовать для rollout restricted policy к namespace, где уже работают legacy apps?
ОтветAnswer
Сначала warn=restricted + audit=restricted (можно одновременно с enforce=baseline). Это даёт visibility: kubectl warnings при обновлении legacy manifests + audit log. После исправления всех violations — переключить на enforce=restricted. Прыжок сразу в enforce ломает существующие workloads при их recreation.
Проверка знанийKnowledge check
DaemonSet для CNI plugin использует hostNetwork и privileged: true. В каком namespace его деплоить и какой PSA label поставить?
ОтветAnswer
В kube-system или dedicated namespace типа cni-system, с label pod-security.kubernetes.io/enforce: privileged. CNI Pods принципиально не могут пройти baseline — им нужен hostNetwork для конфигурации сетевых интерфейсов node. Privileged namespace явно говорит 'тут разрешён full host access'.
Проверка знанийKnowledge check
Что заменило PodSecurityPolicy и почему?
ОтветAnswer
Pod Security Admission (PSA), GA с v1.25. PSP был сложен в использовании: требовал RBAC bindings (если SA не имел use на PSP — Pod падал), не имел dry-run, поведение зависело от ordering policies. PSA — built-in admission controller, конфигурируется простыми namespace labels, имеет audit/warn modes для безопасного rollout.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Namespace помечен enforce=restricted. Pod создаётся с runAsNonRoot: true и capabilities.drop: [ALL], но без allowPrivilegeEscalation: false. Что произойдёт?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5