てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] azure.azcollection.azure_rm インベントリプラグインで停止中のVMも対象にする

はじめに

Ansible から Azure の VM の情報を取得して動的にインベントリを生成できる azure.azcollection.azure_rm インベントリプラグインという便利なものがあります。

こちらの issueを見てなるほどと思ったのですが、デフォルトだと実行中(running)でない VM や、provisioning_statesucceeded でない VM は除外されます。何らかの事情で、状態に関わらずインベントリとして取得したい場合は、default_host_filters オプションで空リストを指定すればいいということなので、試してみました。

  • 環境
    • ansible-core 2.12.1
    • azure.azcollection 1.10.0

(比較用)デフォルトの default_host_filters の場合

比較のためまず、default_host_filters の指定なしで試します。サービスプリンシパル~/.azure/credentials に定義済みの状態です。

---
plugin: azure.azcollection.azure_rm
include_vm_resource_groups:
  - "*"
plain_host_names: true # インベントリ名を仮想マシン名にする(本件とは直接関係ない)

確認には、単純にインベントリの情報だけ確認したいので、ansible-inventory コマンドを利用します。

$ ansible-inventory -i inventory_azure_rm.yml --graph
@all:
  |--@ungrouped:
  |  |--ansible01

ポータルと見比べると起動中の VM だけが対象になりました。

停止中含め 全 VM を対象にする

次は、状態に関わらず全 VM を対象にする場合です。

---
plugin: azure.azcollection.azure_rm
include_vm_resource_groups:
  - "*"
plain_host_names: true # インベントリ名を仮想マシン名にする(本件とは直接関係ない)

default_host_filters:  []  # ポイント         

また ansible-inventory を実行して確認します。

$ ansible-inventory -i inventory_azure_rm.yml --graph
@all:
  |--@ungrouped:
  |  |--ansible01
  |  |--iwana01
  |  |--yamame01
  |  |--yokoyoko

無事実行中以外の VM も表示されました。

参考

