Хранить пароли рядом с кодом, но так, чтобы репозиторий можно было показать
В модуле 06 пароль базы лежал открытым текстом:
$ cat group_vars/db.yml
postgres_database: price
postgres_user: price_app
# Пароль открытым текстом — так делать нельзя; в модуле 07 он уедет в Ansible Vault
postgres_password: Uchebnyi-Parol-2026
Проект живёт в Git. Значит, пароль видит каждый, у кого есть доступ к репозиторию, он остаётся в истории навсегда и уезжает на каждый ноутбук, где проект склонирован. Хранить секреты отдельно от проекта неудобно: плейбук без них не работает, и при каждом запуске их приходится откуда-то брать. Ansible Vault шифрует файлы и значения прямо в проекте. Без ключа зашифрованное — набор цифр, с ключом Ansible расшифровывает его на лету при прогоне.
Если зашифровать весь group_vars/db.yml, никто без ключа не увидит даже, какие переменные там есть, и поиск по проекту перестанет их находить. Поэтому принято делить переменные группы на два файла в каталоге group_vars/db/ — Ansible читает все файлы каталога:
$ mkdir group_vars/db && mv group_vars/db.yml group_vars/db/vars.yml
$ printf "vault_postgres_password: Uchebnyi-Parol-2026\n" > group_vars/db/vault.yml
$ sed -i "s/^postgres_password: .*/postgres_password: \"{{ vault_postgres_password }}\"/; /^# Пароль открытым/d" group_vars/db/vars.yml
$ cat group_vars/db/vars.yml
postgres_database: price
postgres_user: price_app
postgres_password: "{{ vault_postgres_password }}"
vars.yml — открытый: все переменные группы, в том числе postgres_password, но вместо значения ссылка на vault_postgres_password.vault.yml — зашифрованный: только значения секретов, имена с префиксом vault_.Теперь по открытому файлу видно, что пароль есть и откуда он берётся, а поиск vault_postgres_password сразу ведёт к зашифрованному файлу.
Шифровать нужно ключом — паролем Vault. Его можно вводить при каждом запуске (--ask-vault-pass), но удобнее держать в файле вне проекта с правами только для владельца:
$ printf "%s\n" "Uchebnyi-Kluch-Vault-2026" > ~/.vault_pass && chmod 600 ~/.vault_pass
В .gitignore проекта на всякий случай есть и .vault_pass — если кто-то положит ключ в каталог проекта, Git его не возьмёт:
# пароль Vault в репозиторий не кладут никогда
.vault_pass
*.retry
Ключ хранят в менеджере паролей команды и выдают тем, кому нужно запускать плейбуки. Длинный случайный ключ лучше придуманного: зашифрованные файлы лежат в репозитории, и их можно подбирать сколько угодно долго без всяких ограничений.
$ ansible-vault encrypt --vault-password-file ~/.vault_pass group_vars/db/vault.yml
$ cat group_vars/db/vault.yml
$ANSIBLE_VAULT;1.1;AES256
62363965646533653866373734373932613561363935626464373137336562373961346464366132
3562373133316633653462383731653138323164666465620a623062666235353665663163306463
35633461303233323264323661396334613633623436366462376234623631613534356362393263
3130383261303833350a333132383237643031666531633237633931363061396530363831303635
38363263643264623838613839633063666161396635313965653338623533346533626562346464
3933623266363335366634363535343665316138643033323933
$ ansible-vault view --vault-password-file ~/.vault_pass group_vars/db/vault.yml
vault_postgres_password: Uchebnyi-Parol-2026
Первая строка — заголовок: формат Vault и алгоритм AES-256. Остальное — зашифрованное содержимое. Такой файл можно коммитить. Основные команды:
| Команда | Что делает |
|---|---|
ansible-vault encrypt файл | Зашифровать существующий файл на месте |
ansible-vault view файл | Показать расшифрованное, не сохраняя на диск |
ansible-vault edit файл | Открыть в редакторе и зашифровать обратно при сохранении |
ansible-vault decrypt файл | Расшифровать на месте — легко забыть зашифровать обратно и закоммитить |
ansible-vault rekey файл | Перешифровать новым ключом |
ansible-vault encrypt_string | Зашифровать одно значение для вставки в обычный YAML |
Править секреты — только через edit: расшифрованная копия не остаётся на диске и не попадёт в коммит.
Без ключа Ansible не может прочитать vault.yml и останавливается сразу, ничего не сделав:
$ ansible-playbook site.yml --limit db1 2>&1 | grep -E "ERROR|vault" | head -2
[ERROR]: Attempting to decrypt but no vault secrets found.
С ключом всё работает как раньше:
$ ansible-playbook site.yml --limit db1 --vault-password-file ~/.vault_pass 2>&1 | grep -E "^db1 "
db1 : ok=9 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Чтобы не писать ключ в каждой команде, путь к файлу ключа задают в ansible.cfg (vault_password_file = ~/.vault_pass) или переменной окружения ANSIBLE_VAULT_PASSWORD_FILE. Вместо файла можно указать исполняемый скрипт — он вернёт ключ из менеджера паролей или системного хранилища. В конвейере CI ключ кладут в защищённую переменную-файл и передают тем же параметром (курс Основы CI/CD).
Если у окружений разные секреты, у них могут быть и разные ключи: --vault-id prod@~/.vault_prod --vault-id stage@~/.vault_stage. Тогда разработчик с ключом stage сможет запускать плейбуки на тестовых узлах, но не расшифрует пароли боя.
Когда секрет один, а файл с ним в основном открытый, шифруют только значение. Результат вставляют прямо в YAML:
$ ansible-vault encrypt_string --vault-password-file ~/.vault_pass --name smtp_password "Pochta-Uchebnaya-2026"
smtp_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
34666166613339353463333034313935656664376463653764656166646530323335353030373364
3832326638393631363062323638633931613035373236650a336364343631383765333135396139
38396134666531333631343464663636316534613961663539323434643061343031353163616662
3834326561393838610a643234353233383634653432666264353235303232323533666166366361
62616536343832343165393931313561646639313337353561323732336231333335
Минус — по такому файлу неудобно делать ревью: изменение секрета выглядит как замена одного блока цифр другим. Для нескольких секретов схема vars/vault из раздела 02 удобнее.
Vault защищает секреты в репозитории. Во время прогона они расшифрованы и обычные переменные, которые можно вывести:
$ ansible db1 -m debug -a "var=postgres_password" --vault-password-file ~/.vault_pass
db1 | SUCCESS => {
"postgres_password": "Uchebnyi-Parol-2026"
}
Поэтому задачи, в параметрах которых есть секреты, помечают no_log: true — как задачу создания пользователя базы в роли postgres. Даже с подробным выводом -v её результат скрыт:
$ ansible-playbook site.yml --limit db1 --vault-password-file ~/.vault_pass -v 2>&1 | grep -A2 "Пользователь приложения"
TASK [postgres : Пользователь приложения] **************************************
ok: [db1] => {"censored": "the output has been hidden due to the fact that 'no_log: true' was specified for this result", "changed": false}
debug «для проверки» — журналы прогонов хранятся в CI и пересылаются в чаты.0600 или 0640 и нужным владельцем — расшифрованный пароль окажется на сервере.no_log скрывает и сообщения об ошибках задачи. Если такая задача падает, для отладки её временно запускают без no_log на тестовом узле, а не на боевом.Ушёл сотрудник, у которого был ключ, — ключ меняют. rekey перешифровывает файлы новым ключом:
$ printf "%s\n" "Novyi-Kluch-Vault-2026" > ~/.vault_pass.new && chmod 600 ~/.vault_pass.new
$ ansible-vault rekey --vault-password-file ~/.vault_pass --new-vault-password-file ~/.vault_pass.new group_vars/db/vault.yml
Rekey successful
$ mv ~/.vault_pass.new ~/.vault_pass && ansible-vault view --vault-password-file ~/.vault_pass group_vars/db/vault.yml
vault_postgres_password: Uchebnyi-Parol-2026
Важно: старые версии зашифрованных файлов остались в истории Git, и бывший сотрудник со старым ключом расшифрует их. Поэтому вместе с ключом Vault меняют и сами секреты — пароли баз, токены, — а потом шифруют новые значения новым ключом.
group_vars/группа/vault.yml с префиксом vault_; в vars.yml — ссылки на нихansible-vault edit, смотреть — view; decrypt на месте — путь к утечке--vault-idno_log: true