0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS SAM では独自に命名した IAM ロールを作成した方が良い気がしたのでメモ

Posted at

前置き

以下のような AWS::Serverless::Function のリソースを作成する SAM(CloudFormation)テンプレートがありました。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  Sample SAM Template

Resources:
  NuxtServerFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-nuxt-server"
      CodeUri: nuxt-app/.output/server/
      Handler: index.handler
      Description: Nuxt4 Server application
      MemorySize: 1024
      FunctionUrlConfig:
        AuthType: NONE
        Cors:
          AllowMethods: ["*"]
          AllowOrigins: ["*"]
          AllowHeaders: ["*"]

AWS::Serverless::Function は AWS SAM で利用可能なサーバーレスアプリケーションを作るのに特化したリソースで Lambda 関数に紐づく実行ロールや API Gateway の設定を含めた構築が可能となっています。Lambda 関数に紐づく実行ロールについて自動生成されるロールの名称は以下のような規則に基づいたものとなっています。

実行ロールの命名規則
<スタック名>-<AWS::Serverless::Function のリソース名>Role-<ランダムな12桁の文字列>
↓
hogefuga-stack-stg-NuxtServerFunctionRole-abcd1234efgh


IAM ロールの名称には最大64文字までという制限があります。

image.png


今回は AWS SAM を使ったアプリのデプロイを GitHub Actions から実行しています。
あらかじめ AWS アカウント側に IAM OIDC ID プロバイダー を構築し、GitHub Actions と AWS の間に信頼関係を作っておくことでワークフロー実行時に一時的なクレデンシャルを使った認証を可能としています。

デプロイする際のロールには PowerUserAccess という強力なマネージドポリシーと以下のような一部の iam の操作を許可するポリシーを付与しています。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "iam:CreateRole",
                "iam:DeleteRole",
                "iam:AttachRolePolicy",
                "iam:DetachRolePolicy",
                "iam:PutRolePolicy",
                "iam:DeleteRolePolicy",
                "iam:GetRole",
                "iam:PassRole",
                "iam:TagRole",
                "iam:UntagRole"
            ],
            "Resource": [
                "arn:aws:iam::<アカウントID>:role/<アプリ名>-stg-*",
                "arn:aws:iam::<アカウントID>:role/<アプリ名>-prod-*"
            ],
            "Effect": "Allow"
        }
    ]
}

Resource の記述によって iam について前方一致でAWSの操作可能なリソースの範囲を制限するといった施策を取っています。

image.png

何が問題なのか

こちらスタック名(アプリ名)にそこそこ長い名称を指定した際にスタック名の一部が欠落し、結果としてデプロイに失敗するという問題が発生してしまいました。。:sob:

例)
スタック名:hogehoge-fugafuga-abcdefg-stg
AWS::Serverless::Function のリソース名:NuxtServerFunction
ランダム文字列:abcd1234efgh

これらを連結すると hogehoge-fugafuga-abcdefg-stg-NuxtServerFunctionRole-abcd1234efgh という 65 文字の文字列になりますが、IAMロールには前述の通りで最大で 64 文字の制限があります。
こちら実際にはプレフィックス部分である hogehoge-fugafuga-abcdefg-stg の一部が取り除かれた hogehoge-fugafuga-abcdefg-st-NuxtServerFunctionRole-abcd1234efgh といったロールを生成しようとしていました。

前置きの中で話として挙げたデプロイ用ロールは <アプリ名>-stg-* に合致するリソースしか操作できないため、この切り詰めで名前が一致せず、以下のような iam:CreateRole 権限エラーが発生しました。

CloudFormation のエラーログ(アカウントIDなどは適当な値に置換済)
Resource handler returned message: "Encountered a permissions error performing a tagging operation, please add required tag permissions.
See https://repost.aws/knowledge-center/cloudformation-tagging-permission-error for how to resolve.
Resource handler returned message: "User: arn:aws:sts::123456789012:assumed-role/deploy-role-for-<アプリ名>/GitHubActions is not authorized to perform: iam:CreateRole on resource: arn:aws:iam::123456789012:role/<アプリ名>-st-NuxtServerFunctionRole-7MYDjp6EaYMm because no identity-based policy allows the iam:CreateRole action (Service: Iam, Status Code: 403, Request ID: 4fc3ffde-0b9f-4462-b26b-2fd0d364d98c) (SDK Attempt Count: 1)"" (RequestToken: z9x8y7w6-v5u4-3210-tsrq-0987654321po, HandlerErrorCode: UnauthorizedTaggingOperation)

image.png


ということで SAM を使う場合でも IAM ロール名には余裕を持たせるべく、必要に応じて 独自にロールを自作する方針 を取ることにしました。

実行ロールについて自作する

