1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ssh-agentを復号パスワードのキャッシュのように利用する簡易的なデータ暗号化/復号化するPythonモジュールを作ってみた。

Posted at

動機

cron等で定期的に認証のあるサーバーにhttp(s)アクセスするpythonスクリプトを書こうと思ったのだが、認証情報(http_user,http_password)を安全に保管する方法がないだろうか?と考えた。

  • 一般的な方法は、スクリプトとは別のファイルに保存して、ファイルのアクセス権限をファイルオーナーのみにする方法(chmod 0600 ....)である。 この場合、root権限のある人には見えてしまいそう。あと、ファイルバックアップとかでファイルが複製されたりする可能性とかも考えると、情報管理的に心配。
  • これを避けるためには、暗号化してファイルに書き込む必要がある。Pythonのスクリプトだと、ソースコードが丸見えで暗号化/復号化の方法を隠すことができないので、暗号化されたデータとともに復号のための情報(暗号化の際に用いたキーとか)が揃ってしまうと数行のスクリプトを書けば復号できてしまうので、これらの情報をファイルにセーブすると前項と同じ問題が生じる。
  • 上記の問題を避けるには、暗号化キーなどをファイル等にセーブするのではなく、人間が記憶して(コマンドラインオプション等で)スクリプトを実行する際に与える、といったことが必要。ただ、スクリプトをcron等で定期的に自動起動したい場合には別の手を考える必要がある。なにか別の方法が必要。
  • たとえば, SSH経由のrsyncなどで定期的にファイルを同期したい場合、ssh-agentに鍵をキャッシュさせたりする。最初に一度ssh-addをする必要があるが、ssh-agentに鍵が登録されている間は,ssh-agentのクライアントは鍵の利用が可能である。これを利用できないか?
  • ssh-agentから得られるのは秘密鍵なのでデータを直接暗号化することには適さないが、あらかじめ決めたデータを秘密鍵で署名することで、データを暗号化するためのキーの生成にはつかえるのでは?

と思ったところで、pythonにssh-agentのクライアントとしてつかえるモジュールparamikoを見つけたので、ssh-agentにある鍵を使って暗号/復号キーを生成して、データを暗号/復号するライブラリを作成することにした。 自分は暗号の専門家ではないので本当に安全な方法かわからないので、簡易的なデータのモザイク加工程度だと思って利用することにする。

暗号/復号の具体的な方法の概要

上記で思いついた方法を(絵で)まとめると下記。(図中のEncDSUtil....()は、後述の自作モジュールの関数)

復号化の手順をまとめると、下記。 暗号化されたデータと、暗号化の際に用いたMaster Key Phraseは平文で保存しておいたとしても、ssh-agentから秘密鍵をもってこないと復号できないはずで、そのためには ssh-agentに秘密鍵をデコードして渡すためのパスフレーズが必要 である。(実用的には、このほかにssh-agentに複数の登録されていることがありうるので、どの鍵を使うかという情報も必要。) そのため ssh-agentの信頼性と同程度には信頼できる気がする。(あくまでも無保証)

ちなみにRSA暗号ではうまくいくが、ed25519では、署名が必ずしも一定値でないのでこの目的には適さない模様。

実装(1)

この目的で使うRSAの鍵ペアとしては、普段sshコマンドで使う鍵ペアとは別途用意するのが無難に思われる。
paramikoは、ssh-agentにある鍵のリストを作る機能はあるが、
この目的ではいくつかの鍵を使い分けることにもなると思うので、まず、pythonSSHの鍵を管理するモジュールsshkeyringを作成した。

  • ファイル置き場
  • インストール方法
    sample
    % pip install sshkeyring
    
  • 機能
    • 必要な場合にSSH鍵ペアの自動生成
    • 必要な場合にSSH鍵をssh-agentに登録
    • 必要な場合にssh-agentを起動
    • ssh-agentから特定のIDの秘密鍵を取得
    • (ssh-agentを使わず、ローカルの鍵ファイルの利用することにも対応)

paramikoを拡張してみた件については、別記事にあります。

実装(2)

実際にデータを暗号化/復号化する機能を持ったクラスを提供するモジュールenc-dsを作成した。

  • ファイル置き場
  • インストール方法
    sample
    % pip install enc-ds
    
  • 機能:
    • sshkeyringを使って、SSH鍵を使えるようにセットアップ
    • 多層のdict型、list型による木構造のデータ構造(enc_ds.DataTree クラス)のバッファをもつ。
    • バッファにあるデータの暗号化、復号化
    • 暗号化されたデータをファイルから読み込んで復号
    • データを暗号化してファイルに保存
    • ファイル形式としては、json形式,yaml形式,toml形式,ini形式および、これらの圧縮ファイル(bzip2,xz,gzip)に対応。

