Netbox と Ansible と Gitlabでネットワーク機器のコンフィグ取得(その２:設定)

Netboxで機器を管理して、その情報をつかって自動でコンフィグ保存を定期的に実行する環境を作ったメモ

前回は、Netbox と Ansible と Gitlabのインストールを実施したので、今回は各ソフトの設定をして最終的なコンフィグ取得まで実施します
とりあえず全部の機器のコンフィグを取得するにしてます、バックアップする機器を絞りたいなど条件に合わせて変更してください

前回の記事

https://qiita.com/k-maki/items/e30e312dcbc448ebafeb

# 動作イメージ
各ソフトウェアと全体的な動作のは以下のイメージで、Netboxでネットワーク機器を管理して、GitLabからAnsibleをつかってコンフィグ取得して最終的にGitLab内にコンフィグ保存させようとしました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/4a1fd527-58e5-40b7-b1a7-ce7f8475b6a1.png)

# 今回の確認環境
Ubuntu 24.04.1 LTS で構築しました
(ネットワークシュミレータ上に作りました)
各ソフトのバージョンは以下となります
- NetBox Community v4.2.4
- Ansible core 2.18.3
- GitLab Community Edition v17.9.1 


以下のようにサーバ以外にコンフィグ取得対象のネットワーク機器として vJunosEvolved と VyOS をつなげてます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/878cf8dc-a04b-450a-b98b-f6c1b24d2ce8.png)

ネームシュミレータでvJunosEvolvedを利用の方法は以下を参考にしてください

https://qiita.com/k-maki/items/d331b9306291b6c56afe

事前にネットワーク機器(vJunosEvolvedとVyOS)は以下でコンフィグ設定

<details><summary>vJunosEvolvedコンフィグ</summary>
<div>

```:vJunosEvolvedコンフィグ
set version 23.4R2-S2.1-EVO
set system host-name vJunosEvolved-1
set system root-authentication encrypted-password "$6$MmGV7bPW$AuqgoIhnFiZQD9eLmmhS.Fwywh63knLvg96p9VLQ"
set system login user admin uid 2000
set system login user admin class super-user
set system login user admin authentication encrypted-password "$6$A9pQ0/kI$TRLFL.HhfGICoqPmCjdWV6OJxjQPOCfS5u54KrQYC1iX
r6VCEzDl.pErElayNP/GU6kf0DqTcBseu3VBJ.jq3."
set system syslog file interactive-commands interactive-commands any
set system syslog file messages any notice
set system syslog file messages authorization info
set system services ssh
set interfaces et-0/0/0 description et-0/0/0
set interfaces et-0/0/0 unit 0 family inet address 192.168.100.1/24
set interfaces et-0/0/11 unit 0 family inet address 10.99.0.101/24
set interfaces lo0 unit 0 family inet address 10.10.0.1/32
set routing-options router-id 10.10.0.1
set protocols ospf area 0.0.0.0 interface et-0/0/0.0 interface-type p2p
set protocols ospf area 0.0.0.0 interface et-0/0/0.0 metric 100
set protocols ospf area 0.0.0.0 interface lo0.0 passive

```
</div></details>


<details><summary>VyOSコンフィグ</summary>
<div>

```:VyOSコンフィグ
set interfaces ethernet eth0 address '192.168.100.2/24'
set interfaces ethernet eth3 address '10.99.0.102/24'
set interfaces loopback lo address '10.10.0.2/32'
set protocols ospf area 0 network '10.10.0.2/32'
set protocols ospf area 0 network '192.168.100.0/24'
set protocols ospf interface eth0 cost '100'
set protocols ospf interface eth0 network 'point-to-point'
set protocols ospf interface lo passive
set protocols ospf parameters router-id '10.10.0.2'
set service ssh port '22'
set system config-management commit-revisions '100'
set system console device ttyS0 speed '115200'
set system host-name 'VyOS-1'
set system login user admin authentication encrypted-password '$6$rounds=656000$JII/FqbcOHqIrWew$q0ul.syebUf/IDyCWzQIDU
k5SWTTgiWoGvbP3kuCN1xRU/S3Wq9elh46UEWk5518OlC19llYzHfUmLttQ1zw10'
set system login user vyos authentication encrypted-password '$6$rounds=656000$LA0Bw9dLH8Bzrxwh$NoKZvYnFx2ETtQXQfAc3QkO
BwfYqJ9p.B.1bbW3ABJk3Dyn3QF/8Mn.ZGXNQxEDgE6F2ogmruWESz8jMECF0k.'
set system login user vyos authentication plaintext-password ''
set system syslog local facility all level 'info'
set system syslog local facility local7 level 'debug'

```
</div></details>


