ansible-askpass
先日の記事 で、 Ansible には vault パスワード入力の手間を省く機能がないと書きました。
理想的には SSH や GnuPG のエージェントのように、 ユーザが端末から入力したパスワードをメモリ内に保持して再利用できる仕組みが Ansible でも使えればよいと思います。
本来は Ansible 本体が備えるべき機能だと思いますが、 今回は Ansible のパスワードファイルの仕様と Linux カーネルの機能を活用して、 外付けでこれを実現する方法を考えてみました。
概要
Ansible では --vault-password-file
オプションを使うことで
vault の復号に使用するパスワードファイルを指定することができます。
実は Ansible のパスワードファイルはパスワードを書き込んだ単純なテキストファイルだけでなく 実行可能ファイルを指定することもでき、 その場合はそれを実行して標準出力に出た文字列をパスワードにしてくれます。 この仕様を活用して SSH エージェントのようなプログラムを指定すれば、 冒頭に書いた理想的な挙動を実現できそうです。
ポータブルにするにはまさに ssh-agent
的な Unix の常駐プログラムを
書くことになるのでしょうがそれも大変なので、ここでは Linux カーネルの
Key Retention Service
という機能を利用する bash スクリプト
ansible-askpass
を書いてみました。
使用法
このスクリプトは
vault 用でないパスワードファイルにも使えるよう汎用的に作られているので、
ansible-vault-askpass
のように、
わかりやすい名前に変更して使ってください。
配置場所はプレイブックファイルと同じディレクトリか、
/usr/local/bin
のようなパスの通ったディレクトリをおすすめします。
$ wget https://raw.githubusercontent.com/yaegashi/ansible-snippets/master/askpass/ansible-askpass -O ansible-vault-askpass
$ sudo chmod +x ansible-vault-askpass
またスクリプトからカーネルの
Key Retention Service を使うためにユーザーランドツールの
keyctl
が必要になります。
Debian/Ubuntu では
keyutils パッケージ
に入っていますので事前にインストールしておいてください。
$ sudo apt-get install keyutils
Ansible からの使用では毎回
--vault-password-file=ansible-vault-askpass
といったコマンドラインオプションを指定するのは大変なので、
ansible.cfg で vault_password_file
に設定するか、
環境変数 ANSIBLE_VAULT_PASSWORD_FILE
に設定するのがよいでしょう。
$ export ANSIBLE_VAULT_PASSWORD_FILE=ansible-vault-askpass
$ ssh-agent ansible-playbook -i hosts ping.yml
ansible-vault-askpass: Enter password: ← vault パスワードを入力
ansible-vault-askpass: Password saved.
ansible-vault-askpass: Run "ansible-vault-askpass -d" to remove.
...
このように初回の起動時に
ansible-vault-askpass
によりパスワードが尋ねられます。
入力したパスワードはカーネルに記憶され、
2 回目以降の起動ではパスワードを尋ねられることはありません。
記憶されたパスワードは 300 秒経過するか、 ユーザがログアウトするなどしてセッションを終了する時に 自動的にメモリから削除されます。
記憶されたパスワードをすぐ忘れさせたい、
間違えたパスワードを入力して Ansible がエラーになってしまった、
というときには ansible-vault-askpass -d
を実行すれば明示的に削除できます。
$ ssh-agent ansible-playbook -i hosts ping.yml
ERROR: Decryption failed
$ ./ansible-vault-askpass -d
ansible-vault-askpass: Password removed.
このようにセットアップした ansible-vault-askpass
の機能は
ansible-playbook
以外のコマンドでも同様に有効です。
例えば ansible-vault edit
で vault ファイルを編集して
ansible-playbook
で試すのを繰り返す場合は特に便利に感じられると思います。
注意点
ansible-askpass
からパスワードが尋ねられている最中に Ctrl+C
などで実行を止めてしまうと、
端末がエコーなし状態のままになってしまうことがあります。
その場合は stty sane
を実行することで端末を正常な状態に回復することができます。
$ ssh-agent ansible-playbook -i hosts ping.yml
ansible-vault-askpass: Enter password: ERROR: interrupted
$ $ $ $ ← エコーされなくなるので stty sane と入力
おわりに
Ansible のパスワードファイルの仕様と Linux カーネルの Key Retention Service を利用して SSH エージェントと同じようなパスワード保存機能を Ansible で実現する方法を紹介しました。
Key Retention Service については今回初めて知ったので、 使い方を間違っているかもしれません。 なにかありましたらご指摘いただけると幸いです。
2014/10/15 01:41:19 JST