AWS SAM Pipelineで、二つのアカウントを横断してデプロイ

# はじめに
「テストのアカウントで一度デプロイしてから、本番アカウントにデプロイ」というCI/CDパイプラインの構築を、SAM Pipelineのテンプレートでやってみましたので記事にしました。

# 参考

https://aws.amazon.com/jp/builders-flash/202110/new-lambda-container-development-6/?awsf.filter-name=*all

# イメージ図
1. CodeCommitにPUSH
1. それをトリガーに、パイプラインが実行
    1. Test側アカウントでCodeBuildによってデプロイ等が実行
        1. AWS SAMによってLambdaを生成
    1. Test側アカウントのデプロイが成功すれば、Prod側アカウントにもデプロイ

大まか以下のような構成と思われます（厳密には違うかもしれません）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/9e4b2390-3ccf-9120-a7aa-4f1e49b416a3.png)

# やったこと

## 環境
両アカウントでCloud9を使いました。最安価インスタンスで大丈夫なはずです。

## 事前準備
各種ファイルをCodeCommitにPUSHまでしておきます。以前の記事の以下のところまでになります。

https://qiita.com/a_b_/items/a0db6047c964fdc00f24#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E4%BD%9C%E6%88%90push

## リソース作成

### Test側アカウントでのリソース作成

まずはTest側アカウントで、SAM Pipelineの機能で必要なリソースを作成します。

```bash:Test側アカウントのCloud9上コンソール
sam pipeline bootstrap
```

新規作成なので、設定する値はほぼ未指定としています。
```:Test側アカウントのCloud9上コンソール
[1] Stage definition
Enter a name for this stage. This will be referenced later when you use the sam pipeline init command:
Stage name: teststage

[2] Account details
The following AWS credential sources are available to use:
To know more about configuration AWS credentials, visit the link below:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html                
        1 - Environment variables (not available)
        2 - default (named profile)
        q - Quit and configure AWS credentials
Select a credential source to associate with this stage: 2

Enter the region in which you want these resources to be created [ap-northeast-1]: 
Enter the pipeline IAM user ARN if you have previously created one, or we will create one for you []: 

[3] Reference application build resources
Enter the pipeline execution role ARN if you have previously created one, or we will create one for you []: 
Enter the CloudFormation execution role ARN if you have previously created one, or we will create one for you []: 
Please enter the artifact bucket ARN for your Lambda function. If you do not have a bucket, we will create one for you []: 
Does your application contain any IMAGE type Lambda functions? [y/N]: N

[4] Summary
Below is the summary of the answers:
        1 - Account: 123456789012
        2 - Stage name: teststage
        3 - Region: ap-northeast-1
        4 - Pipeline user: [to be created]
        5 - Pipeline execution role: [to be created]
        6 - CloudFormation execution role: [to be created]
        7 - Artifacts bucket: [to be created]
        8 - ECR image repository: [skipped]
Press enter to confirm the values above, or select an item to edit the value: 

This will create the following required resources for the 'teststage' environment: 
        - Pipeline IAM user
        - Pipeline execution role
        - CloudFormation execution role
        - Artifact bucket
Should we proceed with the creation? [y/N]: y
```
作成後、`.aws-sam/pipeline/pipelineconfig.toml`を開いて、`pipeline_user`を控えておきます。
このユーザで、Prod側アカウント上のデプロイを行うため、Prod側アカウント側のリソース作成の際に指定するのに使います。
```toml:.aws-sam/pipeline/pipelineconfig.toml
version = 0.1
[default]
[default.pipeline_bootstrap]
[default.pipeline_bootstrap.parameters]
pipeline_user = "arn:aws:iam::123456789012:user/aws-sam-cli-managed-teststage-pipelin-PipelineUser-XXXXXXXXXXXXX"

[teststage]
[teststage.pipeline_bootstrap]
[teststage.pipeline_bootstrap.parameters]
pipeline_execution_role = "arn:aws:iam::123456789012:role/aws-sam-cli-managed-teststag-PipelineExecutionRole-XXXXXXXXXXXXX"
cloudformation_execution_role = "arn:aws:iam::123456789012:role/aws-sam-cli-managed-tests-CloudFormationExecutionR-XXXXXXXXXXXXX"
artifacts_bucket = "aws-sam-cli-managed-teststage-pip-artifactsbucket-xxxxxxxxxxxxx"
image_repository = ""
region = "ap-northeast-1"
```

### Prod側アカウントのリソース作成
次にProd側アカウントの操作です。
リソースを作るためだけに、Cloud9を作って以下のコマンドを実行します。
```bash:Prod側アカウントのCloud9上コンソール
sam pipeline bootstrap
```