# Netboxにデバイス登録
今回のvJunosEvolvedとVyOSを以下のように登録
コンフィグの取得方法が機器によって異なるので、あとでPlaybook実行時に判断できるようにTYPE(device_type)も入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/61978a47-f3e5-4d97-bb32-ad22bce40980.png)

具体的な登録は以下を参考にさせていただきました

https://qiita.com/strawberryjam/items/461b6ab82136262de288

# NetboxでAPI Tokenをつくる
この後のAnsibleからNetboxの情報をAPIを使って参照するためのAPI Tokenを作成します
作成したらKEY控えておいてください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/251b7339-65c6-4021-843c-0ac0ccdb305d.png)


# Ansible設定
Ansibleを使って以下をできるようにします
- Netboxから「デバイス名」と「IPアドレス(Primary IPv4)」と「デバイスタイプ(機種)」を取得
    - `inventory_netbox.yml`で定義してます
- 初めてSSH接続する機器でSSH ホストキー検証のエラーにならないように、公開鍵を検証する機能を無効にする
    - `ansible.cfg`で設定
- 機器にSSHログインしてコンフィグ取得、`playbook_backup.yml`で設定
    - デバイスタイプに合わせて取得する方法を変える
    - コンフィグは階層構造(`show configuration`)ではなく、`show configuration | display set`の`set`形式で取得
    - 取得したコンフィグを`backup-config`ディレクトリに保存する


上記を実施するために、3つのファイルを作成
```:ansible.cfg
[defaults]
host_key_checking = False
```

inventory_netbox.ymlについて`token`の部分は、事前に作成したNetbox APIトークンのKEYに変更してください
```:inventory_netbox.yml
plugin: netbox.netbox.nb_inventory  # NetBoxのインベントリプラグインを使用
api_endpoint: http://localhost:8000/  # NetBox APIのエンドポイント
token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  # Netbox APIトークン（認証用）
validate_certs: false  # SSL証明書の検証を無効にする
group_by: device_roles  # デバイスをロールごとにグループ化

inventory:
  plugin: netbox.netbox.nb_inventory

compose:
  ansible_host: primary_ip4.address | regex_replace('/.*$', '')  # IPアドレスを抽出してansible_hostに設定
  ansible_netbox_name: name  # デバイス名を取得してansible_netbox_nameに設定
  ansible_netbox_device_type: device_type.display  # デバイスタイプを取得してansible_netbox_device_typeに設定
```

SSH 接続用のユーザー名とパスワードの`ansible_user`と`ansible_password`の部分はネットワーク機器のログイン情報に修正してください

