- Первый шаг задачи закрыт коммитом b7b1f49; остались вынос секретов в файлы и проверка от дрейфа. - Записано исключение: compose miniflux оставлен без no_log, из vault он тянет только имя пользователя и имя базы.
7.7 KiB
Никаких секретов в выводе плейбуков
Приоритет: Высокий
inv pl всегда запускает ansible-playbook --diff, поэтому любая задача
template/copy, чей целевой файл содержит переменную vault, печатает значение
в терминал — целой строкой, при каждом изменении файла. no_log: true стоит
ровно в одном месте на весь репозиторий (roles/secrets), и именно поэтому
miniflux деплоится молча, а остальные — нет.
Это тот же класс, что инцидент 24 июля: секрет попадает не в vault-файл, а в поток вывода, у которого нет никакой модели угроз. Скроллбек терминала, мультиплексор, лог CI, транскрипт агента — всё это места, куда расшифрованному значению попадать не должно, и куда оно попадает бесплатно.
Инвентарь (сверено 2026-07-25)
Задачи без no_log, рендерящие файл с секретом:
- backups —
config.template.toml,restic-shell.template.sh,rclone.template.conf: пароли репозиториев restic, ключи S3, доступ rclone - authelia —
configuration.template.yml: jwt-секрет, секрет сессий, ключ шифрования хранилища, hmac и jwks OIDC, четыре client secret, SMTP; плюсusers.secrets.yml— vault-файл копируется как есть, дифф покажет его расшифрованным - transcriber —
config.secrets.toml, тоже vault-файл копией - bifrost —
config.template.json: ключ DeepSeek, ключ шифрования - apprise —
server.template.cfg: токен бота Telegram, SMTP - remembos —
config.template.toml: токены memos и Telegram - outline, tududi, wakapi, wanderer, gramps, gitea — секреты в
environment:docker-compose, см. серию задачsecrets-file-*
Чисто: miniflux (образец), memos, calibre, tuwunel, dashboard, caddy, netdata, dozzle, goaccess, rssbridge, homepage.
Отдельным пунктом — docker_login в homepage, transcriber и remembos:
yc_oauth_token идёт параметром модуля. По умолчанию аргументы не печатаются, но
всплывают при -v и в отчёте о падении. Закрывается тем же no_log, а совсем
уходит после local-image-build.
Рычаги и их цена
no_log: trueна задачу — прячет результат целиком, включая дифф. Так уже сделано вroles/secrets. Цена: не видно, что именно изменилось; на отладке снимать руками.diff: falseна задачу — прячет только содержимое диффа, статусchangedостаётся виден. Хирургичнее, но не закрывает вывод при падении задачи, поэтому для файлов, состоящих из одних секретов, слабее.- Структурный вынос — секрет живёт в отдельном файле, который рендерит роль
secretsподno_log, а основной файл ссылается на путь. Тогда дифф основного файла остаётся полезным. Это серияsecrets-file-*, но она проenvironment:и не покрывает конфиги. - Убрать
--diffизinv plили выставить глобальныйANSIBLE_NO_LOG— режет обзор на всех задачах разом ради десятка проблемных. Не годится.
Порядок
— сделано (коммитno_log: trueна весь инвентарь вышеb7b1f49, 2026-07-25): пятнадцать задач-рендеров и триdocker_login, всего 13 плейбуков. Не подno_logосталась одна задача — compose miniflux: он тянет из vault толькоminiflux_postgres_userиminiflux_postgres_database, а это имя пользователя и имя базы, не секреты (вsecrets_varsролиsecretsих нет). Дифф образцового файла оставлен читаемым сознательно.- Где файл смешанный (compose, конфиг authelia) — вернуться и вынести секреты в
отдельные файлы, сняв
no_logс основного: он нужен ради диффа, который сейчас и теряется. Что именно умеет каждое приложение — матрица в справке, сверенная по исходникам, и задачиsecrets-file-*по одной на приложение. Для authelia (конфиг на тысячу строк, дифф там самый ценный) ответ такой: пять полей закрываютсяAUTHELIA_..._FILE, оставшиеся два — только template-фильтром, а четыреclient_secretштатно хранятся хэшем и тогда вообще перестают быть секретами. Для tududi и wanderer ответа нет: они не умеют читать секреты из файлов, иno_logдля них — не первый шаг, а единственный. - Защита от дрейфа: проверка в lefthook или CI — если шаблон ссылается на
переменную, которой нет в открытых
group_vars/vars, задача, которая его рендерит, обязана иметьno_log. Иначе следующее приложение заведут по образцу без него. Единственное исключение на сегодня — miniflux (см. шаг 1); чище не заводить исключение в правиле, а перенестиminiflux_postgres_userиminiflux_postgres_databaseиз vault вgroup_vars/all/main.yml— секретами они не являются. Правка в зашифрованном файле, поэтому за пользователем.
Готово, когда первый (создающий все файлы) прогон любого плейбука не печатает ни одного значения из vault, и это держится проверкой, а не вниманием.
Попутно стоит выяснить, почему молчит правило no-log-password в ansible-lint:
похоже, оно смотрит на список модулей с параметром password, а не на содержимое
шаблонов — тогда на него в этой задаче полагаться нельзя.
Связано: tasks.py (inv pl), roles/secrets (образец), files/backups,
files/authelia, files/bifrost, files/apprise, files/remembos,
files/transcriber/config.secrets.toml,
vault-password-storage,
narrow-secret-scopes.