あけましておめでとうございます。河内です。
数ヶ月前に aws-vault を使い始めて安全の高まりを感じるので紹介します。
AWSのサービス上では IAM Role をできるだけ使ってアクセスキーを使わないようにしていますが、ローカルでの開発時にIAMのアクセスキーを利用することはあります。 アクセスキーが漏れると困ったことになります。 本番環境で利用している AWS アカウントで漏れると、付与している権限次第では機密情報が漏洩したりサービスが壊される可能性があります。 また開発環境としてのみ利用しているAWSアカウントであっても、ビットコインのマイニングなどで容赦なくリソースを消費され高額な請求が来たりする可能性ががあります。 そのようなことが起きないようにアクセスキーは安全に管理する必要があります。
通常はAWS SDK のデフォルト参照先である ~/.aws/credentials
にアクセスキーを保存しますが、平文で保存しているためディスクが盗難にあった場合に不安が残ります。
aws-vault は KeyChain にアクセスキーを保存します。
ディスクを暗号化していない場合にはこれだけでも少し安心感が増します*1。
アクセスキーは開発中のプログラムで利用することが多いと思います。 その中で利用しているライブラリやフレームワークに悪さをするものが居ないと言い切れるでしょうか? 開発中には新しいライブラリを試す機会も多くあります。 もしアクセスキーを抜き出して外部に送信するコードが混じっていると、、怖いですね。 昨年は有名ライブラリに似た名前の malware が npm に公開されたことがニュースになりました。
The npm Blog — `crossenv` malware on the npm registry
不審なプログラムを不用心に実行することはほとんど無いと思いますが、開発中のプログラムだけではなく同一ホスト上で実行するいずれかのプログラムが悪さをする可能性もあります。
aws-vault は STS を利用し一時的なアクセスキーをプロセスに渡します。 プロセスが悪さをした場合には漏れる可能性がありますが、その場合でも攻撃者がアクセスキーを利用できるのは短時間です。
使い方
さて使い方を見ていきましょう。 brew cask でインストールできます。
$ brew cask install aws-vault
home というプロファイルでアクセスキーを登録します。
$ aws-vault add home Enter Access Key ID: AKIAIOSFODNN7EXAMPLE Enter Secret Access Key:
aws-vault ls
で登録したプロフィールが確認できます。
$ aws-vault ls
home
aws-vault
から一時的なアクセスキーをわたしてプロセスを実行します。
$ aws-vault exec home -- aws s3 ls
--debug
を付けて実行すると動作の様子が出力されます。
$ aws-vault exec --debug home aws s3 ls 2018/01/06 23:10:57 Parsing config file /Users/kawachi/.aws/config 2018/01/06 23:10:57 Session not found in keyring 2018/01/06 23:10:57 Looking up keyring for home 2018/01/06 23:10:57 Getting new session token for profile home 2018/01/06 23:10:58 Writing session for home to keyring 2018/01/06 23:10:58 Adding service="aws-vault", label="aws-vault session for home", account="home session (30366365326436383761)" to osx keychain aws-vault.keychain 2018/01/06 23:10:58 Using session ****************RNWQ, expires in 3h59m59.105955s 2018/01/06 23:10:58 Parsing config file /Users/kawachi/.aws/config 2018/01/06 23:10:58 Setting subprocess env: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 2018/01/06 23:10:58 Setting subprocess env: AWS_SESSION_TOKEN, AWS_SECURITY_TOKEN
一時的なアクセスキーが発行され、 AWS_ACCESS_KEY_ID
, AWS_SECRET_ACCESS_KEY
, AWS_SESSION_TOKEN
, AWS_SECURITY_TOKEN
がプロセスの環境変数に設定されていることがわかります。
AWS SDK のデフォルトでは認証情報としてこれらの環境変数が参照されます。
AWS SDK for Java に関しては以前 AWS SDK for Java がデフォルトで参照する credential に書きましたのでご参照ください。
基本的な使い方はここまでです。 シンプルですね。良い。
AWS management console へのログイン
aws-vault login <profile>
で AWS management console へログインできます。
$ aws-vault login home
# ログインした状態でブラウザが開く
これで嬉しいのは IAM ユーザにパスワードが必要ないこと。 アクセスキーさえあれば良いのです。 パスワードが無ければ漏れることもない。 またひとつ安全になりました。
内部的には フェデレーションユーザーに対して AWS マネジメントコンソール へのアクセスを許可する URL の作成 が行われています。
AssumeRole
IAMユーザには最低限の権限を付与しておき、必要な時に多くの権限を持つロールに AssumeRole するという運用をしていることもあるかと思います。
~/.aws/config
に AssumeRole 用の設定を書いておけば、その名前で aws-vault exec
できます。
たとえば arn:aws:iam::123456789012:role/admin
という IAM ロールを作成しておき、 home プロファイルから AssumeRole するとします。
次の内容を ~/.aws/config
に記述します。
[profile home-admin] source_profile = home role_arn = arn:aws:iam::123456789012:role/admin
次のように利用できます。
$ aws-vault exec home-admin -- some-command
長時間プロセスの実行
aws s3 ls
のように短時間で終了するプロセスは問題ないのですが、長時間動作し続けるプロセスを aws-vault 経由で動作させたいこともあります。
aws-vault exec
は一時的なアクセスキーを取得してプロセスへ渡すため、長時間動作し続けるプロセスの場合には途中でアクセスキーの期限が切れることがあります。
AssumeRole を使わない場合は GetSessionToken API を利用するので36時間まで有効期限を伸ばせます。
AssumeRole を使う場合は伸ばせるのは1時間までです。
(参考: AWS STS API の比較)
それぞれ -t
あるいは --session-ttl
オプションと --assume-role-ttl
オプションを aws-vault exec 時に指定します。
伸ばせる上限以上の時間に渡って処理が続く場合には -s
あるいは --server
オプションを付けて aws-vault exec
を実行します。
するとローカルに インスタンスメタデータ サーバが立ち上がります*2。
loopback device に 169.254.169.254 を割り当てて 169.254.169.254:80
としてサーバが立ち上がるので、sudo のパスワードが必要になります。
AWS SDK はこのサーバにアクセスして一時的なアクセスキーを受取ります。 この方法の良い点は、アクセスキーの期限が切れた場合に自動的に再取得するようにAWS SDK が実装されている点です。 そのため、長時間プロセスでも問題なく動作します。
$ aws-vault exec -s home -- long-running-process
インスタンスメタデータサーバにアクセスしてみると確かに一時的なアクセスキーが取得できます。
$ aws-vault exec -s home -- curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/local-credentials | jq { "AccessKeyId": "ASIAEXAMPLE", "Code": "Success", "Expiration": "2018-01-07T17:04:27Z", "LastUpdated": "2018-01-07T22:27:02Z", "SecretAccessKey": "N+3gexample", "Token": "FQoDexample==", "Type": "AWS-HMAC" }
一方でこの方法で動かせるプロセスは同時にひとつまでです。ふたつめ以降の aws-vault exec -s
を並列して実行しようとすると、 address already in use
でエラーとなります。
aws-vault exec
終了後も aws-vault server
プロセスがのこっていることが確認できます。
$ ps ax | grep aws-vault 16482 s002 S 0:00.00 sudo -b aws-vault server 16483 s002 S 0:00.17 aws-vault server
AWS SDK のデフォルトではインスタンスメタデータより ~/.aws/credentials
の方が先にアクセスされます。
従って ~/.aws/credentials
が存在していると期待したとおりに動かないことがあることには注意が必要です。
平文で残さないことが aws-vault の良い点でもあるので、全てを aws-vault add
したら ~/.aws/credentials
は消してしまうのが良いでしょう。
MFA
Multi-Factor Authentication (多要素認証) を有効にしている場合には ~/.aws/config
に次のように書きます。
[profile home] mfa_serial = arn:aws:iam::123456789012:mfa/home
すると aws-vault exec
時にトークンの入力を求められます。
生のアクセスキーを使いたい時
aws-vault exec
の際に -n
あるいは --no-session
を付けることで、KeyChain に保存した生のアクセスキーをプロセスに渡すことが出来ます。
「せっかく一時的なアクセスキーを利用する仕組みがあるのに、生を使いたくなることあるの?」という声が聞こえてきそうです。
多く場合で一時的なアクセスキーを利用できますが、次のパターンはありそうです。
MFA を設定していない IAM ユーザで、AssumeRole しない状態で IAM の API を呼び出したいとき。 AssumeRole しない場合は GetSessionToken を用いて一時的なアクセスキーを得ます。 GetSessionToken で得られたアクセスキーはMFA を使用しない場合に IAM の API を呼び出せないという制限があります。 terraform で IAM API を呼び出したいがMFA設定していない…ということがありました。
長時間実行したいプロセスがふたつ以上あるとき。
-s
によるメタデータサーバは同時にひとつしか実行できないので、ふたつ以上の場合には泣く泣く生を使うことになりそうです。
アクセスキーのローテート
aws-vault rotate <profile>
でアクセスキーのローテートができます。
$ aws-vault rotate home Rotating credentials for profile "home" Done!
aws-vault rotate
に最低限必要な権限は次のとおりです。(READMEより)
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:CreateAccessKey", "iam:DeleteAccessKey", "iam:GetUser" ], "Resource": [ "arn:aws:iam::*:user/${aws:username}" ] } ] }
手軽にできるので、頻繁にローテートすると良さそうですね*3。
デメリット
デメリットとして次のことが挙げられます。
- KeyChain のパスワード入力が煩わしい
- コマンドの入力が長くなる
- 長時間実行する場合に考慮点がある
というわけで
デメリットもありますが、それに見合うだけの良さがあるのではないでしょうか。 アクセスキーが安全に保管され一時的なアクセスキーが利用されるという点も良いのですが、個人的には management console にログインする際にパスワードが不要な点が気に入っています。 アクセスキー漏洩が心配で少しでも安全にしたい方は利用を検討してみてはいかがでしょう。