てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] Ansible から HashiCorp Vault のシークレットを取得する

はじめに

前回の記事で、HashiCorp Vault の kv シークレットエンジンを使ってシークレットの登録をしました。

今回は、そのシークレットを Ansible から取得して表示したり、機器への接続パスワードに利用することを試します。

Ansible の community.hashi_vault.hashi_vault ルックアッププラグインを利用します。

少し紛らわしいかもしれませんが、Ansible Vaultとは直接は関係ありません。

  • 環境
    • Vault v1.10.0
    • ansible 5.6.0 (ansible-core 2.12.4)
    • community.hashi_vault コレクション 2.4.0
      • hashi_vault ルックアッププラグインは、もともとは community.general コレクションにありましたが、2.0.0 で削除されました

Vault 側の準備

Ansible の前にまず Vault 側の準備です。

vault -dev でサーバーを起動済みの状態から始めます。今回は Vault サーバーもAnsible も同じサーバーという構成です。

シークレットの確認

前回からのおさらいになりますが secret/mypassword の中に password というキーで、パスワード p@ssw0rd が登録されています。これを後で Ansible から取得します。

$ vault kv get secret/mypassword
===== Secret Path =====
secret/data/mypassword

======= Metadata =======
Key                Value
---                -----
created_time       2022-04-07T13:34:41.03484313Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

====== Data ======
Key         Value
---         -----
password    p@ssw0rd

ポリシーの追加

シークレットの読み込みだけできるポリシーを追加します。ここでは read-secret という名前にします。

$ vault policy write read-secret - << EOF
path "secret/data/*" {
  capabilities = ["read"]
}
EOF
Success! Uploaded policy: read-secret

ポリシーのリストを確認すると read-secret が表示されます。

$ vault policy list
default
read-secret
root

内容も確認します。意図通りになっています。

$ vault policy read read-secret
path "secret/data/*" {
  capabilities = ["read"]
}

参考 Policies | Vault | HashiCorp Developer

トークンの生成

先ほど作成したポリシー read-secret に対するトークンを生成します。

$ vault token create -policy=read-secret
Key                  Value
---                  -----
token                hvs.dummyyyyyyyyyy
token_duration       768h
token_renewable      true
token_policies       ["default" "read-secret"]
identity_policies    []
policies             ["default" "read-secret"]

ここではダミーの値に伏せていますが、token に表示された値を後で使います。

参考 Authentication | Vault | HashiCorp Developer

Vault 側の準備はここまでです。

Ansible 側の準備

今度は Ansible 側の準備です。

hvac のインストール

ドキュメントの Requirementsにあるとおり、HashiCorp Vault API クライアントのPython パッケージ hvac が必要です。コントロールノード(Ansibleをインストールしたノード)に pip でインストールします。

pip install hvac

お試し1: 取得したシークレットを表示する

実用性はありませんが、とりあえず確認のため、取得したシークレットを表示するだけの Playbook を作成します。

---
- hosts: localhost
  gather_facts: false 

  tasks:
    - name: debug vault secret
      debug:
        msg: "{{ lookup('community.hashi_vault.hashi_vault', 'secret=secret/data/mypassword:password') }}"

secret のところで、取得したいシークレットのパスを指定します。password の値がほしいので、 :password も含めて指定します。

この他の代表的な設定要素として Vault サーバーへの接続先URLとトークンがあります。これらをルックアッププラグイン呼び出しのオプションで指定すると、複数箇所で呼び出すとき場合に毎回指定が必要になり冗長です。そのため、今回はURLとトークンは環境変数で指定します。トークンには Vault 側の準備で read-secret ポリシーに対して生成したものを指定します。

$ export ANSIBLE_HASHI_VAULT_TOKEN=hvs.dummyyyyyyyyyy
$ export ANSIBLE_HASHI_VAULT_ADDR=http://localhost:8200

なお、環境変数以外にはファイルに記載しておく方法もあります。詳細は、community.hashi_vault.hashi_vault ルックアッププラグインのドキュメントの urltokenを参照してください。

Playbook 実行

Playbook を実行します。

$ ansible-playbook -i localhost, debug_vault.yml 

PLAY [localhost] ****************************************************************************************************

TASK [debug vault secret] *******************************************************************************************
ok: [localhost] => {
    "msg": "p@ssw0rd"
}

PLAY RECAP **********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

p@ssw0rd が表示できたため、無事に Vault からシークレットを取得できたことが確認できました。

お試し2: 取得したシークレットを機器接続パスワードとして利用する。

今度は少し実用的な例です。(URLとトークンの環境変数は設定したままです)

Vault のシークレットから取得した値を、Cisco IOS への接続パスワードとして利用します。

インベントリファイルに ios というグループの定義がされている状態で、group_vars/ios.yml に以下のように定義します。

---
ansible_network_os: cisco.ios.ios
ansible_connection: ansible.netcommon.network_cli
ansible_user: admin
ansible_password: "{{ lookup('community.hashi_vault.hashi_vault', 'secret=secret/data/mypassword:password') }}"

ansible_password 変数に対して、Vault から取得した値を利用するように指定します。

Playbook 自体は以下のものを利用します。無事に接続、認証できたことを確認できればいいので、show コマンドを実行して表示するだけです。

---
- hosts: ios
  gather_facts: false

  tasks:
    - name: exec show commands
      cisco.ios.ios_command:
        commands:
          - show running-config
      register: res_show_commands

    - name: debug show commands
      ansible.builtin.debug:
        msg: "{{ res_show_commands.stdout_lines[0] }}"

Playbook を実行します。

$ ansible-playbook -i inventory ios_show.yml 

PLAY [ios] **********************************************************************************************************

TASK [exec show commands] *******************************************************************************************
ok: [ios01]

TASK [debug show commands] ******************************************************************************************
ok: [ios01] => {
    "msg": [
        "Building configuration...",
        "",
        "  ",
        "Current configuration : 4076 bytes",
        "!",
        "! Last configuration change at 10:07:41 UTC Wed Apr 6 2022",
        "!",
        "version 15.9",
...(略)...
PLAY RECAP **********************************************************************************************************
ios01                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

無事に Playbook を実行できます。

おわりに

お試しレベルですが、Ansible から HashiCorp Vault のシークレットの値を取得する動作を確認しました。

簡単に連携できたなと思いました。