詳しい使い方の説明はこれから整備したいとおもいますが、サンプルスクリプトenciphered_datastorage(.py)も同梱しています。このサンプルスクリプトは、コマンドラインツールとして、データやファイルの暗号化・復号が可能です。

初回起動時には、

sample
% ./bin/enciphered_datastorage -p ...somewhere... -v -i id_rsa_test 'Sample Plain Text' 'Second Data'

...
[Enc_ds.enc_ds.setup_sshkeyinfo:744] Info :  Key ID in use : id_rsa_test, Key Type in use : rsa
[SSHKeyInfo.set_passphrase:108] private key passphrase: 
[SSHKeyRing.ssh_add_keyinfo:308] Info ssh-add : ssh-agent ( key id: id_rsa_test, type: rsa, sock :  *******)
...

とSSH鍵をつくるためのパスフレーズのプロンプトが出て、入力するとRSA鍵ペアができて、ssh-agentが登録されます。2回目以降はssh-agentに登録されている鍵が使われます。上記の例では、

---------------------------------------------------------------
(0) Input              : Sample Plain Text
---------------------------------------------------------------
(0) Enciphered         : b'\x00\x00\x00\x10\xab\x85\x18\x9d\xa3Op\xa9$\x1eD\x1fuEY\x9e\xa4~\xf5G/\xd2\xb9\xbf\xa3\xbd\xd2\x10&\xb6XS\xbb\xf1Y\x94\xcd\xcdwnrX\x1a\x94Can\x10\xe7+#YO\xde\xa6\xe8\xcc*\xefdx\x8e\x9d\xc8\x1d'
(0) Enciphered data    : {'data': b'\x00\x00\x00\x10\xab\x85\x18\x9d\xa3Op\xa9$\x1eD\x1fuEY\x9e\xa4~\xf5G/\xd2\xb9\xbf\xa3\xbd\xd2\x10&\xb6XS\xbb\xf1Y\x94\xcd\xcdwnrX\x1a\x94Can\x10\xe7+#YO\xde\xa6\xe8\xcc*\xefdx\x8e\x9d\xc8\x1d', 'iv': b'\xe7\xff\x89+J\xae}\xa7S\x91\xa3\xd0', 'salt': b'\xb8\xcf\xa9+}\xb3\xf8Lw%\x02M\xac\x16\x9f:\xa5W4V\x07p\x8eMP\t+K\xcfI#`', 'mkey': 'A0/WJqvYO6VtnpmXH/cUGj5s2a5ACw8minvHvhemLnw=', 'pkey': '8e04UCkhFk+eW7nM8ewH9g=='}
(0) Deciphered (Check) : Sample Plain Text
---------------------------------------------------------------
[EncDSUtil.CheckBytesLength:52] New 256-bytes data is created recreated
---------------------------------------------------------------
(1) Input              : Second Data
---------------------------------------------------------------
(1) Enciphered         : b'\x00\x00\x00\x10\x9dL\x10\x07\x15\x17\xe6\x081\xa8\xbd\x19I@\xdaR\xf7a\x81K\x97\xb6c\xe8 G\xb2\xeav\xb7\x1a\xe0\xf6\xcf\x1f\xfe\x82\x03X\n[\xdbT(}\xc4\x9c\x8d\xfa\x05\xba\x0b\x96\xf3z\xbc/\xda\xe4'
(1) Enciphered data    : {'data': b'\x00\x00\x00\x10\x9dL\x10\x07\x15\x17\xe6\x081\xa8\xbd\x19I@\xdaR\xf7a\x81K\x97\xb6c\xe8 G\xb2\xeav\xb7\x1a\xe0\xf6\xcf\x1f\xfe\x82\x03X\n[\xdbT(}\xc4\x9c\x8d\xfa\x05\xba\x0b\x96\xf3z\xbc/\xda\xe4', 'iv': b'\xbb\xdd\xe4yH+\xea\xb1\xd5T)f', 'salt': b'a\x95j\xa6~\x03\xb4\xfd\xe0F\xa3\x92\x0cq&\x1a\x00\x9a\x96"\x1aXD7X\xf1}d\x82[\x83\xbf', 'mkey': 'A0/WJqvYO6VtnpmXH/cUGj5s2a5ACw8minvHvhemLnw=', 'pkey': '8e04UCkhFk+eW7nM8ewH9g=='}
(1) Deciphered (Check) : Second Data
---------------------------------------------------------------

といった感じで、引数の文字列を暗号化し、また復号できることをチェックします。また、
--encode-mode --decode-modeというオプション引数をつけると、ファイルIOに対応します。

まとめ

汎用性の高いクラスになった気もしますが、説明が足りないですね。おいおい使用例を作っていこうと思います。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?