[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 のシークレットの値を取得する動作を確認しました。

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

HashiCorp Vault によるシークレットの登録と確認を気軽に試してみた

はじめに

Software Design 2022年4月号で始まった連載「HashiCorp Vaultではじめるシークレット管理」を読んで、HashiCorp Vault(以下 Vault)に興味を持ちました。

他、HashiCorp Learn の Vualt のコンテンツも参照してみました。

あくまでお試しレベルですが、インストールからシークレットの登録、確認までやってみたことをまとめます。

インストール

ドキュメントに掲載されていた、yum コマンドによるインストールを行いました。

$ sudo yum install -y yum-utils
$ sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
$ sudo yum -y install vault

インストールできたら、バージョンの確認をします。今回はこちらです。

$ vault --version
Vault v1.10.0 (7738ec5d0d6f5bf94a809ee0f6ff0142cfa525a6)

起動・接続準備

簡易的な、開発モードでサーバーを起動します。

$ vault server -dev
==> Vault server configuration:
...(略)...
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.

You may need to set the following environment variable:

    $ export VAULT_ADDR='http://127.0.0.1:8200'

The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.

Unseal Key: dummyxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Root Token: hvs.dummyxxxxxxxxx

Development mode should NOT be used in production installations!

サーバーを起動したターミナルはそのままにして、別のターミナルを開きます。

接続の準備として、サーバーへの接続先を環境変数に設定します。

export VAULT_ADDR='http://127.0.0.1:8200'

今回は、サーバーもクライアントも同じマシンの上です。

参考 Starting the Server | Vault | HashiCorp Developer

シークレットの追加

さっそく kv シークレットエンジンを使ってシークレットを登録します。

今回は secret/mypassword 内に password の値として p@ssw0rd を登録します。

$ vault kv put secret/mypassword password=p@ssw0rd
===== 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

参考 Your First Secret | Vault | HashiCorp Developer

シークレットの確認

登録できたことを vault kv get で確認します。

$ 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

password の値として p@ssw0rd が登録されていることが確認できました。

参考 Your First Secret | Vault | HashiCorp Developer

おわりに

かんたんですが Vault で試したことをまとめました。おそらくまだ Vault が持っている機能のうちのほんの少しだけだと思います。

Software Design での連載の次の記事も楽しみです。

このブログととしては別途、Ansible からシークレットを呼び出す方法を書きたいと思います。

[追記]

tekunabe.hatenablog.jp

[Ansible] Ansible 3 以降のモジュール一覧のページ

はじめに

Ansible のモジュールの一覧を確認したいときは、よく公式ドキュメントを参照します。Ansible 2.9 までは、Module Indexというページがあり、さらにカテゴリごとのページに飛べます。また、All modules というページでは全モジュールの一覧が表示されます。

Ansible-base 2.10 / Ansible 3 からは、本体と一緒に管理されていたモジュールの多くがコレクションに移行した関係で、ドキュメントの構造も変わりました。

「前にあった All modules みたいにモジュール一覧のページどっかないのかな」と思ってたら、ちゃんとあることに最近気が付きました。

モジュール一覧のページ

f:id:akira6592:20220407204101p:plain:w200
Indexes of all modules and plugins > Index of all Modules
こちらです。

左メニューの [Indexes of all modules and plugins] 内の [Index of all Modules] です。 

docs.ansible.com

ここに、ansible.builtin コレクション内のモジュールの他、Ansible Community Package に同梱される様々なコレクションのモジュールがリストになっています。

2.9 までにあったカテゴリごとではなく、コレクションごとに並んでいます。

なお、ansible-core 側のドキュメントの同じページには、ansible.builtin コレクションのみ掲載されています。

docs.ansible.com

(参考) コレクションのリスト

先程はコレクション串刺しのモジュールのリストでしたが、コレクションのリストは以下のページです。この切り口のリストは 2.9 は無かったものです。

docs.ansible.com

[Ansible] スキップされたタスクの結果は is skipped でもあり is succeeded でもある

はじめに

Ansible では、タスクの実行結果を変数に保存し、その結果を後続のタスクで確認する機能があります。

docs.ansible.com

そういえばどうなんだろうシリーズといいますか、「スキップされたタスクって succeeded 扱いだっけ?」と思ったことがありました。

結果としては、is skipped でもあり is succeeded でもありました。

試した結果をまとめます。

  • 検証環境
    • ansible 5.4.0
    • ansible-core 2.12.3

Playbook

こんな Playbook で試します。

---
- hosts: localhost
  gather_facts: false

  tasks:
    # (1) 必ずスキップされるタスク
    - name: skipped task
      ansible.builtin.debug:
        msg: this task is skipped
      register: resister_skipped
      when:
        - false

    # (2) 1が skipped 扱いの場合に実行されるタスク
    - name: debug result skipped
      ansible.builtin.debug:
        msg: resister_skipped is skipped
      when:
        - resister_skipped is skipped

    # (3) 1が succeeded 扱いの場合に実行されるタスク
    - name: debug result succeeded
      ansible.builtin.debug:
        msg: resister_skipped is succeeded
      when:
        - resister_skipped is succeeded

一番確かめたいたいのは (3) のタスクです。

結果

実行結果は以下のとおりです。 is succeeded を条件にしたタスク3も実行されました。

$ ansible-playbook -i localhost, success.yml     

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

TASK [skipped task] ************************************************************************************
skipping: [localhost]

TASK [debug result skipped] ****************************************************************************
ok: [localhost] => {
    "msg": "resister_skipped is skipped"
}

TASK [debug result succeeded] **************************************************************************
ok: [localhost] => {
    "msg": "resister_skipped is succeeded"
}

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

なお resister_skipped 変数をデバッグ表示すると以下のとおりです。

    "resister_skipped": {
        "changed": false,
        "failed": false,
        "msg": "this task is skipped"
    }

私の解釈

コードでいうとこのあたりでしょうか。

github.com

failed でない場合は succeededまたは successsuccessful )のようです。

今回の場合は「正常に判断処理がされた結果、スキップできた」ことをもって succeeded なのかなと捉えています。

一方たとえば、(1) のタスクで、when に未定義の変数をした場合(確認のためにignore_errors: true も併用)はさすがに succeeded にはなりませんでした。

---
- hosts: localhost
  gather_facts: false

  tasks:
    # (1) when が異常
    - name: skipped task
      ansible.builtin.debug:
        msg: this task is skipped
      register: resister_skipped
      when:
        - hogehoge_undefined_variable
      ignore_errors: true
        
    # (2) 1が skipped 扱いの場合に実行されるタスク
    - name: debug result skipped
      ansible.builtin.debug:
        msg: resister_skipped is skipped
      when:
        - resister_skipped is skipped

    #  (3) 1がsucceeded 扱いの場合に実行されるタスク
    - name: debug result succeeded
      ansible.builtin.debug:
        msg: resister_skipped is succeeded
      when:
        - resister_skipped is succeeded

