Lambda関数を作成する開発者に必要な権限を考えてみた

## はじめに
日頃Lambda関数の構築において、都度インフラ管理者に依頼して、IAMポリシーとIAMロールを作成してもらうようにしていますが、後から必要な権限が出てきたりして、開発がなかなか進まないこともありますよね。
Lambda関数にアタッチするIAMポリシーとIAMロールを自分で作って試せると嬉しいなと思い、Lambda関数を構築する開発者に必要なIAM周りのIAMポリシーについて考えてみました。

**先にお伝えすると、下記のポリシーだと穴があるので、ご使用はお控えください。**
別のアイデア大歓迎です！コメントください！

## 前提条件
AWSの環境は次の通りとします。

### Assume Roleを使う
Assume Roleを使っている場合、ユーザーに権限をつける際は下記のようなフローになります。

**①  IAMポリシーの作成**
必要な権限をつけたIAMポリシーを作成する。

**② IAMロールの作成**
①で作成したポリシーをAssume用のロールにアタッチする。

**③ IAMポリシーの作成**
②のIAMロールにAssumeできる権限をつけたIAMポリシーを作成する。

**④  IAMグループの作成**
③番のIAMポリシーをIAMグループにアタッチする。

**⑤ IAMユーザーの追加**
④番で作成したIAMグループにユーザーを追加する。

今回はIAMポリシーとIAMロールの作成・更新ができる権限が必要です。しかし上記のフローより①③IAMポリシー、②IAMロールに権限が自由に付けられるのは避けたいです。

### 既にLambda関数のフルアクセスがついている
私にもともとついていた権限はLambda関数のフルアクセスで、IAM周りに関しては、こちらの8つがついているので、既存のIAMロールをLambda関数に付与することはできます。

+ iam:GetPolicy
+ iam:GetPolicyVersion
+ iam:GetRole
+ iam:GetRolePolicy
+ iam:ListAttachedRolePolicies
+ iam:ListRolePolicies
+ iam:ListRoles
+ iam:PassRole

ただ、自分でIAMポリシーを作成し、そのポリシーをアタッチしたIAMロールを作成することができません。

ちなみに、`iam:PassRole`に関しては、Lambdaのみに制限されているので、EC2などにはアタッチできないようになっています。

```json
{
   "Effect": "Allow",
   "Action": "iam:PassRole",
   "Resource": "*",
   "Condition": {
        "StringEquals": {
             "iam:PassedToService": "lambda.amazonaws.com"
        }
   }
}
```

## IAMポリシーについて
IAMポリシーは基本的に次の4つの要素で権限をしぼっていきます。

| 要素 | 内容 |
| ---- | ---- |
| Effect | Allow または Deny を指定してこのポリシーを許可するのか拒否するかを設定 |
| Action | 許可(拒否)したいサービスと操作を設定 |
| Resource | どのリソースに対してActionを許可(拒否)したいのかを設定|
|Condition| タグ、送信元IPなど、細かく条件を設定|

ポリシーが適用される優先順位は**明示的な Deny > 明示的な Allow > デフォルト Deny**となります。

## 結論
### リソースの命名規則を制定
IAMポリシーの作成の前に、運用面で以下の規程を決めます。
ユーザーに権限をつけるフローに沿って、以下を名前の先頭につけるように命名規則を作りました。今後ユーザー周りの権限を作る際には、以下の命名規則に則ってリソースに名前をつけるようにします。

+ ①IAMポリシー：user-policy-
+ ②IAMロール：assumerole-
+ ③IAMポリシー：assumerole-policy-


### IAMポリシー
上記、命名規則を踏まえて作成したIAMポリシーはこちらです。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:CreatePolicy",
                "iam:ListPolicies",
                "iam:CreateRole",
                "iam:AttachRolePolicy",
                "iam:PutRolePolicy",
                "iam:CreatePolicyVersion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Deny",
            "Action": "iam:AttachRolePolicy",
            "Resource": "arn:aws:iam::＜アカウントID＞:role/assumerole-*"
        },
        {
            "Sid": "VisualEditor2",
            "Effect": "Deny",
            "Action": "iam:CreatePolicyVersion",
            "Resource": [
                "arn:aws:iam::＜アカウントID＞:policy/user-policy-*",
                "arn:aws:iam::＜アカウントID＞:policy/assumerole-policy-*"
            ]
        }
    ]
}
```

明示的なDenyで、ユーザーの権限に使っているリソースの編集はできないようになりました。ここで上記で制定した命名規則が役に立ってきます。優先順位の関係で、Denyで指定しているリソース以外のロールの更新、ポリシーの更新はできるというようになります。

### ここで問題が
上記のように、改変されたくないリソースの命名規則を決めて、そのリソースを改変できないようにするだけでは、adminポリシーをアタッチしたIAMロールを作ってしまえば、なんでもできてしまいます。そうなると、IAMのアクションを含むポリシーの作成をできなくしたり、既存のポリシーからもIAMの操作を含むポリシーはアタッチできないようにする必要がありそうです。

また、これだと自分とは関係ないポリシーやロールも変え放題ですね。複数のプロジェクトが混在しているAWSだと、命名規則を設定して、このプロジェクトに関するのだけ変えられるようにしないといけないです。

### 改めて結論
上記のIAMポリシーだと抜け道ができてしまっているので、改良が必要です。やっぱりIAM関連はインフラ管理者に依頼して作ってもらうほうが良いのかもしれないと思えてきました。


## おわりに
Lambda関数を作成したい開発者に付与するIAMポリシーについて考えてみました！最初はインフラ管理者に提案するぞと意気込んで始めましたが、解決できるポリシーを見つけることができませんでした。

ただ、AWSのIAMについて勉強するいい機会にはなりました。これまでLambdaにつけるIAMポリシーはよく作ってきましたが、Lambdaにつける権限はSDKで使うアクションを追加していくだけなので、そんなに深く考えることがありませんでした。結局はLambdaに権限をつけるのと同じと言えば同じなのですが、この操作にどんな権限がいるのか考えていくのは大変な作業だなと感じました。