```:playbook_backup.yml
- name: Configuration backup from Netbox information  # Netboxの情報からコンフィグを取得するタスク
  hosts: all  # すべてのホストに対して実行
  gather_facts: false  # ファクト収集は行わない
  tasks:

    # -------------------------------
    # Juniper
    # -------------------------------
    - name: Set variables for Juniper devices  # Juniper デバイスの変数を設定
      set_fact:
        ansible_user: admin  # SSH 接続用のユーザー名
        ansible_password: admin123  # SSH 接続用のパスワード
        ansible_connection: network_cli  # ネットワークデバイス用の接続タイプ
        ansible_network_os: junos  # 使用するネットワーク OS
      when: ansible_netbox_device_type in ["vJunosEvolved", "PTX10001-MR"]  # デバイスタイプが Juniper機器の場合

    - name: Get Junos configuration (display set format)  # Junos 設定を取得（set 形式で表示）
      when: ansible_netbox_device_type in ["vJunosEvolved", "PTX10001-MR"]  # デバイスタイプが Juniper機器の場合
      junipernetworks.junos.junos_command:
        commands: "show configuration | display set"  # 実行するコマンド
      register: junos_config  # 実行結果を junos_config に登録

    - name: Save Junos config to a file  # Junos 設定をファイルに保存
      when: ansible_netbox_device_type in ["vJunosEvolved", "PTX10001-MR"]  # デバイスタイプが Juniper機器の場合
      copy:
        content: "{{ junos_config.stdout[0] }}"  # 取得した設定内容
        dest: "./backup-config/{{ ansible_netbox_name }}.config"  # 保存先ファイル名

    # -------------------------------
    # VyOS
    # -------------------------------
    - name: Set variables for VyOS devices  # VyOS デバイスの変数を設定
      set_fact:
        ansible_user: vyos  # SSH 接続用のユーザー名
        ansible_password: vyos  # SSH 接続用のパスワード
        ansible_connection: network_cli  # ネットワークデバイス用の接続タイプ
        ansible_network_os: vyos  # 使用するネットワーク OS
      when: ansible_netbox_device_type == "VyOS"  # デバイスタイプが VyOS の場合

    - name: Get VyOS configuration (set format)  # VyOS 設定を取得（set 形式）
      when: ansible_netbox_device_type == "VyOS"  # デバイスタイプが VyOS の場合
      vyos.vyos.vyos_command:
        commands: "show configuration commands"  # 実行するコマンド
      register: vyos_config  # 実行結果を vyos_config に登録

    - name: Save VyOS config to a file  # VyOS 設定をファイルに保存
      when: ansible_netbox_device_type == "VyOS"  # デバイスタイプが VyOS の場合
      copy:
        content: "{{ vyos_config.stdout[0] }}"  # 取得した設定内容
        dest: "./backup-config/{{ ansible_netbox_name }}.config"  # 保存先ファイル名
```

上記を実施したら`backup-config`ディレクトリを作成した後に、以下を実行するとコンフィグ取得ができます
```
ansible-playbook -i inventory_netbox.yml playbook_backup.yml
```

参考にAnsibleを実行した結果と、`backup-config`ディレクトリの中身を確認したログを記載します

<details><summary>Ansible実行ログ</summary>
<div>

```:Ansible実行ログ
# ansible-playbook -i inventory_netbox.yml playbook_backup.yml

PLAY [Configuration backup from Netbox information] *******************************************************************
[WARNING]: Found variable using reserved name: tags
[WARNING]: Found variable using reserved name: serial

TASK [Set variables for Juniper devices] ******************************************************************************
skipping: [VyOS-1]
ok: [vJunosEvolved-1]

TASK [Get Junos configuration (display set format)] *******************************************************************
skipping: [VyOS-1]
[WARNING]: arguments wait_for, match, rpcs are not supported when using transport=cli
ok: [vJunosEvolved-1]

TASK [Save Junos config to a file] ************************************************************************************
skipping: [VyOS-1]
changed: [vJunosEvolved-1]

TASK [Set variables for VyOS devices] *********************************************************************************
skipping: [vJunosEvolved-1]
ok: [VyOS-1]

TASK [Get VyOS configuration (set format)] ****************************************************************************
skipping: [vJunosEvolved-1]
ok: [VyOS-1]

TASK [Save VyOS config to a file] *************************************************************************************
skipping: [vJunosEvolved-1]
changed: [VyOS-1]

PLAY RECAP ************************************************************************************************************
VyOS-1                     : ok=3    changed=1    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0
vJunosEvolved-1            : ok=3    changed=1    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0

#
# ls backup-config/
VyOS-1.config  vJunosEvolved-1.config
#
```
</div></details>



