Деплой и инфра
Secrets at deploy: перепроложить дырявый деплой
Читать про утёкшие секреты — не то же самое, что самому закрыть дыры. Начните с деплоя, где сделано всё неправильно — secret вшит в образ, base64 Secret в git, пароль в env-переменной — и перепроложите его от и до, пока утёкший манифест, украденный бэкап etcd и crash dump не перестанут раскрывать что-либо полезное.
Превратите модель угроз юнита в воспроизводимый цикл укрепления: докажите исходные утечки, вынесите secret из образа, зашифруйте его at rest и в git, переключите инъекцию на файлы, ротируйте без рестарта и подтвердите каждое исправление доказательством, а не утверждением.
Возьмите небольшой сервис в Kubernetes, чей secret вшит в образ, закоммичен как base64 Secret и инъецирован как env-переменная, и перепроложите его так, чтобы secret попадал внутрь только в рантайме, был зашифрован at rest и в git и ротировался без рестарта пода. Докажите закрытие каждой утечки конкретной командой, а не утверждением.
- Таблица утечек до/после: для каждой из трёх исходных утечек (слой образа, base64 Secret в git, env crash dump) — точная команда, раскрывшая её до, и та же команда, не показывающая ничего полезного после.
- Доказательство, что продакшен-образ не содержит секретного материала ни в одном слое (вывод docker history) и что etcd теперь хранит значение как шифртекст (сырое чтение etcd).
- Закоммиченный git-артефакт — это Sealed Secret (или ссылка ExternalSecret), который нельзя декодировать без in-cluster контроллера, что показано неудачной попыткой декодирования.
- Демонстрация rotation: новое значение применено, работающий под отдаёт его без рестарта, с зафиксированным измеренным временем вступления в силу.
- Добавьте CI-гейт сканирования секретов (gitleaks/trufflehog), который роняет сборку при коммите любого плейнтекст-секрета или base64 Secret, и покажите, как он ловит намеренно повторно внесённую утечку.
- Замените статический secret на Vault dynamic secret (короткоживущий per-app credential с авто-отзывом) и покажите, что credential, захваченный в момент T, перестаёт работать после своего TTL.
- Ужесточите RBAC так, чтобы Secret мог читать только ServiceAccount нагрузки, и докажите, что другому ServiceAccount отказано — закрыв путь утечки через неверный RBAC, который называет урок.
- Напишите однастраничный on-call runbook: пять мест утечки секрета (образ, base64 Secret, etcd, env/crash dump, история git), команда триажа для каждого и лестница приоритета исправлений от never-bake до dynamic credentials.
Это цикл, который вы будете прогонять на каждом реальном деплое, касающемся credential: докажите, где он течёт, прежде чем довериться любому исправлению, вынесите его из образа, зашифруйте at rest и перепишите старые Secrets, сделайте закоммиченный артефакт настоящим шифртекстом, переключите инъекцию на файлы, чтобы сузить поверхность crash dump, и ротируйте на месте без рестарта. Проделав это один раз на игрушечном сервисе, вы превращаете «мы используем Secrets, значит всё в порядке» в модель угроз, которую реально можно защитить под аудитом.