データ利活用基盤を作ってみたその７(構築・IAM)




## はじめに
こんにちは。NTTデータ先端技術の@fujitak-intellilinkです。
本記事は、データ活用基盤を作ってみた連載記事のその７です。
本シリーズの取り組みの内容については[データ活用基盤を作ってみたその１(構成シナリオ)](https://qiita.com/kamein/items/81df29ef9d32bf0a0810) をご覧ください。
前の記事は、[データ活用基盤を作ってみたその６(構築・デプロイ方法) ](https://qiita.com/shiraki_ils/items/863465b40c0bf85f9a03) からご覧ください。
本記事では、データ活用基盤におけるIAMの構成・設定について記載します。

## 目次
[アクター一覧](#アクター一覧)
[構築内容](#構築内容)
[反省と注意点](#反省と注意点)
[まとめ](#まとめ)

## アクター一覧
主に以下の5種類のアクターを想定しています。
本システムは、「データ活用基盤側」と「既存システム側」に分かれています。
今回のメインはあくまで「データ活用基盤側」のリソースであるため、「既存システム側」のリソース（項番5のお客様のIAMリソース）について、データ活用基盤の開発にあたって新規で構築したものは記載しますが、既存システムとして既に構築済みであるリソース（EC2へのアクセス権限等）について本資料では記載を省略させていただきます。
![アクター一覧.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3418658/85b7634d-b13a-ed14-2811-968aed1127e8.png)




各アクターがアクセスできるサービスはIAMロールで制御しており、各ユーザがスイッチロールするための必要最小限の権限をIAMグループで定義しております。
各アクターのロールにアタッチされたポリシーは以下の通りです。


■基盤運用責任者
〇ポリシー付与方針
アカウントの管理と、運用作業を実施するユーザ。
運用作業時にシステムの構成変更を実施できるように管理者権限を付与します。

〇AWSマネージドポリシー
- AdministratorAccess

![基盤運用責任者ロール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3418658/0e70213e-7510-1b24-959a-441c3c473ecb.png)

■監査運用者
〇ポリシー付与方針
セキュリティ監査用のユーザのため、監査系サービス、監査ログバケットへのアクセス権を付与します。

〇AWSマネージドポリシー
- AWSCloudTrail_FullAccess
- AWSSecurityHubFullAccess
- AWSAuditManagerAdministratorAccess
- AmazonGuardDutyFullAccess
- CloudWatchFullAccess

〇カスタマーマネージドポリシー
- biwa-prod-iam-policy-ConfigFullAccess-001
⇒Configへのフルアクセスを定義するポリシー
- biwa-prod-iam-policy-AuditS3BucketAccess-001
⇒監査用・監査レポート用・リソース確認用S3バケットへのアクセス権限を定義するポリシー


![監査運用者.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3418658/b7ed57d0-3045-745a-3275-4b537e85d6da.png)

■データエンジニア
〇ポリシー付与方針
投入データ管理用のユーザのため、データ活用（収集・加工・蓄積・分析）系サービスへのフルアクセス権限を付与します。

〇AWSマネージドポリシー
- AmazonAthenaFullAccess
- AWSGlueConsoleFullAccess
- AWSLambda_FullAccess
- AWSStepFunctionsFullAccess
- AmazonSNSFullAccess
- AmazonEventBridgeFullAccess

〇カスタマーマネージドポリシー
- biwa-prod-iam-policy-devS3BucketAccess-001
⇒データ加工用・Athenaの結果出力用S3バケットへのアクセス権限を定義するポリシー

![データエンジニアロール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3418658/58f19ea4-1e2a-6256-395d-286db7c05321.png)

■運用作業者
〇ポリシー付与方針
監視異常発生時に通知を受け、簡単な運用作業を実施するための共同会社のオペレータ。（対応が明確でない場合は、基盤運用責任者へ対応依頼を行う。）
対応内容が明確なものに関しては是正対応を行うため、データ活用系サービス、CloudWatch、利用者サーバへのアクセス権を付与します。

〇AWSマネージドポリシー
- AmazonAthenaFullAccess
- AWSGlueConsoleFullAccess
- AWSLambda_FullAccess
- AWSStepFunctionsFullAccess
- AmazonSNSFullAccess
- AmazonEventBridgeFullAccess
- CloudWatchReadOnlyAccess

〇カスタマーマネージドポリシー
- biwa-prod-iam-policy-operatorS3BucketAccess-001
⇒データ加工用・Athenaの結果出力用S3バケットへのアクセス権限を定義するポリシー

![運用作業者ロール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3418658/87f1253d-19be-4c6d-805c-1c6ec1dcee11.png)


■既存システムのデータ活用者
〇ポリシー付与方針
データ活用を行う顧客ユーザ。
データ活用基盤側のデータ分析用リソース（Athena、S3、Glue等）へのアクセス権限を付与します。
※ 既存システム側にはデータ活用者ロールのarnを連携して、既存システム側のIAMロールにAssumeRoleのポリシー付与を依頼します。

〇AWSマネージドポリシー
- AmazonAthenaFullAccess
- AWSGlueConsoleFullAccess

〇カスタマーマネージドポリシー
- biwa-prod-iam-policy-analystS3BucketAccess-001
⇒データ加工用・Athenaの結果出力用S3バケットへのアクセス権限を定義するポリシー

![既存システムのデータ活用者.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3418658/e47692cc-0607-5829-1efa-0e6bb6e70001.png)

## 構築内容
「データ活用基盤側」のリソースの定義は、「iam-admin.tf」ファイルで実施しました。

IAMユーザのみマネコンで手動構築済みのものを使用しそれ以外のIAMリソースをIaCで管理するものとします。

以下に作成したtfファイルの内容と解説を記載します。
なお、データ活用基盤の試験（単体試験・結合試験・システムテスト）は全て「biwauser-01」で実施するため、今回は「biwauser-01」が全てのアクターの試験を行えるように設定してあります。

### 手動作成済みIAMユーザの取得
マネコンで手動作成済みのデータ活用基盤試験用ユーザを取得します。
本システムはまだ構築～試験の段階であり、まだ試験実施用の「biwauser-01」ユーザしか作成していませんが、運用フェーズに向けて、各個人用のIAMユーザを作成していく予定です。

```terraform:iam-admin.tf
# IAMユーザ取得
data "aws_iam_user" "biwauser-01" {
  user_name = "biwauser-01"
}
```

### AWSマネージドポリシーの取得
AWS側ですでに定義されている、AWSマネージドポリシーを取得します。
ここで、各ロールにアタッチするAWSマネージドポリシーを全て記載する必要があります。
分量が多いため一部だけ記載します。
以下のコードでは基盤運用責任者ロールにアタッチするAdministratorAccessを取得しています。

```terraform:iam-admin.tf
# AWS管理IAMポリシー取得
data "aws_iam_policy" "AdministratorAccess" {
  arn = "arn:aws:iam::aws:policy/AdministratorAccess"
}
#--------------------------------以下割愛---------------------------------
```

### カスタマーマネージドポリシーの作成
各ロール・グループにアタッチする、カスタムポリシーを作成します。
以下のコードでは、監査運用者グループにアタッチするポリシーと監査運用者ロールにアタッチするConfigフルアクセス用ポリシーと監査運用者S3バケットアクセス用ポリシーのみ載せており、他は割愛していますが、実際にはほかのアクター用のカスタマーマネージドポリシーもここで定義されています。

```terraform:iam-admin.tf
# カスタマーマネージドポリシー作成
# 監査運用者グループ用
resource "aws_iam_policy" "biwa-prod-iam-policy-auditor-001" {
  name = "biwa-prod-iam-policy-auditor-001"

  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Deny",
        "NotAction" : [
          "iam:CreateVirtualMFADevice",
          "iam:EnableMFADevice",
          "iam:ListMFADevices",
          "iam:ListUsers",
          "iam:ListVirtualMFADevices",
          "iam:ResyncMFADevice",
          "iam:ChangePassword"
        ],
        "Resource" : "*",
        "Condition" : {
          "BoolIfExists" : {
            "aws:MultiFactorAuthPresent" : "false"
          }
        }
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "iam:CreateVirtualMFADevice",
          "iam:EnableMFADevice",
          "iam:ListMFADevices",
          "iam:ListUsers",
          "iam:ListVirtualMFADevices",
          "iam:ResyncMFADevice",
          "iam:ChangePassword"
        ],
        "Resource" : [
          "arn:aws:iam::*:mfa/*",
          "arn:aws:iam::*:user/$${aws:username}"
        ]
      },
      {
        "Sid": "1",
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "arm:aws:iam::{アカウントID}:role/biwa-prod-iam-role-auditor-001"
      }
    ]
  })
}

# 監査運用者ロール用
# ConfigFullAccess
resource "aws_iam_policy" "biwa-prod-iam-policy-ConfigFullAccess-001" {
  name = "biwa-prod-iam-policy-ConfigFullAccess-001"

  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Action" : [
          "sns:AddPermission",
          "sns:CreateTopic",
          "sns:DeleteTopic",
          "sns:GetTopicAttributes",
          "sns:ListPlatformApplications",
          "sns:ListTopics",
          "sns:SetTopicAttributes"
        ],
        "Resource" : "*"
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "s3:CreateBucket",
          "s3:GetBucketAcl",
          "s3:GetBucketLocation",
          "s3:GetBucketNotification",
          "s3:GetBucketPolicy",
          "s3:GetBucketRequestPayment",
          "s3:GetBucketVersioning",
          "s3:ListAllMyBuckets",
          "s3:ListBucket",
          "s3:ListBucketMultipartUploads",
          "s3:ListBucketVersions",
          "s3:PutBucketPolicy"
        ],
        "Resource" : "arn:aws:s3:::*"
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "iam:CreateRole",
          "iam:GetRole",
          "iam:GetRolePolicy",
          "iam:ListRolePolicies",
          "iam:ListRoles",
          "iam:PutRolePolicy",
          "iam:AttachRolePolicy",
          "iam:CreatePolicy",
          "iam:CreatePolicyVersion",
          "iam:DeletePolicyVersion",
          "iam:CreateServiceLinkedRole"
        ],
        "Resource" : "*"
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "iam:PassRole"
        ],
        "Resource" : "*",
        "Condition" : {
          "StringEquals" : {
            "iam:PassedToService" : [
              "config.amazonaws.com",
              "ssm.amazonaws.com"
            ]
          }
        }
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "cloudtrail:DescribeTrails",
          "cloudtrail:GetTrailStatus",
          "cloudtrail:LookupEvents"
        ],
        "Resource" : "*"
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "config:*",
          "tag:Get*"
        ],
        "Resource" : "*"
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "ssm:DescribeDocument",
          "ssm:GetDocument",
          "ssm:DescribeAutomationExecutions",
          "ssm:GetAutomationExecution",
          "ssm:ListDocuments",
          "ssm:StartAutomationExecution"
        ],
        "Resource" : "*"
      }
    ]
  })
}


# 監査運用者S3バケットアクセス用ポリシー
resource "aws_iam_policy" "biwa-prod-iam-policy-AuditS3BucketAccess-001" {
  name = "biwa-prod-iam-policy-AuditS3BucketAccess-001"

  policy = jsonencode({
    "Version" : "2012-10-17",
    "Statement" : [
      {
        "Effect" : "Allow",
        "Action" : [
          "s3:*"
        ],
        "Resource" : [
          "arn:aws:s3:::biwa-prod-s3-bucket-audit*",
          "arn:aws:s3:::biwa-prod-s3-bucket-audit*/*",
          "arn:aws:s3:::biwa-prod-s3-bucket-auditmanager*",
          "arn:aws:s3:::biwa-prod-s3-bucket-auditmanager*/*",
          "arn:aws:s3:::biwa-prod-s3-bucket-cloudwatch*",
          "arn:aws:s3:::biwa-prod-s3-bucket-cloudwatch*/*"
        ]
      },
      {
        "Effect" : "Allow",
        "Action" : [
          "kms:Decrypt",
          "kms:GenerateDataKey"
        ],
        "Resource" : "${aws_kms_key.biwa-prod-kms-key-s3bucket-001.arn}"
      }
    ]
  })
}
#--------------------------------以下割愛---------------------------------
```


### IAMグループ・ロールの作成
各ユーザ用のグループやロールを作成します。
ロールの信頼ポリシーはここで作成します。

```terraform:iam-admin.tf
# IAMグループ作成
resource "aws_iam_group" "biwa-prod-iam-group-admin-001" {
  name = "biwa-prod-iam-group-admin-001"
#--------------------------------以下割愛---------------------------------
```



```terraform:iam-admin.tf
# IAMロール作成
resource "aws_iam_role" "biwa-prod-iam-role-admin-001" {
  name = "biwa-prod-iam-role-admin-001"
  assume_role_policy = jsonencode({
    "Version" : "2012-10-17"
    "Statement" : [
      {
        "Effect": "Allow",
        "Principal": {
          "AWS": [
            "arn:aws:iam::{アカウントID}:user/biwauser-01",
          ]
        },
        "Action": "sts:AssumeRole",
        "Condition": {
          "Bool": {
            "aws:MultiFactorAuthPresent": "true"
          }
        }
      }
    ]
  })
}
#--------------------------------以下割愛---------------------------------
```

### IAMグループ・ロールにポリシーをアタッチ
先ほど作成したポリシーを各グループ・ロールにアタッチします。

```terraform:iam-admin.tf
# IAMグループにアタッチするポリシーを指定
resource "aws_iam_group_policy_attachment" "biwa-prod-iam-policy-admin-001" {
  group      = aws_iam_group.biwa-prod-iam-group-admin-001.name
  policy_arn = "arn:aws:iam::{アカウントID}:policy/biwa-prod-iam-policy-admin-001"
#--------------------------------以下割愛---------------------------------
```
```terraform:iam-admin.tf
# IAMロールにアタッチするポリシーを指定
resource "aws_iam_role_policy_attachment" "AdministratorAccess-admin" {
  role       = aws_iam_role.biwa-prod-iam-role-admin-001.name
  policy_arn = data.aws_iam_policy.AdministratorAccess.arn
}
#--------------------------------以下割愛---------------------------------
```


### 各グループに所属させるユーザを定義
先ほど作成したグループにユーザを所属させます。
割愛していますが、データ活用基盤の試験は全て「biwauser-01」で実施するため、「biwauser-01」が全てのアクターの試験を行えるように設定してあります。

```terraform:iam-admin.tf
# IAMグループに所属させるユーザを指定
resource "aws_iam_group_membership" "biwa-prod-iam-group-admin-001" {
  name = "biwa-prod-iam-group-admin-001-membership"
  users = [
    "biwauser-01"
  ]
  group = aws_iam_group.biwa-prod-iam-group-admin-001.name
}
#--------------------------------以下割愛---------------------------------
```


## 反省と注意点
### IAM設計全般
- 今回、アクター定義のところが曖昧なまま進んでしまい、IaC作成フェーズで実際にアクターの権限設定を実施する所に至ってから、本来要件定義フェーズで実施すべきだった詳細なアクター定義を再実施することになったため、上流フェーズの時点で詳細なアクター定義を実施する必要がありました。
- 今回は、スケジュールがかつかつだったのと、あくまでメインはデータ分析機能の構築であることから、ポリシーは広めに付与（基本的に各アクターが使用するサービスのFullAccessを付与）しましたが、本来は最小権限の原則に従ってポリシーを付与する必要があります。
- 基本設計書で構築するリソースのリソース名が未定義のものがあったことで、ポリシーやロールの設定が滞るということがあったため、設計段階で名称付与方針やリソース名一覧があると進めやすいと思いました。
### IaCでIAM設計を実施する場合の反省・注意点
- どこまでを手動構築して、どこをIaC化するかを検討する必要があります。今回、新規ユーザの作成が頻繁に実施されることと、運用フェーズに至ったときに、技術力のない人でもユーザ追加を実施できる必要があることを想定して、IAMユーザの作成のみIaC化せず手動で実施しましたが、構築後運用していくうえでどこをIaC化すれば運用負荷が抑えられるかを検討した上で設計する必要があります。
- IAMの権限がないと他のサービスの構築が進まないため、まずは構築用のユーザの作成とポリシー・ロール・グループの設定だけは急いで実施するべきでした。手動での構築であれば割とすぐ終わりますが、IaCで構築用のユーザを設定を行うとなると、IaCのデプロイ環境の準備も必要になるため、そこをスケジュールに盛り込むべきでした。（今回はスケジュールに盛り込めていなかったため遅延が発生しました）

## 最後に
今回はIaCを用いてIAMリソースを定義する際の設定・構成について紹介しました。
次の記事は[データ活用基盤を作ってみたその８(構築・データ収集-Lambda)](https://qiita.com/tsuchidahrk/items/92cee4db92d68010e3c9) です。
最後までお読みいただきありがとうございました。