電通総研 テックブログ

電通総研が運営する技術ブログ

Ansibleで機密情報を安全に扱うにはAnsible Vaultを利用しよう

こんにちは。X(クロス)イノベーション本部 ソフトウェアデザインセンター の山下です。 今回は、Ansible Vaultを利用して、Ansibleを使う場合に機密情報を安全に扱う方法について紹介します。

ansibleと機密情報の管理についての課題

Ansibleを使ってデプロイなどを自動化していると、Amazon Web Services(AWS) の機密情報やパスワード、SSHに利用する秘密鍵といった機密情報を扱う場面があります。また、Ansibleを利用している場合はplaybookをGitHubなどで管理することが多いと思います。こういったGitHubなどのリポジトリに機密情報を直接置いてしまうと情報漏洩といった事故につながる場合があります。

機密情報を別システム ( dashlaneやAWSのsecret managerなど ) で管理するといった方法もあるかと思います。しかしこの方法では機密情報だけをバージョン管理の仕組みから別で管理することとなってしまい、管理コストが高くなってしまいます。また、CI/CDといった自動化を行う場合にもansible以外のツール、機密情報へのアクセス方法を考えなければならなくなってしまいます。

理想的には以下のような状態になっていてほしいです。

  • 機密情報は安全に扱いたい
  • 新規のツールの導入は避けたい
  • playbookと機密情報の両方を1つのリポジトリ上で安全にバージョン管理できる

今回はこの問題を解決するAnsible Vaultというツールについて紹介します。

Ansible Vaultとは

このような機密情報を扱うために、AnsibleにはAnsible Vaultと呼ばれる暗号化の機能が付属しています。暗号化した情報であればリポジトリ上に置くリスクを大幅に減らすことができます。本記事ではこのAnsible Vaultを使って、ssh秘密鍵AWSの認証情報といった機密情報を暗号化してCI/CDから利用する方法について記載します。

なお、Ansible Vaultの公式のドキュメントは以下となります。より詳細な説明は以下のドキュメントを参照してください。 https://docs.ansible.com/ansible/latest/user_guide/vault.html

この記事で紹介している利用方法は、

  • 10人に満たない小規模なチーム
  • 機密情報はメンバ内で共有して問題がない

上記のような想定となっています。 このため、Ansible Vaultで暗号化に利用するパスワードはvaultd-idを利用して分割したりせず単一で共通のものを想定しています。

Ansible Vaultを使った暗号化、復号化

Ansible Vaultは、ansible-vaultコマンドを通じて利用します。サブコマンドとしてcreateencryptdecryptrekeyeditview というサブコマンドがあります。ここでは、既存のファイルの暗号化、復号を行うencryptdecryptの動作について述べます。

まずは、encryptを使ってファイルを暗号化してみましょう。以下のような中身のファイルを、test.txtという名前で作成します。

hello,world!

そのファイルを、ansible-vault encrypt で暗号化します。 途中でパスワードを聞かれるので、適宜入力して忘れない様にしてください。

$ansible-vault encrypt test.txt
New Vault password:
Confirm New Vault password:
Encryption successful

暗号化に成功したようです。暗号化された中身を確認してみます。

$ cat test.txt
$ANSIBLE_VAULT;1.1;AES256
34646636663564393432303436353932613263346534373439353133303137333064343363326266
6565386564393437316139353031333063316663363466300a376534313035373630356663376661
35663263663265383861346162306630353636316534626165313638616433373566373632306339
6438646236316431380a643737343561376133313334616162303737616561386262633338313761
6436

ちゃんと暗号化できたようです。

今度は復号できるか確認してみましょう。復号に使うコマンドはansible-vault decryptです。 途中で先ほど入力したパスワードを求められます。打ち間違いに注意してパスワードを入力しましょう。

ansible-vault decrypt test.txt
Vault password:
Decryption successful

無事復号できたようです。 それでは、中身も正しいかを確認してみましょう。

$ cat test.txt
hello,world!

ちゃんとファイルの中身も復号できていることが分かりました。 このansible-vaultの機能を使って機密情報を扱うplaybookを作ってみましょう。

SSH接続情報の保護

ansibleではSSHの接続に秘密鍵を利用することが多いですが、この秘密鍵リポジトリに暗号化せずに登録してしまうと、その情報を入手した人は誰でも接続できてしまいます。まずはこの情報の暗号化を実施してみましょう。

まず、以下のように接続に利用する秘密鍵(private_key)を暗号化しておきます。