こちらも新規作成なので、設定する値はほぼ未指定ですが、ユーザはTest側アカウントで作成されたユーザのArnを指定します。
```:Prod側アカウントのCloud9上コンソール
[1] Stage definition
Enter a name for this stage. This will be referenced later when you use the sam pipeline init command:
Stage name: prodstage

[2] Account details
The following AWS credential sources are available to use:
To know more about configuration AWS credentials, visit the link below:
https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html                
        1 - Environment variables (not available)
        2 - default (named profile)
        q - Quit and configure AWS credentials
Select a credential source to associate with this stage: 2

Enter the region in which you want these resources to be created [ap-northeast-1]: 
Enter the pipeline IAM user ARN if you have previously created one, or we will create one for you []: arn:aws:iam::123456789012:user/aws-sam-cli-managed-teststage-pipelin-PipelineUser-XXXXXXXXXXXXX

[3] Reference application build resources
Enter the pipeline execution role ARN if you have previously created one, or we will create one for you []: 
Enter the CloudFormation execution role ARN if you have previously created one, or we will create one for you []: 
Please enter the artifact bucket ARN for your Lambda function. If you do not have a bucket, we will create one for you []: 
Does your application contain any IMAGE type Lambda functions? [y/N]: N

[4] Summary
Below is the summary of the answers:
        1 - Account: 222222222222
        2 - Stage name: prodstage
        3 - Region: ap-northeast-1
        4 - Pipeline user ARN: arn:aws:iam::123456789012:user/aws-sam-cli-managed-teststage-pipelin-PipelineUser-XXXXXXXXXXXXX
        5 - Pipeline execution role: [to be created]
        6 - CloudFormation execution role: [to be created]
        7 - Artifacts bucket: [to be created]
        8 - ECR image repository: [skipped]
Press enter to confirm the values above, or select an item to edit the value: 

This will create the following required resources for the 'prodstage' environment: 
        - Pipeline execution role
        - CloudFormation execution role
        - Artifact bucket
Should we proceed with the creation? [y/N]: 
```
Prod側アカウントで`.aws-sam/pipeline/pipelineconfig.toml`が作成されます。これをTest側アカウントで使いますので、ファイルをダウンロードしておきます。
```toml:.aws-sam/pipeline/pipelineconfig.toml
version = 0.1
[default]
[default.pipeline_bootstrap]
[default.pipeline_bootstrap.parameters]
pipeline_user = "arn:aws:iam::123456789012:user/aws-sam-cli-managed-teststage-pipelin-PipelineUser-XXXXXXXXXXXXX"

[prodstage]
[prodstage.pipeline_bootstrap]
[prodstage.pipeline_bootstrap.parameters]
pipeline_execution_role = "arn:aws:iam::222222222222:role/aws-sam-cli-managed-prodstag-PipelineExecutionRole-XXXXXXXXXXXXX"
cloudformation_execution_role = "arn:aws:iam::222222222222:role/aws-sam-cli-managed-prods-CloudFormationExecutionR-XXXXXXXXXXXXX"
artifacts_bucket = "aws-sam-cli-managed-prodstage-pip-artifactsbucket-xxxxxxxxxxxxx"
image_repository = ""
region = "ap-northeast-1"
```
CloudFormationで対象のスタックを確認しリソースが作られていることを確認したら、以降はCloud9は不要なので削除しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/bdd29de6-6ee6-841a-b3b0-5a0dce47567f.png)


### 設定値のマージ
Test側アカウントに戻り、`.aws-sam/pipeline/pipelineconfig.toml`に、Prod側アカウントの設定をマージします。

