概要
Python の paramiko を使っていろいろな ssh 接続をしてみました 便利だけどケースによってはハマる点も多いと思います
環境
- macOS 11.4
- Python 3.8.3
- paramiko
インストール
- pipenv install paramiko scp
普通に ssh する
connect メソッドを使って各種 ssh の基本パラメータを指定するだけです
コネクションを貼るので with を使うのをオススメします
import paramiko
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.100.10', port=22, username='user1', password='xxxxxxxxxx')
stdin, stdout, stderr = ssh.exec_command('hostname')
stdin.close()
print(stdout.read())
トラブルシューティング
paramiko.ssh_exception.SSHException: Server ‘192.168.100.10’ not found in known_hosts
以下で回避できます
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
AttributeError: ‘NoneType’ object has no attribute ‘time’
以下で回避できます
stdin.close()
もしくはコマンド実行後に 5 秒ほど wait を入れましょう 参考: https://github.com/paramiko/paramiko/issues/1617
鍵を使ってログインする
paramiko.RSAKey
を使います
鍵へのパスはフルパスを指定しましょう
相対パスやカレントパスを使うとうまく鍵ファイルを読み込めない場合があります
パスフレーズがある場合は一緒に指定します
import paramiko
rsa_key = paramiko.RSAKey.from_private_key_file("/path/to/key/privkey.pem", "xxxxxxxxx")
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.100.10', port=22, username='root', pkey=rsa_key)
stdin, stdout, stderr = ssh.exec_command('hostname')
stdin.close()
print(stdout.read())
scp する
scp モジュールと組み合わせることで使えます paramiko オンリーでは scp は使えません https://github.com/paramiko/paramiko/issues/150
以下はファイルをローカルからサーバにアップロードする方法になります 逆にダウンロードする場合は scp.get を使います
import paramiko
import scp
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.100.10', port=22, username='user1', password='xxxxxxxxxx')
with scp.SCPClient(ssh.get_transport()) as scp:
scp.put('hoge.txt', '/tmp/hoge.txt')
鍵を使って scp する
鍵認証+scp を組み合わせるだけです
import paramiko
import scp
rsa_key = paramiko.RSAKey.from_private_key_file("/path/to/key/privkey.pem", "xxxxxxxxx")
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.100.10', port=22, username='root', pkey=rsa_key)
with scp.SCPClient(ssh.get_transport()) as scp:
scp.put('hoge.txt', '/tmp/hoge.txt')
プロキシを使う
これがかなり曲者です ProxyCommand と組み合わせて使うのですが %h や %p などのテンプレート変数を paramiko は展開してくれません なので ssh コマンドで使っている ProxyCommand をそのまま使うと
paramiko.ssh_exception.ProxyCommandFailure: ProxyCommand(“nc -X connect -x 192.168.100.20:3128 %h %p”) returned nonzero exit status: Broken pipe」
と言ったエラーが発生します なお以下のサンプルは squid で ssh をプロキシした場合の ProxyCommand の設定になります
192.168.100.20 が squid プロキシで 192.168.100.10 が接続したい ssh サーバになります
import paramiko
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.100.10',
port=22,
username='user1',
password='xxxxxxxxx',
sock=paramiko.ProxyCommand("nc -X connect -x 192.168.100.20:3128 192.168.100.10 22"))
stdin, stdout, stderr = ssh.exec_command('hostname')
stdin.close()
print(stdout.read())
なお謎が解けなかったのは ProxyCommand で多段 ssh プロキシを使っている場合でプロキシも ssh でかつ鍵認証の場合に ProxyCommand で指定している ssh サーバの鍵のパスフレーズを指定する方法がわかりませんでした
もしかするとその場合はプロキシサーバにパスフレーズなしの鍵を登録しろってことなのかもしれません
最後に
多段プロキシで paramiko を使う場合はハマりどころがかなり多いと印象です 可能であれば多段プロキシを使わないケースで paramiko は使ったほうが良いかもしれません
0 件のコメント:
コメントを投稿