#概要
Cisco ASA (ファイアーウォール)のLocal DBにユーザーを登録した時の話。
ユーザー数が多くて、CLIのコマンドをExcelで作ろうかなと思いましたが、せっかくなのでPythonのNetmikoモジュール使って登録してみました。
#実行環境
Python 3.8
Cisco ASA 9.8.4
使用するPythonモジュール
・netmiko 3.1.0
・pandas 1.0.3
#フォルダ構成
project/
├ input
│ └ user_list
├ output
└ asa_conf.py
input/user_list
csv形式のファイルでasa_conf.pyからユーザー情報を読み取ります。
内容↓
username1 , password , group
username2 , password , group
...
※ヘッダーはつけてません^^;
#コーディング
import pandas as pd
import os
import netmiko
cwd = os.path.dirname(os.path.abspath(__file__))
userlist = os.path.join(cwd, r"input\userlist")
#Cisco ASAへの接続情報
asa = {
"device_type":"cisco_asa",
"ip":"10.0.1.1",
"username":"asa_user",
"password":"asa_pass",
"secret": "super"
}
con=netmiko.ConnectHandler(**asa)
con.enable()
#ユーザーリストの読み込み
df = pd.read_csv(userlist, header=None, names=("user","pass","group"), sep=",")
#一行ずつ読みこみ
for index,row in df.iterrows():
data = pd.Series(row, index=["user", "pass","group"])
#変数に代入しコマンドセット作成
command_set=[
"username {0} password {1}\n".format(data["user"],data["pass"]),
"username {0} attributes\n".format(data["user"]),
"vpn-group-policy {0}\n".format(data["group"]),
"service-type remote-access\n",
]
#デバッグ用
output = con.send_config_set(cm, exit_config_mode=False)
print(output)
#接続切断
con.disconnect()
#解説
cwd = os.path.dirname(os.path.abspath(__file__))
userlist = os.path.join(cwd, r"input\userlist")
user_listファイルの場所を指定しています。
今回のディレクトリ構成を考慮し、1行目で実行ファイルの絶対パス情報から、projectディレクトリまでのパスを取得、2行目で以降、userlistまでのパスを連結しています。
asa = {
"device_type":"cisco_asa",
"ip":"10.0.1.1",
"username":"asa_user",
"password":"asa_pass",
"secret": "super"
}
con=netmiko.ConnectHandler(**asa)
con.enable()
接続するための情報を辞書型で指定し、接続ハンドラーに渡しています。
Device_Typeは機器に応じたものを指定する必要がありますので以下リンク参照。
[Git-Hub_ssh_dispatcher.py]
https://github.com/ktbyers/netmiko/blob/master/netmiko/ssh_dispatcher.py
#####・ユーザーリスト読み込み
df = pd.read_csv(userlist, header=None, names=("user","pass","group"), sep=",")
for index,row in df.iterrows():
data = pd.Series(row, index=["user", "pass","group"])
pandasを使ってユーザーリストを読み込んでいます。
ファイル内でヘッダーを用意していないので、names引数で読み込むときにヘッダーをつけています。
登録するユーザーごとに登録コマンドを生成する必要があったので、今回は順読みする形で処理をしています。
df.iterrowsを使うと、行データを(index, data)の形式で値を返し、実際の行データを取得するにはpd.serieseを使う必要があります。
#####・コマンドの作成
command_set=[
"username {0} password {1}\n".format(data["user"],data["pass"]),
"username {0} attributes\n".format(data["user"]),
"vpn-group-policy {0}\n".format(data["group"]),
"service-type remote-access\n",
]
実際の行データへのアクセスはdata["index"]で行えるので、コマンドテンプレートをあらかじめ用意しておき、formadメソッドで値を置き換えてます。
#####・コマンド実行
for cm in command_set:
output = con.send_config_set(cm, exit_config_mode=False)
作成したコマンドをcon.send_config_setで実行しています。ここでポイントなのが、exit_config_mode=Falseとすること。
デフォルトでは1回コマンドを実行するごとにendを実行するようで、各コンフィグレーションモードに以降してから実行する必要があるコマンドはErrorになります。※今回のケースだと、コマンドセットの2行目以降。
#まとめ
とりあえず、あまり時間をかけず、エイヤァで作成したので例外処理はしていません。
今回のようにコマンドが複数行にわたる場合はExcelだと結構面倒くさいイメージなので、その点は解消できるかなと思います。※単純に自分にExcelスキルがないだけ。。。
今回、勉強のためPandasを無理やり使いましたが、csvモジュールでも全く問題ありません。
con.send_config_setはコマンド実行間隔がデフォルト1秒(delay_factorで変更可能)になっていますので対話作業でのツール用途としてはストレスかも。Netmikoではなく、コマンドをファイルに吐き出してTeratermでコマンド流しこむのもありかと思います。
Netmikoのドキュメント
[Nttmiko]https://ktbyers.github.io/netmiko/docs/netmiko/base_connection.html