DevSecOps для самых маленьких: 8\n. Автоатака
В Dota есть автоатака. Ты не жмёшь кнопку на каждый удар: герой бьёт сам, пока цель в радиусе. Ты занят другим: позиционированием, способностями, картой. Автоатака работает по правилам, которые ты один раз задал. Policy as Code для меня выглядит так же. Правило описано один раз и дальше применяется без твоего участия. Не безопасник на встрече сказал «так нельзя», а admission controller отклонил манифест, потому что в нём нет resource limits.
Policy as Code — политики безопасности, описанные кодом. Не регламент в вики и не письмо в чат, а код в Git: версионируется, проходит ревью, применяется автоматически. Admission controller — компонент Kubernetes, который проверяет объект до того, как он сохранится в кластере. Разработчик получает фидбек сразу, а не через неделю на ревью и не после инцидента.
Почему дефолт — дыра
В обычном кластере политики живут в головах и в переписках. Кто-то помнит, что контейнеры не должны работать от root, кто-то помнит про лимиты, кто-то про доверенный registry. Но помнят не все и не всегда, а помнить бесполезно, если никто не проверяет. Манифест с privileged-контейнером спокойно доезжает до прода: на ревью не заметили, а после деплоя уже поздно. Правила на памяти и внимательности работают до первого отпуска или аврала. Код не забывает.
Я видел кластеры, где политики применялись руками. Специальный человек раз в месяц проходил по манифестам и оставлял комментарии. Потом он ушёл в отпуск, потом сменил проект, и политики тихо умерли. Никто не заметил: они никогда не были частью процесса. С кодом так не получится. Если политика в Git и её применяет admission controller, она работает, пока её не выключат осознанно.
Первая политика: запрет latest
Не пытайся описать всё сразу. Возьми одно правило, которое болит сегодня. Например, запрет тега latest:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: disallow-latest-tag
spec:
validationFailureAction: Audit # сначала аудит, потом Enforce
background: true
rules:
- name: require-image-tag
match:
any:
- resources:
kinds: [Pod]
validate:
message: Укажи тег образа, лучше digest
pattern:
spec:
containers:
- image: '*:*'
- name: no-latest
match:
any:
- resources:
kinds: [Pod]
validate:
message: Тег latest запрещён
pattern:
spec:
containers:
- image: '!*:latest'
Посмотри, что она отклонила бы:
kubectl get policyreport -A
Скорее всего, выяснится, что половина команды деплоит с latest и никто об этом не задумывался. Когда картина понятна, переключи политику на Enforce. Дальше добавь второе правило (resource limits), потом третье (запрет privileged). По одному, с наблюдением, чтобы не уронить прод.
Чего не делать
Не включай все политики сразу в режиме блокировки. Аудит сначала: политика проверяет, но не блокирует.
Не пиши политики ради политик. Каждое правило должно закрывать конкретный риск, иначе это шум, который все начнут обходить.
Инструменты
Kyverno — Kubernetes-native, правила на YAML. Для многих проще всего.
OPA Gatekeeper — политики на Rego. Мощный, но язык нужно учить, порог входа выше.
Conftest — проверка конфигов в CI, ловит нарушения до того, как манифест доехал до кластера.
Kubewarden — политики на WebAssembly.
Российские: Luntry. Сверь, какие функции Policy as Code входят в твою редакцию.
Для Kyverno и Gatekeeper есть открытые библиотеки готовых политик: не пиши с нуля то, что уже написано.
Policy as Code — не про то, чтобы запретить всё, а про то, чтобы правила работали без тебя. Без неё остальные практики работают вполсилы: можно харденить контейнеры, но без проверки манифестов root вернётся при первом удобном случае. Можно спрятать секреты в Vault, но если политика не запрещает класть их в переменные окружения, кто-нибудь положит. Начни с одного правила в режиме аудита, потом переведи в блокировку, потом добавь второе. Через месяц правила будут работать сами, а ты займёшься тем, что требует твоего внимания.
Обсуждаем статьи в Telegram-канале. Недушный ИнфоБез.
