[Ansible]Config ContextでNetBoxをパラメータ保管場所にする


はじめに

NetBoxとAnsibleの連携機能紹介の2記事目になります。

1記事目はこちら

今回は、NetBoxのConfig Context機能を使ってAnsibleのInventory情報とパラメータを取得する方法となります。
ちなみに、Ansibleは2.9.x、NetBoxは3.0.xを使用しています。

利用前提

requirements.{txt|yml}

AnsibleからNetBoxの情報を取得するためには、netbox.netboxコレクションが必要になります。
そのため、事前に下記コマンドでコレクションとPythonモジュールをインストールしておきます。

pip install pynetbox
ansible-galaxy collection install netbox.netbox

NetBox接続情報を用意

NetBoxに接続するためのサーバ接続先API Tokenを用意してAnsibleを実行するサーバの環境変数に定義しておきます。
NetBox TokenはNetBoxのユーザのプロファイルから作成できます。

.bashrc
export NETBOX_API=<NetBox IPアドレス or FQDN>
export NETBOX_TOKEN=<NetBox Token>

NetBoxのパラメータをダイナミックインベントリとして取得

ダイナミックインベントリファイル作成

NetBoxのデバイス情報をダイナミックインベントリとして取得するには、インベントリファイルを作成する必要があります。
pluginはnetboxも利用できますが、ドキュメントの最新版ではnetbox.netbox.nb_inventoryにリダイレクトされていたので今後はこちらに統合されるのではないかなと思います。

netbox_inventory.yml
---
plugin: netbox.netbox.nb_inventory
validate_certs: no # 証明書無視
group_names_raw: yes # 取得したときのグループ名prefixに「group_by」がつかないようにする
strict: yes # APIエラーなどがあれば、以降の処理を止める
device_query_filters:
  - has_primary_ip: yes # デバイス情報にprimary ipがないとインベントリとして読み込まない(primary ip=ansible_hostとなる)
group_by:
  - device_roles # device_roleをAnsibleのグループとする
config_context: yes # config_contextを読み込む
flatten_config_context: yes # config_contextをデバイスパラメータの第一階層にマージする
flatten_custom_fields: yes # カスタムフィールドデバイスパラメータの第一階層にマージする
flatten_local_context: yes # デバイスに設定されているlocal_contextをデバイスパラメータの第一階層にマージする

v0.2.1(2020/5/20)以前は、flatten_config_contextがなかったのでcomposeディレクティブを使ってhoge: config_context.hogeとする必要があったらしいですが、このオプションができたことによってかなり柔軟性は上がったのではないかと思います。

インベントリ情報取得テスト

実際にNetBoxからデータをどのように取れているかはansible-inventoryコマンドを使って確かめます。

ansible-inventory -i netbox_inventory.yml -y
結果
all:
  children:
    center_router:
      hosts:
        rt-center:
          ansible_become: true
          ansible_become_method: enable
          ansible_connection: ansible.netcommon.network_cli
          ansible_host: x.x.x.x
          ansible_network_os: cisco.ios.ios
          device_roles:
          - center_router
          device_types:
          - csr
          is_virtual: false
          local_context_data:
          - null
          locations: []
          manufacturers:
          - cisco
          ospf:
          - interface:
              name: GigabitEthernet2
              ospf_cost: 10
              shutdown: false
            route:
              nexthop: x.x.x.x
              target: x.x.x.x/24
          platforms:
          - ios-xe
          primary_ip4: x.x.x.x
          regions: []
          services: []
          sites:
          - center
          status:
            label: Active
            value: active
          tags: []
          - secondary
    ungrouped: {}

あとは、上記ファイルをインベントリとしてPlaybookを実行してあげるとNetBoxから自動でインベントリ情報取得して利用されます。

Config Contextによるパラメータ定義

先ほどのインベントリ取得で、ospfだったり、ansible_network_osがあったと思いますがこれはNetBox側が勝手に作成してくれるものではありません。(将来的にそうなったら嬉しいのですが・・・)

そのため、Config Context機能を使ってNetBox上でユーザが定義してあげる必要があります。

Config Contextは、下記オブジェクトにアサインして、そのオブジェクトが紐づいているデバイスに対してJSON形式でパラメータが適用されるかたちとなります。

アサインされるオブジェクトは下記の通り(ver.3.0.x時点)

  • Regions
  • Site Groups
  • Sites
  • Device Types
  • Roles
  • Platforms
  • Cluster Groups
  • Clusters
  • Tenant Groups
  • Tenants
  • Tags

また、Priorityの概念もありパラメータが被った場合でもPriority値が高いものが優先的にマージされる仕組みとなっています。

汎用的なパラメータ定義

Ansibleからデバイスに接続するためのansible_connectionのようなパラメータは対応する機器種別のすべてのデバイスに適用してあげる必要があります。
そういった場合は、以下画像のように「Platformios-xeのデバイスすべてにCiscoの接続情報を定義」とすることができます。

状況によって変化するパラメータ定義

次に、一時的にパラメータが変更となるような場合についても先ほど紹介したPriority値を使うことでConfig Contextのパラメータを変更せずに柔軟に変更することもできます。

例として、OSPFの設定で一時的に経路変更が必要となった場合のConfig Context設定を紹介したいと思います。

事前に、経路変更を示すタグを作成したうえで下記2つのConfig Contextを作成します。

  • 通常状態のConfig Context
    • Priority: 1000
    • Assignments: 対象ルータのDevice Role
  • フェイルオーバー時のConfig Context
    • Priority: 2000
    • Assignments: 対象ルータのDevice Roleと経路変更タグ

こうすることで、対象デバイスに対して経路変更タグをつけ外しするだけでパラメータを変更することができます。

通常時のOSPF設定

経路変更時のOSPF設定

image.png

経路変更タグが付いているときのConfig Context結果

デバイス情報以外のNetBoxデータの取得

Playbookの中でデバイス情報以外のNetBox情報を取得したい時があるかと思います。

その際は、APIのURLとTOKENは環境変数に登録されていること前提としたうえでnetbox.netbox.nb_lookupプラグインを使うことで取得できます。

例として、下記PlaybookにてadminユーザのユーザIDが取得できます。

playbook.yml
・・・
  tasks:
    - name: パラメータに必要な情報を取得
      set_fact:
        admin_user_id: |
          {{
              query('netbox.netbox.nb_lookup',
                'users',
                api_filter='name=admin',
                validate_certs=false)
              [0].value.id
          }}

おわりに

Config Contextは、シンプルながらもとてもパワフルな機能です。
今回紹介しなかったですが、local_contextcustom_fieldsとマージして利用することもできるので柔軟にパラメータを管理できるかと思います。

ただし、NetBoxはユーザの閲覧権限を柔軟に設定することができないため、パスワードのような機密情報をConfig Contextで管理するのはやめておいた方がいいかと思います。

NetBoxは過去、SecretsというSecret情報を保存するための仕組みを用意していましたがどこかのタイミング(v2.10.4?)で標準搭載から外れてアドオン提供になっています。

また、公式ドキュメントからもHashicorp Vault使った方がいいよと言われており、プラグイン開発が活発になっているのでこちらを検討した方がよさそうですね。

参考URL