ansible-askpass

Ansible Logo

先日の記事 で、 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