Cisco SD-WAN OCN MAP-E証明書の一括インストール

# はじめに
この記事は2023年CiscoSystems合同会社 社員有志 による Advent Calendar の記事の一つです。
残念ながらカレンダーに空きがなかったので個別に投稿しています。

https://qiita.com/advent-calendar/2023/cisco

<!-- 発端や概要を記載 -->

# この記事の目的
[OCN MAP-E設定](https://qiita.com/KoheiYamashita1/items/8e6a8e5c774c0a65be88)
上記サイトはCiscoSD-WANのMAP-E機能を使ってSD-WANルータをIPoE環境で構築する基本設定を紹介しています。この設定のうち、MAP-EのAddressサーバとのHTTPSアクセスのためのRoot証明書をルータにインストールする手順を簡素化するためのスクリプトを作成しました。

![スクリーンショット 2022-12-07 11.41.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259135/37abfc28-12b0-d3f1-6ddf-5aca77a1fe4a.png)

<a>Pythonスクリプトの使い方</a>
vManageには必要なモジュールがすでにインストールされていますのでPIPインストール等は不要です。PCなどで使う時には必要に応じてインストールしてください。

 1. [ここ](https://certs.secureserver.net/repository/sf-class2-root.crt)からRoot証明書をダウンロード
 1. vManageに必要なpython本体とRoot証明書をアップロード
 1. コマンド実行
  ```python
  vmanage#vshell
  vmanage:~/$ python3 tools.py 8.1.1.1 admin admin
  ```

<a>スクリプト本体</a>
```python
#!/usr/bin/python3
import os
import paramiko
import argparse
import time
import multiprocessing

def transfer_file_and_execute(router_ip, username, password):
    transfer_file(router_ip, username, password)
    connect_and_execute(router_ip, username, password)

def transfer_file(sip, loginid, loginpass):
    file_path = './TP.ca'
    remote_path = f'/bootflash/sdwan/TP.ca'
    command = f'sshpass -p {loginpass} scp -o StrictHostKeyChecking=no -P 830 {file_path} {loginid}@{sip}:{remote_path}'
    os.system(command)

def connect_and_execute(router_ip, username, password):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    try:
        ssh.connect(router_ip, port=830, username=username, password=password)
        shell = ssh.invoke_shell()

        shell.send("shell\n")
        time.sleep(1)
        output = ""
        while shell.recv_ready():
            output += shell.recv(1024).decode()

        if "password:" in output.lower():
            shell.send(f"{password}\n")

        shell.send("terminal length 0\n")
        time.sleep(1)
        output = ""
        while shell.recv_ready():
            output += shell.recv(1024).decode()

        shell.send("copy bootflash:sdwan/TP.ca bootflash:TP.ca\n")
        time.sleep(1)
        output += shell.recv(1024).decode()

        shell.send("\n")
        time.sleep(5)
        output_copy = ""
        while shell.recv_ready():
            output_copy += shell.recv(1024).decode()

        shell.send("crypto pki authenticate TP\n")
        time.sleep(3)
        output_authenticate = ""
        while shell.recv_ready():
            output_authenticate += shell.recv(1024).decode()

        print(f"Output of 'copy' command for {router_ip}:\n", output_copy)
        print(f"Output of 'crypto pki authenticate' command for {router_ip}:\n", output_authenticate)

        ssh.close()

    except paramiko.AuthenticationException:
        print("Authentication failed. Please check your credentials.")
    except paramiko.SSHException as ssh_ex:
        print(f"Error while connecting: {ssh_ex}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Connect to Cisco SD-WAN router and execute commands.")
    parser.add_argument("routers", nargs='+', help="The router IP addresses")
    parser.add_argument("username", help="The router username")
    parser.add_argument("password", help="The router password")
    args = parser.parse_args()

    processes = []
    for router_ip in args.routers:
        process = multiprocessing.Process(target=transfer_file_and_execute, args=(router_ip, args.username, args.password))
        processes.append(process)
        process.start()

    for process in processes:
        process.join()
```

<a>実行結果</a>

```
vmanage:~/star$ python3 tools.py 8.1.1.1 admin admin
Output of 'copy' command:

Copy in progress...C
1468 bytes copied in 0.011 secs (133455 bytes/sec)
c8kv-001#
```
<a>確認コマンド</a>
show crypt pkt trustpoint TP

<a>ルータ上であらかじめ設定が必要なConfig
```
crypto pki trustpoint TP
 enrollment url bootflash:
 fingerprint      AD7E1C28B064EF8F6003402014C3D0E3370EB58A
 revocation-check none
!
```

<a id="#参考文献"></a>
# 参考文献
- [OSVerion17.13のリリースノート](https://www.cisco.com/c/en/us/support/routers/sd-wan/products-release-notes-list.html)
- [エンドユーザマニュアルのリンク](https://www.cisco.com/c/en/us/td/docs/routers/sdwan/config/ios-xe-sdwan17.html)
- [MAP-Eのアドレス算出方法 *Cisco以外のサイト](https://www.janog.gr.jp/meeting/janog31/doc/janog31-MAP-asama-01.pdf)