Ansibleを使ったCisco機器への接続・設定変更

# はじめに
前々からAnsibleによるネットワーク自動化には興味があったんですが、中々ネットワーク機器に対するナレッジが少なくて敬遠していました。

この記事が他のエンジニアの参考になるように残しておきます。

# 利用環境
サーバー：Ubuntu20.04
NW機器：Cisco WS-C3560CG-8PC-S
　→IOS Version：15.2(2)E10

【インストールソフト&バージョン】
Ansible：2.12.6
python：3.8.10

### 設定情報
サーバーホスト名：ansi101v
NW機器ホスト名：crhm02.nw.home.net
SSHログインユーザー名：ansible
SSHログインパスワード：password

# 事前準備
## サーバー側準備
サーバーにはもろもろのソフトをインストールしておきましょう。

### apt update
事前準備として、updateはしておきましょう。
```
apt update
```
### Ansibleインストール
公式ページの通りにインストールしましょう。
下記はubuntuのインストール方法です。
```
sudo apt update
sudo apt install software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install ansible
```
Ansible公式インストール方法
https://docs.ansible.com/ansible/2.9_ja/installation_guide/intro_installation.html#ubuntu-ansible

### python3-pipインストール
pipはPythonパッケージのインストールなどを行うユーティリティですが、後のansible-pylibsshインストールのためにやっておきます。
```
apt install python3-pip
```

### ansible-pylibsshインストール
```
pip install ansible-pylibssh
```
後にテストでAnsibleコマンドを使って対象機器にPingを打つんですが、その時にこいつをインストールしておかないとエラーが出ます。

```
root@ansi101v:~# ansible router -m ping
[WARNING]: ansible-pylibssh not installed, falling back to paramiko

#翻訳
[警告]: ansible-pylibssh がインストールされていないため、paramiko にフォールバックします。
```

## Network側準備
事前に下記のことは設定しておきましょう
他の細かい設定は割愛します。
・ホスト名設定
・enableパスワード設定
・SSH接続設定

AnsibleはSSHで接続できることが前提になっています。
下記を参照に設定してみてください。

https://www.infraexpert.com/study/ciscorouter7.html

# SSH接続確認
Cisco機器にSSHの設定を入れて、実際にサーバーからSSH接続できるか実験しておきましょう。

※もし引っかかったら
どうやらciscoでは鍵交換のハッシュ関数にSHA-1を使っているようですが、2005年に攻撃法が発見されて数年後の2017年にUbuntu17.04からデフォルトでSHA-1は無効化されているようです。

なので、サーバーから「そんな関数知らん」と怒られるらしいです。
解決方法としては、/etc/ssh/ssh_configに下記の文章を追加してあげてください。
```
KexAlgorithms=+diffie-hellman-group1-sha1
```

# hostsの作成
ここでは対象となる機器を記載したり、機器に付随する情報を記載していきます。
ここではroutersというグループを作って、そこに機器のFQDNを記載しています。
ただここはIPでも問題ありません。

```
[routers]
crhm02.nw.homw.net

[routers:vars]
ansible_user = ansible
ansible_password = password
ansible_connection = network_cli
ansible_network_os = ios
ansible_port = 22
```

| コマンド | 説明 |
| ---- | ---- |
| ansible_user | SSH接続をするためのユーザ名 |
| ansible_password | SSH接続をするときに使うパスワード |
| ansible_connection | 接続設定 |
| ansible_network_os | 対象OSの記載 |
| ansible_port | SSH接続時のポート番号(基本的に22) |

# Ping疎通確認
まずはAnsibleから対象機器へpingが通る確認します。
これで通れば今までの設定は問題ないと思ってもいいでしょう。

コマンドは`ansible routers -m ping`です。


問題がなければ下記の通り返ってきます。
```
root@ansi101v:~# ansible routers -m ping
crhm02.nw.home.net | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
```
# showコマンドのテスト
実際に設定変更をする前に、showコマンドを打って、返ってくるか確認してみます。
試しに"show interface status"を打ってみることにします。

コマンドは`ansible routers -m ios_command -a "commands='show int status'"`です。

結果として、上手くいくと下記の様に返ってきます。
```
root@ansi101v:~# ansible routers -m ios_command -a "commands='show int status'"
crhm02.nw.home.net | SUCCESS => {
    "changed": false,
    "stdout": [
        "Load for five secs: 17%/0%; one minute: 18%; five minutes: 18%\nTime source is NTP, 21:53:57.831 JST Mon Jun 13 2022\n\n\nPort      Name               Status       Vlan       Duplex  Speed Type \nGi0/1       connected    trunk      a-full a-1000 10/100/1000BaseTX\nGi0/2                        disabled     1            auto   auto 10/100/1000BaseTX\nGi0/3      connected    1          a-full a-1000 10/100/1000BaseTX\nGi0/4      connected    155        a-full a-1000 10/100/1000BaseTX\nGi0/5      connected    trunk      a-full a-1000 10/100/1000BaseTX\nGi0/6          connected    610        a-full a-1000 10/100/1000BaseTX\nGi0/7       connected    trunk      a-full a-1000 10/100/1000BaseTX\nGi0/8      connected    trunk      a-full a-1000 10/100/1000BaseTX\nGi0/9            notconnect   1            auto   auto Not Present\nGi0/10           connected    trunk      a-full a-1000 10/100/1000BaseTX"
    ],
    "stdout_lines": [
        [
            "Load for five secs: 17%/0%; one minute: 18%; five minutes: 18%",
            "Time source is NTP, 21:53:57.831 JST Mon Jun 13 2022",
            "",
            "",
            "Port      Name               Status       Vlan       Duplex  Speed Type ",
            "Gi0/1                        connected    trunk      a-full a-1000 10/100/1000BaseTX",
            "Gi0/2                        disabled     1            auto   auto 10/100/1000BaseTX",
            "Gi0/3                        connected    1          a-full a-1000 10/100/1000BaseTX",
            "Gi0/4                        connected    155        a-full a-1000 10/100/1000BaseTX",
            "Gi0/5                        connected    trunk      a-full a-1000 10/100/1000BaseTX",
            "Gi0/6                        connected    610        a-full a-1000 10/100/1000BaseTX",
            "Gi0/7                        connected    trunk      a-full a-1000 10/100/1000BaseTX",
            "Gi0/8                        connected    trunk      a-full a-1000 10/100/1000BaseTX",
            "Gi0/9                        notconnect   1            auto   auto Not Present",
            "Gi0/10                       connected    trunk      a-full a-1000 10/100/1000BaseTX"
        ]
    ]
}
root@ansi101v:~#
```
※もし下記のようなエラーが発生したら
```
The authenticity of host 'crhm02.nw.home.net' can't be established due to 'Host is unknown: 

##翻訳
ホスト 'crhm02.nw.home.net' の真正性は 'Host is unknown' のため確立できません。
```
これは「SSH接続先のホストを知りません。」という感じで疑っていると思ってください。
これを解決するには`/etc/ansible/ansible.cfg`に設定を追加します。