実行結果

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

TASK [skipped task] ************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'hogehoge_undefined_variable' failed. The error was: error while evaluating conditional (hogehoge_undefined_variable): 'hogehoge_undefined_variable' is undefined\n\nThe error appears to be in '/Users/akira/Documents/git/general/vagrant/nwlab/qa/success.yml': line 7, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n    # (1) when が異常\n    - name: skipped task\n      ^ here\n"}
...ignoring

TASK [debug result skipped] ****************************************************************************************
skipping: [localhost]

TASK [debug result succeeded] **************************************************************************************
skipping: [localhost]

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

[Ansible] もくもく会コンテンツのリポジトリにある資料「Ansible Best Practices」

Ansible ユーザー会では定期的にもくもく会というハンズオンイベントを開催しています。

次回は 2022/04/21 です

コンテンツは以下のリポジトリにあります。

github.com

先日見つけたのですが、Ansible Best Practicesという資料がありました。

こうかいても動くけど、こう書いたほうがいい、というようなことや、テクニックが書かれています。

良い資料だなと思ったのでリンクを共有します。

github.com

ディレクトリは以下。

github.com

[Ansible] Automation Controller 上で実行環境コンテナ内のコレクション一覧を確認する(やや力技)

はじめに

AAP 2.x になってから、Ansible の実行環境が Python の venv から、コンテナに変わりました。

コンテナの中に、利用するコレクションを仕込んでおくわけですが、Automation Controller を触ってるときに、コンテナ内のコレクション一覧を確認したいときがあります。 ターミナルの戻らずに。横着かもなんですが・・。

そんなときの力技です。

アドホック実行を利用

Automation Controller にも、CLI 同様にアドホック実行機能があります。これを応用して localhost を対象として、確認したい実行環境を選んで ansible-galaxy colleciton list を実行すればコレクションの一覧を表示できます。

まず localhost があるインベントリで localhost を選択し、コマンドの実行をクリックします。デフォルトでは、Demo Inventory の中にあります。

localhost でコマンド実行

ここからアドホック実行のウィザード画面になります。

モジュールに command、引数に ansible-galaxy colleciton list を指定します。

利用モジュールと引数を指定

アドホック実行だと何故か認証情報の指定が必須(ジョブテンプレートでは任意)なので、ダミー的に Demo Credential を選択します。

認証情報の指定

確認画面になるので起動ボタンをクリックします。

確認画面

実行結果として、コレクション一覧が表示されます。

コレクション一覧の表示

Automation Controller 4.1.0 の Default execution environment (registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest ) では以下の表示になりました。

# /usr/share/ansible/collections/ansible_collections
Collection              Version
----------------------- -------
amazon.aws              2.0.0  
ansible.controller      4.1.0  
ansible.netcommon       2.4.0  
ansible.network         1.2.0  
ansible.posix           1.2.0  
ansible.security        1.0.0  
ansible.utils           2.4.2  
ansible.windows         1.7.3  
arista.eos              3.1.0  
cisco.asa               2.1.0  
cisco.ios               2.5.0  
cisco.iosxr             2.5.0  
cisco.nxos              2.7.1  
cloud.common            2.0.3  
frr.frr                 1.0.3  
ibm.qradar              1.0.3  
junipernetworks.junos   2.6.0  
kubernetes.core         2.1.1  
openvswitch.openvswitch 2.0.2  
redhat.insights         1.0.5  
redhat.openshift        2.0.1  
redhat.rhv              1.4.4  
redhat.satellite        2.2.0  
servicenow.itsm         1.2.0  
splunk.es               1.0.2  
trendmicro.deepsec      1.1.0  
vmware.vmware_rest      2.1.0  
vyos.vyos               2.6.0  

もちろん、途中で選択する実行環境によって、内容が変わります。

別の実行環境の場合

おまけ(ansible-navigator の場合)

ansible-navigator collectionsだとこんな表示ができます。ターミナルに戻ってこれをやるのが正攻法かなと思います。

ansible-navigator によるコレクション一覧

コレクションを指定すると、所属するモジュール類が表示されます。さらに進んでいくとドキュメントに相当する情報も見れます。

モジュール類の一覧