Ansible: использование Vault – зашифрованного хранилища

By | 05/13/2018
 

Начиная с версии 1.5 в Ansible была доабвлена возможность хранения секретных данных, таких как пароли или RSA ключи, в зашифрованных файлах – vault (“хранилище”).

Для работы с такими хранилищами используется утилита ansible-vault, которая принимает два основных аргумента – --ask-vault-pass или --vault-password-file, которые могут быть заданы через ansible.cfg.

Располагается в /usr/bin/ansible-vault и представялет собой Python-скрипт.

 

Шифрование файлов

Для создания хранилища – используется create:

ansible-vault create file.yml
New Vault password:
Confirm New Vault password:

После чего открывается редактор по умолчанию, что бы в файл можно было добавить данные.

Результат:

cat file.yml
ANSIBLE_VAULT;1.1;AES256
32333262313562656230663934383566373966633138346137313937306230373633333730343839
6330346166626235376530333662663961636365393631340a623165306231383636643066306665
39303633623361643065636338326336333366656363313762316336623732626631643437336663
6466336232316131390a316464383837623361333964383235616365316263336565336136663063
6635

Что бы зашифровать уже имеющий файл – используется encrypt:

echo "data" > raw_file.txt
ansible-vault encrypt raw_file.txt
New Vault password:
Confirm New Vault password:
Encryption successful
cat raw_file.txt
ANSIBLE_VAULT;1.1;AES256
65303737323263313938656134323635313039363131626331643835393034323335343432383438
3232643162313534643231613661623264656365663437650a353661376235346134313362653066
64393066333937373334353361623735366334666463346633613463373532646535636566663831
3434623235653933650a313038343833323236623061633065323266336237623461383930646662
6538

Расшифровка файлов

Что бы зашифрованный файл снова вернуть в plaintext – используем decrypt:

ansible-vault decrypt file.yml
Vault password:
Decryption successful
cat file.yml
test data

Редактирование файлов

Используется ansible-vault edit:

ansible-vault edit file.yml
Vault password:

Файл расшифровывается во временный файл, открывается для редактирования, после завершения – снова шифруется и сохраняется в старом месте:

Просмотр файла

Что бы просто просмотреть содержимое хранилища – используем view.

Шифруем файл опять:

ansible-vault encrypt file.yml
New Vault password:
Confirm New Vault password:
Encryption successful

И проверяем содержимое:

ansible-vault view file.yml
Vault password:
test data

Смена пароля

Для смены пароля используется rekey, который можно применять к нескольким файлам сразу, если они зашифрованы одним ключём (паролем).

Создадим новый:

ansible-vault create file2.yml
New Vault password:
Confirm New Vault password:

И меняем пароль для обоих файлов:

ansible-vault rekey file.yml file2.yml
Vault password:
New Vault password:
Confirm New Vault password:
Rekey successful

Примеры

Прмиеры будем запускать на локальной машине.

Пример использования зашифрованного файла

Создаём простой плейбук helloworld.yml:

---
- hosts: all
  tasks:
    - debug:
        msg: "hello world"

Проверяем:

ansible-playbook -i "localhost," -c local helloworld.yml
PLAY [all] ****
TASK [Gathering Facts] ****
ok: [localhost]
TASK [debug] ****
ok: [localhost] => {
"msg": "hello world"
}
PLAY RECAP ****
localhost                  : ok=2    changed=0    unreachable=0    failed=0

ОК, теперь добавим создание файла с текстом из зашифрованного файла в Ansible.

Создаём файл vars/exmple_text.yml со строкой:

data_text: |
  some text data
  another text data

Создаём файл с паролем:

echo “MySuperPass” > ~/.ansible_pass.txt

Шифруем файл vars/exmple_text.yml:

ansible-vault encrypt vars/exmple_text.yml --vault-password-file ~/.ansible_pass.txt
Encryption successful

Проверяем его:

head -n 2 vars/exmple_text.yml
ANSIBLE_VAULT;1.1;AES256
33303034383034313365383135323837613963646235393533643361343061306336373236663837

Обновляем наш helloworld.yml, добавляем создание файла, который будет содержать текст :

---
- hosts: all
  tasks:
    - debug:
        msg: "hello world"
    - name: add var
      include_vars:
        file: exmple_text.yml
    - name: Add descrypted text from exmple_text.yml
      copy:
        content="{{ data_text }}"
        dest=/tmp/example_text_out.txt

Запускаем, передавая --vault-password-file:

ansible-playbook -i "localhost," -c local helloworld.yml --vault-password-file ~/.ansible_pass.txt
PLAY [all] ****
TASK [Gathering Facts] ****
ok: [localhost]
TASK [debug] ****
ok: [localhost] => {
"msg": "hello world"
}
TASK [add var] ****
ok: [localhost]
TASK [Add descrypted text from exmple_text.yml] ****
changed: [localhost]
PLAY RECAP ****
localhost                  : ok=4    changed=1    unreachable=0    failed=0

Проверяем:

cat /tmp/example_text_out.txt
some text data
another text data

Всё на месте.

Пример шифрования переменной

Кроме файла – можно зашифровать строку, например:

ansible-vault encrypt_string
New Vault password:
Confirm New Vault password:
Reading plaintext input from stdin. (ctrl-d to end input)
This is Text String
!vault |
ANSIBLE_VAULT;1.1;AES256
38363965343563353962666264646337613464663263663632626264373563633430323633356639
3737333233393662336533376661333163653035333334370a373565343330633537363563656430
37363632636664353864353532633030326231356238643634623033396539656164666437343565
3964653033343136620a356438316635663561313665323739353766383233656261646538616165
66313237633635646265653633323635333861636539313937343363666539366465
Encryption successful

