のべラボ.blog

Tech Blog | AWS や サーバーレスやコンテナ などなど

AWS SAM connectors を試してみた

前回と同じく、今回も AWS SAM ネタです。

下記の AWS ブログの記事を読んだので、 AWS SAM connectors を試してみたいと思います。

aws.amazon.com

AWS SAM connectors は、AWS SAM テンプレートで指定するリソースタイプの一種で、サーバーレスアプリケーションを構成するコンポーネント間のアクセス権限設定を容易に指定することができます。

今回は、次のドキュメントの記載内容を少しアレンジして、Node.js の AWS Lambda 関数から Amazon DynamoDB のテーブルにアイテムを Put するシンプルなアプリケーションの権限を AWS SAM connectors を使って設定していきます。

docs.aws.amazon.com

前提として、この記事の内容は、2022年 10月 16日時点のものです。

東京リージョンを使用し、AWS Cloud9 を使用して SAM CLI version 1.52.0 のコマンドを発行します。

また、AWS アカウント ID は12桁すべて 0 で表記します。

ではまず、sam init を実行します。今回は Node.js 16.x をランタイムに指定します。

sam init --runtime nodejs16.x

その後、対話形式で尋ねられる項目へは、次のように応答しました。今回は AWS X-Ray のトレースは有効化していません。

Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Standalone function
        4 - Scheduled task
        5 - Data processing
        6 - Serverless API
Template: 1

Based on your selections, the only Package type available is Zip.
We will proceed to selecting the Package type as Zip.

Based on your selections, the only dependency manager available is npm.
We will proceed copying the template using npm.

Select your starter template
        1 - Hello World Example
        2 - Hello World Example TypeScript
Template: 1

Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]: 

Project name [sam-app]: sam-connectors-test   

これで、SAM のリソースを取得できました。

次に、AWS Lambda 関数のコードを書き替えます。

今回だと、sam-connectors-test/hello-world/app.js というファイルが作成されているので、それを開きます。

そして、既存のコードをすべて削除し、次のコードに置換えます。

const AWS = require("aws-sdk");
const docClient = new AWS.DynamoDB.DocumentClient();
exports.handler = async (event, context) => {
  await docClient.put({
    TableName: process.env.TABLE_NAME,
    Item: {
      id: context.awsRequestId,
      event: JSON.stringify(event) 
    }
  }).promise();
}

このコードでは、環境変数Amazon DynamoDB のテーブル名を取得して、リクエスト ID をキー属性に、イベントオブジェクトの内容をバリュー属性として Put を行っています。

では、次は SAM テンプレートを編集します。

今回だと、sam-connectors-test/template.yaml というファイルがあるので、それを開きます。

前述の AWS のドキュメントのサンプルの一部を流用、アレンジして、次のような内容にしました。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  sam-connectors-test

  Sample SAM Template for sam-connectors-test
  
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
  Function:
    Timeout: 3

Resources:
  MyTable:
    Type: AWS::Serverless::SimpleTable
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello-world/
      Handler: app.handler
      Runtime: nodejs16.x
      Architectures:
        - x86_64
      Environment:
        Variables:
          TABLE_NAME: !Ref MyTable
  MyConnector:
    Type: AWS::Serverless::Connector
    Properties:
      Source:
        Id: HelloWorldFunction
      Destination:
        Id: MyTable
      Permissions:
        - Write
Outputs:
  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

このテンプレート内の、MyConnectorAWS SAM connectors になります。

  MyConnector:
    Type: AWS::Serverless::Connector
    Properties:
      Source:
        Id: HelloWorldFunction
      Destination:
        Id: MyTable
      Permissions:
        - Write

今回だと、HelloWorldFunction 関数から MyTable テーブルへの Write 権限を許可するという指定になります。 IAMポリシーを直接作成するよりは、シンプルな書き方といえますね。

では、ビルドしてデプロイを実行します。

今回は、デプロイで --guided オプションをつけています。

cd sam-connectors-test
sam build
sam deploy --guided

--guided オプション を付けた場合にプロンプトで求められる入力の例を記載しておきます。

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: sam-connectors-test
        AWS Region [ap-northeast-1]: 
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: 
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: 
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]: 
        Save arguments to configuration file [Y/n]: 
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

デプロイが正常に完了すると、次のようなメッセージが出力されます。

Successfully created/updated stack - sam-connectors-test in ap-northeast-1

また、今回の例だと次のような IAM ロールの ARN の Output があります。

これは、AWS Lambda 関数に付与された実行ロールの ARN になります。

Key                 HelloWorldFunctionIamRole                                                   
Description         Implicit IAM Role created for Hello World function                          
Value               arn:aws:iam::000000000000:role/sam-connectors-test-HelloWorldFunctionRole-  
WB0KUJXSC9YP                                                                                    

この IAM ロールの ARN うち、 arn:aws:iam::000000000000:role/より後のロールの名前の部分をメモします。

今回の例だと、sam-connectors-test-HelloWorldFunctionRole-WB0KUJXSC9YP になります。

そして、次のようにロール名を環境変数で指定して AWS CLI を実行し、ロールにアタッチされているポリシーの内容を表示してみましょう。

ROLE_NAME=sam-connectors-test-HelloWorldFunctionRole-WB0KUJXSC9YP  
aws iam list-attached-role-policies --role-name ${ROLE_NAME} --query "AttachedPolicies[].[PolicyArn]" --output text

出力例

arn:aws:iam::000000000000:policy/sam-connectors-test-MyConnectorPolicy-1LGRZ5UMK7FFY
arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

出力結果のうち、MyConnector という文字を含んでいる ポリシーがあります。

これが、AWS SAM connectors により作成された IAM ポリシーになります。

この IAM ポリシーの ARN をメモして、次のように環境変数で指定して AWS CLI コマンドを実行します。

POLICY_ARN=arn:aws:iam::000000000000:policy/sam-connectors-test-MyConnectorPolicy-1LGRZ5UMK7FFY
VERSION_ID=`aws iam get-policy --policy-arn ${POLICY_ARN} --query "Policy.DefaultVersionId"  --output text`
aws iam get-policy-version --policy-arn  ${POLICY_ARN} --version-id ${VERSION_ID}

出力例

{
    "PolicyVersion": {
        "CreateDate": "2022-10-16T01:29:31Z", 
        "VersionId": "v1", 
        "Document": {
            "Version": "2012-10-17", 
            "Statement": [
                {
                    "Action": [
                        "dynamodb:PutItem", 
                        "dynamodb:UpdateItem", 
                        "dynamodb:DeleteItem", 
                        "dynamodb:BatchWriteItem", 
                        "dynamodb:PartiQLDelete", 
                        "dynamodb:PartiQLInsert", 
                        "dynamodb:PartiQLUpdate"
                    ], 
                    "Resource": [
                        "arn:aws:dynamodb:ap-northeast-1:000000000000:table/sam-connectors-test-MyTable-1ONWBBRN2LWXQ", 
                        "arn:aws:dynamodb:ap-northeast-1:000000000000:table/sam-connectors-test-MyTable-1ONWBBRN2LWXQ/index/*"
                    ], 
                    "Effect": "Allow"
                }
            ]
        }, 
        "IsDefaultVersion": true
    }
}

AWS SAM connectors により作成された IAM ポリシーの内容が確認できました。PutItem や UpdateItem や DeleteItem など Action として許可されていますね。

今回は、AWS Lambda 関数から、Amazon DynamoDB へのアクセスを例にしましたが、他にも次のようなパターンがサポートされているので、今後は他のパターンも試していきたいです!

docs.aws.amazon.com

/* -----codeの行番号----- */