複数のIAMポリシーを1つにまとめる

MEGAZONE 株式会社 のテック陣「MEGAZONEのゆかいな仲間たち」がおくる、Megazone Japan Advent Calendar 2023 の17日目のエントリーです。


## はじめに

[前回](https://qiita.com/Bibulous/items/8d624861d3de7b624363 "ReadOnlyAccessは何を見るか？")はReadOnlyAccessが存在しないAWSサービス用のIAMポリシーを作成しました。その話の続きとなります。

>僕「あるAWSアカウントの環境をチェックしたいので **ReadOnlyAccessのIAMユーザー**を発行してください。」
>管理者「必要となる権限の詳細を知りたい。 **対象のAWSサービスを絞れますか？**」
>僕 （利用中のAWSサービスは知っている...。そのAWSサービスの 〇〇ReadOnlyAccess を全部アタッチしてもらおうかな:thinking:）


僕「対象AWSサービスのIAMポリシーまとめたぞ。自作が必要なポリシーはActionを記載した。全部アタッチしてくれ。」

管理者「すまん、1つにまとめてくれないか？JSONで頼む。」

## 課題: 複数のIAMポリシーを1つにまとめる(JSON)

以下の IAMポリシー(**ReadOnly**) が欲しいものとします。

| 対象AWSサービス | 欲しいIAMポリシー |
|:-:|:-:|
| Amazon EC2 | AmazonEC2ReadOnlyAccess  |
| Amazon S3  | AmazonS3ReadOnlyAccess  |
| Amazon Route53  | AmazonRoute53ReadOnlyAccess  |
| AWS Key Management Service (AWS KMS)  | AWSKMS_ReadOnlyAccess(※)|

※AWS Key Management Service (AWS KMS)は自作した以下の内容とします
```
{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "VisualEditor0",
			"Effect": "Allow",
			"Action": [
				"kms:Describe*",
				"kms:Get*",
				"kms:List*"
			],
			"Resource": "*"
		}
	]
}
```

上記4つのIAMポリシーを1つのIAMポリシーにまとめます。

## そもそもJSONって何？
JSONはデータフォーマットの1つです。
AWS IAMポリシーのJSONについては下記の記事でとても丁寧に説明されています。

https://qiita.com/Ohtak/items/886e2b25227777a4306e

## 既存のIAMポリシー(JSON)から必要な部分をコピーする
やり方はいろいろありますが、既存のIAMポリシーから拝借すれば漏れがないと思います。

* EC2(AmazonEC2ReadOnlyAccess)の場合

IAM > Policies で「AmazonEC2ReadOnlyAccess」と検索。
Policy nameの「+」をクリックするとJSONが表示されるので、右上のCopy JSONをクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632907/9add3b9d-a888-8609-6e34-b0d5060ed864.png)

AmazonEC2ReadOnlyAccessのJSONがコピーされるので、テキストエディタ等にペーストして、以下のように"Statement"内の記述を抜き出します。

```
{
    "Version": "2012-10-17",
    "Statement": [
--------------------------ココカラ-------------------------
        {
            "Effect": "Allow",
            "Action": "ec2:Describe*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "elasticloadbalancing:Describe*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:ListMetrics",
                "cloudwatch:GetMetricStatistics",
                "cloudwatch:Describe*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "autoscaling:Describe*",
            "Resource": "*"
        }
-------------------------ココマデ-------------------------
    ]
}
```

抜き取ったJSON記述は以下のようになります。

```
        {
            "Effect": "Allow",
            "Action": "ec2:Describe*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "elasticloadbalancing:Describe*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:ListMetrics",
                "cloudwatch:GetMetricStatistics",
                "cloudwatch:Describe*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "autoscaling:Describe*",
            "Resource": "*"
        }
```

他のAWSサービスも同じ手順で"Statement"内の記述を抜き取っていきます。

* S3(AmazonS3ReadOnlyAccess)
```
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*",
                "s3:Describe*",
                "s3-object-lambda:Get*",
                "s3-object-lambda:List*"
            ],
            "Resource": "*"
        }
```
* Route53(AmazonRoute53ReadOnlyAccess)
```
        {
            "Effect": "Allow",
            "Action": [
                "route53:Get*",
                "route53:List*",
                "route53:TestDNSAnswer"
            ],
            "Resource": [
                "*"
            ]
        }
```
* AWS KMS(AWSKMS_ReadOnlyAccess)
```
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "kms:Describe*",
                "kms:Get*",
                "kms:List*"
            ],
            "Resource": "*"
        }
```

* 抜き取ったJSONを1つにまとめる
先ほどまで各ポリシーの"Statement"内の記述を抜き取ってきましたが、今度は抜き取った記述を"Statement"内に戻すイメージです。
このときの注意点として、**区切りのカンマ(,)を付ける箇所があります。**

```
{
    "Version": "2012-10-17",
    "Statement": [
※AmazonEC2ReadOnlyAccessの抜き取った記述をペースト(末尾に「,」を付ける)
※AmazonS3ReadOnlyAccessの抜き取った記述をペースト(末尾に「,」を付ける)
※AmazonRoute53ReadOnlyAccessの抜き取った記述をペースト(末尾に「,」を付ける)
※AWSKMS_ReadOnlyAccessの抜き取った記述をペースト(末尾に「,」は付けない!)
    ]
}
```
↓↓↓

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ec2:Describe*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "elasticloadbalancing:Describe*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudwatch:ListMetrics",
                "cloudwatch:GetMetricStatistics",
                "cloudwatch:Describe*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "autoscaling:Describe*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*",
                "s3:Describe*",
                "s3-object-lambda:Get*",
                "s3-object-lambda:List*"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:Get*",
                "route53:List*",
                "route53:TestDNSAnswer"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "kms:Describe*",
                "kms:Get*",
                "kms:List*"
            ],
            "Resource": "*"
        }
    ]
}
```
JSONのカンマ( , )については下記サイト等を参考にしてください。

https://pikawaka.com/javascript/json

AmazonEC2ReadOnlyAccessのJSONを眺めていると分かりやすいかもです。

## 新規のIAMポリシーに、1つにまとめたJSONをペーストする
IAM > Policiesで右上の「Create policy」をクリックします。
Policy editorが表示されるので、右上のJSONをクリックします。

デフォルトのJSON(内容は空っぽ)が記述されているので、1つにまとめたJSONをペーストします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632907/8256cbb7-8c9d-5537-bdb9-a9d1f0c96fb6.png)

↓↓↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632907/93f38933-1bb1-29d9-cf11-d8506370b29d.png)

:::note info
もし構文エラーが表示された場合は、余計なカンマ等が入っていないかよくチェックしてみてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632907/75079943-16f4-8f93-e77b-ccd8eac3249c.png)
:::

構文エラーがなければ右下のNextをクリックします。
次のReview and createページで対象AWSサービスや権限に漏れがなければ、右下のCreate policyをクリックでIAMポリシーの作成完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632907/3d87127c-c68c-e410-7b6b-f652013adeaf.png)

念のため新規IMAユーザー等にアタッチして、期待する動作となっているか確認しておきましょう。

## おわりに
今回の手順はかなり大雑把なので、JSONのコピー元となるIAMポリシーが増えると、重複する"Action"も出てくるかと思います。元々アタッチしていた(する予定だった)ポリシーを1つにまとめるだけ、という前提なので問題ありませんが。

重複した場合の動作は下記をご参考ください。

https://qiita.com/snaka/items/1fd4b3a55264108d8be8

ありがとうございました！