😀

SAMを使って別のAWSアカウントへLambdaをデプロイする方法

2021/12/08に公開

やりたいこと

AWSアカウントAにあるLambda関数をAWSアカウントBにも作成したい

悩ましいところ

Layerは移行すべきか
->今回はAWSアカウントAのLayerをAWSアカウントBでも使用できるようにします。

Lambda関数のIAM Roleをどうするか
->今回はAWSアカウントBにも同名のIAM Roleを作成します。

やりかた

SAMテンプレートは既にある前提で話をします。
公式ドキュメント
https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html

適当にSAMのtemplate.ymlを用意しました。
Lambdaの関数とそのLambdaに紐づくIAM Roleを作成するテンプレートです。

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  Youre description here

Parameters:
  EnvName:
    Type: String
    Default: "Development"
    AllowedValues:
      - Production
      - Development
      - Staging

Resources:
  LambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: app/
      Environment:
        Variables:
          EnvName: !Ref EnvName
      Handler: app.lambda_handler
      FunctionName: !Sub "${EnvName}-test-function"
      Layers:
        - arn:aws:lambda:ap-northeast-1:123456789:layer:your-layer-name:6
      MemorySize: 256
      Runtime: python3.8
      Role: !GetAtt LambdaIamRole.Arn
      Timeout: 60

  LambdaIamRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Description: A Role for Lambda to save file to s3
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      MaxSessionDuration: 3600
      # Path: String
      # PermissionsBoundary: String
      RoleName: !Sub "${EnvName}testrole"
      Tags:
        - Key: LambdaName
          Value: !Sub "${EnvName}-test-function"


まず、AWSアカウントAのLayerを使えるようにする必要があるので、その設定を行います。
ドンピシャな公式ドキュメントがありました。
https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-xaccountlayer

コンソールから出来ないのか疑問ですが、CLIで以下のコマンドをたたけば一発です。

aws lambda add-layer-version-permission --layer-name your-layer-name --statement-id xaccount --action lambda:GetLayerVersion  --principal 987654321 --version-number 1 --output text

次に、SAMテンプレートをAWS CLIを使ってデプロイします。
普通にやるなら、sam deploy --capabilities CAPABILITY_NAMED_IAMですね。
今回はIAM Roleを作成しているので、CAPABILITY_NAMED_IAMを指定しています。

sam deployコマンドを実行すると、AWSアカウントAにデプロイされます。

では、どうやってAWSアカウントBにデプロイするかというと、AWS CLIのProfileで別アカウントのProfileを使います。

私の場合は、スイッチロール出来るロールをAWSアカウントBに用意し、profileに設定します。
.aws/configファイルにスイッチロールするロールを記述するということです。
configファイルについての公式ドキュメント↓
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-configure-files.html

こんな感じですね。

[default]
region=ap-northeast-1
output=text

[profile accountb]
region=ap-northeast-1
role_arn=arn:aws:iam::987654321:role/accountb-admin
source_profile=default

これで、accountbのprofileを使うとLambda関数がaccountbに作成されます。

なのでデプロイ時のコマンドは以下のようになります。

sam deploy --profile accountb --capabilities CAPABILITY_NAMED_IAM

ちなみに、
AWSアカウントAを開発環境、AWSアカウントBを本番環境とするなら、EnvNameをDevelopmentやProductionと変更することで、アカウント毎に環境の違うLambdaをデプロイできます。

2021/12/22追記
SAMデプロイ時のパラメータはsamconfig.tomlファイルに保存されています。sam deploy --guidedした時にsamconfig.tomlへ設定情報を書き込む、にYesを答えれば毎回パラメータを入力しないですみます。
このsamconfig.tomlですが、複数環境(複数のAWSアカウント)を設定することもできます。
結果的に今の私のsamconfig.tomlは以下のようになっています。(バケット名などはぼかしています)。

version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "your-stack-name"
s3_bucket = "accounta-bucket-name"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
parameter_overrides = EnvName=\"Production\""

[accontb]
[accontb.deploy]
[accontb.deploy.parameters]
stack_name = "your-stack-name"
s3_bucket = "accontb-bucket-name"
region = "ap-northeast-1"
confirm_changeset = true
capabilities = "CAPABILITY_NAMED_IAM"
parameter_overrides = EnvName=\"Development\""

この設定ファイルを使って、普段はdefaultのバケット(アカウントA)へデプロイしていて、アカウントBへデプロイしたいときだけaccountbを使いたいです。
そのためのパラメータが--config-envというパラメータです。
https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

なのでデプロイ時のコマンドは以下のようになります。
capabilitiesもsamconfig.tomlに書かれているので、わざわざ書く必要がなくなりました。

sam deploy --profile accountb --config-eng accountb

注意点ですが、--profileはAWSの認証情報でどれを使うかなのでAWSのconfigファイルを見に行っています。--config-envはSAMデプロイ時にどの環境でデプロイするかなのでsamconfig.tomlを見に行っています。

2022/1/20追記
次はLambdaではなくChalice(API Gateway)のデプロイ先をアカウントA、Bで切り替えたいケースが発生しました。Chaliceの設定ではsamconfig.tomlのようなファイルはないのでどうしようと思ったのですが、単純に--config-envのオプションを外せばよいだけでした。
つまり、下のコマンドでアカウントA(デフォルト)へデプロイできます。

chalice deploy

そして下のコマンドでアカウントB(profile=devのアカウント)へデプロイできます。

sam deploy --profile accountb

以上

Discussion