rancid の.cloginrc をvault 管理にする
rancid というツールがある.ネットワーク運用するにあたって,もはや手放せなくなっている.rancid のなにが便利かについては別エントリで書こうと思うが,本来の目的よりも付随する xlogin スクリプト (clogin, jlogin, …) を気に入って使っている.
xlogin について簡単に言えば
ようなやつで,1. のための認証情報を~/.cloginrc
に書いておく必要がある.パスワード入力が不要になるので「10 台のルーターでshow interfaces descriptions
とshow bgp summary
とshow ospf neighbor
を打ってgrep に渡す」とか「100 台のルーターでsyslog の設定を変える」みたいなことが簡単にできる.
問題意識
ネットワークデバイスにログインするために 共有のジャンプサーバーを用意することが多く,xlogin をつかうには そこに~/.cloginrc
を置く必要がある.
「共有サーバーに ファイルとして認証情報(id + password) を置く」というのがイマイチだなあと思っていた.*1 というのは,
そこでvault を手元のローカルホストで動かしておいて,.cloginrc
の情報をそこに格納しておくと ずいぶんマシになった.
- super-user に読まれてしまうのは変わらない
- 認証情報の実体がローカルホストにあり,暗号化される.ssh セッションを切れば認証情報にアクセスできなくなる
- 認証情報へのアクセスログが残るので,不正アクセスに気づける
vault の設定
セットアップ (ローカルホスト)
プラットフォームにあったvault をダウンロード し,PATH のどこかに置く.
設定ファイルを書く.
# ~/.vault backend "file" { path = "/Users/codeout/.vault.d" } listener "tcp" { address = "localhost:8200" tls_disable = 1 # ssh tunnel を通すのでTLS 不要 }
vault server を起動し,初期化する.
$ vault server -config ~/.vault >&/dev/null & $ export VAULT_ADDR=http://localhost:8200 $ vault init -key-threshold 1 -key-shares 1 vault $ vault init -key-threshold 1 -key-shares 1 Key 1: ced979c0b1c0ff62b2ac2aa08e54b8258bd4d88170ed67627b4c0fc3dd87133c Initial Root Token: b5aae184-0fcf-3f7d-09db-9928d82eca56 Vault initialized with 1 keys and a key threshold of 1. Please securely distribute the above keys. When the Vault is re-sealed, restarted, or stopped, you must provide at least 1 of these keys to unseal it again. Vault does not store the master key. Without at least 1 keys, your Vault will remain permanently sealed.
ローカルホストでの利用なので master key は1つにした.
デフォルト設定ファイルの評価タイミングが雑っぽくて,今日時点では-config ~/.vault
やexport VAULT_ADDR=http://localhost:8200
を省略することができない.そのうち~/.vault
がきちんと評価されるようになって,省略可能になる気がする.
起動直後はsealed なので unseal しておく.
$ vault unseal ced979c0b1c0ff62b2ac2aa08e54b8258bd4d88170ed67627b4c0fc3dd87133c Sealed: false Key Shares: 1 Key Threshold: 1 Unseal Progress: 0
ログの設定.
$ mkdir ~/.vault.d/log vault $ vault audit-enable file path=/Users/codeout/.vault.d/log/vault_audit.log Successfully enabled audit backend 'file'!
.cloginrc
をvault に格納する.組織ごとに異なる.cloginrc
を1つのvault に入れる必要があるので,key を分ける.ついでにpolicy も分けておいて 必要最小限のデータにのみアクセスを許可する.
チームA の.cloginrc
をsecret/team-a
に格納する例:
$ vault auth b5aae184-0fcf-3f7d-09db-9928d82eca56
Successfully authenticated!
token: b5aae184-0fcf-3f7d-09db-9928d82eca56
token_duration: 0
token_policies: [root]
# ./team-a.hcl path "sys/*" { policy = "deny" } path "secret/*" { policy = "deny" } path "secret/team-a" { policy = "write" } path "auth/token/lookup-self" { policy = "read" }
$ vault policy-write team-a team-a.hcl Policy 'team-a' written. $ vault write secret/team-a cloginrc=@/Users/codeout/.cloginrc Success! Data written to: secret/team-a
最後に,ポートフォワードと環境変数を転送するよう~/.ssh/config
を設定しておく.
# ~/.ssh/config Host jump-server Hostname 192.168.3.102 RemoteForward 8200 localhost:8200 SendEnv VAULT_TOKEN
確認
5分で失効するトークンを発行して ローカルホストから値が取れることを確認する.
$ vault token-create -lease=5m -policy=team-a Key Value token ccc70554-da81-4d2f-08be-d0d38232395c token_duration 300 token_renewable true token_policies [team-a] $ VAULT_TOKEN=ccc70554-da81-4d2f-08be-d0d38232395c vault read secret/team-a Key Value lease_duration 2592000 cloginrc ### default add method * {ssh} {telnet} add user * codeout add password * {some!secret} {some!secret} add method 192.168.0.79 {telnet} add password 192.168.0.79 {another!secret} {another!secret}
ログが残ることも確認.
{"time":"2015-11-28T15:29:11Z","type":"request","auth":{"display_name":"token","policies":["team-a"],"metadata":null},"request":{"operation":"read","path":"secret/team-a","data":null,"remote_address":"127.0.0.1"},"error":""} {"time":"2015-11-28T15:29:11Z","type":"response","error":"","auth":{"display_name":"","policies":["team-a"],"metadata":null},"request":{"operation":"read","path":"secret/team-a","data":null,"remote_address":"127.0.0.1"},"response":{"secret":{"lease_id":""},"data":{"cloginrc":"hmac-sha256:46ac8a23ac9efff3c42e5b9e31a7854e50f4a4e713810388003dbfcb1c9a607b"},"redirect":""}}
5分後には値が取れなくなっているはず.
セットアップ (ジャンプサーバー)
こちらも プラットフォームにあったvault をダウンロードし,PATH のどこかに置く.
.zshrc
などにvault のURL を設定する.外部からジャンプサーバーにssh するときに張るssh tunnel を指定しておく.
# ~/.zshrc export VAULT_ADDR=http://localhost:8200
rancid がインストールされているものとして,.cloginrc
を書き換える.
.cloginrc
はtcl スクリプトとして読まれるため,必要に応じてvault から認証情報を取得する動作になる.
# ~/.cloginrc if [ catch {eval [eval exec "vault read -field=cloginrc secret/team-a"]} reason ] { send_user "\nError: $reason\n" exit 1 }
可能であれば,ssh クライアントから環境変数VAULT_TOKEN
を受け付けるよう sshd を設定する.
# /etc/ssh/sshd_config AcceptEnv LANG LC_* VAULT_TOKEN
つかいかた
ローカルホストでvault を起動し,トークンを発行する.-lease
を指定しなければ30日有効なトークンが発行されるが,期間は適宜.
$ vault server -config ~/.vault >&/dev/null& $ vault unseal ced979c0b1c0ff62b2ac2aa08e54b8258bd4d88170ed67627b4c0fc3dd87133c $ vault auth b5aae184-0fcf-3f7d-09db-9928d82eca56 # 普段は上記の状態で動かしっぱなし $ vault token-create -lease=24h -policy=team-a Key Value token d78015ad-e903-2122-dea9-6b1bcb970391 token_duration 86400 token_renewable true token_policies [team-a]
$ VAULT_TOKEN=d78015ad-e903-2122-dea9-6b1bcb970391 ssh jump-server
これでxlogin できるようになっているはず.
$ jlogin 192.168.3.103 192.168.3.103 spawn ssh -c 3des -x -l codeout 192.168.3.103 Password: --- JUNOS 12.1X46-D10 built 2013-12-05 15:04:51 UTC codeout@vsrx>
ローカルホストでvault がunsealed で動いており,ssh tunnel 経由でジャンプサーバーからvault にアクセスでき,トークンがある場合のみ認証情報にアクセスできるようになった.
ローカルホストの~/.vault.d/log/vault_audit.log
には認証情報へのアクセスがすべて記録されるので,不正アクセスの調査ができる.
別のチームB のジャンプサーバーにssh する場合は,vault に格納するkey, policy 名を切り替えればよい.
ジャンプサーバーのsshd を設定変更できない場合は クライアントから環境変数を渡せないので,ログイン後にexport VAULT_TOKEN=d78015ad-e903-2122-dea9-6b1bcb970391
する.
このとき,一応コマンドヒストリーに残らないよう気をつける.たとえばzsh でhist_ignore_space
が設定されている場合は,export
の先頭に半角スペースを入れておけばヒストリーに残らない.
どうせsuper-user には/proc/<pid>/environ
やps e
などで環境変数を読まれてしまうが,いちおう余計なところに残さないほうがいい.
まとめ
.cloginrc
をまるまるvault 管理にすることで,より安全にxlogin を使えるようになった.やはりsuper-user は認証情報にアクセスできてしまうため 完全ではないが
構成を実現できた.
環境変数をsuper-user から隠す方法 もしくはうまく暗号化する方法があれば完璧なので,知見をお持ちのかたはぜひ教えてください.