Junos PyEZ を使用した Junos デバイスとの接続
概要 Junos PyEZアプリケーションで、異なる接続方法とプロトコルを使用して、Junosデバイスまたは接続されているコンソールサーバーに接続します。
Junos PyEZは、Junosデバイスの管理を可能にするPython用マイクロフレームワークです。Junos PyEZは、各デバイスを jnpr.junos.device.Deviceクラスの インスタンスとしてモデル化します。この Device
クラスを使用すると、シリアルコンソール接続、telnet、またはSSH経由でNETCONFセッションを確立することで、Junosデバイスに接続できます。さらに、Junos PyEZは、コンソールサーバーへのtelnetまたはSSH接続を介したデバイスへの接続もサポートしています。コンソール サーバーは、ターミナル サーバーとも呼ばれ、デバイスの帯域外管理コンソール ポートへのネットワーク接続を提供する特殊なデバイスです。
このトピックでは、Junos PyEZでサポートされている接続方法の概要と、さまざまな方法を使用してJunosデバイスに接続する方法について説明します。Junos PyEZの例では様々な認証方法を使用していますが、ユーザーの認証の詳細については、 Junos PyEZユーザーの認証を参照してください。
接続方法の概要
Junos PyEZでは、シリアルコンソール接続、Telnet、またはSSH経由のNETCONFセッションを使用して、Junosデバイスに接続することができます。デバイスの CONSOLE ポートに物理的に接続している場合は、シリアル コンソール接続を使用する必要があります。TelnetまたはSSHを使用して、デバイスの管理インターフェイス、またはデバイスの コンソール ポートに接続されているコンソール サーバーに接続できます。さらに、Junos PyEZはアウトバウンドSSH接続をサポートしており、Junosデバイスがクライアント管理アプリケーションとの接続を開始します。
工場出荷時のデフォルト設定の新しいデバイスまたはゼロ化されたデバイスは、コンソール接続を介してアクセスする必要があります。このように、Junos PyEZを使用して、デバイスに直接接続している場合はシリアルコンソール接続を使用するか、デバイスに接続されているコンソールサーバーを介してtelnetまたはSSHを使用して、リモートアクセス用にまだ設定されていないデバイスを最初に構成することができます。
デフォルトでは、Junos PyEZはSSHを使用してデバイスに接続します。別の接続の種類を指定するには、引数リストにパラメーターDevice
を含めるmode
必要があります。デバイスに telnet 接続するには、 引数を含めますmode='telnet'
。シリアル コンソール接続を使用してデバイスに接続するには、引数を含めますmode='serial'
。表1は、Junos PyEZの接続方法、特定のパラメーターのデフォルト値、必要なJunos OS設定、およびその接続方法のサポートが最初に導入されたJunos PyEZリリースをまとめたものです。
接続モード |
引数の値 |
デフォルトポート |
必要な Junos OS 設定 |
最初にサポートされた Junos PyEZ リリース |
---|---|---|---|---|
SSH経由のNETCONF(デフォルト) |
– |
830 |
[edit system services] netconf { ssh; } |
1.0.0 |
シリアルコンソール接続 |
シリアル |
/dev/ttyUSB0 |
– |
2.0.0 (*ニックス) 2.4.0 (ウィンドウズ) |
JunosデバイスへのTelnet |
Telnet |
23 |
[edit system services] telnet; |
2.0.0 |
コンソール・サーバーを介した Telnet |
Telnet |
23 |
– |
2.0.0 |
コンソール サーバー経由の SSH |
– |
22 |
– |
2.2.0 |
アウトバウンド SSH |
– |
– |
[edit system services] outbound-ssh { ... } |
2.2.0 |
SSH経由でTelnetまたはNETCONFを使用してデバイスの管理インターフェイスにアクセスするには、まず 階層レベルで適切なサービス [edit system services]
を有効にする必要があります。詳細については、 Junos PyEZマネージドノードのセットアップを参照してください。Telnet はクリア テキスト パスワードを使用するため (したがって、潜在的なセキュリティの脆弱性を生み出す)、SSH の使用を推奨します。
ユーザー名とパスワードの認証資格情報を、環境に適した安全な方法で取得するのはユーザーの責任です。暗号化されていない形式で資格情報を格納するのではなく、スクリプトを呼び出すたびにこれらの認証資格情報の入力を求めることをお勧めします。
Junos PyEZは、すべての接続方法でコンテキストマネージャー(with
...as
シンタックス)の使用をサポートしています。コンテキストマネージャーを使用すると、Junos PyEZ は自動的に メソッドとopen()
close()
メソッドを呼び出して、デバイスへの接続と切断を行います。コンテキスト・マネージャーを使用しない場合は、アプリケーションで and open()
close()
メソッドを明示的に呼び出す必要があります。コンソール接続にはコンテキスト・マネージャーを使用することをお勧めします。コンテキスト・マネージャーは接続のクローズを自動的に処理し、接続をクローズしないと予期しない結果が生じる可能性があるためです。
Junos PyEZ接続プロパティについて
Junosデバイスに接続すると、Junos PyEZは現在の接続に関する情報をインスタンスのプロパティとして保存します Device
。 表 2 に、使用可能な接続プロパティの概要を示します。
プロパティ |
説明 |
---|---|
|
接続の現在の状態を指定するブール値。接続時に戻ります |
|
アプリケーションが接続されているデバイスのホスト名を指定する文字列。 |
|
アプリケーションが接続されているルーティングエンジンがプライマリルーティングエンジンの場合に返される |
|
接続に使用するポートを指定する整数または文字列。 |
|
アプリケーションの接続先のルーティング エンジン名を指定する文字列。 |
|
RPC タイムアウト値を秒単位で指定する整数。 |
|
現在のルーティング エンジンが起動されてからの秒数を表す整数。このプロパティは、Junos PyEZ リリース 2.1.5 以降で利用可能です。 |
|
Junos デバイスにアクセスするユーザーを指定する文字列。 |
たとえば、デバイスに接続した後、プロパティに対してconnected
クエリを実行して、接続の現在の状態を返すことができます。A SessionListener
はセッションを監視し、例外を発生させTransportError
てプロパティFalse
を Device.connected
に設定することでトランスポート エラーに応答します。
次のサンプル コードは、Junos デバイスに接続した後、セッションを閉じた後にプロパティの値を connected
出力します。
from jnpr.junos import Device dev = Device(host='router.example.net') dev.open() print (dev.connected) dev.close() print (dev.connected)
プログラムを実行すると、アプリケーションがデバイスに接続されている間は connected
プロパティが返 True
され、接続が閉じられると制御 False
が戻ります。
user@host:~$ python connect.py True False
SSH を使用したデバイスへの接続
Junos PyEZ Device
クラスは、SSHを使用したJunosデバイスへの接続をサポートしています。デバイスの管理インターフェイスとSSH経由でNETCONFセッションを確立するか、デバイスの コンソール ポートに直接接続されているコンソールサーバーとSSH接続を確立できます。SSHサーバーは、 Junos PyEZユーザーの認証で説明されているように、標準のSSH認証メカニズムを使用してユーザーを認証できる必要があります。SSH経由でNETCONFセッションを確立するには、 Junos PyEZマネージドノードのセットアップで説明されている要件も満たす必要があります。
Junos PyEZ は、デフォルトの SSH 設定ファイル (~/.ssh/config) があれば、自動的にクエリーを実行します。SSH を使用して Junos デバイスまたはデバイスに接続されているコンソール サーバーに接続する場合、Junos PyEZ はまず SSH 公開キーベースの認証を試み、次にパスワードベースの認証を試みます。パスワードベースの認証を使用する場合、指定されたパスワードがデバイスパスワードとして使用されます。SSHキーが使用されている場合、提供されたパスワードが秘密キーのロックを解除するためのパスフレーズとして使用されます。SSH 秘密キーのパスフレーズが空の場合、パスワードは必要ありません。ただし、空のパスフレーズを含むSSHプライベートキーは推奨されません。
JunosデバイスとSSH経由でNETCONFセッションを確立し、Python 3を使用してJunos PyEZアプリケーションにデバイスファクトを印刷するには:
サンプルプログラム全体を以下に示します。
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.exception import ConnectError hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS or SSH key password: ") dev = Device(host=hostname, user=junos_username, passwd=junos_password) try: dev.open() except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) sys.exit(1) except Exception as err: print (err) sys.exit(1) print (dev.facts) dev.close()
または、デバイスに接続するときにコンテキストマネージャーを使用して、メソッドopen()
close()
とメソッドを自動的に呼び出すこともできます。例えば:
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.exception import ConnectError hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS or SSH key password: ") try: with Device(host=hostname, user=junos_username, passwd=junos_password) as dev: print (dev.facts) except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) sys.exit(1) except Exception as err: print (err) sys.exit(1)
Junos PyEZでは、クライアントがコンソールサーバーへのSSH接続を介してJunosデバイスに接続することもできます。この場合、引数リストに および 引数Device
を含めてcs_user
cs_passwd
、コンソール・サーバーのログイン資格情報を指定する必要があります。SSH キーが使用されている場合は、秘密キーのパスフレーズを含む変数に引数を設定しますcs_passwd
。
コンソール サーバーがシリアル接続を介してJunosデバイスに接続する場合、速度が低下する場合があります。コンソール サーバーを経由するJunos PyEZ接続のデフォルトの接続タイムアウト値は0.5秒です。その結果、クライアント アプリケーションが接続を確立するのに十分な時間を確保するために、引数を含めてDevice
timeout=seconds
接続タイムアウト間隔を増やす必要がある場合があります。
次のPython 3の例では、コンソールサーバーとJunosデバイスで認証します。クライアントが接続を確立するのに十分な時間を確保するために、接続タイムアウトは 6 秒に設定されます。
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.exception import ConnectError hostname = input("Console server hostname: ") cs_username = input("Console server username: ") cs_password = getpass("Console server or SSH key password: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") try: with Device(host=hostname, user=junos_username, passwd=junos_password, cs_user=cs_username, cs_passwd=cs_password, timeout=6) as dev: print (dev.facts) except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) sys.exit(1) except Exception as err: print (err) sys.exit(1)
Junos PyEZ は、デフォルトの SSH 設定ファイル (~/.ssh/config) があれば、自動的にクエリーを実行します。ただし、デバイス インスタンスを作成するときに、引数リストに パラメーターDevice
を含めるssh_config
ことで、別の SSH 構成ファイルを指定できます。例えば:
ssh_config_file = "~/.ssh/config_dc" dev = Device(host='198.51.100.1', ssh_config=ssh_config_file)
Junos PyEZは、netcatをサポートする中間ホストを介してターゲットデバイスにアクセスできるようにするプロキシコマンドもサポートしています。これは、中間ホストを介してのみターゲットデバイスにログインできる場合に便利です。
プロキシ コマンドを構成するには、SSH 構成ファイルに適切な情報を追加します。例えば:
[user1@server ~]$ cat ~/.ssh/config Host 198.51.100.1 User user1 ProxyCommand ssh -l user1 198.51.100.2 nc %h 22 2>/dev/null
アウトバウンド SSH を使用したデバイスへの接続
Junosデバイスを設定して、クライアントが接続を開始しようとした場合(デバイスがファイアウォールの内側にある場合など)にブロックされるクライアント管理アプリケーションとのTCP/IP接続を開始できます。この outbound-ssh
構成は、クライアント管理アプリケーションとの TCP/IP 接続を作成し、デバイスの ID を転送するようにデバイスに指示します。接続が確立されると、管理アプリケーションがクライアントとして動作してSSHシーケンスを開始し、Junosデバイスがサーバーとして動作してクライアントを認証します。
JunosデバイスでアウトバウンドSSHを設定してコミットすると、デバイスはコミットされた設定に基づいてアウトバウンドSSH接続を開始します。デバイスは、成功するまでこの接続を繰り返し試みます。デバイスとクライアント管理アプリケーション間の接続が切断されると、デバイスは成功するまで新しいアウトバウンド SSH 接続の作成を再試行します。この接続は、アウトバウンドSSH設定が削除されるか、無効化されるまで維持されます。
アウトバウンド SSH 接続用に Junos デバイスを設定するには、 階層レベルに ステートメントを含め outbound-ssh
ます [edit system services]
。次の例では、Junos デバイスはポート 2200 の 198.51.100.101 にあるホストとの接続を開始しようとします。
user@router1> show configuration system services outbound-ssh client nms1 { device-id router1; secret "$9$h1/ceWbs4UDkGD/Cpu1I-Vb"; ## SECRET-DATA services netconf; 198.51.100.101 port 2200; }
アウトバウンド SSH を使用して Junos デバイスとの接続を確立するために、Junos PyEZ アプリケーションは、コンストラクターの引数をsock_fd
既存のソケットのファイル記述子と等しく設定し、引数をhost
省略するか、 に設定しますNone
。Device
次のJunos PyEZの例では、Junosデバイスからの着信SSHセッションを、設定されたTCPポートでリッスンしています。アプリケーションは着信接続を受け入れ、引数の値 sock_fd
に使用されるその接続のソケットのファイル記述子を取得します。クライアントアプリケーションは、デバイスとの SSH 接続を確立し、デバイスファクトを収集して出力し、デバイスから切断して、さらなる接続を待ちます。
import socket from jnpr.junos import Device from jnpr.junos.exception import ConnectError from getpass import getpass from pprint import pprint """ Listen on TCP port 2200 for incoming SSH session with a Junos device. Upon connecting, collect and print the devices facts, then disconnect from that device and wait for more connections. """ def launch_junos_proxy(client, addr): val = { 'MSG-ID': None, 'MSG-VER': None, 'DEVICE-ID': None, 'HOST-KEY': None, 'HMAC': None } msg = '' count = 0 while count < 5: c = client.recv(1) c = c.decode("utf-8") msg += str(c) if c == '\n': count += 1 for line in msg.splitlines(): (key, value) = line.split(': ') val[key] = value print("{}: {}".format(key, val[key])) return client.fileno() def main(): PORT = 2200 junos_username = input('Junos OS username: ') junos_password = getpass('Junos OS password: ') s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(('', PORT)) s.listen(5) print('\nListening on port %d for incoming sessions ...' % (PORT)) sock_fd = 0 while True: client, addr = s.accept() print('\nGot a connection from %s:%d' % (addr[0], addr[1])) sock_fd = launch_junos_proxy(client, addr) print('Logging in ...') try: with Device(host=None, sock_fd=sock_fd, user=junos_username, passwd=junos_password) as dev: pprint(dev.facts) except ConnectError as err: print ("Cannot connect to device: {0}".format(err)) if __name__ == "__main__": main()
user@nms1:~$ python3 junos-pyez-outbound-ssh.py Junos OS username: user Junos OS password: Listening on port 2200 for incoming sessions ... Got a connection from 10.10.0.5:57881 MSG-ID : DEVICE-CONN-INFO MSG-VER : V1 DEVICE-ID : router1 HOST-KEY : ssh-rsa AAAAB...0aF4Mk= HMAC : 4e61201ec27a8312104f63bfaf77a4478a892c82 Logging in ... {'2RE': True, 'HOME': '/var/home/user', 'RE0': {'last_reboot_reason': 'Router rebooted after a normal shutdown.', 'mastership_state': 'master', 'model': 'RE-MX-104', 'status': 'OK', 'up_time': '2 days, 6 hours, 22 minutes, 22 seconds'}, 'RE1': {'last_reboot_reason': 'Router rebooted after a normal shutdown.', 'mastership_state': 'backup', 'model': 'RE-MX-104', 'status': 'OK', 'up_time': '2 days, 6 hours, 22 minutes, 12 seconds'}, 'RE_hw_mi': False, 'current_re': ['re0', 'master', 'node', 'fwdd', 'member', 'pfem'], 'domain': 'example.com', 'fqdn': 'router1.example.com', 'hostname': 'router1', ...
JunosデバイスでのアウトバウンドSSHの設定の詳細については、 アウトバウンドSSHサービスの設定を参照してください。
Telnet を使用したデバイスへの接続
Junos PyEZ Device
クラスは、ネットワーク デバイスへの暗号化されていないアクセスを提供する telnet を使用した Junos デバイスへの接続をサポートしています。デバイスの管理インターフェイス、またはデバイスの コンソール ポートに直接接続されているコンソール サーバーに Telnet で接続できます。管理インターフェイスへのアクセスを必要とするすべてのデバイスで、 [edit system services]
階層レベルで Telnet サービスを設定する必要があります。コンソール・サーバーを介してデバイスにアクセスすると、リモート・アクセス用にまだ構成されていない新規デバイスまたはゼロ化されたデバイスを最初に構成できます。
Junos PyEZ を使用して Junos デバイスに telnet 接続するには、引数リストに を含めmode='telnet'
Device
、オプションでポートを指定するための パラメーターを含めるport
必要があります。パラメーターを指定してmode='telnet'
省略port
した場合、 の値はport
デフォルトで 23 になります。アプリケーションがコンソール サーバー経由で接続する場合、コンソール サーバーが Junos デバイスに接続するときに使用するポートを指定します。
Junos PyEZを使用してJunosデバイスにtelnet接続し、Python 3を使用してJunos PyEZアプリケーションにデバイスファクトを印刷するには、次のようにします。
サンプルプログラム全体を以下に示します。
import sys from getpass import getpass from jnpr.junos import Device hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") dev = Device(host=hostname, user=junos_username, passwd=junos_password, mode='telnet', port='23') try: dev.open() except Exception as err: print (err) sys.exit(1) print (dev.facts) dev.close()
または、デバイスに接続するときに、接続のオープンとクローズを処理するコンテキストマネージャーを使用することもできます。例えば:
import sys from getpass import getpass from jnpr.junos import Device hostname = input("Device hostname: ") junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") try: with Device(host=hostname, user=junos_username, passwd=junos_password, mode='telnet', port='23') as dev: print (dev.facts) except Exception as err: print (err) sys.exit(1)
場合によっては、バナー・メッセージを出力するコンソール・サーバーに接続するときに、ログイン・プロンプトを表示するために、メッセージの後に Enter キーを押しなければならないことがあります。Junos PyEZ アプリケーションが、バナー メッセージの後に Enter キーを押す必要があるコンソール サーバーとの Telnet セッションを開くと、アプリケーションがログイン プロンプトを受信できず、接続がハングすることがあります。
Junos PyEZリリース2.6.2以降、Junos PyEZはコンソールサーバーのバナーを自動的に処理します。Junos PyEZリリース2.1.0から2.6.1では、Junos PyEZアプリケーションは、バナーメッセージを出力するコンソールサーバーにtelnetするための引数リストに含めるconsole_has_banner=True
Device
ことができます。
dev = Device(host=hostname, user=username, passwd=password, mode='telnet', console_has_banner=True)
引数を指定し console_has_banner=True
、最初の接続時にアプリケーションがログインプロンプトを受信しない場合、アプリケーションは5秒間待機してから改行(\n
)文字を出力し、コンソールサーバーがログインプロンプトを発行します。引数を省略して接続がハングした場合、アプリケーションは代わりに RPC を生成 <close-session/>
して接続を終了します。
シリアルコンソール接続を使用したデバイスとの接続
Junos PyEZ Device
クラスを使用すると、シリアル コンソール接続を使用して Junos デバイスに接続できます。リモート アクセス用にまだ設定されていない新しいデバイスやゼロ化されたデバイスを最初に設定する必要がある場合に便利です。この接続方法を使用するには、 CONSOLE ポートを介してデバイスに物理的に接続されている必要があります。デバイスの コンソール ポートへの接続に関する詳細な手順については、特定のデバイスのハードウェアマニュアルを参照してください。
Junos PyEZは、シリアルコンソール接続でのコンテキストマネージャーの使用をサポートしています。コンテキストマネージャーは接続のオープンとクローズを自動的に処理するため、コンソール接続にはコンテキストマネージャーを使用することをお勧めします。接続を閉じないと、予期しない結果が生じる可能性があります。
Junos PyEZ を使用して、シリアル コンソール接続を介して Junos デバイスに接続するには、引数リストに を含めmode='serial'
Device
、オプションでポートを指定するための パラメーターを含めるport
必要があります。パラメーターを指定してmode='serial'
省略port
した場合、 の値はport
デフォルトで /dev/ttyUSB0
になります。
シリアルコンソール接続を使用してJunosデバイスに接続し、Python 3を使用してJunos PyEZアプリケーションでデバイス上にコンフィグレーションを読み込んでコミットするには、次の手順に従います。
サンプルプログラム全体を以下に示します。
import sys from getpass import getpass from jnpr.junos import Device from jnpr.junos.utils.config import Config junos_username = input("Junos OS username: ") junos_password = getpass("Junos OS password: ") try: with Device(mode='serial', port='port', user=junos_username, passwd=junos_password) as dev: print (dev.facts) cu = Config(dev) cu.lock() cu.load(path='/tmp/config_mx.conf') cu.commit() cu.unlock() except Exception as err: print (err) sys.exit(1)