web-dev-qa-db-ja.com

Paramiko-OSXで暗号化された秘密鍵ファイルを使用

Paramikoを使用してPythonからSSHサーバーに接続しようとしています。これは私がこれまでに試したことです:

>>> import paramiko
>>> import os
>>> privatekeyfile = os.path.expanduser('~/.ssh/id_rsa')
>>> mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/pkey.py", line 198, in from_private_key_file
    key = cls(filename=filename, password=password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/rsakey.py", line 51, in __init__
    self._from_private_key_file(filename, password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/rsakey.py", line 163, in _from_private_key_file
    data = self._read_private_key_file('RSA', filename, password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/pkey.py", line 280, in _read_private_key_file
    data = self._read_private_key(tag, f, password)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/paramiko/pkey.py", line 323, in _read_private_key
    raise PasswordRequiredException('Private key file is encrypted')
paramiko.PasswordRequiredException: Private key file is encrypted

ご覧のとおり、秘密鍵が暗号化されているために失敗しています。ただし、パスワードはOS Xログインキーチェーンに保存されており、ssh Hostと入力しても、パスワードは要求されません(むしろ、一度だけ要求され、次の再起動まで記憶されます)。 paramikoのように、sshにパスワードを使用させたり、キーチェーンからパスワードを取得させたりする方法はありますか?

19
houbysoft

RSAKey.from_private_key_file()PKey() ;から継承されます。このメソッドのオプションのパラメーターはパスワードです。引用するには:

秘密鍵が暗号化されていて、パスワードがNoneでない場合、指定されたパスワードが鍵の復号化に使用されます(そうでない場合、PasswordRequiredExceptionがスローされます)。

パスワードを渡さず、キーが暗号化されているため、この例外は常にスローされます。この問題を回避する唯一の方法は、実際にメソッドにパスワードを与えることです。したがって、OSXKeychainからパスワードを取得する方法が必要です。

クロスプラットフォーム Keyring モジュールを使用してこれを行うことができます。

8
Ben

次のアプローチは問題なく機能するようです(OS Xでは、パスフレーズがキーチェーンに保存されている暗号化された秘密鍵の通常のセットアップで、ユーザーの操作は必要ありません)。

import paramiko

ssh = paramiko.SSHClient()
ssh.load_system_Host_keys()
ssh.connect(Host, username=USER, look_for_keys=False)
...
ssh.close()

look_for_keys=Falseは絶対に必要というわけではないようです。ただし、これを使用すると、認証に失敗した場合のエラーメッセージが大幅に改善されます(「PasswordRequiredException」ではなく「AuthenticationException」)。


本当に秘密鍵を直接使用したい場合は、could次のようにします。

import os
import paramiko
import keyring

keyfile = os.path.expanduser('~/.ssh/id_rsa')
password = keyring.get_password('SSH', keyfile)
key = paramiko.RSAKey.from_private_key_file(keyfile, password=password)

しかし、私のテストに基づくと、これはnot必要です。 ssh.connectを簡単な方法で使用する上記のソリューションで十分です。

13
Jukka Suomela

ssh-agentは秘密鍵を提供しない (メモリダンプなし)のため、Paramikoで暗号化された秘密鍵を使用することはできません。

解決策は、subprocessを使用し、そこからsshコマンドを呼び出すことです(通常のコマンドと同様)。秘密鍵の復号化を要求しませんでした(sshエージェントを使用します。ssh -vvvを使用して見つけることができます)。

ところで、私はparamikoを使用する利点を見つけることができませんでした。 SSHエージェントは、より開発された、より一般的なツールのようです。たとえば、paramikoでは SSHエージェントを転送できません の場合、そのためにサブプロセスに頼る必要があります。また、注意してください この問題 2014年から、「キー処理はひどいです」(オープン):

SSHClient._authは、プロセスの最後に発生する単一の例外の保存と組み合わせた複数出口戦略を使用します。これは、認証時に発生した例外が、認証不能の真の原因に関して完全に不正確であることを意味することがよくあります。

このスレッドには多くのparamikoバグがリンクされています。現在活発に開発されているようで、paramikoで修正されることを願っていますが、私のアドバイスは次のとおりです。単一のライブラリに依存しないでください。要求を満たさない可能性があります。

はい、暗号化されたキーにパスワードを提供する可能性はありますが、それはその目的を損ないます。自分でパスワードを入力するか(sshのキーは必要ありません)、パスワードをディスクに保存します(もちろん、バージョン管理ではありません)。その後、秘密キーを暗号化する必要はありません(そのアイデア誰かがあなたのHDDを手に入れても、プレーンテキストであなたの秘密鍵を手に入れることはできないということです)。

0