Admission-контроль и безопасность образов
Последний рубеж обороны — не пустить в кластер то, что не должно туда попасть.
Admission controller — компонент, который перехватывает запросы к API-серверу после аутентификации и авторизации, но до записи объекта в etcd, и может его проверить (validating) или изменить (mutating).
RBAC отвечает на вопрос «кому можно», securityContext — «как запускать под». Admission-контроль отвечает на вопрос «что вообще допустимо создать»: запретить привилегированные поды, потребовать лимиты ресурсов, не пустить образ с тегом latest или из неизвестного реестра. Это политика, применяемая ко всему кластеру централизованно.
Зачем это на практике
Полагаться на то, что все команды напишут безопасные манифесты, нельзя — кто-то забудет, кто-то скопирует пример из интернета с privileged: true. Admission-политики переводят правила безопасности из «договорённости» в «технически невозможно нарушить». Пример: политика «образы только из registry.company.io» физически блокирует деплой левого образа, даже если у разработчика есть права на создание подов.
Это закрывает важный класс угроз цепочки поставок (supply chain). Современное приложение в кластере — это не только ваш код, но и десятки базовых образов, библиотек и слоёв, пришедших из публичных реестров. Любой из них может содержать уязвимость или быть подменён. Admission-контроль вместе с проверкой образов даёт точку, где кластер один раз и для всех решает: какие источники доверенные, какие версии допустимы и подписан ли тот код, который вот-вот начнёт исполняться с правами вашего пода. Без такой точки каждое решение принимается вразнобой в десятках пайплайнов — и одно неверное открывает дверь.
Два вида admission-контроллеров
Запрос проходит две фазы admission. Сначала mutating-контроллеры могут дополнить объект (вписать sidecar, проставить дефолты), затем validating — проверить итог и принять решение «пустить или отклонить»:
| Тип | Что делает | Пример |
| Mutating | изменяет объект до записи | добавить метку, sidecar, дефолтные ресурсы |
| Validating | принимает или отклоняет | запретить privileged, latest, чужой реестр |
В кластере уже работают встроенные admission-плагины. Pod Security Admission из урока про безопасность подов — как раз validating-контроллер. А для своих правил подключают policy-движки.
Policy-движки: OPA/Gatekeeper и Kyverno
Писать свой admission-webhook на каждое правило тяжело, поэтому используют готовые движки. Два самых популярных:
Kyverno: политики как обычный YAML
Kyverno описывает правила в виде Kubernetes-ресурсов, без отдельного языка. Запретим тег latest у любого контейнера:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
spec:
validationFailureAction: Enforce # Enforce = блокировать, Audit = только лог
rules:
- name: require-image-tag
match:
any:
- resources:
kinds: ["Pod"]
validate:
message: "Тег образа обязателен и не должен быть :latest"
pattern:
spec:
containers:
- image: "!*:latest" # запрещаем суффикс :latest
Теперь попытка применить под с image: nginx:latest или вовсе без тега будет отклонена с понятным сообщением.
OPA/Gatekeeper: политики на языке Rego
Gatekeeper применяет Open Policy Agent: правила пишутся на языке Rego и оформляются как ConstraintTemplate + Constraint. Тот же запрет latest на Rego выглядит так:
package k8srequiredtag
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("образ %v использует запрещённый тег latest", [container.image])
}
Rego мощнее для сложной логики, но требует отдельного языка; Kyverno проще для типовых правил «запрети/потребуй». Выбор зависит от команды.
Безопасность образов
Образ — это код, который вы запускаете в кластере с правами своего пода. Оборонительные меры:
- Запрет тега
latest.latestнепредсказуем: один и тот же манифест завтра запустит другой образ. Требуйте конкретные теги или дайджесты. - Образ по дайджесту.
image: app@sha256:abc...привязывает под к точному содержимому — подменить его нельзя. - Доверенные реестры. Политика, разрешающая только
registry.company.io/*, отсекает образы из публичного интернета. - Подписи образов. Инструменты вроде Cosign подписывают образы, а admission-политика (например, в Kyverno) проверяет подпись и не пускает неподписанный образ.
- Сканирование уязвимостей. Сканеры (Trivy, Grype) ищут известные CVE в слоях образа; запускайте их в CI и блокируйте сборку при критических находках.
Проверку подписи в Kyverno описывают отдельным правилом verifyImages:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-image-signature
spec:
validationFailureAction: Enforce
rules:
- name: verify-signature
match:
any:
- resources:
kinds: ["Pod"]
verifyImages:
- imageReferences:
- "registry.company.io/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
Как это работает под капотом
Policy-движок регистрируется в API-сервере как ValidatingWebhookConfiguration (а Kyverno при мутации — ещё и MutatingWebhookConfiguration). Когда приходит запрос на создание пода, API-сервер после RBAC отправляет объект на webhook движка; тот возвращает allowed: true/false и при отказе — сообщение. В режиме Enforce отказ webhook'а означает, что объект не будет записан в etcd и kubectl apply вернёт ошибку. Важная деталь: для каждого webhook задаётся failurePolicy — Fail (если движок недоступен, запрос отклоняется) или Ignore (пропускается); для security-политик выбирают Fail, чтобы падение движка не открывало лазейку.
Частые ошибки
- Сразу Enforce без обкатки. Жёсткая политика на работающий кластер может разом заблокировать все деплои; начинайте с режима Audit/warn.
- failurePolicy: Ignore для security-правил. Если движок упадёт, проверки молча пропадут — для безопасности нужен Fail.
- Запрет latest без альтернативы. Команды должны заранее перейти на версионные теги, иначе политика ломает их пайплайны.
- Сканирование «для галочки». Отчёт сканера без блокировки в CI ничего не предотвращает — настройте порог критичности.
- Доверие к подписи без проверки реестра. Подпись бессмысленна, если разрешён любой реестр; комбинируйте verifyImages с ограничением источников.
Итоги
- Admission-контроль — последний рубеж: он решает, что вообще допустимо создать в кластере, после RBAC и до записи в etcd.
- Mutating-контроллеры дополняют объект, validating — принимают или отклоняют; Pod Security Admission и policy-движки работают на этом этапе.
- OPA/Gatekeeper (язык Rego) и Kyverno (политики как YAML) задают свои правила: запрет latest, привилегий, чужих реестров.
- Безопасность образов: конкретные теги или дайджесты, доверенные реестры, подписи (Cosign + verifyImages), сканирование на CVE.
- Включайте политики через Audit, ставьте failurePolicy: Fail для security-правил и блокируйте сборку при критических уязвимостях.