GPG + Expect で複数のパスワードを共通管理

お仕事のソフトウェア開発は複数の会社(日本 + 海外)で共同で行っている。そのため、必然的に海外のマシンに接続する必要が出てくる。バグ管理システム(Bugzilla)やビルドマシンは言うに及ばず、開発チームの wikiテスト管理システム(Testopia)、Subversion レポジトリなどなど…とにかくリモートから色々なサービスを利用することになる。

このリモート間での作業を効率化するため、このたび OpenVPN が開通した。これであたかもリモートのマシンが内部のネットワークにいるかのごとく作業できる。

ただ、その度に悩むのがパスワードの管理。システム管理者から「あなたの OpenVPN パスワードはこれよん」という GPG メールが送られてくるのだが、他にもいろいろあって覚えきれない。そこで複数のアプリに使用するパスワードを共通のパスフレーズで一元管理できないか考えてみた.

以下は dia で描いた設計アイデア


1. まず、各種パスワード(例として OpenVPN 用、マシンA の root 用、mysql 用)をそれぞれのテキストファイルに保存する(ここではサンプルなので mkpasswd を使っている)。

$ cat "BwJRjKvqlZeOc" > pass.openvpn
$ cat "ltubEfK.ZKxJ6" > pass.machineAroot
$ cat "Jzq.XM5OwhUsQ" > pass.mysql

2. 次にこの 3 つのパスワードファイルを gpg を使って共通のパスフレーズ「hirake, goma」で暗号化する。暗号化した後は、元の平文ファイルを削除する。

$ ls
pass.machineAroot  pass.mysql  pass.openvpn
$ echo "hirake, goma" | gpg --force-mdc --passphrase-fd 0 --batch -c pass.openvpn
$ echo "hirake, goma" | gpg --force-mdc --passphrase-fd 0 --batch -c pass.machineAroot
$ echo "hirake, goma" | gpg --force-mdc --passphrase-fd 0 --batch -c pass.mysql
$ ls
pass.machineAroot      pass.mysql      pass.openvpn
pass.machineAroot.gpg  pass.mysql.gpg  pass.openvpn.gpg
$ rm pass.openvpn pass.machineAroot pass.mysql
$ ls
pass.machineAroot.gpg  pass.mysql.gpg  pass.openvpn.gpg

3. 最後にこの暗号化されたパスワードファイルからパスワードを読み取り各種処理(OpenVPN スタート、scp, mysql の DB データ抽出など)を実行するスクリプトを作成する。どのスクリプトにも共通のパスフレーズである「hirake, goma」を唱えると gpg がパスワードファイルを復号化してパスワードを Expect に渡すようにしている。

#!/bin/bash

DECRYPT_PASSWORD=`gpg -d pass.openvpn.gpg`
expect -c "
spawn startopenvpn.sh
expect password:
send $DECRYPT_PASSWORD\n
expect eof"
#!/bin/bash

DECRYPT_PASSWORD=`gpg -d pass.machineAroot.gpg`

expect -c "
spawn scp -rp src machineA:/tmp
# rsync など各種処理 ...
expect password:
send $DECRYPT_PASSWORD\n
expect eof"
#!/bin/bash

DECRYPT_PASSWORD=`gpg -d pass.mysql.gpg`

expect -c "
spawn mysql -u root -p
expect password:
send $DECRYPT_PASSWORD\n
# データ抽出など各種処理
expect eof"

古典的な「環境変数にパスワードを保存 + Expect で渡す」方法だと確かに全自動でラクなのだが、メモリ上に残るため、set や declare -x などで閲覧が可能なところがなんとなく気持ちが悪い。上記の方法ならば画面にも出てこないし、メモリにも各種スクリプト(プロセス)の動作時のみなので安心。