Kubernetes 1.25: PSP выпилили, мигрируем клиентов на Pod Security Admission
Kubernetes 1.25 окончательно убрал PodSecurityPolicy. Рассказываем, где замена прошла почти автоматически, а где пришлось переписывать манифесты вручную.
Kubernetes 1.25 GA - окончательное удаление PodSecurityPolicy из кодовой базы, Pod Security Admission стал единственным встроенным механизмом контроля безопасности подов
PodSecurityPolicy в Kubernetes был помечен deprecated ещё в 1.21. Полтора года у всех было время подготовиться. Тем не менее, когда вышел Kubernetes 1.25 и PSP физически исчез из кодовой базы, несколько клиентских кластеров оказались не готовы. Пришлось заняться миграцией в авральном режиме - не потому что не знали о дедлайне, а потому что «потом разберёмся» работает ровно до дня X.
Что изменилось и почему это важно
PSP был admission controller: при создании пода Kubernetes проверял, соответствует ли под одной из разрешённых PodSecurityPolicy в неймспейсе. Механизм мощный, но запутанный - связка PSP с ServiceAccount через RBAC давала обильное поле для ошибок. Достаточно было забыть привязать роль к правильному SA, и поды просто не запускались. Или, наоборот, кто-то давал wildcard-доступ «чтобы работало» и вся политика превращалась в декорацию.
Pod Security Admission (PSA) - другая концепция. Вместо кастомных политик с произвольными параметрами - три фиксированных профиля: privileged, baseline и restricted. Назначаются на уровне неймспейса тремя лейблами, три режима для каждого: enforce, audit, warn. Проще для понимания, проще для аудита, но менее гибко.
Где замена прошла почти сама
Первая категория клиентов - те, кто использовал PSP формально. Политики были созданы «по шаблону из интернета», реально ни от чего не защищали, просто потому что кто-то когда-то сказал что PSP надо настроить.
Для таких кластеров миграция выглядела примерно так:
- Смотрим, какие PSP реально применяются (не созданы, а применяются к живым подам) через
kubectl get pods -A -o jsonpath. - Если профиль PSP грубо соответствует
baseline- навешиваемpod-security.kubernetes.io/enforce: baselineна неймспейс. - Откатываем PSP и смотрим, что упало.
В большинстве случаев не упало ничего. Кластер работал, люди не замечали разницы. Это немного обескураживает - значит, политики реально ни на что не влияли.
Где пришлось копаться
Сложнее там, где PSP использовались осмысленно - особенно для workload с повышенными привилегиями.
Первый случай - daemonset для сетевого плагина Calico. Он требует hostNetwork: true, доступ к /proc и ряд capability. В PSP это описывалось явно: allowedCapabilities, hostNetwork: true в разрешённых. В PSA уровень restricted это не пропустит. Нужен либо privileged на системный неймспейс (что мы и сделали для kube-system - там он и должен быть), либо исключения через exemptions в конфигурации admission controller.
Второй случай - кастомный агент мониторинга. Клиент использует собственный агент, который монтирует hostPath для чтения системных метрик. PSP разрешал конкретные пути через allowedHostPaths. PSA этого механизма не имеет - уровни либо разрешают hostPath вообще (baseline допускает), либо нет (restricted запрещает). Пришлось переехать на baseline для неймспейса с мониторингом и смириться с тем, что часть ограничений PSP без аналога в PSA.
Третий случай - legacy-приложение, которое запускало контейнеры от root. PSP позволял детально управлять UID/GID через runAsUser с диапазонами. PSA в restricted требует runAsNonRoot: true в securityContext. Приложение не имело возможности запуститься не от root - пришлось либо фиксить образ, либо оставаться на baseline. Выбрали fix образа, заодно закрыли техдолг.
Про инструмент миграции от upstream
Kubernetes проект выпустил скрипт kubectl-convert и документ с гайдом по миграции. Утилита kube-psp-advisor от Sysdig умеет анализировать кластер и предлагать эквивалентный PSA-уровень для каждого неймспейса. В теории.
На практике kube-psp-advisor даёт отправную точку, но не финальный ответ. Он не учитывает будущих подов - только те, что запущены в момент анализа. Если в неймспейсе есть Jobs или CronJobs с другими требованиями - их надо анализировать отдельно. И конечно, он не знает про бизнес-контекст: что в одном неймспейсе - тестовая среда, а в другом - прод с PCI-данными.
Где PSA не хватает
Говорить об этом немного некомфортно, потому что выглядит как жалоба на бесплатный инструмент. Но честно: PSA не закрывает все сценарии, которые закрывал PSP.
Нет allowedCapabilities с точным списком - только грубые профили. Нет контроля над конкретными hostPath. Нет seccomp-профилей на уровне policy (хотя restricted требует seccomp RuntimeDefault или Localhost). Для тех, кому нужна реально тонкая настройка, путь - сторонние инструменты: OPA/Gatekeeper или Kyverno. PSA - это встроенный минимум, не полная замена.
Мы ведём кластеры клиентов в рамках managed-сопровождения и уже добавили чеклист PSA-миграции в стандартный процесс обновления Kubernetes. Несколько кластеров ещё в процессе - там где legacy-workload требует более аккуратного подхода. В следующем обновлении разберём, как Kyverno закрывает то, что PSA не умеет.