[初学者向け]Terraform によるIAM ポリシー/ロール の作り方

3月 25, 2022【初学者向け】実践演習,AWS,IAM_Policy関連,terraform

概要

  • 今回は、Terraform を使ってIAM ポリシーIAM ロールIAM インスタンスプロファイルを作成します。Terraform によるIAM リソースの管理は複数のパターンがありますが、つい十分理解をせず使い回すことも多いかと思います。今回は、"aws_iam_policy_document" を使いデータソースにポリシードキュメントを定義する方法、および"aws_iam_policy" リソースのpolicy属性にヒアドキュメントとしてポリシードキュメントを記述する方法の2パターンを記載しております。
  • IAM ロールにIAM ポリシーを割り当てる方法は、以前失敗した経験を元に、"aws_iam_role_policy_attachment" リソースを使用するようにします。失敗談の詳細は、こちら
  • 今回モチーフとして作成するポリシーは、指定した S3バケットに対するread/write を許可します。EC2用のロールを作成し、ロールにこのポリシーを関連付けます。

 

Terraform によるIAM Policy の作り方

ポリシードキュメントをデータソースで定義する方法

  • 先ず、S3 バケット名、IAM ポリシー名、IAM ロール名を変数として扱います。
variable "s3_bucket_name" {
  type = string
}

variable "iam_policy_name" {
  type = string
}

variable "iam_role_name" {
  type = string
}
  • 次に、"aws_iam_policy_document" のデータソースを定義します。HCLを使って、ポリシードキュメントが定義可能です。この方法は柔軟にポリシードキュメントの設定が可能となり、source_policy_documents やoverride_policy_documents の属性を利用することでポリシーを上書き、追加、更新もできます。
  • “aws_iam_policy_document" の詳細は、こちらのドキュメントを参照ください。
data "aws_iam_policy_document" "allow_rw_access_s3_bucket" {
    statement {
        actions = ["s3:ListStorageLensConfigurations",
                "s3:ListAccessPointsForObjectLambda",
                "s3:GetAccessPoint",
                "s3:PutAccountPublicAccessBlock",
                "s3:GetAccountPublicAccessBlock",
                "s3:ListAllMyBuckets",
                "s3:ListAccessPoints",
                "s3:PutAccessPointPublicAccessBlock",
                "s3:ListJobs",
                "s3:PutStorageLensConfiguration",
                "s3:ListMultiRegionAccessPoints",
                "s3:CreateJob"
        ]
        resources = ["*"]
        effect  = "Allow"
    }
    statement {
        actions = ["s3:*"]
        resources = ["arn:aws:s3:::${var.s3_bucket_name}",
                "arn:aws:s3:::${var.s3_bucket_name}/*"]
        effect  = "Allow"
    }
}
  • actionsや resources 属性は、"[ ]" で括りリスト形式で指定する必要があります。"[ ]" がない場合は、下記のエラーとなります。

Error: Incorrect attribute value type

on iam.tf line 32, in data “aws_iam_policy_document" “allow_rw_access_s3_bucket":
32: actions = “s3:*"

Inappropriate value for attribute “actions": set of string required.

 

  • 次に、"aws_iam_policy" のリソースを定義します。policy 属性に、上記で準備したポリシードキュメントを設定します。"aws_iam_policy" の詳細は、こちらのドキュメントを参照ください。
resource "aws_iam_policy" "policy_allow_rw_access_s3_bucket" {
    name = var.iam_policy_name
    policy = data.aws_iam_policy_document.allow_rw_access_s3_bucket.json
}

 

リソースのpolicy属性にヒアドキュメントとして記述する方法

  • 先ず、S3 バケット名、IAM ポリシー名、IAM ロール名を変数として扱います。
variable "s3_bucket_name" {
  type = string
}

variable "iam_policy_name" {
  type = string
}

variable "iam_role_name" {
  type = string
}
  • 次に、"aws_iam_policy" のリソースを定義します。policy 属性に、複数行のヒアドキュメントを使用してポリシードキュメントを設定します。ヒアドキュメントは、シンプルなポリシーであれば便利な方法です。ポリシーが複雑な場合や他のリソースで再利用する場合は、データソースで定義する方法が良いと思います。"aws_iam_policy" の詳細は、こちらのドキュメントを参照ください。
  • 以下では<<を使用していますが、<< ではなく <<- (ハイフンあり)を使用すると、インデント有りのヒアドキュメントが利用できます。
resource "aws_iam_policy" "policy_allow_rw_access_s3_bucket" {
    name = var.iam_policy_name
    policy = <<EOT
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListStorageLensConfigurations",
                "s3:ListAccessPointsForObjectLambda",
                "s3:GetAccessPoint",
                "s3:PutAccountPublicAccessBlock",
                "s3:GetAccountPublicAccessBlock",
                "s3:ListAllMyBuckets",
                "s3:ListAccessPoints",
                "s3:PutAccessPointPublicAccessBlock",
                "s3:ListJobs",
                "s3:PutStorageLensConfiguration",
                "s3:ListMultiRegionAccessPoints",
                "s3:CreateJob"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::${var.s3_bucket_name}",
                "arn:aws:s3:::${var.s3_bucket_name}/*"
            ]
        }
    ]
}
EOT
}

 

  • IAM リソースの作成は、下記ドキュメントが参考になります。

 

