皆様こんにちは。
今回はTerraformを利用して、AWSで高可用性アーキテクトの構築をしていきます。
IAMロール、IAMポリシーの作成を行い、EC2インスタンスにアタッチするまでの過程を記事にします。

1.高可用性アーキテクト構築目次

目次はこちら

2.IAM概要

AWS Identity and Access Management (IAM) は、AWS リソースへのアクセスを安全に管理するためのウェブサービスです。IAM により、誰を認証 (サインイン) し、誰にリソースの使用を承認する (アクセス権限を持たせる) かを制御します。

引用元:IAMとは

IAMの詳細については引用の公式ドキュメントを参照してください。
IAMを使用することで、下記のような問題を防ぐことができます。

  • 開発環境のEC2を削除するはずが、本番環境のEC2を誤って削除してしまう。
  • 不正ログインによってIAMユーザーが乗っ取られる

下記に今回使用するIAMサービスについての概要を記載します。

IAMポリシー

AWSリソースに対してどのような操作を許可または拒否するのかを定義したものです。

IAMロール

ポリシーをアタッチしてできる操作をひとまとめにしたものです。AWSのサービスや他のAWSアカウント、IDプロバイダーに対してAWSの操作権限を付与するための仕組みです。

カスタマー管理ポリシー

ユーザーが作成し管理するIAMポリシーでユーザー、グループ、ロールにアタッチして使用します。カスタマー管理ポリシーを作成する際はJSON形式で記述します。
今回はロールにアタッチして使用します。

3.フロー図

4.IAM作成

IAMを作成していきます。
ソースコードは下記の通りです。

#--------------------------------------
# IAMの作成
#----------------------------------------
#1.IAMポリシーの作成
//CloudwatchAlarmにカスタムメトリクスをプッシュする権限を持ったポリシーの作成
resource "aws_iam_policy" "higa_CW_policy" {
  name = "higa_CW_policy"

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "cloudwatch:PutMetricData",
          "ec2:DescribeTags",
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}
//S3の権限を設定したIAMポリシーを作成
resource "aws_iam_policy" "higa_S3_policy" {
  name = "higa_S3_policy"

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:PutObject",
          "s3:GetObject",
          "s3:DeleteObject",
          "s3:PutObjectAcl"
        ]
        Effect   = "Allow"
        Resource = "arn:aws:s3:::higa-wordpress-s3/*"
      },
      {
        Action = [
          "s3:GetBucketPublicAccessBlock",
          "s3:ListBucket",
          "s3:GetBucketLocation"

        ]
        Effect   = "Allow"
        Resource = "arn:aws:s3:::higa-wordpress-s3"
      },
    ]
  })
}

# 2.IAMロールの作成
resource "aws_iam_role" "higa-wordpress-role" {
  name = "higa-ec2-role"

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

# 3.IAMロールにIAMポリシーをアタッチ
//CloudwatchAlarmに関するポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "CW-polisy_attach" {
  role       = aws_iam_role.higa-wordpress-role.name
  policy_arn = aws_iam_policy.higa_CW_policy.arn
}
//S3に関するポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "S3-polisy_attach" {
  role       = aws_iam_role.higa-wordpress-role.name
  policy_arn = aws_iam_policy.higa_S3_policy.arn
}

# 4.IAMロールをEC2インスタンス(higa-ec2-1,2)に設定
resource "aws_iam_instance_profile" "higa_profile" {
  name = "higa_profile"
  role = aws_iam_role.higa-wordpress-role.name
}

作成手順は下記の通りです。

  1. IAMポリシーの作成(2つ)
  2. IAMロールの作成
  3. 作成したIAMポリシーをIAMロールにアタッチ
  4. IAMロールをEC2インスタンスにアタッチ

よく使用するオプションの説明を下記に記載します。

使用するオプション 説明
Version 「2012-10-17」「2008-10-17」の2つがあります。20012-10-17はポリシー言語の現行バージョンであり、常にVersion要素を含め、2012-10-17に設定する必要があります。このようにしない場合、このバージョンで導入されたポリシー変数などの機能は使用できません。
Statement ポリシーの主要要素です。この要素は必須です。Statement要素には、単一のStatementまたは個々のStatementの配列を含めることができます。
Action Effectで許可または拒否される特定のアクションについて説明します。
Effect Effect要素は必須です。Statementの結果を許可または明示的な拒否のどちらにするかを指定します。Effectの有効値は、AllowとDenyです。
Principal リソースへのアクセスを許可または拒否するPrincipalを指定します。
Resource Statementで取り扱う一連のオブジェクトを指定します。
リソースを特定するためには必ずARNを使用しますが、それぞれのリソースのARNの詳細は、そのサービスおよびリソースによって異なります。

