タイトルまんまですが、terraformでIAM role及びpolicyを作成してEC2インスタンスに当てようとした時に手こずったので記事にします。
まずはEC2本体を用意
data "aws_ssm_parameter" "sgw_ami" {
name = "/aws/service/storagegateway/ami/FILE_S3/latest"
}
resource "aws_instance" "sdw_test" {
ami = data.aws_ssm_parameter.sgw_ami.value
vpc_security_group_ids = ["sg-00000000"]
subnet_id = "subnet-00000000"
iam_instance_profile = aws_iam_instance_profile.instance_role.id
key_name = "hoge-key"
instance_type = "m4.xlarge"
tags = {
Name = "sgw_test"
}
root_block_device {
volume_type = "gp3"
iops = 3000
throughput = 125
volume_size = 80
delete_on_termination = true
encrypted = false
tags = {
Name = "sgw_root"
}
}
ebs_block_device {
device_name = "/dev/sdf"
volume_type = "gp3"
iops = 3000
throughput = 125
volume_size = 150
delete_on_termination = true
encrypted = false
tags = {
Name = "sgw_cache"
}
}
}
storage gatewayをterraformで構築しようとしている途中での記事なので、AMIとかEBSが余分にぶら下がっているとか権限違うんじゃね?みたいな話は本題ではないのでスルーでお願いします(後日記事にする予定。つまり未定)。
tips 1
順番的にポリシー→ロール→アタッチなのですが、先にEC2のファイルを載せたので先に書いておきます。
肝はこれ
iam_instance_profile = aws_iam_instance_profile.instance_role.id
EC2にroleを当てる時はインスタンスプロファイルとしてroleを当てる必要があるということです(まぁ当然のことなんですが。。。)。
ロール書いた!ロールを直接指定したのにエラー吐く!なんでや!!という初歩的なトラップに引っかかりました。
例えばですが以下のように
iam_role = aws_iam_role.ec2_role.id
こんな書き方でEC2.tfの中に書いてもダメですよ、ということです。
見た目的に行けそうな気がしますがちゃんとインスタンスプロファイルにしてから当ててましょう。
tips 2
では順番にポリシーから行きましょう。
公式はこれ
ここだとtfファイルに直接jsonファイルを書いている例が出ていますね。
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = [
"ec2:Describe*",
]
Effect = "Allow"
Resource = "*"
},
]
})
}
これでも勿論問題ないですが、IAMポリシーはterraformさんの書式に合わせて書くよりjsonをそのまま書いちゃったほうがなんだかんだ便利だったりします
(JSONシンタックスチェックが使えたりコピペでレッツゴーしたい時とか)。
ってことでポリシー本体部分を別途hoge.jsonみたいな感じで外出しして、ポリシーのtfファイルからjsonファイルを参照してあげることが出来ます。
./からポリシー用のディレクトリを掘ってjsonファイルを書いていきます(pathを指定すればjsonの置き場はお好みでおk)。
今回は特定のS3バケットにのみアクセスできるようにするポリシーを書いています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::sgw-hoge",
"arn:aws:s3:::sgw-hoge/*"
]
}
]
}
まぁこれはよくあるやつですね。内容については割愛します。
んで、このjsonファイルをtfファイルから参照してあげる書き方は以下
resource "aws_iam_role_policy" "s3_policy_01" {
name = "s3_sgw-hoge_role"
role = aws_iam_role.s3_role.id
policy = file("./policy/s3_sgw-hoge.json")
}
ココですね
policy = file("./policy/s3_sgw-hoge.json")
これでポリシー本体をファイル指定しています。
jsonファイルとして外出ししてあげたほうが個人的には見やすいので割とおすすめです、jsonで書けるし。
これに関しては後述(一番手こずった)
role = aws_iam_role.s3_role.id
tips 3
roleについてです。
さてココが本番です。
最終的なファイルはこんな感じ
resource "aws_iam_role" "s3_role" {
name = "sgw_s3_role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
結論から書いてしまうと、GUIではポリシーを作成→ロールを作成してポリシーを指定ですがterraformだと逆です。
先入観というか、固定観念は非常によろしくないですね。
先にも書いたポリシー
resource "aws_iam_role_policy" "s3_policy_01" {
name = "s3_sgw-hoge_role"
role = aws_iam_role.s3_role.id
policy = file("./policy/s3_sgw-hoge.json")
}
ここでポリシーを紐つけるroleを指定します。
role側で
policy = aws_iam_role_policy. s3_policy_01
こんな感じに書いてもダメなわけです。
terraformではポリシー側からロールを指定、です。
次にこれ
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
最初はこれを書かないでplan叩いて怒られました。
こんな感じ
resource "aws_iam_role" "s3_role" {
name = "sgw_s3_role"
}
これだとassume_role_policyが無いよと怒られます。
GUIから作成する時はあまり意識してなかった部分だったのですが(最悪)、これの正体はこれ
これのことなんですねぇ
普段は脳死でEC2をクリックしていたのが最大の敗因。AWS認定の資格持っててもこういうところで躓いてちゃ型無しなわけです、反省。
ってことでEC2に当てたいロールなのでさっきのような書き方でOKということでした。
最後に上記で作成したroleを、インスタンスプロファイル作成時に指定してあげます。
resource "aws_iam_instance_profile" "instance_role" {
name = "sgw_instance_role"
role = aws_iam_role.s3_role.name
}
ここでのロールの指定は.nameで指定する必要があるようです、
んで、最終的にec2_sgw.tfのここで指定して完了です。
iam_instance_profile = aws_iam_instance_profile.instance_role.id
いかがだったでしょうか(アフィ並感(書いてみたかっただけ(これ書いてある記事ry)))Invalid syntax
何かと便利なterraform先生ですが、気を抜いてるとこういう罠に引っかかってしまうので気をつけましょう。
最後まで閲覧頂きありがとうございました。