ansible-vault private_key

次に、実行するplaybookの先頭にこの暗号化された秘密鍵を復号するタスクを追加します。 内容としてはcopyモジュールを実行するだけのものになっています。ansibleのcopyモジュールは、ansible-vaultで暗号化されたファイルを扱う際に復号してくれる機能があります。その機能を利用して、秘密鍵を復号しています。

- hosts: localhost
  gather_facts: false
  vars:
    src_key: ./private_key
    dest_key: ./decrypted_private_key
  tasks:
  - copy:
      src: "{{ src_key }}"
      dest: "{{ dest_key }}"
      mode: 0600

そして ansible-playbook で利用する inventory.yml を以下のように記述します。 XXXで示している部分は各自の環境に合わせて書き換えてください。 ここで、ansible_ssh_private_key_fileには上記の手順で復号された秘密鍵が指定されるように設定します。

all:
  children:
    XXXX:
      hosts:
        XXXX:
           ansible_ssh_private_key_file: ./decrypted_private_key
           ansible_ssh_user: XXXX
           ansible_host: XXX.XXX.XXX.XXX
    ungrouped: {}

これで、秘密鍵を暗号化して管理することが可能になりました。

機密情報を利用するPlaybookの実行方法

ansible-playbook を実行する際にvaultで利用したパスワードが必要になりました。 以下のように引数でパスワードファイルを渡すか、毎回入力する方法があります。 自動化などを考えるとパスワードファイルを作成する方法が手軽です。

# 端末で毎回パスワードを入力する方法
ansible-playbook site.yml -ask-vault-pass
# パスワードファイルを引数で与える方法
ansible-playbook site.yml –vault-password-file ~/.vault_pass.txt

例えば、環境変数$VAULT_PASSにパスワードが格納されているような場合では、以下のようなスクリプトを実行する方法があります。

echo "$VAULT_PASS" > .vault_pass.txt
ansible-playbook -i inventory.yml site.yml –vault-password-file ~/.vault_pass.txt
rm .vault_pass.txt

Playbook上で利用する機密情報の保護

ここまででSSHに利用する秘密鍵の暗号化は実現できました。次にplaybookの中で利用したい機密情報についても暗号化していきましょう。

先ほどの秘密鍵の例では、copyモジュールは自動的にansible-vaultの復号を実施してくれると説明しました。この機能がansibleの変数のファイルに対しても自動的に復号を行ってくれます。

従ってAnsibleが利用する group_vars/all.yml といった変数ファイルをansible-vaultコマンドで事前に暗号化しておくことで、機密情報を暗号化したままで利用することが出来ます。以下のように事前に変数のファイルを暗号化しておくだけで安全に管理することが可能となります。

group_vars/all.ymlには以下のように、sudoのパスワードやAWSの接続情報が含まれています。

---
ansible_sudo_pass: "XXXXXXXXXX"
aws_access_key_id: "XXXXXXXXXXXXXXXXXXX"
aws_secret_access_key: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

これを、ansible-vaultで暗号化します。

ansible-vault encrypt group_vars/all.yml

この状態で、ansible-playbookの実行時にgroup_vars/allの変数を利用する際に自動的に復号処理が行われます。

実行方法は前項で述べた方法と変わらず実行できます。

GitHub Actions で実行する方法

それでは、最後にGitHub Actionsで実行する場合の方法について紹介します。 vaultのパスワードをGitHubのsecretとして与えるような設定を行って実行します。

jobs:
  deploy:
    steps:
      - name: Exec ansible-playbook
        env:
          VAULT_PASS: ${{secrets.VAULT_PASS}}
        run: |
          echo $VAULT_PASS > ./vault_pass.txt
          ansible-playbook -i inventory.yml site.yml --vault-password-file ./vault_pass.txt"

簡単ですね!

まとめ

この記事では、Ansible Vaultを使った機密情報の扱い方の簡単な紹介を行いました。またそれらを組みわせてGitHub Actionsから実行する方法も紹介しました。これで、安全にリポジトリ上の機密情報を置きながら、CI/CDも手軽に実行できる環境が構築できます。仮想マシンなどにサービスをAnsibleを使ってデプロイする場面では是非有効活用していきたいですね。


私たちは同じチームで働いてくれる仲間を探しています。今回のエントリで紹介したような仕事に興味のある方、ご応募お待ちしています。

執筆:@yamashita.tsuyoshi、レビュー:@sato.taichiShodoで執筆されました