やりたいこと
- Terraform で DynamoDB の Table を作る。
- 既存のテーブルに読み込みだけが出来る IAM Role を割り当てる。
- 権限が設定されたかテスト。
Terraform で DynamoDB の Table を作る。
まず AWS ルートユーザや IAM ユーザで aws コマンドが動く事を確認します。
$ export AWS_PROFILE=hoge
$ aws configure list
Name Value Type Location
---- ----- ---- --------
profile hoge manual --profile
access_key hogehoge shared-credentials-file
secret_key ********************* shared-credentials-file
region us-west-2 config-file ~/.aws/config
... 適切な access_key, secret_key, region が表示されると OK。
次のような Terraform file で aws_dynamodb_table を作ります。
resource "aws_dynamodb_table" "music" {
name = "Music"
read_capacity = 1
write_capacity = 1
hash_key = "Artist"
range_key = "SongTitle"
attribute {
name = "Artist"
type = "S"
}
attribute {
name = "SongTitle"
type = "S"
}
}
初期化
terraform init
設定
terraform apply
これで、DynamoDB へのアクセス » CLI の使用 と同じテーブルが出来ます。
動作確認
$ aws dynamodb put-item --table-name Music --item '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}}'
$ aws dynamodb query --table-name Music --key-condition-expression 'Artist = :a' --expression-attribute-values '{ ":a": {"S": "No One You Know"}}'
{
"Count": 1,
"Items": [
{
"AlbumTitle": {
"S": "Somewhat Famous"
},
"SongTitle": {
"S": "Call Me Today"
},
"Artist": {
"S": "No One You Know"
}
}
],
"ScannedCount": 1,
"ConsumedCapacity": null
}
削除
terraform destroy
terraform だと削除が簡単なのが良いですね。
既存のテーブルに Query だけが出来る IAM Policy を作る。
次に、うっかりテーブルを変更してしまわないように、作ったテーブルの Query と GetItem だけが出来る IAM Policy を作ります。
AWS では、テーブル等すべてのリソースに ARN が付きます。DynamoDB のテーブルは以下の ARN で表します。
arn:aws:dynamodb:region:account-id:table/table-name
例えばもしも account-id が 123456789012 で region が us-west-2 なら、上の例は arn:aws:dynamodb:us-west-2:123456789012:table/Music
です。terraform で作った ARN は terraform show
で確認出来ます。
このテーブルのアクセス権を設定するには Policy 言語 を使います。DynamoDB の例が Amazon DynamoDB でアイデンティティベースのポリシー (IAM ポリシー) を使用する に色々あります。
Policy を Terraform で定義する場合は aws_iam_policy に埋め込む事が出来ます。Music の読み書きを行う Policy は以下のようになります。
resource "aws_iam_policy" "music" {
name = "music_policy"
description = "DynamoDB Music policy"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"dynamodb:Query",
"dynamodb:GetItem"
],
"Effect": "Allow",
"Resource": "${aws_dynamodb_table.music.arn}"
}
]
}
EOF
}
IAM Role を作る。
作った Policy で制限がかかっているか試すにはいくつか方法があります。ここでは IAM Role を作って自分の IAM User から切り替えて使ってみます。IAM Role を作るには aws_iam_role を使います。assume_role_policy で Role を与える対象 (Principal) を選びます。実用上では Principal に ec2.amazonaws.com
等を選んで特定の AWS サービスに IAM Role を与える事が多いかと思いますが、ここではテストが簡単なように Principal として今まで作業してきた自分の IAM User を設定し、aws cli で Role を切り替えて使うことします。
data "aws_caller_identity" "current" {}
resource "aws_iam_role" "music" {
name = "music_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": "${data.aws_caller_identity.current.arn}"
}
}
]
}
EOF
}
このように aws_iam_role
の assume_role_policy
も aws_iam_policy
と同様 Policy 言語で記述します。IAM User を Principal として指定するためには ARN を設定しますが、次のような種類があります。
- アカウント 123456789012 の任意のユーザ: arn:aws:iam::123456789012:root
- アカウント 123456789012 のユーザ hoge: arn:aws:iam::123456789012:user/hoge
上の例では Terraform の aws_caller_identity 機能を使って現在のユーザの ARN を取得しているため、実際の ARN をベタ書きする必要がありません。便利。
IAM Policy と IAM Role を関連付ける
これも Terraform だと参照を使えるので非常に簡単です。
resource "aws_iam_role_policy_attachment" "music" {
role = "${aws_iam_role.music.name}"
policy_arn = "${aws_iam_policy.music.arn}"
}
ここまでで Terraform の設定は終わりなので、terraform apply
で再度反映させます。
テスト
IAM ロールへの切り替え を参考に作った IAM Role に切り替えてテストしてみます。
もしも現在 AWS_PROFILE=hoge を使っていて、デフォルト region が us-west-2
で、アカウント ID が 123456789012 の場合、~/.aws/config
に以下を追記します。
role_arn は terraform show
で aws_iam_role.music: の欄に出てくる arn です。
...
[profile music]
role_arn = arn:aws:iam::123456789012:role/music_role
source_profile = hoge
region = us-west-2
このように設定すると、music という aws profile で music_role が有効になります。例えば --profile music
をつけて DynamoDB にアクセスしてみます。
$ aws dynamodb query --profile music --table-name Music --key-condition-expression 'Artist = :a' --expression-attribute-values '{ ":a": {"S": "No One You Know"}}'
{
"Count": 1,
"Items": [
{
"AlbumTitle": {
"S": "Somewhat Famous"
},
"SongTitle": {
"S": "Call Me Today"
},
"Artist": {
"S": "No One You Know"
}
}
],
"ScannedCount": 1,
"ConsumedCapacity": null
}
のように query は成功しますが、
$ aws dynamodb put-item --profile music --table-name Music --item '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}}'
An error occurred (AccessDeniedException) when calling the PutItem operation: User: arn:aws:sts::123456789012:assumed-role/music_role/botocore-session-1557893071 is not authorized to perform: dynamodb:PutItem on resource: arn:aws:dynamodb:us-west-2:123456789012:table/Music
のように put-item は目出度くエラーになります。
実際に業務で使う時はこの IAM Role を EC2 とか Kubernetes pod とかに割り当てると、ACCESS_KEY を書かなくても適切な権限を与えられるので便利という物です。