1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

terraformでIAM roleを作成しEC2にアタッチする時のtips

Last updated at Posted at 2021-10-12

タイトルまんまですが、terraformでIAM role及びpolicyを作成してEC2インスタンスに当てようとした時に手こずったので記事にします。

まずはEC2本体を用意

ec2_sgw.tf
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バケットにのみアクセスできるようにするポリシーを書いています。

policy/s3_sgw-hoge.json
{
    "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から作成する時はあまり意識してなかった部分だったのですが(最悪)、これの正体はこれ

スクリーンショット 2021-10-12 19.37.57.png

これのことなんですねぇ
普段は脳死で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先生ですが、気を抜いてるとこういう罠に引っかかってしまうので気をつけましょう。

最後まで閲覧頂きありがとうございました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?