以下のような感じで AWS::IAM::Role リソースを追加し、その ARN を AWS::Serverless::Function リソースの Role プロパティで渡すことで IAM ロールの名称について独自のものを設定することができました。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  Sample SAM Template

Resources:
  NuxtServerFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${AWS::StackName}-nuxt-server"
+      Role: !GetAtt NuxtServerFunctionRole.Arn
      CodeUri: nuxt-app/.output/server/
      Handler: index.handler
      Description: Nuxt4 Server application
      MemorySize: 1024
      FunctionUrlConfig:
        AuthType: NONE
        Cors:
          AllowMethods: ["*"]
          AllowOrigins: ["*"]
          AllowHeaders: ["*"]

+  NuxtServerFunctionRole:
+    Type: AWS::IAM::Role
+    Properties:
+      # ロール名を設定(スタック名だけだとわかりにくいので Lambda 関数の実行ロールであることがわかるようなサフィックスを付与)
+      RoleName: !Sub "${AWS::StackName}-nuxt-server-role"
+      # 以下の信頼ポリシーと許可ポリシーは AWS::Serverless::Function でポリシーなど特に追記せずに作成した場合のデフォルトと同じ
+      AssumeRolePolicyDocument:
+        Version: '2012-10-17'
+        Statement:
+          - Effect: Allow
+            Principal:
+              Service: lambda.amazonaws.com
+            Action: sts:AssumeRole
+      ManagedPolicyArns:
+        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

↓ 修正前

image.png

↓ 修正後(短くなった!)

image.png

意図したロール名での生成が行えてることを確認できました。

今回はサフィックスとして -nuxt-server-role という17文字を付与しているのでスタック名には 64 - 17 で 47 文字まで設定できるようになったものと思われます。

備考

capabilities に関するエラーー

IAM ロールを自作する過程で、capabilities に関するエラーが発生しました。

Error: Failed to create changeset for the stack: <アプリ名>-stg, ex: Waiter ChangeSetCreateComplete failed: Waiter encountered a terminal failure state: For expression "Status" we matched expected path: "FAILED" Status: FAILED. Reason: Requires capabilities : [CAPABILITY_NAMED_IAM]

原因は、samconfig.toml の CI 用デプロイ設定で capabilities = "CAPABILITY_IAM" としていたためです。
AWS::Serverless::Function を使っている場合はこれでも問題なかったみたいですが、IAM ロールを独自に作る場合には CAPABILITY_NAMED_IAM を明示する必要がありました。

samconfig.toml
~~~ 省略 ~~~

# GitHub Actions 用デプロイ設定
[ci.deploy.parameters]
-capabilities = "CAPABILITY_IAM"
+capabilities = "CAPABILITY_NAMED_IAM"
confirm_changeset = false
fail_on_empty_changeset = false
resolve_s3 = true

GitHub Actions からのデプロイの中で以下のように --config-env ci を指定して ci.deploy.parameters の設定を読み込んでいます。

.github/workflows/sam-deploy.yml
      - name: 🌐 メインスタックをデプロイ(CloudFront + Lambda + S3 + etc など)
        run: |
          sam build
          sam deploy \
            --config-env ci \
            --stack-name ${{ env.STACK_NAME }} \
            --region ${{ env.AWS_REGION }} \
            --no-progressbar

スタック名の生成について

GitHub Actions ではリポジトリ名と環境名を組み合わせてスタック名を生成しています。

.github/workflows/sam-deploy.yml
      - name: 🔧 スタック環境変数を設定
        run: |
          REPO_NAME="${{ github.event.repository.name }}"
          ENVIRONMENT=$([[ "$GITHUB_REF" == "refs/heads/prod" ]] && echo "prod" || echo "stg")
          STACK_NAME=$(echo "${REPO_NAME}-${ENVIRONMENT}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
          echo "REPO_NAME=${REPO_NAME}" >> $GITHUB_ENV
          echo "ENVIRONMENT=${ENVIRONMENT}" >> $GITHUB_ENV
          echo "STACK_NAME=${STACK_NAME}" >> $GITHUB_ENV
          echo "✅ スタック名を設定: ${STACK_NAME}"
  • 後続のステップで ${{ env.~~ }} で参照可能とするため $GITHUB_ENV に格納しています。

まとめ

今回の件は私の SAM テンプレート内の AWS::Serverless::Function リソースの名称が長かったことや、スタック名の長さなどについてこれと言ってチェックしていなかったことが原因で引き起こされたそこそこレアな症状な気がします。
一応、他のリソースなども可能な範囲で小文字のケバブケースで定義しているので今回の修正によって IAM の実行ロールについても統一感が出たのはメリットと言えるかも?

参考リンク

↑ 記事内でさらっと触れた GitHub Actions からの AWS リソースの操作を行う件について日本語で読みやすかったページ:pray:

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?