はじめに
AdministratorAccess
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "*", "Resource": "*" } ] }
こんな権限を持った IAM ユーザーのアクセスキーがインターネットに流出したら、いやですよね。
そもそも、そんな権限を付与するなよっていう話ですが、 Serverless 開発とかやっているとカジュアルに AdministratorAccess
を求められることがよくあるし、なんだかんだ AmazonEC2FullAccess
やら AmazonS3FullAccess
やらが必要になる場面はザラにある。
かといって、下記のように単純な IAM ユーザーに IP 制限 (aws:SourceIp
条件) をかけると、マネジメントコンソールからの操作が謎に失敗するなど正常なオペレーションにも支障が出る。
{ "Version": "2012-10-17", "Statement": { "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": {"NotIpAddress": {"aws:SourceIp": [ "192.168.1.0/24" ]}} } }
aws:SourceIp 条件キーは、ユーザーに代わって呼び出しを実行する AWS CloudFormation などの AWS サービスへのアクセスを拒否します。
AWS: 送信元 IP に基づいて AWS へのアクセスを拒否する – AWS Identity and Access Management
解決策
「IAM ユーザーによる AWS の API 呼び出し権限に対して IP 制限を設定」
するのではなく、
「IAM ユーザーが特権的な IAM ロールを引き受ける (AssumeRole
する) ことに対して IP 制限を設定」
すればよいらしい。
・長期のアクセスキーの代わりに一時的なセキュリティ認証情報 (IAM ロール) を使用する
……IAM ロールや AWS Security Token Service の他の機能を通して取得した一時的なセキュリティ認証情報は、短期間で期限切れとなります。認証情報が誤って開示された場合のリスクに備えて、一時的なセキュリティ認証情報を使用することができます。
AWS アクセスキーを管理するためのベストプラクティス – アマゾン ウェブ サービス
部外者 => NG
中の人 => 特権ロール利用可
一時的な認証情報を利用して特権ロールを使用
方法
特権ロールを使用する (特権ロールを引き受ける) IAM ユーザーの作成
CLI から使用する (プログラムからのアクセス) 想定で IAM ユーザーを追加。
アタッチするポリシーは新規作成。
とりあえず、特定 IP 以外を全拒否するポリシーを設定する。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "SourceIPRestriction", "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "NotIpAddress": { "aws:SourceIp": [ "xxx.xxx.xxx.xxx/32" ] } } } ] }
AllowAssumeRoleWithSourceIPRestriction
というポリシー名で作成。
作成した AllowAssumeRoleWithSourceIPRestriction
をアタッチ。
作成した IAM ユーザーのアクセスキーを忘れずに保存。
特権 IAM ロール (引き受けられるロール) の作成
信頼されたエンティティとして、とりあえず、自分の AWS アカウント ID の数字 12 桁を指定 (あとで変更する)。
必要に応じて MFA を必須にするとより安全。
特権的なポリシーをアタッチ。
ここでは AdministratorAccess
を選択。
ロール名 AssumedAdministratorAccessRole
として作成。
信頼関係を編集。
特定 IP から、先に作成した IAM ユーザーがこのロールを引き受けられるように設定。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::xxxxxxxxxxxxx:user/test-user" }, "Action": "sts:AssumeRole", "Condition": { "IpAddress": { "aws:SourceIp": "xxx.xxx.xxx.xxx/32" } } } ] }
信頼関係の表示が変わることを確認。
AllowAssumeRoleWithSourceIPRestriction
ポリシーの編集
特定 IP のみ特権ロールの AssumeRole
を許可する。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowAssumeRole", "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::xxxxxxxxxx:role/AssumedAdministratorAccessRole" }, { "Sid": "SourceIPRestriction", "Effect": "Deny", "Action": "*", "Resource": "*", "Condition": { "NotIpAddress": { "aws:SourceIp": [ "xxx.xxx.xxx.xxx/32" ] } } } ] }
AWSCLI での設定と使い方
参考: ロールを割り当てる – AWS Command Line Interface
~/.aws/credentials
IAM ユーザーのアクセスキーを設定。
[test-user] aws_access_key_id = xxxxxxxxxxxxxxxxx aws_secret_access_key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
~/.aws/config
[profile test-user] region = ap-northeast-1 output = json [profile admin-access] region = ap-northeast-1 output = json role_arn = arn:aws:iam::xxxxxxxxxxxx:role/AssumedAdministratorAccessRole source_profile = test-user
使い方
こんな感じ。
AWS CLI が AWS STS
からの一時的セキュリティ認証情報の取り回しを勝手にうまいことやってくれる。
$ aws s3 --profile admin-access ls 2014-10-01 15:17:33 test 2014-11-21 17:51:43 prod . . .
権限ないのでこっちは無理。
$ aws s3 --profile test-user ls An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
許可済み IP 以外からのアクセスも弾かれる。
$ aws --profile admin-access s3 ls An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::xxxxxxxxxx:user/zzzzzzzzzzzzz is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::xxxxxxxxxxxx:role/AssumedAdministratorAccessRole with an explicit deny
AWS SDK 周りでの使い方
Serverless Framework など、AWS SDK を使っているコマンドは AWS_SDK_LOAD_CONFIG=1
のような変数を定義すれば大丈夫そう。
# serverless framework $ AWS_SDK_LOAD_CONFIG=1 sls deploy -v # gulp-awspublish $ AWS_SDK_LOAD_CONFIG=1 gulp publish
おわりに
これで、認証情報流出からの破滅に震えながら眠る夜が少しでも減らせそう。