引用元:IAM JSON ポリシー要素のリファレンス

4-1.IAMポリシーの作成

下記2つのIAMポリシーを作成します。

  • CloudwatchAlarmにカスタムメトリクスをプッシュする権限を持ったポリシーの作成
  • S3の権限を設定したIAMポリシーを作成

CloudwatchAlarmに関するIAMポリシーの作成

ソースコードは5~24行目に該当します。

//CloudwatchAlarmにカスタムメトリクスをプッシュする権限を持ったポリシーの作成
resource "aws_iam_policy" "higa_CW_policy" {
  name = "higa_CW_policy"

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "cloudwatch:PutMetricData",
          "ec2:DescribeTags",
        ]
        Effect   = "Allow"
        Resource = "*"
      },
    ]
  })
}

下記はCloudwatchAlarmに関するIAMポリシーの設定項目です。

使用するオプション 設定値 説明
name higa_CW_policy IAMポリシー名を設定
Action cloudwatch:PutMetricData
ec2:DescribeTags
下記に記載(※1,※2)
Resource * EffectとActionの対象となる全リソース

※1.cloudwatch:PutMetricDataはインスタンスがカスタムメトリクスを発行できる権限を付与します。
※2.ec2:DescribeTagsはカスタムメトリクス発行時に必要なインスタンスの情報をインスタンス自身が取得できる権限を付与します。

S3に関するIAMポリシーの作成

ソースコードは23~56行目に該当します。

//S3の権限を設定したIAMポリシーを作成
resource "aws_iam_policy" "higa_S3_policy" {
  name = "higa_S3_policy"

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:PutObject",
          "s3:GetObject",
          "s3:DeleteObject",
        ]
        Effect   = "Allow"
        Resource = "arn:aws:s3:::higa-wordpress-s3/*"
      },
      {
        Action = [
          "s3:listObject",
        ]
        Effect   = "Allow"
        Resource = "arn:aws:s3:::higa-wordpress-s3"
      },
    ]
  })
}

下記はS3のIAMポリシーの設定項目です。