/etc/ansible/ansible.cfgに下記を追加。
```
[defaults]
host_key_checking = False
```
こうすることで、Ansibleに対してはホスト鍵を自動的に追加してくれます。サーバー全体の設定を変える場合は`/etc/ssh/ssh_config`の`StrictHostKeyChecking`設定を変更しましょう。

> 参考
>https://qiita.com/toshiro3/items/e380ac6c4e31e7588e19


# hostsの編集
設定変更をするために必要な情報を書き足します。
Ciscoの設定変更をする場合は権限昇格をしないといけません。所謂、特権モードにならないといけません。
そのため下記の通り、hostsファイルを書き換えます。
```
[routers]
crhm02.nw.home.net

[routers:vars]
ansible_user = ansible
ansible_password = password
ansible_connection = network_cli
ansible_network_os = ios
ansible_port = 22
ansible_become = yes #追加
ansible_become_method = enable #追加
ansible_become_password = password #追加
```
| コマンド | 説明 |
| ---- | ---- |
| ansible_become | 権限昇格をするかどうか(特権モードを許可するか) |
| ansible_become_method | 特権モードへ入るためのコマンド |
| ansible_become_password | 特権モードへ入るためのパスワード |

ちなみに、hostsのvarsへ記載する内容については、各OSのプラットフォームオプションを見るとわかります。
### Cisco IOSプラットフォームオプション
https://docs.ansible.com/ansible/latest/network/user_guide/platform_ios.html

# playbookの作成
今回は試しにLoopback21インターフェースを追加する設定を入れていきます。
PlaybookはYAML形式で記載されます。

そのため、まずは/etc/ansibleにyamlファイルを作成します。
ファイル名は例でdevnet.ymlとしています。特に決まりはないので、自由な名前にしましょう。

下記の様に記載します。
```
---
- name: General Config
  hosts: routers

  tasks:
  - name: Add loopback
    cisco.ios.ios_interface:
      name: Loopback21
      description: test-interface
      state: present
...
```
少し説明
```
---　←yamlを書く上での決まりで文章のはじめはハイフンを3つ記載します。
- name: General Config　←Playbookの名前のようなものです。
  hosts: routers　←対象の機器を設定しています。

  tasks:　←ここでどんな作業を実施するか記載します。
  - name: Add loopback　←作業名です。「動詞 + 名詞」などわかりやすく記載しましょう。
    cisco.ios.ios_interface:　←どこの設定をいじるか指定します。
      name: Loopback21　←IFの名前です。
      description: test-interface　←descriptionを指定します。
      state: present ←ステータス確認をするように設定します。
...　←yamlを書く上での決まりで文章の終わりにはピリオドを3つ記載します。
```
## Playbookの実行
Playbookも書けたのでさっそく実行します。
コマンドは`ansible-playbook devnet.yml`です。
※私は/etc/ansibleにファイルを保存しているので、cdでディレクトリを移動しています。


実行結果
```
root@ansi101v:/etc/ansible# ansible-playbook devnet.yml
[DEPRECATION WARNING]: cisco.ios.ios_interface has been deprecated. See the plugin documentation for more details.
This feature will be removed from cisco.ios in a release after 2022-06-01. Deprecation warnings can be disabled by
setting deprecation_warnings=False in ansible.cfg.

PLAY [General Config] ***********************************************************************************************

TASK [Gathering Facts] **********************************************************************************************
[WARNING]: Ignoring timeout(10) for ansible.legacy.ios_facts
ok: [crhm02.nw.home.net]

TASK [Add loopback] *************************************************************************************************
changed: [crhm02.nw.home.net]

PLAY RECAP **********************************************************************************************************
crhm02.nw.home.net         : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

root@ansi101v:/etc/ansible#
```
ちゃんと変更が完了すると、[PLAY RECAP]のokとchangedに数字が加算されます。

では、SWの方も見てみます。
```
#show run int loopback 21
Load for five secs: 18%/0%; one minute: 23%; five minutes: 20%
Time source is NTP, 22:06:32.654 JST Mon Jun 13 2022

Building configuration...

Current configuration : 71 bytes
!
interface Loopback21
 description test-interface
 no ip address
end
```
ちゃんと追加されていました。

#### 参考サイト
下記は構築の際に参考にしたサイトです。

https://docs.ansible.com/ansible/latest/network/index.html#network-guide

https://www.youtube.com/watch?v=OWKPxAgh9DU