```toml:.aws-sam/pipeline/pipelineconfig.toml (Test側アカウント)
version = 0.1
[default]
[default.pipeline_bootstrap]
[default.pipeline_bootstrap.parameters]
pipeline_user = "arn:aws:iam::123456789012:user/aws-sam-cli-managed-teststage-pipelin-PipelineUser-XXXXXXXXXXXXX"

[teststage]
[teststage.pipeline_bootstrap]
[teststage.pipeline_bootstrap.parameters]
pipeline_execution_role = "arn:aws:iam::123456789012:role/aws-sam-cli-managed-teststag-PipelineExecutionRole-XXXXXXXXXXXXX"
cloudformation_execution_role = "arn:aws:iam::123456789012:role/aws-sam-cli-managed-tests-CloudFormationExecutionR-XXXXXXXXXXXXX"
artifacts_bucket = "aws-sam-cli-managed-teststage-pip-artifactsbucket-xxxxxxxxxxxxx"
image_repository = ""
region = "ap-northeast-1"

[prodstage]
[prodstage.pipeline_bootstrap]
[prodstage.pipeline_bootstrap.parameters]
pipeline_execution_role = "arn:aws:iam::222222222222:role/aws-sam-cli-managed-prodstag-PipelineExecutionRole-XXXXXXXXXXXXX"
cloudformation_execution_role = "arn:aws:iam::222222222222:role/aws-sam-cli-managed-prods-CloudFormationExecutionR-XXXXXXXXXXXXX"
artifacts_bucket = "aws-sam-cli-managed-prodstage-pip-artifactsbucket-xxxxxxxxxxxxx"
image_repository = ""
region = "ap-northeast-1"
```
## テンプレート作成（Test側アカウント）

マージ後、テンプレートを作成します。

```bash
sam pipeline init
```

```
Select a pipeline structure template to get started:
Select template
        1 - AWS Quick Start Pipeline Templates
        2 - Custom Pipeline Template Location
Choice: 1

Cloning from https://github.com/aws/aws-sam-cli-pipeline-init-templates.git
CI/CD system
        1 - Jenkins
        2 - GitLab CI/CD
        3 - GitHub Actions
        4 - Bitbucket Pipelines
        5 - AWS CodePipeline
Choice: 5
You are using the 2-stage pipeline template.
 _________    _________ 
|         |  |         |
| Stage 1 |->| Stage 2 |
|_________|  |_________|

Checking for existing stages...

What is the Git provider?
        1 - Bitbucket
        2 - CodeCommit
        3 - GitHub
        4 - GitHubEnterpriseServer
Choice []: 2
What is the CodeCommit repository name?: simple-lambda-2022913
What is the Git branch used for production deployments? [main]: 
What is the template file path? [template.yaml]: 
We use the stage configuration name to automatically retrieve the bootstrapped resources created when you ran `sam pipeline bootstrap`.
```

各ステージで使う設定を指定します
```
Here are the stage names detected in .aws-sam/pipeline/pipelineconfig.toml:
        1 - teststage
        2 - prodstage
Select an index or enter the stage 1's configuration name (as provided during the bootstrapping): 1
What is the sam application stack name for stage 1? [sam-app]: sam-teststage

Here are the stage names detected in .aws-sam/pipeline/pipelineconfig.toml:
        1 - teststage
        2 - prodstage
Select an index or enter the stage 2's configuration name (as provided during the bootstrapping): 2
What is the sam application stack name for stage 2? [sam-app]: sam-prodstage
```

テンプレートが作成されました。以下の修正を行います。

- Lambda用のIAMロールを作成するので、`sam deploy`の箇所に、`--capabilities CAPABILITY_NAMED_IAM`を設定
    - 今回は2ステージモデルなので、`pipeline/buildspec_deploy.yml`を修正
- パイプライン作成の際の、IAMロール依存関係を明記

修正の詳細は、以前の記事を参考にしてください。

https://qiita.com/a_b_/items/a0db6047c964fdc00f24#%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E7%94%9F%E6%88%90

## デプロイ
以前の記事と同様に作成すればOKです。

https://qiita.com/a_b_/items/a0db6047c964fdc00f24#%E7%92%B0%E5%A2%83%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4

前回と異なり、2ステージモデルなので、Featureブランチの設定は空になることを確認ください。
```
        Parameter FeatureGitBranch []: 
```

以前と同様、パイプライン作成は出来ていても、実行には失敗しています。PUSHして、両アカウントでLambdaが作成されることを確認します。

```bash
git add .
git commit -m "feat: add pipeline."
git push
```
DeployProdまで成功しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/01fa5f6e-84b2-f76e-681a-20457c519209.png)

Pord側アカウントで、スタックが作成されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/3392f99b-1da4-bc1f-d400-0704f3737c4f.png)

# 片づけ
前回と同様、スタックを作成の逆順で削除していきます。

https://qiita.com/a_b_/items/a0db6047c964fdc00f24#%E7%89%87%E3%81%A5%E3%81%91

今回は2ステージモデルで2アカウントにまたがっているので、消し残しが無いように気を付けてください。

# おわりに
アカウントを「テスト/本番」で分けるのはよくあることかと思います。
その際にはAWS SAM Pipelineを使うことで、アカウントを横断するCI/CDパイプラインが非常に簡単に作成できます。

そのような環境が必要になった際は積極的に使っていきたいと感じる、便利な機能でした。