使用するオプション 設定値 説明
name higa_S3_policy IAMポリシー名を設定
Action 別途記述 別途記述
Resource ・arn:aws:s3:::higa-wordpress-s3/*
・arn:aws:s3:::higa-wordpress-s3
・S3バケット(higa-wordpress-s3)の指定
・S3バケット(higa-wordpress-s3)の中身を指定

Actionの設定項目は下記の通りです。

使用するオプション 設定値 説明
Action ・s3:PutObject
・s3:GetObject
・s3:DeleteObject
・s3:PutObjectAcl
・インスタンスがS3に対し画像をアップロードできる権限
・インスタンスがS3に対し画像を取得できる権限
・インスタンスがS3の画像を削除できる権限
・インスタンスがS3に対しACLで画像をアップロードできる権限
Action ・s3:GetBucketPublicAccessBlock
・s3:ListBucket
・s3:GetBucketLocation
ソースで指定したS3の情報を取得できる権限を付与

これで2つのIAMポリシーが作成できました。

4-2.IAMロールの作成

IAMロールを作成します。
ソースコードは58~76行目に該当します。

# IAMロールの作成
resource "aws_iam_role" "higa-wordpress-role" {
  name = "higa-ec2-role"

  # Terraform's "jsonencode" function converts a
  # Terraform expression result to valid JSON syntax.
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

下記はIAMロールの設定項目です。

使用するオプション 設定値 説明
name higa-ec2-role IAMロール名を設定
Action sts:AssumeRole AsumeRoleにすることで、IAMロールに設定された権限を引き受けることができる
Principal Service = "ec2.amazonaws.com" EC2へのアクセスの許可

4-3.IAMロールに作成したポリシーをアタッチ

「4-1」で作成した2つのIAMポリシーを「4-2」で作成したIAMロールにアタッチします。
ソースコードは78~88行目に該当します。

#IAMロールにIAMポリシーをアタッチ
//CloudwatchAlarmに関するポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "CW-polisy_attach" {
  role       = aws_iam_role.higa-wordpress-role.name
  policy_arn = aws_iam_policy.higa_CW_policy.arn
}
//S3に関するポリシーをアタッチ
resource "aws_iam_role_policy_attachment" "S3-polisy_attach" {
  role       = aws_iam_role.higa-wordpress-role.name
  policy_arn = aws_iam_policy.higa_S3_policy.arn
}
使用するオプション 設定値 説明
role aws_iam_role.higa-wordpress-role.name アタッチしたいIAMロール名を指定
policy_arn ・aws_iam_policy.higa_CW_policy.arn
・aws_iam_policy.higa_S3_policy.arn
アタッチしたいIAMポリシーを指定

これでIAMポリシーをIAMロールにアタッチすることができました。

4-4.EC2インスタンスに付与するための設定

「4-3」でできたIAMロールをEC2インスタンスにアタッチします。
まず、アタッチするために必要な設定を行います。

ソースコードは90~94行目に該当します。

#IAMロールをEC2インスタンス(higa-ec2-1,2)に設定
resource "aws_iam_instance_profile" "higa-wordpress-role" {
  name = "higa-wordpress-role"
  role = aws_iam_role.higa-wordpress-role.name
}

設定項目は下記の通りです。

使用するオプション 設定値 説明
name higa-wordpress-role IAMロールのリソース名
role aws_iam_role.higa-wordpress-role.name IAMロール名

上記でIAMロールをEC2インスタンスにアタッチするための設定ができました。
設定ができたので、アタッチします。
コードは"aws_instance"リソースに記述する必要があり、「aws_higa_ec2.tf」記述しています。下記を参照ください。

作成したIAMロールをEC2インスタンスに付与

5.検証

作成したIAMロールが動作するのか検証していきます。
EC2インスタンスがS3に対し、ファイルの転送、コピー、削除が実行できるのか検証します。

①.まず、S3バケットを作成します。

terraformで「aws_higa_s3.tf」ファイルに下記のコードを記述します。

resource "aws_s3_bucket" "higa-wordpress-s3" {
  bucket = "higa-wordpress-s3"

  tags = {
    Name        = "higa-wordpress-s3"
  }
}

これでS3バケットが作成できました。

②.Tera TermでEC2インスタンス(higa-ec2-user)にSSHログインして、下記のコマンドで「test.txt」ファイルを作成します。
touch test.txt

③.下記コマンドで②で作成したファイルをS3に転送します。(権限設定がされていない場合、転送に失敗します。)
aws s3 cp test.txt s3://higa-wordpress-s3

[ec2-user@ip-10-0-1-10 ~]$ aws s3 cp test.txt s3://higa-wordpress-s3
upload: ./test.txt to s3://higa-wordpress-s3/test.txt

上記より、「test.txt」の転送の確認ができました。

次に、S3のファイルをコピーできるのか確認します。

④.まず、下記コマンドでインスタンスの「test.txt」ファイルを削除します。
rm test.txt

[ec2-user@ip-10-0-1-10 ~]$ rm test.txt
[ec2-user@ip-10-0-1-10 ~]$ ls
[ec2-user@ip-10-0-1-10 ~]$

上記より、ec2インスタンスから「test.txt」ファイルの削除ができました。

⑤.次に、下記コマンドでS3からファイルをコピーします。
aws s3 cp s3://higa-wordpress-s3/test.txt ./

[ec2-user@ip-10-0-1-10 ~]$ aws s3 cp s3://higa-wordpress-s3/test.txt ./
download: s3://higa-wordpress-s3/test.txt to ./test.txt
[ec2-user@ip-10-0-1-10 ~]$ ls
test.txt

上記より、S3から「test.txt」ファイルのコピーができていることが確認できました。

⑥.最後に下記コマンドでS3バケットにある「test.txt」ファイルを削除します。
aws s3 rm s3://higa-wordpress-s3/test.txt

[ec2-user@ip-10-0-1-10 ~]$ aws s3 rm s3://higa-wordpress-s3/test.txt
delete: s3://higa-wordpress-s3/test.txt

上記より、S3バケットから「test.txt」ファイルの削除ができていることが確認できました。

6.まとめ

IAMポリシーに関して、初めは「CloudWatchAgentServerPolicy」「AmazonS3FullAccess」の2つのAWS管理ポリシーを使用していましたが、AWSのベストプラクティスとして、IAMの最小権限の原則を実現するために、カスタマー管理ポリシーを作成しました。
IAMは奥が深く、非常に取っつきづらいので、まだまだ勉強が必要だと感じました。
IAMの権限に関して、状況に応じて何が必要で、何が不必要なのかを明確に説明できるレベルまで目指したいです。

また、TerraformでIAMの作成をした感想として、IAMの設定項目が一目で分かるので、非常に便利だと感じました。

7.参考文献

Last modified: 2022-06-24

Author