Terraform によるIAM Role の作り方

ポリシードキュメントをデータソースで定義する方法

  • IAM ポリシーと同様に、"aws_iam_policy_document" のデータソースを定義します。HCLを使って、信頼関係のポリシードキュメントが定義可能です。以下は、EC2 の場合です。
data "aws_iam_policy_document" "ec2_assume_role" {
    statement {
        actions = ["sts:AssumeRole"]

        principals {
            type    = "Service"
            identifiers =["ec2.amazonaws.com"]
        }
    }
}

 

  • 次に、"aws_iam_role" のリソースを定義します。assume_role_policy 属性に、上記で準備した信頼関係のポリシードキュメントを設定します。"aws_iam_role" の詳細は、こちらのドキュメントを参照ください。
resource "aws_iam_role" "s3-role-for-ec2" {
    name = var.iam_role_name
    description = "Allows EC2 instances to call AWS services on your behalf."
    assume_role_policy = data.aws_iam_policy_document.ec2_assume_role.json
}

 

  • 次に、EC2 インスタンス(Elastic BeansTalk を含む)で必要となるインスタンスプロファイルを作成します。コンソールの場合は自動で作成されるため意識しませんが、AWS CLI or API を使用する場合に必要です。
  • なお、インスタンスプロファイルに含めることができる IAM ロールは 1 つのみです。ただし、1 つのロールを複数のインスタンスプロファイルに含めることはできます。
resource "aws_iam_instance_profile" "instance-profile_s3-role-for-ec2" {
    name = var.iam_role_name
    path = "/"
    role = aws_iam_role.s3-role-for-ec2.name
}

 

  • 最後に、"aws_iam_role_policy_attachment" のリソースを定義し、IAM ロールにIAM ポリシーをアタッチします。今回は、先ほど準備したカスタマー管理のポリシーと、AWS管理ポリシー(AmazonSSMManagedInstanceCore)の2つを設定しています。
resource "aws_iam_role_policy_attachment" "role-policy-attachment_s3-role-for-ec2-attach1" {
    role = aws_iam_role.s3-role-for-ec2.name
    policy_arn = aws_iam_policy.policy_allow_rw_access_s3_bucket.arn
}

resource "aws_iam_role_policy_attachment" "role-policy-attachment_s3-role-for-ec2-attach2" {
    role = aws_iam_role.s3-role-for-ec2.name
    policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

 

リソースのpolicy属性にヒアドキュメントとして記述する方法

  • “aws_iam_role" のリソースを定義します。assume_role_policy 属性に、複数行のヒアドキュメントを使用してポリシードキュメントを設定します。ヒアドキュメントは、シンプルなポリシーであれば便利な方法です。ポリシーが複雑な場合や他のリソースで再利用する場合は、データソースで定義する方法が良いと思います。"aws_iam_role" の詳細は、こちらのドキュメントを参照ください。
  • 以下では<<を使用していますが、<< ではなく <<- (ハイフンあり)を使用すると、インデント有りのヒアドキュメントが利用できます。
resource "aws_iam_role" "s3-role-for-ec2" {
    name = var.iam_role_name
    description = "Allows EC2 instances to call AWS services on your behalf."
    assume_role_policy = <<EOT
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOT
}
  • 次に、EC2 インスタンス(Elastic BeansTalk を含む)で必要となるインスタンスプロファイルを作成します。コンソールの場合は自動で作成されるため意識しませんが、AWS CLI or API を使用する場合に必要です。
  • なお、インスタンスプロファイルに含めることができる IAM ロールは 1 つのみです。ただし、1 つのロールを複数のインスタンスプロファイルに含めることはできます。
resource "aws_iam_instance_profile" "instance-profile_s3-role-for-ec2" {
    name = var.iam_role_name
    path = "/"
    role = aws_iam_role.s3-role-for-ec2.name
}

 

  • 最後に、"aws_iam_role_policy_attachment" のリソースを定義し、IAM ロールにIAM ポリシーをアタッチします。今回は、先ほど準備したカスタマー管理のポリシーと、AWS管理ポリシー(AmazonSSMManagedInstanceCore)の2つを設定しています。
resource "aws_iam_role_policy_attachment" "role-policy-attachment_s3-role-for-ec2-attach1" {
    role = aws_iam_role.s3-role-for-ec2.name
    policy_arn = aws_iam_policy.policy_allow_rw_access_s3_bucket.arn
}

resource "aws_iam_role_policy_attachment" "role-policy-attachment_s3-role-for-ec2-attach2" {
    role = aws_iam_role.s3-role-for-ec2.name
    policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

 

Terraform を実行する

Terraform のtfvars を準備する

  • tf ファイルに、変数を定義します。
  • 今回使用する変数は、以下の3つでしたね。
s3_bucket_name = "niikawa-test"
iam_policy_name = "s3-policy-example1"
iam_role_name = "s3-role-example1"

 

Terraform を実行する

  • tfvars ファイルを指定して、terraform を実行します。
terraform plan --var-file=terraform.tfvars
terraform apply --var-file=terraform.tfvars

 

 

 

参考資料