IAM RoleとBucket PolicyでAmazon S3へのアクセス制御を行う

cloudpackエバンジェリストの吉田真吾@yoshidashingo)です。

AWSの各リソースへのアクセスは、デフォルトでは認証なしのアクセスができないため、たとえば1つのEC2を起動し、1つのS3バケットを作成し、EC2から中身を見ようとしてもcredentialが必要というエラーになります。

$ aws s3 ls bucket-policy-control-test
Unable to locate credentials. You can configure credentials by running "aws configure".

文言のとおり `aws configure` コマンドでS3の中身を参照可能なcredentialをインスタンス内に定義すればアクセス可能になりますが、たくさんのEC2を起動した後に `aws configure` コマンドを叩いて回るのは大変ですよね。

そこで`IAM Roles for EC2`を使うと便利です。

IAM Roleを作成する

1.IAM Management ConsoleのRolesで「Create New Role」を押下する

f:id:yoshidashingo:20140803185124p:plain

2.Role Nameを入力する

任意の文字列で構いませんが今回はS3にだけRoleでのアクセスが可能なものを作るためこんな名前にしました
f:id:yoshidashingo:20140803185152p:plain

3.Roleの使い方(適用先)に合わせて`Role Type`を選択する

今回はEC2に割り当てて使うRoleを作成するので、`Amazon EC2` を選択します
f:id:yoshidashingo:20140803185212p:plain

4.Permissionの設定でテンプレートから`Amazon S3 Full Access`を選択する

今回割り当てるPermissionとして、S3へのフルアクセスを選択します。
f:id:yoshidashingo:20140803185248p:plain

5.内容を確認してContinue

f:id:yoshidashingo:20140803185317p:plain

6.内容を確認してCreate

f:id:yoshidashingo:20140803185339p:plain

7.IAM Management Consoleに該当のRoleが作成されたことを確認する

f:id:yoshidashingo:20140803185401p:plain

8.EC2 Management ConsoleでEC2インスタンスを作成するときに該当のRoleを指定する

f:id:yoshidashingo:20140803185427p:plain


RoleのPermissionが有効か確認する

該当のEC2から、credentials設定なしでアクセスできることを確認する

Roleを指定しないと以下のような出力でしたが

$ aws s3 ls bucket-policy-control-test
Unable to locate credentials. You can configure credentials by running "aws configure".

Roleを指定すると、RoleのPermission指定どおりS3へのアクセスができるようになっていることが分かります。

$ aws s3 ls bucket-policy-control-test
2014-08-02 09:36:17         45 test.txt

どこにcredentialがあるの?

EC2固有の、OSの外にあるメタデータ「インスタンスメタデータ」の中にあり、インスタンスからはこちらを参照して透過的に利用できるようになってます。

$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/s3access
{
  "Code" : "Success",
  "LastUpdated" : "2014-08-03T06:43:14Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "xxxxxxxxxxxxxxxxxxx",
  "SecretAccessKey" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "Token" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "Expiration" : "2014-08-03T12:58:28Z"
}



S3のBucket Policyでさらに細かくアクセス制御したい

さて、このRoleを適用して起動したEC2からはS3がフル権限で利用可能です。バケットによっては、IPアドレスでファイルのPutやGetを拒否したいことがあるかもしれません。
そんなときは、該当のバケット側に個別に `Bucket Policy` を設定することができます。

1.S3 Management Consoleで該当のBucket Policyを編集する

該当のバケットのProperties(虫眼鏡アイコンを押下するとアクセス可能)から`Edit bucket policy`を押下
f:id:yoshidashingo:20140803185640p:plain

2.Bucket Policy Editorで以下のように編集してSaveする

f:id:yoshidashingo:20140803185704p:plain

{
	"Statement": [
		{
			"Sid": "",
			"Effect": "Deny",
			"Principal": {
				"AWS": "*"
			},
			"Action": "s3:*",
			"Resource": "arn:aws:s3:::bucketname/*",
			"Condition": {
				"IpAddress": {
					"aws:SourceIp": "0.0.0.0/0"
				},
				"NotIpAddress": {
					"aws:SourceIp": "許可するIPaddress/32"
				}
			}
		}
	]
}

3.Roleを適用した、IPアドレス許可/不許可のインスタンスからアップロード/ダウンロードしてみる

  • IPアドレスが許可されている
$ aws s3 cp filename s3://bucket-policy-control-test
upload: ./filename to s3://bucket-policy-control-test/filename

$ aws s3 cp s3://bucket-policy-control-test/filename .
download: s3://bucket-policy-control-test/filename to ./filename
  • IPアドレスが許可されていない
$ aws s3 cp filename s3://bucket-policy-control-test
upload failed: ./filename to s3://bucket-policy-control-test/filename A client error (AccessDenied) occurred when calling the PutObject operation: Access Denied

$ aws s3 cp s3://bucket-policy-control-test/filename .
A client error (Forbidden) occurred when calling the HeadObject operation: Forbidden
Completed 1 part(s) with ... file(s) remaining

こんな感じでアクセス許可/拒否設定ができます。