opened image

Ansible Vault: шифрование секретов в плейбуках

 

Пароли баз данных, API-ключи и токены в Ansible-плейбуках нельзя хранить открытым текстом — они попадут в Git-историю и будут видны всем участникам репозитория. Ansible Vault шифрует файлы с секретами алгоритмом AES-256. Зашифрованные файлы безопасно коммитить в Git, а пароль vault хранится отдельно. В статье разберём создание vault-файла, использование в playbook и best practices.

 

 

Установка Ansible

 

Если Ansible ещё не установлен:

# Ubuntu 22.04 / 24.04
sudo apt update
sudo apt install ansible -y

# Проверка версии
ansible --version
# ansible [core 2.16.3]

 

 

Создание vault-файла

 

ansible-vault create

 

Создаём новый зашифрованный файл:

ansible-vault create group_vars/all/vault.yml

 

Vault запросит пароль дважды, затем откроет редактор (по умолчанию vi). Введите секреты в формате YAML:

# Содержимое vault.yml (до шифрования)
vault_db_password: "SuperSecretPassword123!"
vault_api_key: "sk-proj-abc123xyz456"
vault_smtp_password: "MailPass!99"
vault_redis_password: "RedisSecret2025"

 

После сохранения и выхода файл будет зашифрован. Содержимое файла:

$ANSIBLE_VAULT;1.1;AES256
36343161326533633037363032623437633861313839613932613465333632303034666130
3361613662336530306135356135313766636662303163610a333563616232353834373864
...

 

 

 

ansible-vault encrypt

 

Если файл уже существует в открытом виде — зашифровать его:

ansible-vault encrypt group_vars/all/vault.yml

 

Расшифровать для просмотра:

ansible-vault decrypt group_vars/all/vault.yml
# ОСТОРОЖНО: файл становится открытым на диске

 

Просмотреть без расшифровки на диске:

ansible-vault view group_vars/all/vault.yml

 

Редактировать зашифрованный файл:

ansible-vault edit group_vars/all/vault.yml
# Открывает редактор, шифрует обратно при сохранении

 

Сменить пароль vault:

ansible-vault rekey group_vars/all/vault.yml

 

 

Структура переменных

 

Рекомендуемая практика: хранить незашифрованные переменные в одном файле, зашифрованные в другом. Незашифрованный файл ссылается на переменные из vault.

 

Структура:

inventory/
    group_vars/
        all/
            vars.yml        <- открытые переменные
            vault.yml       <- зашифрованные секреты
        webservers/
            vars.yml
            vault.yml
    host_vars/
        web-01/
            vars.yml
            vault.yml

 

Файл group_vars/all/vars.yml (открытый, коммитится в Git):

# Параметры БД
db_host: "db.internal.example.com"
db_port: 5432
db_name: "myapp_production"
db_user: "myapp"
db_password: "{{ vault_db_password }}"

# API
api_endpoint: "https://api.example.com/v2"
api_key: "{{ vault_api_key }}"

# SMTP
smtp_host: "smtp.sendgrid.net"
smtp_port: 587
smtp_user: "apikey"
smtp_password: "{{ vault_smtp_password }}"

 

Файл group_vars/all/vault.yml (зашифрованный):

vault_db_password: "SuperSecretPassword123!"
vault_api_key: "sk-proj-abc123xyz456"
vault_smtp_password: "MailPass!99"

 

Такой подход удобен: в vars.yml видна структура конфигурации (имена переменных, логика), а секреты изолированы в vault.yml.

 

 

Использование vault в playbook

 

Если vault-файлы находятся в group_vars/ или host_vars/, Ansible подхватывает их автоматически. Явно указывать через vars_files не нужно.

 

Playbook deploy.yml:

---
- name: Deploy application
  hosts: webservers
  become: yes

  tasks:
    - name: Install required packages
      ansible.builtin.apt:
        name:
          - python3
          - python3-pip
        state: present
        update_cache: yes

    - name: Configure database connection
      ansible.builtin.template:
        src: templates/database.conf.j2
        dest: /etc/myapp/database.conf
        owner: myapp
        group: myapp
        mode: "0640"
      notify: Restart application

    - name: Set API key in environment
      ansible.builtin.lineinfile:
        path: /etc/myapp/environment
        line: "API_KEY={{ api_key }}"
        regexp: "^API_KEY="
        create: yes

  handlers:
    - name: Restart application
      ansible.builtin.systemd:
        name: myapp
        state: restarted

 

 

Шаблон templates/database.conf.j2:

