Ansible Vaultを利用して秘密情報を暗号化する

ANSIBLE

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

今日はAnsible VaultというAnsibleの暗号化ツールの紹介です。

Ansible Vault

Ansibleは各種設定をYAML形式で記載していきます。YAMLは単なるテキスト情報ですので、そのファイルを開く権限さえ持っていれば誰でもそこに記載された情報を確認することができます。ですが、例えばプロジェクト内でAnsibleのPlaybookを共有する時に、SSHの秘密鍵やDBへの接続情報などの秘密情報は、プロジェクトメンバー全員が知る必要はないはずです。

そういった時にAnsible Vaultを使うと、ファイルの内容が暗号化され、ファイルを開いただけでは内容を確認することができなくなります。公開すべきでない情報に関してはAnsible Vaultを利用して暗号化しておきましょう。

早速試してみます。

導入

Ansible Vaultは、Ansibleをインストールすると一緒に導入されるansible-vaultコマンドを利用して行います。

流れとしては以下の通りです。簡単ですね。 - YAMLファイルをansible-vaultコマンドを使って編集する。 - その時にパスワードを設定することで、そのパスワードを利用してファイル内容を暗号化する - ansible-playbookコマンドを実行する時にそのパスワードを与えることでファイル内容を復号化し、通常のAnsible Playbookとして利用できるようにする。

それでは早速試してみます。今回は例として、Ansibleで以下の設定を行うPlaybookを作成します。

  • OSユーザ、グループの作成
  • SSH秘密鍵の配置

OSユーザとグループの作成には、それぞれAnsibleのuserモジュールとgroupモジュールを利用します。秘密鍵の配置にはauthorized_keyモジュールが利用できます。

作成対象のユーザと、そのユーザに割り当てるSSHの公開鍵を、Ansibleで利用する変数を定義するgroup_vars/allに記載します。今回はこのファイルをAnsible Vaultでの暗号化対象にします。 記載する内容は以下の通りです。(SSH公開鍵はブログのためにダミーとして作成したものです)

users:
  userA:
    authorized_key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC85yp9hJ8RfclyE1mgQT4rHtDuNIiWQDdaYzmwIJImr9LUycGm4OGjGoxQZ49xHZNisVNbyuWtaGkZ0hy1cLwuH6HkcYu8eMY9NZr5ZuSF7zRDY/vilM2j1Cw8hQ8tajvDfIXwFEhPS78mSCe3lamazbhyEghcUoBq/YGoVnE1SN3mNs0YaogJ5lHH8hdF8Ji+X3nHBnmvsiX+ROj1dL0b/qvHba9vZ3+6KCcbVWvqHbn8L0bbHZShygKobr6eAszOy4j0AgvuYi6naN66RybeRFkYFij6bQHlNKDh692vkKLVAuOrFbqXs0eTCo1SIc0K7xpPyk0A7pIh4YD0BHs9 userA_key'
  userB:
    authorized_key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0NgZhWXfpQPhLrIFPXL3kdJlsI+NOvbHltacQ4kgACbhg1CSjt4EOhxIOv8vXzRql0ylCxNWGF4z/LOx0pB4F7XQzJcso6xMpAZY5AmM3nEQyxWqL1t+90VykHjOLiGF+SWdNGD9vwC48wCLpJZCVC2QXVuZxTXdoC6inxAMAwDJmbRJq9Oe9zOiMXDjrT65nHamggL27J0YoVJRYX+Eh9Q9E4CO268ljTxDHjVJgs6EUruf1sW3uT63LOcm3b/DVwhz7Hm+xEIKUnmiweGHNYL7QsACOo0VjpQLES6UUPc/vktpZoxarI9Vqm+IdRGyaiQeiRwadg0u4h8Jrl7K5 userB_key'

さて、この内容をansible-vaultコマンドを利用して記入します。

$ mkdir group_vars
$ ansible-vault create group_vars/all
Vault password: # パスワードを入力
Confirm Vault password: # もう一度入力

# 編集画面が開くので、上記のYAML内容を記載して、保存して終了

完了です。ファイルの中身を覗いてみます。

$ head -n 5 group_vars/all
$ANSIBLE_VAULT;1.1;AES256
34313733373565323464366131636462366637366335636464643138643536313831643261316561
3662303832336239663365363465396532633734393730320a366337396234363935323933376265
33376361383838383761343134663032643066626466386336383133306636646664616437303465
6632626363333862380a636236383333333166333965633034303863663162323231636438376130

ファイルの内容が暗号化されていることが確認できました。このファイルの内容を再度編集する場合には ansible-vault edit group_vars/allコマンドでOKです。

実行するPlaybookの内容は以下の通りです。

