はじめに。aws_iam_policy_documentは便利だが、、、
terraformでIAMのポリシーを書く時に、いくつか選択肢がありますが、そのうちの一つで aws_iam_policy_document を使うという手段があります。
Terraformでテンプレートを使ってポリシーを定義する - Qiita
HCLのシンタックスハイライトを使ってポリシーを書ける
plan 実行時にある程度の構文チェックができる
書くものが減りすこしスッキリする(テンプレートの方式だと、 json ファイル、 data ソース、 aws_iam_policy リソースを用意しないといけない)
ということで基本的にすごく便利なのですが、JSONで書かれた各種サンプルをHCLに変換して書き直さないといけない(コピペできない)というデメリットがあります。
というわけで、いくつか例を挙げながら、JSONのポリシーをaws_iam_policy_documentで書き換えてみます。
初級編
お題はこちら。
ビルドプロジェクトに関する情報の取得をユーザーに許可する
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "codebuild:BatchGetProjects",
"Resource": "arn:aws:codebuild:us-east-2:123456789012:project/my*"
}
]
}
一番シンプルなパターンです。
正解はこう。
data "aws_iam_policy_document" "sample" {
version = "2012-10-17"
statement {
sid = ""
actions = [
"codebuild:BatchGetProjects",
]
effect = "Allow"
resources = [
"arn:aws:codebuild:us-east-2:123456789012:project/my*"
]
}
}
// 確認用
output "sample" {
value = data.aws_iam_policy_document.sample.json
}
JSONと1:1の構造になっているのでわかりやすいですね。terraform plan
を実行すると、内容が同じで有ることが確認できます。
+ sample = jsonencode(
{
+ Statement = [
+ {
+ Action = "codebuild:BatchGetProjects"
+ Effect = "Allow"
+ Resource = "arn:aws:codebuild:us-east-2:123456789012:project/my*"
+ Sid = ""
},
]
+ Version = "2012-10-17"
}
)
初級編②
次はこちら。
AWS CodeBuild のアイデンティティベースのポリシーの使用 - AWS CodeBuild
Statementが複数です。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "codebuild:CreateProject",
"Resource": "arn:aws:codebuild:us-east-2:123456789012:project/*"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam:123456789012:role/CodeBuildServiceRole"
}
]
}
正解はこう。
data "aws_iam_policy_document" "sample" {
version = "2012-10-17"
statement {
sid = ""
actions = [
"codebuild:codebuild:CreateProject",
]
effect = "Allow"
resources = [
"arn:aws:codebuild:us-east-2:123456789012:project/*"
]
}
statement {
sid = ""
actions = [
"iam:PassRole",
]
effect = "Allow"
resources = [
"arn:aws:iam:123456789012:role/CodeBuildServiceRole"
]
}
}
シンプルにstatementを複数書いてあげればOKです。
中級編
お題はこちら。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example_bucket",
"Condition": {"NumericLessThanEquals": {"s3:max-keys": "10"}}
}
}
condition
という複雑そうなものがありますが、正解はこう。
data "aws_iam_policy_document" "sample" {
version = "2012-10-17"
statement {
sid = ""
actions = [
"s3:ListBucket",
]
effect = "Allow"
resources = [
"arn:aws:s3:::example_bucket"
]
condition {
test = "NumericLessThanEquals"
values = ["10"]
variable = "s3:max-keys"
}
}
}
書き方がjsonと比べて直感的ではないですが、aws_iam_policy_document
にも同じように condition
が書けます。
上級編
お題はこちら。
VPC ネットワークインターフェイスを作成するために必要な AWS のサービスへのアクセスを CodeBuild に許可する
今までの組み合わせ + Condition
が複雑なパターンです。一番伝えたかったのはこれ。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterface",
"ec2:DescribeDhcpOptions",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeVpcs"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:CreateNetworkInterfacePermission"
],
"Resource": "arn:aws:ec2:region:account-id:network-interface/*",
"Condition": {
"StringEquals": {
"ec2:Subnet": [
"arn:aws:ec2:region:account-id:subnet/subnet-id-1",
"arn:aws:ec2:region:account-id:subnet/subnet-id-2"
],
"ec2:AuthorizedService": "codebuild.amazonaws.com"
}
}
}
]
}
正解はこう
data "aws_iam_policy_document" "sample" {
version = "2012-10-17"
statement {
sid = ""
actions = [
"ec2:CreateNetworkInterface",
"ec2:DescribeDhcpOptions",
"ec2:DescribeNetworkInterfaces",
"ec2:DeleteNetworkInterface",
"ec2:DescribeSubnets",
"ec2:DescribeSecurityGroups",
"ec2:DescribeVpcs"
]
effect = "Allow"
resources = [
"*"
]
}
statement {
sid = ""
actions = [
"ec2:CreateNetworkInterfacePermission"
]
effect = "Allow"
resources = [
"arn:aws:ec2:region:account-id:network-interface/*"
]
condition {
test = "StringEquals"
values = [
"arn:aws:ec2:region:account-id:subnet/subnet-id-1",
"arn:aws:ec2:region:account-id:subnet/subnet-id-2"
]
variable = "ec2:Subnet"
}
condition {
test = "StringEquals"
values = [
"codebuild.amazonaws.com"
]
variable = "ec2:AuthorizedService"
}
}
}
conditionを複数書くのが、元のjsonと構造が変わっているのが難しいですね。
terraform plan
を実行すると同様で有ることが確認できます。
+ sample = jsonencode(
{
+ Statement = [
+ {
+ Action = [
+ "ec2:DescribeVpcs",
+ "ec2:DescribeSubnets",
+ "ec2:DescribeSecurityGroups",
+ "ec2:DescribeNetworkInterfaces",
+ "ec2:DescribeDhcpOptions",
+ "ec2:DeleteNetworkInterface",
+ "ec2:CreateNetworkInterface",
]
+ Effect = "Allow"
+ Resource = "*"
+ Sid = ""
},
+ {
+ Action = "ec2:CreateNetworkInterfacePermission"
+ Condition = {
+ StringEquals = {
+ ec2:AuthorizedService = "codebuild.amazonaws.com"
+ ec2:Subnet = [
+ "arn:aws:ec2:region:account-id:subnet/subnet-id-2",
+ "arn:aws:ec2:region:account-id:subnet/subnet-id-1",
]
}
}
+ Effect = "Allow"
+ Resource = "arn:aws:ec2:region:account-id:network-interface/*"
+ Sid = ""
},
]
+ Version = "2012-10-17"
}
)
おわりに
いくつか具体例を上げてみましたが参考になりましたでしょうか。
このパターンの方がもっと難しい!という題材を見つけた方は教えていただけるとうれしいです。