[database]
host = {{ db_host }}
port = {{ db_port }}
name = {{ db_name }}
user = {{ db_user }}
password = {{ db_password }}

 

Переменная db_password подтянет значение из vault_db_password через цепочку в vars.yml.

 

Для явного указания vault-файла через vars_files:

- name: Deploy with explicit vault
  hosts: webservers
  vars_files:
    - group_vars/all/vars.yml
    - group_vars/all/vault.yml
  tasks:
    ...

 

 

 

 

Хранение пароля vault в файле .vault_pass

 

Вводить пароль вручную при каждом запуске неудобно. Храним пароль в файле:

# Создаём файл с паролем
echo "ВашПарольVault2025" > ~/.vault_pass
chmod 600 ~/.vault_pass

 

Никогда не коммитьте .vault_pass в Git. Добавьте в .gitignore:

.vault_pass
*.vault_pass

 

Запуск playbook без ввода пароля вручную:

ansible-playbook deploy.yml --vault-password-file ~/.vault_pass

 

Или в ansible.cfg:

[defaults]
vault_password_file = ~/.vault_pass
inventory = inventory/

 

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

ansible-playbook deploy.yml
ansible-vault edit group_vars/all/vault.yml

 

 

Несколько vault-паролей

 

Ansible поддерживает несколько vault ID — для разных окружений или уровней секретности.

# Создаём vault с ID "production"
ansible-vault create --vault-id production@~/.vault_pass_production group_vars/production/vault.yml

# Создаём vault с ID "staging"
ansible-vault create --vault-id staging@~/.vault_pass_staging group_vars/staging/vault.yml

 

Запуск с несколькими vault:

ansible-playbook deploy.yml \
  --vault-id production@~/.vault_pass_production \
  --vault-id staging@~/.vault_pass_staging

 

 

CI/CD интеграция

 

В GitHub Actions / GitLab CI пароль vault передаётся через секрет репозитория:

# GitHub Actions
- name: Run Ansible playbook
  run: |
    echo "${{ secrets.VAULT_PASSWORD }}" > /tmp/.vault_pass
    chmod 600 /tmp/.vault_pass
    ansible-playbook deploy.yml --vault-password-file /tmp/.vault_pass
    rm /tmp/.vault_pass

 

 

В GitLab CI:

deploy:
  script:
    - echo "$VAULT_PASSWORD" > /tmp/.vault_pass
    - chmod 600 /tmp/.vault_pass
    - ansible-playbook deploy.yml --vault-password-file /tmp/.vault_pass
    - rm /tmp/.vault_pass

 

 

 

 

 

Шифрование отдельных строк

 

Иногда нужно зашифровать одно поле прямо в незашифрованном YAML-файле:

ansible-vault encrypt_string 'SuperSecret123' --name 'db_password'

 

Вывод:

db_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          61613962356633303031383339353233666239356435623362623061353766633337373761363863
          ...

 

Вставьте этот блок прямо в vars.yml. Файл остаётся незашифрованным, но конкретная переменная защищена.

 

 

Best practices

 

1. Называйте vault-переменные с префиксом vault_ Это сразу показывает что переменная из vault: vault_db_password вместо просто db_password.

2. Не шифруйте всё подряд Шифруйте только реальные секреты. Имена хостов, порты и имена пользователей — открытые данные, их шифровать не нужно.

3. Один vault-файл на окружение Разделяйте секреты production и staging. Если staging-ключ утечёт — production не пострадает.

4. Ротация паролей Меняйте vault-пароль при уходе сотрудника: ansible-vault rekey. Новый пароль рассылается только действующим членам команды.

5. Проверяйте что vault зашифрован перед коммитом Добавьте pre-commit hook:

# .git/hooks/pre-commit
#!/bin/bash
for file in $(git diff --cached --name-only | grep vault); do
    if ! grep -q "ANSIBLE_VAULT" "$file"; then
        echo "ERROR: $file is not encrypted!"
        exit 1
    fi
done
chmod +x .git/hooks/pre-commit

 

 

Итог

 

Ansible Vault защищает секреты через AES-256 шифрование. Рабочая схема: секреты в vault.yml с префиксом vault_, открытые переменные в vars.yml со ссылками на vault-переменные, пароль vault в ~/.vault_pass с правами 600. В CI/CD пароль vault передаётся через секрет репозитория в переменную окружения.

Разделение на vars.yml + vault.yml удобнее чем шифрование всего файла целиком: видна структура конфигурации, легче ревьюить изменения.