Ansible решает проблему встроенным инструментом - Ansible Vault. Идея простая: чувствительные данные лежат в репозитории, но в зашифрованном виде. Без пароля это бесполезный блок base64, а в момент запуска плейбука Ansible расшифровывает их в памяти. Ты коммитишь секреты спокойно, а ключ держишь отдельно. На экзамене EX294 этот навык спрашивают почти гарантированно, так что разберём его руками и до конца.
Что такое шифрование в Ansible и как устроен Vault
Vault - это не отдельный сервис и не демон, как HashiCorp Vault (их часто путают). Это утилита ansible-vault и поддержка шифрованных файлов внутри самого Ansible. Под капотом - симметричное шифрование AES256: один пароль и шифрует, и расшифровывает. Зашифрованный файл начинается со строки-заголовка вида
Код: Выделить всё
$ANSIBLE_VAULT;1.1;AES256Шифровать можно две вещи:
- целый файл переменных (например group_vars/db/vault.yml) - удобно, когда секретов много;
- отдельную переменную внутри обычного YAML через encrypt_string - удобно, когда секрет один-два, а остальное хочется видеть в открытом виде.
- create - создать новый шифрованный файл и сразу открыть редактор;
- edit - редактировать существующий, расшифровка и обратное шифрование происходят прозрачно;
- view - посмотреть содержимое, не редактируя;
- encrypt - зашифровать уже существующий открытый файл;
- decrypt - расшифровать обратно в открытый текст (осторожно, потом не закоммить случайно);
- rekey - сменить пароль шифрования, не трогая содержимое.

Ansible Vault на практике: пример с файлом и с encrypt_string
Начнём с самого частого сценария - шифрование ansible-переменных целым файлом. Лучшая практика, которую ждут и на проде, и на экзамене: держать секреты в отдельном файле group_vars/<группа>/vault.yml, а открытые переменные - рядом в vars.yml. Так в открытом файле ты видишь осмысленные имена, а значения подтягиваются из шифрованного.
Код: Выделить всё
# создаём шифрованный файл секретов для группы webservers
ansible-vault create group_vars/webservers/vault.yml
Код: Выделить всё
---
vault_db_password: "S3cr3t-Pa55!"
vault_api_token: "ghp_xxxxxxxxxxxxxxxxxxxx"
Код: Выделить всё
---
db_password: "{{ vault_db_password }}"
api_token: "{{ vault_api_token }}"
Код: Выделить всё
---
- name: Настройка веб-приложения
hosts: webservers
become: true
tasks:
- name: Положить конфиг приложения с секретами
ansible.builtin.template:
src: app.conf.j2
dest: /etc/myapp/app.conf
owner: root
group: root
mode: "0640"
no_log: true
Второй сценарий - encrypt_string, когда нужно зашифровать ровно одну переменную и вставить её в обычный незашифрованный файл. Это особенно показывают на экзамене, так что разберём подробно:
Код: Выделить всё
ansible-vault encrypt_string 'S3cr3t-Pa55!' --name 'db_password'
Код: Выделить всё
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336462626566653063336164663966303231363934653561363
39383236303664656265656132643135313964353936313731633165633563366
...
Код: Выделить всё
ansible-vault encrypt_string --vault-id dev@~/.vault_pass_dev \
--stdin-name 'db_password'
Ansible vault password: как запускать плейбук и где хранить ключ
Если в деле есть хоть один шифрованный файл, обычный ansible-playbook упадёт с ошибкой "Attempting to decrypt but no vault secrets found". Нужно дать Ansible пароль. Способов два.
Интерактивно - спросить пароль при запуске:
Код: Выделить всё
ansible-playbook site.yml --ask-vault-pass
Код: Выделить всё
ansible-playbook site.yml --vault-password-file ~/.vault_pass
Код: Выделить всё
[defaults]
vault_password_file = ~/.vault_pass
Когда хранилищ несколько (например, отдельные пароли для dev и prod), включается vault-id. Каждому хранилищу даёшь метку и свой файл:
Код: Выделить всё
ansible-playbook site.yml \
--vault-id dev@~/.vault_pass_dev \
--vault-id prod@~/.vault_pass_prod
Код: Выделить всё
ansible-vault rekey group_vars/webservers/vault.yml
ansible-vault rekey --new-vault-id prod@~/.vault_pass_new \
--vault-id prod@~/.vault_pass_old group_vars/webservers/vault.yml
- Закоммитил расшифрованный файл после decrypt и не зашифровал обратно. Секрет уже в истории. Лечится только ротацией пароля у сервиса, не самим vault.
- Забыл no_log: true в задаче с секретом. При -vvv или ошибке пароль уходит в вывод и в логи CI.
- Положил .vault_pass рядом с плейбуком и закоммитил. Шифрование теряет смысл - ключ лежит в том же репо.
- Права на файл пароля не 0600. Ansible может ругаться, а соседи по серверу - читать твой ключ.
- Пытаешься grep по значению секрета и не находишь. Внутри vault его нет в открытом виде - ищи по имени переменной, отсюда и соглашение с префиксом vault_.
- Перепутал ansible-vault и HashiCorp Vault. Это разные вещи: первое - шифрование файлов, второе - отдельный сервис хранения секретов.
- Создай ansible-vault create group_vars/db/vault.yml и положи туда vault_db_password.
- Свяжи его в group_vars/db/vars.yml через db_password: "{{ vault_db_password }}".
- Отдельно зашифруй один токен через encrypt_string --name и вставь блок в обычный vars.yml.
- Запусти плейбук сначала с --ask-vault-pass, потом настрой vault_password_file в ansible.cfg и запусти без флага.
- Сделай rekey файла на новый пароль и проверь, что плейбук всё ещё проходит.
- Открой view на шифрованный файл и убедись, что edit/encrypt/decrypt работают как ожидаешь.
Контрольные вопросы
- Чем отличается шифрование целого файла от encrypt_string и когда что выбирать?
- Какие два способа передать ansible vault password при запуске плейбука и какой подходит для CI?
- Зачем нужно соглашение с префиксом vault_ и связкой через vars.yml?
- Что делает rekey и почему он не спасает, если расшифрованный файл уже попал в git?
Ansible Vault даёт честный способ хранить пароли и токены в репозитории, не раскрывая их. Запомни связку: ansible-vault create/edit/view/rekey для файлов, encrypt_string для одиночных переменных, запуск через --ask-vault-pass или --vault-password-file, а ключ - всегда вне git и с правами 0600. Этого хватит и для прода, и чтобы спокойно пройти задание по vault на EX294.