AWS CDKを使って差分のみの記述で複数IAM Roleを構築する 

この記事は [ハンズラボ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/handslab) 7日目の記事です。

お疲れさまです。@naokiur です。今年もこの季節がきました。
せっかくですので、活用させていただきたいと思います！

---

IAMロールにはいろんな場面で非常にご活躍いただいております。
その時々によってマネジメントコンソールで作成したり、
AWS CLI、CloudFormationやServerless Framework、AWS CDKで…などなど、
さまざまな手段を通して作成する機会があると思います。

そしてシステムの稼働や運用をつづけていくうち、
```
「目的が同じIAMロールをたくさん作ってしまっているのでは…」
「制約をもうけつつ集約する方法はないか…」
```
と考え、以下のようなユースケースを考える方も多いのではないのでしょうか！？！？（※個人の見解です）

* 想像ユースケースA
    * おんなじことをやりたいのだけど、同一AWSアカウント上に構築する上で、稼働環境を変更する必要があり、それに応じてIAMロールを分けて、対象リソースを制限したい
        * 例
            * S3バケット名称がdev, stg, prodで異なる
* 想像ユースケースB
    * 基本実現したいことは同じだけど、微妙に操作したいリソースが異なる
        * 例
            * Github ActionsでServerless Frameworkのデプロイをしたいときに、AというリポジトリではLambdaのみ、BというリポジトリではLambdaとSQSを操作する必要があるが、対象サービスをそれぞれ制限したい

多々考慮不足な点があるかと思いますが、
発想のきっかけになるかもしれないと考えたため、記録させていただきます。

## サンプル

想像ユースケースAについて考えたいと思います

以下のようなdev環境用のS3に、LambdaがアクセスできるIAMロールを検討したとします。
```python

class IAMStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        iam_role = iam.Role(
            self,
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
            id='sample-iam-role-dev',
            path='/',
            role_name=f'sample-iam-role-dev'
        )

        iam_role.attach_inline_policy(
            iam.Policy(
                self,
                "sample-iam-policy",
                statements=[
                    iam.PolicyStatement(
                        actions=[
                            "s3:Get*",
                            "s3:List*",
                            "s3-object-lambda:Get*",
                            "s3-object-lambda:List*"
                        ],
                        resources=["arn:aws:s3:::sample-dev-s3bucket"]
                    )
                ]
            )
        )
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129313/21434f38-88d2-ee2d-f860-b83b537b37ab.png)

その後、stg, prod用のLambda用にIAMロールを構築したい場合、
同じようにコードを複製して、対象のバケット名称やIAMロール、ポリシーの名前を変更することで構築することもできると思います。

しかしあえて、クラスを作成し、差分を設定するのみで実現したいと思います。

```python
class SampleIAM:
    __iam_role: iam.Role

    def __init__(self, stack, env):
        self.__iam_role = iam.Role(
            stack,
            assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
            id=f'sample-iam-role-{env}',
            path='/',
            role_name=f'sample-iam-role-{env}'
        )

        self.__iam_role.attach_inline_policy(
            iam.Policy(
                stack,
                f"sample-iam-policy-{env}",
                statements=[
                    iam.PolicyStatement(
                        actions=[
                            "s3:Get*",
                            "s3:List*",
                            "s3-object-lambda:Get*",
                            "s3-object-lambda:List*"
                        ],
                        resources=[f"arn:aws:s3:::sample-{env}-s3bucket"]
                    )
                ]
            )
        )


class IAMStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)
        dev_role = SampleIAM(self, "dev")
        stg_role = SampleIAM(self, "stg")
        prod_role = SampleIAM(self, "prod")

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129313/2528057c-9b17-b80a-ad6a-55e1305aa988.png)

stg, prodという稼働環境に依存した情報を設定することで、
`おんなじことをやりたいのだけど、対象リソースを絞ったIAMロール` を構築できるのかなと感じました。

今回はS3バケットや、IAMロール名の切り替えですが、
* 適用したいポリシーが異なる
* 利用したいデータソースが異なる

などの、目的が同じ場合だが存在するさまざま差分を、
（必要に応じてクラスや関数をさらに活用することで）吸収することができるのかもしれない…？ と感じました。

---

# 最後に

ご覧いただきありがとうございます。
把握しやすいリソースを表現するために、こちらを活用するためには、

* すべてのCDKにする
* CfnのOutputとして活用する
* インスタンスの生成タイミングがふさわしいか判断する
* コードベースでは同じだが、目的が異なるかどうかを判断する
* 「できるけどできないように」言語仕様で吸収する

などなど、検討しなければならないことが多くあると思いますが、
ご覧になっていただいた方にとって何かのきっかけになりましたら幸いです。

引き続き、現状や今後をよりよくするためにさまざまな技術を活用できるよう、
キャッチアップしていければと存じます！


[ハンズラボ Advent Calendar 2022](https://qiita.com/advent-calendar/2022/handslab) 明日の8日目は、 @shnskfjwr さんです！