- hosts: all
  sudo: yes
  tasks:
  - name: be sure group is created
    group: >
      name={{ item.key }}
      state=present
    with_dict: "{{ users }}"

  - name: be sure user is created
    user: >
      name={{ item.key }}
      group={{ item.key }}
      state=present
    with_dict: "{{ users }}"

  - name: be sure correct authorized_keys are registered
    authorized_key: >
      user={{ item.key }}
      key="{{ item.value.authorized_key }}"
    with_dict: "{{ users }}"

AnsibleのLoop用関数であるwith_dictを利用して、group_vars/allに記載されたユーザぶんだけユーザ・グループの作成とSSH公開鍵の登録を実施しています。 - Loops — Ansible Documentation

実行

ではPlaybookを実行します。上述の通り、実行時に暗号化した際のpasswordを入力することが求められます。passwordの指定方法は2種類あります。 - --ask-vault-passオプションを付ける: 対話式にパスワードを入力する - --vault-password-fileオプションを付ける: パスワードの記載されたファイルを指定する

今回は--ask-vault-pass方式で実行します。

$ ansible-playbook -i hosts main.yml --ask-vault-pass
Vault password: # 作成した際のパスワードを入力。

PLAY [all] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [xx.yy.xx.yy]

TASK: [be sure group is created] ****************************************
ok: [xx.yy.xx.yy] => (item={'key': 'userB', 'value': {'authorized_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0NgZhWXfpQPhLrIFPXL3kdJlsI+NOvbHltacQ4kgACbhg1CSjt4EOhxIOv8vXzRql0ylCxNWGF4z/LOx0pB4F7XQzJcso6xMpAZY5AmM3nEQyxWqL1t+90VykHjOLiGF+SWdNGD9vwC48wCLpJZCVC2QXVuZxTXdoC6inxAMAwDJmbRJq9Oe9zOiMXDjrT65nHamggL27J0YoVJRYX+Eh9Q9E4CO268ljTxDHjVJgs6EUruf1sW3uT63LOcm3b/DVwhz7Hm+xEIKUnmiweGHNYL7QsACOo0VjpQLES6UUPc/vktpZoxarI9Vqm+IdRGyaiQeiRwadg0u4h8Jrl7K5 userB_key'}})
ok: [xx.yy.xx.yy] => (item={'key': 'userA', 'value': {'authorized_key': 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC85yp9hJ8RfclyE1mgQT4rHtDuNIiWQDdaYzmwIJImr9LUycGm4OGjGoxQZ49xHZNisVNbyuWtaGkZ0hy1cLwuH6HkcYu8eMY9NZr5ZuSF7zRDY/vilM2j1Cw8hQ8tajvDfIXwFEhPS78mSCe3lamazbhyEghcUoBq/YGoVnE1SN3mNs0YaogJ5lHH8hdF8Ji+X3nHBnmvsiX+ROj1dL0b/qvHba9vZ3+6KCcbVWvqHbn8L0bbHZShygKobr6eAszOy4j0AgvuYi6naN66RybeRFkYFij6bQHlNKDh692vkKLVAuOrFbqXs0eTCo1SIc0K7xpPyk0A7pIh4YD0BHs9 userA_key'}})

<中略...>
PLAY RECAP ********************************************************************
xx.yy.xx.yy                : ok=4    changed=2    unreachable=0    failed=0

実行が確認できました。

注意点

実行して気になったのは、パスワード化した秘密鍵が標準出力に書かれてしまっていることです。できればこれを非表示にしたかったのですが、やり方を見つけることができませんでした。

6/18 05:30追記: コメントにてご指摘をいただきました。 変数の標準出力への書き込みを抑制するには、各タスクやPlaybookにno_log: Trueを記載すればOKです。 - Frequently Asked Questions — Ansible Documentation

ansible-playbook実行時の2つのパスワード指定方法があることを紹介しました。当然ですが--vault-password-fileオプションを利用する場合、パスワードファイルはバージョン管理などに載せて誰でも閲覧可能な状態にするのはやめましょう。そうしないと暗号化している意味がなくなってしまいます。

また、今回は変数ファイルを暗号化しましたが、実はPlaybook自体をAnsible Vaultを利用して暗号化することもできるようです。場合によっては利用することもあるでしょうか。

まとめ

Ansibleを利用して秘密情報を扱う時に利用できるansible-vaultを紹介しました。Ansible本体と同様に導入は非常に簡単ですので、平文で保存されたままのパスワードなどがある場合は置き換えてみてはいかがでしょうか。

参考

  • shirou

    > パスワード化した秘密鍵が標準出力に書かれてしまっている

    そのtaskに `no_log: True` を設定すれば出力されなくなると思います。

    http://docs.ansible.com/faq.html#how-do-i-keep-secret-data-in-my-playbook

    • M.M

      ありがとうございます。ご指摘のとおりでした!
      後ほど、記事内容を修正しておきます。