# GitLab設定


## GitLab Runner 認証用のSSH鍵を作り登録する
GitLab Runner から GitLab へアクセスする際の認証させるためのSSH鍵を生成します。
`gitlab-runner`のユーザになって`ssh-keygen`コマンドで鍵を作成
`ssh-keygen -t rsa -b 4096`コマンドでいろいろ聞かれますがすべて空エンターでも作成されます
```
(gitlab-runnerユーザになる)
root@ubuntu:~# su - gitlab-runner
gitlab-runner@ubuntu:~$

(SSH鍵を生成)
gitlab-runner@ubuntu:~$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/gitlab-runner/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/gitlab-runner/.ssh/id_rsa
Your public key has been saved in /home/gitlab-runner/.ssh/id_rsa.pub
The key fingerprint is:
 :
 :
```
ここから作成された公開鍵の`id_rsa.pub`を確認します

```
gitlab-runner@ubuntu:~$ cat /home/gitlab-runner/.ssh/id_rsa.pub
ssh-rsa AAAA・・・・・・・・
gitlab-runner@ubuntu:~$
```

作成した公開鍵の`id_rsa.pub`の内容をGitLab側のWEB-GUIから登録します
① SSH登録画面を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/9d5cab62-2146-40c9-b41e-ffd4fbcd0ceb.png)

② 「Add new key」を教えて公開鍵情報を登録
- `key`の箇所は、公開鍵の`id_rsa.pub`を貼り付ける
- `Usage type`の箇所は、「Authentication」
- `Expiration date`の箇所は、初期値で1年後の表示されますが×で削除すると期限がなくなります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/a224446e-7eb2-4fe0-ab1f-3461ad7bd22e.png)


## プロジェクトを作成しファイルを保存
次にGitLab上に空のプロジェクトを作成します
以下のサイトを参考に作成

https://techstep.hatenablog.com/entry/2024/02/21/212339

今回は「NetworkDeviceConfig」という名前で作成
- 事前に動作確認したAnsible用の`ansible.cfg`・`inventory_netbox.yml`・`playbook_backup.yml`を保存
    - 保存の方法は、WEB-GUIで直接ファイルを作って内容を書き込みかアップロードできます
- コンフィグ保存先の``のディレクトリを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/ad655c68-1971-4cfb-8b01-26c1f75f279f.png)

## .gitlab-ci.yml の作成
GitLab Runner で実行される`.gitlab-ci.yml`を作成、先ほどのAnsible関連のファイルと同様にGitLab上のプロジェクトに保存。
内容はざっくり以下の内容です
- Anshible の Playbook 実行と、git コマンドで GitLab 上にコンフィグを保存
- コンフィグは前回差分があった場合のみ反映
- ファイル更新時に自動実行されないようにスケジュール実行時のみ実行されるように定義
```:.gitlab-ci.yml
stages:
  - get_config  # "get_config" ステージを定義

get_config:
  stage: get_config
  image: ansible/ansible:latest  # Ansible の公式イメージを使用
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'  # スケジュール実行時のみ実行
  script:
    - ls -l ./backup-config/  # バックアップファイルの確認
    - ansible-playbook -i inventory_netbox.yml playbook_backup.yml  # NetBox インベントリを使用してバックアップ実行
    - ls -l ./backup-config/  # Ansible 実行後の確認
    - git remote set-url origin git@localhost:root/networkdeviceconfig.git  # Git リモートの設定
    - git fetch origin  # 最新のリモートリポジトリ情報を取得
    - git checkout main  # main ブランチへ切り替え
    - git add -A  # 変更をステージング
    - git commit -m "Upload configuration files" || echo "No changes to commit"  # 変更があればコミット
    - git pull --rebase origin main  # リモートの変更を反映（リベース）
    - git push origin HEAD:main  # 変更をリモートへプッシュ
```