Либо выполнить одной командой:

ansible-vault encrypt_string "This is Text String" --name "encrypted_data_string" --vault-password-file ~/.ansible_pass.txt
encrypted_data_string: !vault |
ANSIBLE_VAULT;1.1;AES256
36653162656434373362396464353061343337343866323436366138636266666165636163623337
3339343833383064303036346661616235396563356362630a363430313566323537363964663636
32303931333561633632323265346136323139616536343466663736666138333638306133653935
3066643730653831300a663735333639343064666636336139336536353734343963313032373338
35643639643136623163346662623763633763366462396433323133306532663038
Encryption successful

Далее эта строка может использоваться в переменной.

Добавим новый файл vars/strings.yml с переменной encrypted_data_string:

---
encrypted_data_string: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          36653162656434373362396464353061343337343866323436366138636266666165636163623337
          3339343833383064303036346661616235396563356362630a363430313566323537363964663636
          32303931333561633632323265346136323139616536343466663736666138333638306133653935
          3066643730653831300a663735333639343064666636336139336536353734343963313032373338
          35643639643136623163346662623763633763366462396433323133306532663038

Обновим плейбук:

---
- hosts: all
  tasks:
    - debug:
        msg: "hello world"
    - name: add vars
      include_vars:
        file: exmple_text.yml
    - name: add another vars
      include_vars:
        file: strings.yml
    - name: Add decrypted text from exmple_text.yml
      copy:
        content="{{ data_text }}"
        dest=/tmp/example_text_out.txt
    - name: Add another decrypted text from strings.yml
      copy:
        content="{{ encrypted_data_string }}"
        dest=/tmp/another_example_text_out.txt

Запускаем выполнение:

ansible-playbook -i "localhost," -c local helloworld.yml --vault-password-file ~/.ansible_pass.txt
PLAY [all] ****
TASK [Gathering Facts] ****
ok: [localhost]
TASK [debug] ****
ok: [localhost] => {
"msg": "hello world"
}
TASK [add vars] ****
ok: [localhost]
TASK [add another vars] ****
ok: [localhost]
TASK [Add decrypted text from exmple_text.yml] ****
ok: [localhost]
TASK [Add another decrypted text from strings.yml] ****
changed: [localhost]
PLAY RECAP ****
localhost                  : ok=6    changed=1    unreachable=0    failed=0

Проверяем:

cat /tmp/another_example_text_out.txt
This is Text String

Или используя --ask-vault-pass:

ansible-playbook -i “localhost,” -c local helloworld.yml --ask-vault-pass
Vault password:

vault-id

В Ansible 2.4 и выше вместо --ask-vault-pass и --vault-password-file можно использовать --vault-id, который позволяет использовать разные пароли для разных файлов.

Создадим новые файлы вместо exmple_text.yml и strings.yml, зашифруем их разными паролями.

Файлы паролей:

echo "pass1" > pass1.txt
echo "pass2" > pass2.txt

Создаём файл vars/data_text1.yml с переменной data_text1:

echo “data_text1: Data Text One” > vars/data_text1.yml

Шифруем его паролем из файла pass1.txt:

ansible-vault --vault-id pass1.txt encrypt vars/data_text1.yml
Encryption successful

Аналогично – второй файл:

echo “data_text2: Data Text Two” > vars/data_text2.yml

И тоже шифруем его, вторым паролем:

ansible-vault --vault-id pass2.txt encrypt vars/data_text2.yml
Encryption successful

Обновим плейбук:

---
- hosts: all
  tasks:
    - debug:
        msg: "hello world"
    - name: add data_text1.yml 
      include_vars:
        file: data_text1.yml 
    - name: add data_text2.yml 
      include_vars:
        file: data_text2.yml 
    - name: Add decrypted data_text1
      copy:
        content="{{ data_text1 }}"
        dest=/tmp/data_text1_out.txt
    - name: Add decrypted data_text2
      copy:
        content="{{ data_text2 }}"
        dest=/tmp/data_text2_out.txt

И запускаем его:

ansible-playbook -i "localhost," -c local --vault-id pass1.txt --vault-id pass2.txt helloworld.yml
PLAY [all] ****
TASK [Gathering Facts] ****
ok: [localhost]
TASK [debug] ****
ok: [localhost] => {
"msg": "hello world"
}
TASK [add data_text1.yml] ****
ok: [localhost]
TASK [add data_text2.yml] ****
ok: [localhost]
TASK [Add decrypted data_text1] ****
changed: [localhost]
TASK [Add decrypted data_text2] ****
changed: [localhost]
PLAY RECAP ****
localhost                  : ok=6    changed=2    unreachable=0    failed=0

Проверяем:

cat /tmp/data_text*
Data Text OneData Text Two

Так же --vault-id можно использовать вместе с --vault-password-file:

rm /tmp/data_text*
ansible-playbook -i "localhost," -c local --vault-id pass1.txt --vault-password-file pass2.txt helloworld.yml
...
localhost                  : ok=6    changed=2    unreachable=0    failed=0

Либо использовать --ask-vault-pass вместо указания файла:

rm /tmp/data_text*
ansible-playbook -i "localhost," -c local --vault-id pass1.txt --ask-vault-pass helloworld.yml
Vault password:
...
localhost                  : ok=6    changed=2    unreachable=0    failed=0

Сам --vault-password-file тоже можно использовать несколько раз:

ansible-playbook -i "localhost," -c local --vault-password-file pass1.txt --vault-password-file pass2.txt helloworld.yml

Ansible попробует каждый из переданных паролей, пока один из них не сработает для зашированного файла.

Ссылки по теме

Ansible Vault

2.4 support for multiple vault passwords, looking for feedback

How Ansible Vault Works

Working with ansible-vault