多数のNW機器をシミュレートするcisshgoについて
Cisco IOS機器を多数シミュレートするcisshgoとその使い方についてご紹介します。
はじめに
こんにちは、NTTテクノクロスの山口です。
皆様は複数のルータを操作する際に、手元にルータの実機がない状態であったり、簡単に早く用意できると良い、
と考えたことはないでしょうか。
具体的にはSDNコントローラのサウスバウンドで「多量のネットワーク機器を操作する見込みだが、
それだけの数の機器を用意できない場合」や「Ansibleで複数のNW機器にコマンドを入れる際に
ダミールータが欲しい場合」などが一例としてあげられます。
図1: SDNコントローラとサウスバウンドについて
今回はCisco IOS機器に限りますが、複数台シミュレートすることが出来るcisshgoについてご紹介します。
また、最後にはAnsibleを用いた、使用例も説明したいと思います。
■ 目次
節番号 | 節タイトル |
1 | cisshgoの使用方法 |
2 | dockerコンテナも組み合わせた使用例 |
3 | Ansibleを使った動作確認 |
cisshgoの使用方法
cisshgoは「はじめに」欄にも記載したように、Cisco IOS端末を疑似できる簡易シミュレータです。
準備は簡単で、Go言語で書かれたプログラムが動く環境で、gitからクローンするだけです。
# git clone https://github.com/tbotnz/cisshgo.git
使用方法はまずは以下3点をご紹介します。
① シンプルな起動例とシミュレータ接続例
② シミュレータの対応コマンド追加と出力結果の変更
③ 注意点
① シンプルな起動例とシミュレータ接続例
cisshgoは、以下のコマンドで起動します。
# go run cissh.go
2023/04/05 02:36:22 Starting cissh.go ssh server on port :10049
2023/04/05 02:36:22 Starting cissh.go ssh server on port :10023
2023/04/05 02:36:22 Starting cissh.go ssh server on port :10010
2023/04/05 02:36:22 Starting cissh.go ssh server on port :10011
2023/04/05 02:36:22 Starting cissh.go ssh server on port :10000
略
標準出力にも書かれているようにポート番号をずらしてシミュレータが起動されます。
デフォルトでは10000~10049の50シミュレータが起動します。
起動数の変更やIPを指定した起動方法は後述しますので、ここではまず接続について説明します。
上記コマンドで起動するとフォアグラウンドでcisshgoが起動する為、接続を試す場合は別ターミナルを立ち上げましょう。
初期設定のままであれば「ssh -p [ポート番号:例 10000] admin@127.0.0.1」で接続できるかと思います。
特にシミュレータ側でSSHで入れるようにする為の設定は不要です。
パスワードはadminとなっているはずです。
以下、例です。
admin@127.0.0.1's password:
cisshgo1000v>
cisshgo1000v>enable
cisshgo1000v#
② シミュレータの対応コマンド追加と出力結果の変更
デフォルト状態ではCisco IOSで使用できるモードやコマンドも、ごく一部しか対応されていません。
コマンドやモードを追加する場合はcisshgo/transcriptsディレクトリ配下にある「transcript_map.yaml」を更新します。
以下に上記ファイルの例を記載します。(赤字は追記箇所です)
platforms:
- csr1000v:
vendor: "cisco"
hostname: "cisshgo1000v"
password: "admin"
command_transcripts:
"show ip interface brief": "transcripts/cisco/csr1000v/show_ip_interface_brief.txt"
"show running-config": "transcripts/cisco/csr1000v/show_running-config.txt"
"show version": "transcripts/cisco/csr1000v/show_version.txt"
"terminal length 0": "transcripts/generic_empty_return.txt"
"terminal width 511": "transcripts/generic_empty_return.txt"
"write mem": "transcripts/cisco/csr1000v/write_mem.txt"
"password ios123" : "transcripts/generic_empty_return.txt"
"login" : "transcripts/generic_empty_return.txt"
context_hierarchy:
"(config-line)#": "(config)#"
"(config)#": "#"
"#": ">"
">": "exit"
context_search:
"line console 0": "(config-line)#"
"configure terminal": "(config)#"
"enable": "#"
"base": ">"
それぞれの項目を簡単に説明します。
項目名 | 説明 |
vendor | シミュレート対象を記載する。 基本的にこのままで良い。 |
hostname | シミュレータのホスト名を指定する。 |
password | シミュレータにログインする際にパスワードを指定する。 |
command_transcripts | シミュレータで受けつけるコマンドと、その出力結果を指定する。 |
context_hierarchy | モードの階層を指定する。 書式: [上層モード] : [下層モード]という記載をします。 ※ 上層/下層モードについては、図2も参照。 |
context_search |
モード切り替えの設定する。 左側に記載したコマンドを打った際に、右側に記載したモードに移行する。 |
図2 Cisco IOSのモードとcisshgoの設定について
上記のように「command_transcripts」と「context_search」に記載があるコマンドが対応しているコマンドです。
デフォルトではモードは「ユーザモード」「特権モード」「グローバルコンフィグレーションモード」しか対応しておらず、
コマンドも最低限のものしかない事がわかるかと思います。
検証で追加のコマンドが必要となった事を想定し、赤字でサンプルを追記しています。
この例ではコンソール接続時にパスワードをきかれるように設定するケースを想定し、
line consoleコマンドで「ラインコンフィグレーションモード」に移行する対応と
「password」コマンド、「login」コマンドの追加を行っています。
また上記の説明にもありますが、コマンドを打った際の標準出力は対象コマンドの右側に指定したパスのファイルをしています。
(追加した「login」コマンドであれば「transcripts/generic_empty_return.txt」に書かれた内容を出力結果として指定しています)
その為、指定されたテキストの中身を変えれば出力結果を変えられる他、新しいテキストを配置して、
「command_transcripts」でマッピングさせることも可能です。
これにより、ハイエンドな機器にしかないコマンドなどもある程度疑似する事が可能です。
③ 注意点
シミュレータの理想としては、使い方(何を確認する為に使いたいのか)にもよりますが、一般的にはより本物のNW機器に
近しい、かつ自由度が高い事が望ましいでしょう。
上記観点で、cisshgoについて特に私が気になった注意点が何点かありますので、以下の表にまとめました。
番号 | 説明 | 例 |
1 |
cisshgoはあくまでシミュレータであり、本物の機能が ※ あくまで呼び出しの応答を受け付けるスタブのような扱いが |
OSPFのような動的ルーティングのコマンドを入れても |
2 |
transcript_map.yamlに関する設定の変更、コマンド出力テキストの変更を |
transcript_map.yamlファイルに新しいコマンドを定義した場合や |
3 |
transcript_map.yamlで指定したコマンドはどのモードでも実行可能である。 この点の確認はログでコマンド投入順をチェックする等の手が有効。 |
本来はグローバルコンフィグレーションモードで |
4 |
transcript_map.yamlの「context_search」に記載するコマンドは ※ もし上記で対応できない細部設定をしたい場合は「utils」配下にある |
これまでの例でいえばラインコンフィグレーションモードと |
dockerコンテナも組み合わせた使用例
シンプルな使い方ではIPアドレスをシミュレータごとに変えることはできませんでした。
実際にNW機器を操作する場合はIPアドレスを指定することが想定される為、このままだと使い勝手が悪い場合があります。
その対応案としてdockerコンテナを使用した例を記載します。
対処方法は簡単で2手順のみとなります。
概要を図3に記載しますので、ご確認ください。
図3: cisshgoとdockerコンテナの組み合わせ方法について
以下で、それぞれの手順詳細を記載します。
① cisshgoディレクトリを対象としたdockerイメージを作成する。(以下はコマンド例です)
docker build --tag cisshgo:latest /home/ubuntu/cisshgo
イメージをビルドする前に「cisshgo」ディレクトリ配下の「Dockerfile」を以下のようにしておくと
良いでしょう。(赤字が追記箇所)
FROM golang:1.15.0-buster
ADD . /app
WORKDIR /app
ENV GO111MODULE=on
RUN go mod download
CMD go run cissh.go -listeners 1
上記はコンテナ内で1シミュレータしか立ち上がらないように設定をしています。
デフォルトでは50シミュレータ起動しますが、そのままではコンテナ内でも50シミュレータ起動し、
不効率となる為です。
② イメージ化したコンテナを起動する。(以下はコマンド例です)
docker run --name test1 --rm -d -it -p 127.0.0.2:222:10000 cisshgo:start1
※ -it でコンテナ起動後にコンテナ内での入力を受け付けるように、
-d でコンテナをバックグラウンドで実行するようにしています。
また、-p で127.0.0.2:222 とコンテナ内のポート10000(cisshgo起動ポート)を紐づけています
この方法でコンテナごとにIPアドレスを振ることが出来ます。
例えば上記例で2つ目のコンテナを立ち上げたければコンテナ名を「test2」とし、
紐づけるIPアドレスを「127.0.0.3」とすれば作成可能です。
接続も、「ssh -p 222 admin@127.0.0.2」で可能です。
今回はループバックアドレスを指定していますが、NICにIPアドレス帯を設定を行い、その範囲内のIPアドレスと紐づけたり、
ルーティング設定を行えば、コンテナごとに異なるIP、かつ外部マシンから直接アクセスも可能となります。
また、スクリプト化などで、多数のシミュレータを更に簡単に運用可能となります。
(この部分は基本的なNW設定やスクリプトの話であり、cisshgoから話が逸れる為、割愛します)
なお、ログはcisshgo直接実行時は、実行ターミナルを確認していましたが、
dockerコンテナとしたことでコンテナを指定して確認します。
docker logs [コンテナ名]
なお、dockerコンテナを再起動するとログはリフレッシュされるのでご注意ください。
また、transcript_map.yamlの設定やコマンド出力テキストを変更した場合はビルドから実行が必要となります。
Ansibleを使った動作確認
最後に、「はじめに」に述べたAnsibleを使った実行例を紹介します。
Ansibleには「ios_command」や「cli_command」と呼ばれる、NW機器にコマンドを入れる為のモジュールが存在します。
詳細な説明は割愛しますが、以下のPlaybookとhostsファイルにてcli_commandモジュールを使って、
cisshgoコンテナに対し「show running-config」を実行した際の実行例を記載します。
▼ Playbook(test_cisshgo.yaml)
- name: TEST COMMAND
hosts: cisco
gather_facts: false
tasks:
- name: insert command
cli_command:
command: show run
register: command_output
- name: show print
debug:
msg: "{{command_output.stdout}}"
▼ hosts
127.0.0.2
127.0.0.3
[all:vars]
ansible_connection=network_cli
ansible_become=yes
ansible_become_method=enable
ansible_network_os=ios
ansible_ssh_user=admin
ansible_ssh_pass=admin
ansible_ssh_port=222
▼ 実行結果
PLAY [TEST COMMAND]*****************************************************
TASK [insert command] *******************************************************
ok: [127.0.0.3]
ok: [127.0.0.2]
TASK [show print] ***********************************************************
ok: [127.0.0.2] => {
"msg": "Building configuration...\n\nCurrent configuration : 2114 bytes\n!\nversion 12.4\nservice timestamps debug datetime msec\nservice timestamps log datetime msec\nno service password-encryption\n!\nhostname cisshgo1000v\n!\nboot-start-marker\nboot-end-marker\n!\n!\nno aaa new-model\nmemory-size iomem 5\nno ip icmp rate-limit unreachable\nip cef\n!\n!\n!\n!\nno ip domain lookup\nip domain name test\nip auth-proxy max-nodata-conns 3\nip admission max-nodata-conns 3\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\nusername admin privilege 15 secret 5 $1$M1ce$SKeVGg2lUCPrsLkJMIdWf.\n!\n!\nip tcp synwait-time 5\nip ssh version 2\nip scp server enable\n!\n!\n!\n!\n!\ninterface FastEthernet0/0\n description netpalm\n ip address 10.0.2.27 255.255.255.0\n duplex auto\n speed auto\n!\ninterface Serial0/0\n no ip address\n shutdown\n clock rate 2000000\n!\ninterface FastEthernet0/1\n no ip address\n shutdown\n duplex auto\n speed auto\n!\ninterface Serial0/1\n no ip address\n shutdown\n clock rate 2000000\n!\ninterface FastEthernet1/0\n no ip address\n shutdown\n duplex auto\n speed auto\n!\ninterface FastEthernet2/0\n no ip address\n shutdown\n duplex auto\n speed auto\n!\ninterface FastEthernet3/0\n!\ninterface FastEthernet3/1\n!\ninterface FastEthernet3/2\n!\ninterface FastEthernet3/3\n!\ninterface FastEthernet3/4\n!\ninterface FastEthernet3/5\n!\ninterface FastEthernet3/6\n!\ninterface FastEthernet3/7\n!\ninterface FastEthernet3/8\n!\ninterface FastEthernet3/9\n!\ninterface FastEthernet3/10\n!\ninterface FastEthernet3/11\n!\ninterface FastEthernet3/12\n!\ninterface FastEthernet3/13\n!\ninterface FastEthernet3/14\n!\ninterface FastEthernet3/15\n!\ninterface Vlan1\n no ip address\n!\nip forward-protocol nd\n!\n!\nno ip http server\nno ip http secure-server\n!\nip access-list standard bob\nip access-list standard yip\n!\nsnmp-server community test RO\nsnmp-server community location RO yip\nsnmp-server community contact RO bob\nno cdp log mismatch duplex\n!\n!\n!\ncontrol-plane\n!\n!\n!\n!\n!\n!\n!\n!\n!\n!\nline con 0\n exec-timeout 0 0\n privilege level 15\n logging synchronous\nline aux 0\n exec-timeout 0 0\n privilege level 15\n logging synchronous\nline vty 0 4\n privilege level 15\n login local\n transport input ssh\nline vty 5 15\n privilege level 15\n login local\n transport input ssh\n!\n!\nend"
}
ok: [127.0.0.3] => {
(略)
PLAY RECAP ***********************************************
127.0.0.2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
127.0.0.3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
「insert command」タスクで問題なくコマンドが投入でき、「show print」タスクにてその出力結果も問題なくとれていることがわかるかと思います。
おわりに
今回は簡易に多数のCisco IOSシミュレータを用意できるツールとして、cisshgoをご紹介しました。
必要なシミュレータ数が少ない等の条件が合えば仮想ルータ等でも良いかもしれませんが、
数を用意する場合や、NW機器の機能自体には着目しない場合、特定機器にしか入らないコマンドがある場合等には
cisshgoが活躍できる場があるかと思います。
本記事、およびそれ以外のネットワーク関連に関して何か問い合わせがございましたら、以下にご連絡ください。
よろしくお願いいたします。
本件に関するお問い合わせ
免責事項
Cisco IOS は Cisco の所有物/商標です。
[著者プロフィール]
フューチャーネットワーク事業部 第一ビジネスユニット
山口 佳輝(YAMAGUCHI YOSHIKI)