Cisco SD-WAN SD-AVC カスタムアプリでZoomアドレスの自動入力

# はじめに
以下の記事を最新のCiscoSD-WANでサポートされたSD-AVCを使ってZoomをIPアドレスからアプリ識別させるために作成しました。

https://qiita.com/KoheiYamashita1/items/df798022b2697464e2d8

# 更新点
### このスクリプトの説明
Zoomのアドレス一式をScrapingしてプレフィックス（10.0.0.0/24のような記載）をピックアップしてこれをAPIで設定する。取得したプレフィックス一式を以前はData-Plefix-listにアップデートしていたが、今回はSD-AVCのカスタムアプリに設定する。カスタムアプリはポリシー設定が動作中であってもアプリ情報が**動的に変更が可能な点**が以前からの更新点です。

# コードサンプル
```python
#!/usr/local/bin/python3
import re
import sys
import requests
import json
import urllib3
from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)

# Enter your vManage credentials, data-prefix-list-uuid, vSmart-polocy-uuid
vManage_IP = "vManageのFQDNもしくはIPを書いてね"
vManage_ID = "admin"
vManage_Password = "admin"
CustmonApp_uuid = "c1be4143-306a-4621-b9fa-9a2639cbc671" 

//カスタムアプリのUUIDはご自身のものをあらかじめダミーで作ってUUIDを作成してください。
//https://vManage Address/apidocs/ 
//Configuration - Policy Custom Application BuilderのGETでUUIDを確認できます

def get_addresslist(url):
    response = requests.get(url)
    return response.content

def export_file(content, list_file_name):
    with open(list_file_name, "wb") as list_file:
        list_file.write(content)

def create_scrape_destination_list(sourcefile):
    result = []
    with open(sourcefile, "r") as f:
        fin = f.read()
        found = re.findall(r'(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\.(?:[\d]{1,3})\/(?:[\d]{1,2})',fin)
        if found not in result:
            result = json.dumps(found)
    return json.loads(result)

def login(vmanage_ip, username, password):
    session = {}
    base_url_str = 'https://%s:443/'%vmanage_ip
    login_action = '/j_security_check'
    login_data = {'j_username' : username, 'j_password' : password}
    login_url = base_url_str + login_action
    url = base_url_str
    sess = requests.session()
    #URL for retrieving client token
    token_url = base_url_str + 'dataservice/client/token'
    # If the vmanage has a certificate signed by a trusted authority change verify to True
    login_response = sess.post(url=login_url, data=login_data, verify=False)
    login_token  = sess.get(url=token_url, verify=False)
    try:
        if login_response.status_code == 200 and login_token.status_code == 200 :
            sess.headers['X-XSRF-TOKEN'] = login_token.content
            session[vmanage_ip] = sess
            return session[vmanage_ip]
        elif '<html>' in login_response.content:
            print ("Login Failed")
            sys.exit(0)
        else:
            print("Unknown exception")
    except Exception as err:
        return

def put_prefix_list_builder(list_IPv4):
    lst = []
    for pn in list_IPv4:
        d = {}
        d['ipAddresses'] = pn,
        lst.append(d)
    json.dumps(list_IPv4)
    payload = {
                "appName": "zoom",
                "serverNames": [
                               "*.zoom.us"
                ],
                "L3L4":lst
                }
    test = json.dumps(payload)
    headers = {'Content-Type': 'application/json'}
    sessions = login(vManage_IP, vManage_ID, vManage_Password)
    url = 'https://'+vManage_IP+':443/dataservice/template/policy/customapp/'+CustmonApp_uuid
    print('vManage API URL :'+url)
    r = sessions.put(url, data=test, headers=headers, verify=False)
    if r.status_code != 200:
        print(r.raise_for_status)
    else:
        return

if __name__ == "__main__":
    MASTER_FILE_NAME = "webex-address-range.txt"
    URL = 'https://onlinezoomappdownload.com/about-firewall-or-proxy-server-configuration-requirements-in-zoom-app/'
    print('webex URL :'+URL)
    address_list_file = get_addresslist(URL)
    export = export_file(address_list_file, MASTER_FILE_NAME)
    list_IPv4 = create_scrape_destination_list(MASTER_FILE_NAME)
    put_prefix_list_builder(list_IPv4)
    print(f"Process Completed!! , check https://{vManage_IP}:443/#/app/config/policy/custom/centralizedPolicy/define_lists/application , move to CustomApplications TAB.")
```

# コマンド実行結果
```bash
webex URL :https://onlinezoomappdownload.com/about-firewall-or-proxy-server-configuration-requirements-in-zoom-app/
vManage API URL :https://vManage Address:443/dataservice/template/policy/customapp/c1be4143-306a-4621-b9fa-9a2639cbc671
Process Completed!! , check https://vManage Address:443/#/app/config/policy/custom/centralizedPolicy/define_lists/application , move to CustomApplications TAB.
```

# 実行結果画像
![スクリーンショット 2021-11-15 12.16.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259135/b8933708-49fa-034c-384a-0fe941a4e8e4.png)

# おわりに
SD-AVCのJSONでアドレスをディクショナリ形式で整形してペイロードに入力する部分が少しトリッキーですが型式が分かれば簡単です。

# 参考文献
SD-WAN SD-AVC関連のリンクを貼っておきます。

https://www.cisco.com/c/en/us/td/docs/routers/sdwan/configuration/policies/ios-xe-17/policies-book-xe/traffic-flow-monitor.html

https://www.cisco.com/c/en/us/td/docs/routers/sdwan/configuration/policies/ios-xe-17/policies-book-xe/m-custom-applications.html