«Прячем» секреты от cluster admin
Vitaliy LikhachevВопрос, который вам могут задать на собеседовании, чтобы почеленджить на тему понимания работы механизмов безопасности в k8s и в Linux.
Представьте, что вам нужно обеспечить недоступность секретов приложения для cluster admin. Концептуально это возможно, конечно, идеальной защиты не существует. На то он и cluster admin. Однако защита может быть не только технической, но и юридической, особенно в зарегулированных сферах типа банковской или медицинской. Для этого понадобятся аудит-логи и алерты на них, которые один человек без доп. апрувов просто поменять не сможет.
Приступим к разбору.
Зашифрованный etcd и RBAC на доступ к секретам — это база. Не секрет, что секреты (такая тавтология) хранятся в base64, и cluster admin может заглянуть куда угодно.
Наша задача — сделать процесс доступа сильно сложнее, так, чтобы по аудит-логам (с настроенными алертами на службу безопасности) можно было понять, что cluster admin целенаправленно полез туда, куда не надо.
Проблема: где текут секреты?
Обычно всё ломается на двух этапах:
- API Server: любой
kubectl get secret -o yamlилиdescribe podвываливает всё содержимое. - Runtime: если админ может сделать
kubectl exec, он просто посмотритenvили залезет в/proc/1/environ.
Поэтому «не давать exec» — это база RBAC. Но админ всё равно сможет создать под, подменив либо образ, либо cmd, либо что-то ещё, чтобы посмотреть env, даже без exec.
Добавляем паранойи: Vault Agent + execve()
Забудьте про envFrom. Мы будем использовать Vault Agent Injector и фокус с подменой процесса через vault-env.
При этом важно, чтобы либо в Vault так же был настроен аудит, либо Vault был недоступен для управления тем же самым админом.
Секреты вообще не должны попадать в Kubernetes как объекты. Под аутентифицируется в Vault через свой ServiceAccount. Админ может обсмотреться на манифест пода — там будут только аннотации.
Подмена процесса
Это киллер-фича. Мы не прописываем переменные окружения в манифесте Deployment. Мы используем утилиту-враппер (например, vault-env) как ENTRYPOINT.
Как это работает на уровне ядра:
- Стартует
vault-env. Он лезет в Vault, забирает секреты и кладёт их в свой массивenviron. - Далее он делает системный вызов
execve("/app/binary", args, envp). - Ядро Linux полностью заменяет образ процесса
vault-envвашим приложением, но передаёт ему обогащённый секретами стек окружения напрямую в память.
Итог: kubectl describe pod покажет чистый список переменных. Секреты не проходили через API-сервер, их нет в etcd, и они не светятся в логах.
Помним: аудит и «правило четырёх глаз»
Допустим, админ настойчивый. Он лезет в логи или пытается перехватить запросы.
- Vault Audit Logs (External): логи Vault должны уходить сразу в изолированный SIEM, к которому у админа куба нет доступа. Любая попытка пода (или того, кто им притворился) достать лишний секрет должна триггерить алерт.
- Control Groups (rule of two keys): для самых критичных штук (например, ключи расшифровки БД) включаем в Vault
control_groups. Даже если под попросит секрет, Vault его не отдаст, пока второй человек (Security Officer) не нажмёт кнопку «Одобрить» у себя. Конечно, это доступно только в enterprise-версии и не подойдёт для автоматической разблокировки, когда Vault неожиданно перезапустится. Но тут уже отдельная история, как делать vault unseal, если всё упало, включая падение кластера Vault.
Добиваем выживших: hardening
Чтобы kubectl exec превратился для админа в тыкву:
- Distroless/Scratch: выкиньте из образа
sh,lsиenv. Нет бинарников — нет простого способа посмотреть окружение. - Drop Capabilities: сносите
CAP_SYS_PTRACEчерезsecurityContext. Да и вообще все capabilities дропайте. Без этого даже root внутри контейнера не сможет легко сделать дамп памяти процесса или прочитать чужой/proc/[pid]/environ. - Dynamic Credentials: используйте динамические секреты Vault для БД. Пароль живёт 5 секунд и умирает вместе с подом. Даже если админ его украл — через 5 секунд это просто мусор.
Итог
Админ видит пустые конфиги, пустой env в манифестах и заблокированный ptrace. Любая его попытка пошпионить залетает во внешний аудит, который он не может почистить
Ещё больше полезных материалов по K8s на ресурсах:
K8s для junior: t.me/Kubernetes_Minkin
K8s для middle и senior: t.me/Kubernetes_Likhachev
Траблшутер-бот в Телеграм: t.me/simulator_kub_bot
Анонсы мероприятий и вебинаров по K8s: t.me/KubWebBot
Беседа-сообщество по K8s: t.me/K8s_and_you