AWS クロスアカウント権限管理 「リソースポリシーからrootに許可するパターン」編

クロスアカウントで色々いじっていて、IAMの権限管理についてのパターンがなんとなくわかってきたのでメモします。

クロスアカウントでの権限管理は色々なパターンがあるようですが、今回扱うのは「AアカウントのリソースポリシーでBアカウントのrootを許可→Bアカウントの中でポリシーアタッチ」のパターンです。

具体的に見ていきましょう。まずはよくあるS3のパターンです。

別アカウントのS3バケットにLambdaからアクセスする

ここではアカウントID:111111111111アカウント1からアカウントID:0000000000000000アカウント0のS3バケットにアクセスしたいとします。

アカウント0のコンソールで、S3のバケットポリシーを以下のように設定します。

{  
    "Version": "2012-10-17",  
    "Statement": [  
        {  
            "Sid": "Example permissions",  
            "Effect": "Allow",  
            "Principal": {  
                "AWS": "arn:aws:iam::1111111111111:root"  
            },  
            "Action": "s3:GetObject",  
            "Resource": "arn:aws:s3:::BUCKET_NAME/*"  
        }  
    ]  
}

ここではアカウント1のrootユーザーに対してS3バケットへのアクセスを許可しています。

次に、許可をもらったアカウント1のコンソールで以下のポリシーを作成し、S3バケットにアクセスするLambdaにアタッチします。

{  
    "Version": "2012-10-17",  
    "Statement": [   
        {  
            "Action": [  
                "s3:GetObject"  
            ],  
            "Resource": "arn:aws:s3:::BUCKET_NAME/*",  
            "Effect": "Allow"  
        }  
    ]  
}

これで、ポリシーをアタッチされたLambdaはアカウント0のS3バケットに対してアクセスすることができるようになります。
まずはアカウントのrootユーザーに権限を与える → 権限を得たroot(admin)ユーザーがリソースに対して権限を与えるという流れでわかりやすいと思います。
もちろん、最初にバケットポリシーで許可したActionしかできないようになっているので、例えば今回の場合s3:GetObject以外の操作権限はLambda にもrootユーザーにも与えられていません。
LambdaからObjectを新たにPUTしたりするためには、再びアカウント0の管理者にバケットポリシーからs3:PutObjectを許可してもらう必要があります。

別アカウントのLambdaにLambdaからアクセスする

先ほどと同様にアカウント1のLambdaからアカウント0のLambdaにアクセスしたいとします。

Lambdaの場合はリソースポリシーというものがあるので、ここで、アカウント1のrootユーザーに権限を与えます。
参考: AWS Lambda でリソースベースのポリシーを使用する (Lambda 関数ポリシー) - AWS Lambda
この操作は現在AWS CLIやAPIでしか行えないようです。

aws lambda add-permission \  
--function-name FUNC_NAME \  
--statement-id Example permissions \  
--action lambda:InvokeFunction \  
--principal 111111111111 \  
--output json

上記のコマンドを実行すると以下のjsonが返ってきます。

{  
    "Statement": "{\"Action\":[\"lambda:InvokeFunction\"],  
                   \"Resource\":\"arn:aws:lambda:YOUR_REGION:000000000000:function:FUNC_NAME\",  
                   \"Effect\":\"Allow\",  
                   \"Principal\":{\"AWS\":\"111111111111\"},  
                   \"Sid\":\"Example permissions\"}"  
}

CLIなので、見ためは違いますが、やっていることとしては先ほどのバケットポリシーと対して変わりません。アカウント1のrootユーザーに対してアカウント0のLambdaへのlambda:InvokeFunctionの権限を与えています。
次に、アカウント1のコンソールから、Lambda(アクセスする方)の実行ロールにアカウント0のLambdaへアクセスする権限を与えるポリシーをアタッチします。

{  
    "Version": "2012-10-17",  
    "Statement": [  
        {  
            "Action": [  
                "lambda:InvokeFunction"  
            ],  
            "Resource": "arn:aws:lambda:YOUR_REGION:000000000000:function:FUNC_NAME",  
            "Effect": "Allow"  
        }  
    ]  
}

これで、アカウント1のLambdaからアカウント0のLambdaにアクセスすることができるようになります。

おまけ: kmsのキーポリシーをIAMポリシーで管理する

実はクロスアカウントの権限管理以外にも、似たような権限の与え方をするパターンがあります。
それが、KMSのキーポリシーです。
AWSでは若干複雑なことに、KMSで作ったCMKに対する権限をKMSのキーポリシーで管理するということになっています。
ただ、特にLambdaに関しては実行ロールに付与されているIAMポリシーでLambdaの権限を管理できた方がわかりやすいため、IAMポリシーで管理できた方が便利だと思います。
そういった場合に、キーポリシーをIAMポリシーで管理できるようにするキーポリシーの書き方が以下です。

{  
  "Sid": "Enable IAM User Permissions",  
  "Effect": "Allow",  
  "Principal": {"AWS": "arn:aws:iam::111111111111:root"},  
  "Action": "kms:*",  
  "Resource": "*"  
}

これで、IAMポリシーでKMSのCMKの権限を管理できるようになります。
Lambdaの実行ロールには以下の権限を付与します。

{  
    "Version": "2012-10-17",  
    "Statement": [  
         {  
            "Action": [  
                "kms:*"  
            ],  
            "Resource": "arn:aws:kms:YOUR_REGION:111111111111:key/xxxxxxxxxx",  
            "Effect": "Allow"  
        }  
    ]  
}