## GitLab Runnerの登録
GitLabからスクリプト実行するためのRunnerを登録します
以下の画面から新しい Runnner を作る画面に移動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/7952cad3-f028-405a-b051-4dfb8f172d0e.png)

次に以下を登録後に「Create runnner」を押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/42d4fc9a-9c41-4eee-b9a7-905a53d07987.png)

すると自分の環境ではlocalhostに転送されてしまって「申し訳ございません。このページに到達できません」になっちゃいました。
ここでブラウザのURL部分のlocalhostをサーバーのIPに変更すると、登録画面にアクセスできます
 `http://localhost:9000/admin/runners/8/register `
　↓
 `http://<サーバーのIP>:9000/admin/runners/8/register`

開いた画面で Step 1 の部分の GitLab Runner の登録用コマンドをコピーする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/0daf086a-202a-4e6f-aa57-1c62fdeb6db5.png)

次にGitlab Runnerのあるサーバーにログインして gitlab-runner ユーザになって先ほどのコマンドを実行する
事前に`su - gitlab-runner`で gitlab-runner になって以下の通り実行
`Enter an executor`は`shell`で登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/ad77a87a-b00c-45f6-a617-c90b021b37b7.png)

ここまで実行するとサーバー上に`/home/gitlab-runner/.gitlab-runner/config.toml`が更新されます。
次に、サーバー上で動作している gitlab-runnerサービスは、`/etc/gitlab-runner/config.toml`の内容で動作しているので、以下を実施
- root に戻る
    - `exit`
- `/home/gitlab-runner/.gitlab-runner/config.toml`を`/etc/gitlab-runner/config.toml`に反映
    - `cp /home/gitlab-runner/.gitlab-runner/config.toml /etc/gitlab-runner/config.toml`
- gitlab-runnerサービスのrestart
    - `systemctl restart gitlab-runner.service`
```
gitlab-runner@ubuntu:~$ exit
logout
root@ubuntu:~#
root@ubuntu:~# cp /home/gitlab-runner/.gitlab-runner/config.toml /etc/gitlab-runner/config.toml
root@ubuntu:~# systemctl restart gitlab-runner.service
root@ubuntu:~#
```
これで、WEB画面が自動更新され、Runnerの登録が完了したことが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/989ba8e3-1b16-4260-9396-221255d836fa.png)

## Pipelineを登録
スケジュールで自動実行されるPipelineを登録

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/e3b90916-802f-45a5-8c87-db503c6dfb61.png)

以下の画面で登録、スケジュールは cron と同じような記載の仕方になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/495c8be8-94d7-4743-8b16-e881d19a0cb0.png)

これで毎日15時に自動実行されます

# コンフィグバックアップを手動で実行
ここまで実施すると15時なればAnsibleコマンドを使ったコンフィグバックアップが実行されますが、手動実行させて動作確認もできます。以下の画面で実行できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/8894d0bb-0bf0-4ef9-ab84-533ec9c50237.png)

「Pipeline」の画面で動作状況が確認できます。正常に終了すると「Passed」になります
なんらかの理由で失敗した場合は赤で「Failed」になります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/3494b62e-8d96-474b-987a-2c17ea2b599f.png)

「Jobs」から実行結果が確認できます。失敗したときなどはこちらにエラー内容が表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/bc0dfebb-f79b-4580-bf68-3395fe723d4d.png)

# GitLab上でコンフィグの確認
以下の画面のとおり`backup-config`ディレクトリにコンフィグが保存されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/cd37e7cb-de9a-46fa-a4ae-c014b5be76cd.png)

コンフィグに差分があったときのみ反映され前回との差分は「History」から確認できます
インターフェースの description を変更した場合の例です、差分部分がわかりやすく表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3043279/2bbe7b1f-1ef6-463a-b814-4920f7e97792.png)

これで終了です

# 最後に
今回はshowコマンドでコンフィグ取得を行いました
（gitlab-runner の登録あたりが一番難しかった・・・）

次は、Netboxでパラメータ管理してその内容と実機の差分チェックや自動で設定反映させたい