В прошлом месяце я наконец сел и посмотрел, как у нас на самом деле устроено управление секретами в проде. Не на схему архитектуры. Не на policy-документ, где написаны все правильные слова. На реальность — на 55 переменных CI/CD пайплайнов, от которых тихо зависел каждый билд. Двенадцать из них лежали открытым текстом. Тридцать вообще не использовались — остатки от проектов, которые давно выкатили и забыли. И ни у одной не было политики ротации. Один пароль от базы не менялся четырнадцать месяцев — и при этом бодро печатался в логи билдов, которые мог прочитать любой, у кого был доступ к пайплайну.

Никто не знал. Никто не проверял. Пайплайны работали — значит, вопросов ни у кого не возникало. В этом и есть тихий ужас работы с безопасностью: её не видно ровно до того момента, когда её становится видно. А этот момент обычно выглядит как совещание, на котором ты объясняешь, как пароль в открытом виде четырнадцатимесячной давности оказался там, где его быть не должно.

Аудит, о котором меня никто не просил

Мне это не поручали. Мне просто надоело не знать. Поэтому я вытащил все переменные из всех пайплайнов и прочитал их по одной. Пятьдесят пять записей. Половина — бессмысленный мусор, ссылки на ресурсы, которых давно нет. А среди этого шума — двенадцать настоящих, живых секретов открытым текстом: пароли от баз, API-ключ, креды к storage. Вещи, утечка которых стоит тебе не испорченного дня, а отчёта об инциденте.

И вот что делает ситуацию хуже, чем звучит: это были не тестовые пайплайны. Это был прод, работавший месяцами и гонявший реальные данные. Креды работали — значит, система была "в порядке". Вот она, ловушка: секрет в плейнтексте не даёт вообще никаких симптомов ровно до той минуты, когда выдаёт их все и сразу.

Почему ручной аудит — это уже ложь

Стандартный ответ на всё это — квартальный security review. Кто-то заходит в консоль, руками проверяет IAM, по очереди прокликивает security-группы и заносит всё в таблицу. К моменту, когда он сохраняет этот файл, он уже художественная литература. Пока шла проверка, кто-то поднял новый ресурс. Кто-то поменял storage account. Аудит — это фотография прошлого, которого уже нет.

Ручной security review не масштабируется, и, что хуже, он врёт тебе в лицо не моргнув. Он ставит зелёную галочку системе, которая изменилась прямо в процессе проверки. Если твоя безопасность живёт в таблице — ты уже отстал. Потому что атакующие не ждут твоего квартального ревью.

У меня есть сертификат CEH. Не ради бейджа в LinkedIn — я его получил, потому что хотел думать так, как думают те, кто эксплуатирует ровно такую вот лень. И честная правда в том, что секреты в открытом виде в переменной билда — это не какая-то экзотическая поверхность атаки. Это первое, что ищет любой.

Что я сделал на самом деле

Сама уборка была совсем не эффектной и заняла примерно неделю:

  • Всё уехало в Azure Key Vault. Больше ни один секрет не живёт сырой переменной пайплайна.
  • Аутентификация через managed identity. Пайплайн доказывает, кто он, и забирает нужное — никаких вечных кредов в поле настроек.
  • 12 секретов из плейнтекста зашифрованы и убраны за RBAC. Доступ теперь — это решение, а не значение по умолчанию.
  • Настроена автоматическая ротация. История с четырнадцатимесячным паролем больше физически невозможна — ничто не живёт достаточно долго, чтобы ею стать.
  • 30 неиспользуемых переменных удалены под корень. Мёртвый конфиг — это поверхность атаки без единого плюса.

Я сделал аудитором сам пайплайн

Разовая уборка решает проблему ровно на один день. Смысл в том, чтобы сделать плохое состояние невозможным к возврату. Поэтому я вшил проверки в сам пайплайн — жёсткими гейтами, не warning-ами, а настоящими блокерами, которые останавливают билд:

  • Terraform compliance-проверки запускаются до любого деплоя, ловя ошибки конфигурации в источнике, а не когда они уже в проде.
  • Сканирование секретов на каждом коммите. Кред в диффе просто не доедет до main.
  • AWS Security Hub собирает находки по всем аккаунтам, а кастомные сканеры на Python закрывают те правила комплаенса, под которые нет готового инструмента.

Открытые security-группы, слишком широкий IAM, незашифрованный storage, публичные бакеты, отсутствие логирования — всё ловится автоматически, за минуты, а не раз в год, когда приходит аудитор.

Фраза, к которой я всё время возвращаюсь

Уязвимость без плана устранения — это просто тревога. Уязвимость, которую вообще никто не ищет, — это обратный отсчёт.

Пятьдесят пять переменных. Четырнадцать месяцев. Никто не смотрел — пока не посмотрел я. В этом вся разница между security-инцидентом и уборкой в среду после обеда. Так что задам тебе тот же неудобный вопрос, что задал себе: когда в последний раз кто-нибудь действительно проверял переменные твоих пайплайнов?