はじめに
Ansible を使用して VM インスタンスなどをセットアップする際に、ユーザー名とパスワード、TLS クライアント証明書、API キーなどの機密情報を扱うケースは多くあるかと思います。機密情報を Ansible Playbook と一緒にバージョン管理することは避けたいですし、Ansible 実行時に手動で用意するのも面倒です。このような背景を受けて、この記事では Vault Module を使用して Hashicorp Vault に保存した機密情報を Ansible で使用する方法を紹介します。
Vault Module とは
Vault Module は Ansible コミュニティでメンテナンスされているサードパーティー製の Module で、こちらを使用することで Ansible 実行時に Vault から機密情報を取得することができます。
インストール方法
ansible-galaxy
コマンドで Vault Module をインストールします。
$ ansible-galaxy collection install community.hashi_vault
Vault Module は hvac
という Python ライブラリに依存しているので、そちらもインストールします。
# Ansible が使用する Python インタープリターを特定
$ ansible -m debug -a 'var=ansible_python_interpreter' localhost
[WARNING]: No inventory was parsed, only implicit localhost is available
localhost | SUCCESS => {
"ansible_python_interpreter": "/usr/local/Cellar/ansible/4.0.0/libexec/bin/python3.9"
}
# 使用される Python インタープリターで hvac をインストール
$ /usr/local/Cellar/ansible/4.0.0/libexec/bin/python3.9 -m pip install hvac
使用例
公式ドキュメントの例ではワンライナーなものが紹介されていますが、メンテナンス性が悪いと感じたので、ここではメンテナンス性を考慮して改良したものを紹介しています。以下の例は、認証方式として Token を使用するものになっているので、実行ホストで vault login
が完了している前提(Token Helper により ~/.vault-token
に認証トークンがキャッシュされている)となることに注意してください。
- name: read secrets from vault
set_fact:
mysql_root_password: >-
{{ lookup(
'community.hashi_vault.hashi_vault',
' url=' + vault_addr +
' ca_cert=' + vault_cacert +
' secret=/path/to/mysql-secrets:root-password'
) }}
client_cert: >-
{{ lookup(
'community.hashi_vault.hashi_vault',
' url=' + vault_addr +
' ca_cert=' + vault_cacert +
' secret=/path/to/tls-client-secrets:client.pem'
) }}
client_key: >-
{{ lookup(
'community.hashi_vault.hashi_vault',
' url=' + vault_addr +
' ca_cert=' + vault_cacert +
' secret=/path/to/tls-client-secrets:client-key.pem'
) }}
vars:
vault_addr: https://your-vault:8200
vault_cacert: /path/to/cacert.pem
上記のタスクで Vault から取得した機密情報は以下のように使用できます。
# ファイル内の文字列として使用する場合はテンプレートファイル内で {{ mysql_root_password }} を定義すること
- name: copy configuration file
template:
src: templates/server.conf
dest: /path/to/server.conf
# ファイルとして使用する場合は Copy Module の content パラメーターを使用すること
- name: copy client cert
copy:
content: "{{ client_cert }}"
dest: /path/to/client.pem
- name: copy client key
copy:
content: "{{ client_key }}"
dest: /path/to/client-key.pem
使用例としてシンプルなものを紹介しましたが、公式ドキュメントでは他にも様々なユースケース毎の設定例が紹介されていますので、そちらも併せて参照するのが良いかと思います。
補足
Vault Module を macOS で使用する際に以下のエラーが出力されることがあります。
objc[43838]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called.
objc[43838]: +[__NSPlaceholderDate initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
これは ansible/ansible#31869 で報告されているとおり macOS 起因の問題なので、ワークアラウンドとして紹介されている以下の環境変数を宣言して再実行する必要があります。
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
さいごに
今回は Vault Module を使用して Hashicorp Vault に保存した機密情報を Ansible で使用する方法を紹介しました。Vault Module はとても便利なので、Ansible での機密情報の扱いに課題を抱えている方々の参考になれば幸いです。