Serverless Application Repositoryで他のAWSアカウントにもアプリを公開しよう

##🔶 はじめに
本内容は、以下の続きです。
[Lambda関数をアプリ化して、Serverless Application Repositoryで公開しよう [15分で完成編]](https://qiita.com/tamura_CD/items/bae4f0252f244f235032)

Serverless Application Repositoryにサーバレスアプリを登録することで、アカウント内でアプリを利用しやすくする事ができたので、今回は他のアカウントでもアプリを使えるようにしたいと思います。

##🔶 作業手順
1. SAMファイルの、IAMの記述の修正
1. Serverless Application Repositoryに、SAMファイルを再登録
1. アプリを利用させたいAWSアカウントの登録

##🔶 SAMファイルの、IAMの記述の修正

**1. SAMファイルの確認**

修正前のSAMファイルは以下の通りです。
`sampleHello`というLambda関数の設定情報のみが記載されています。

```yaml:sample_Hello.yaml（修正前）
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Serverless Specification template describing your function.
Resources:
  sampleHello:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: s3://sample-hello-bucket/sample_Hello-cba9fc2c-bd5b-407c-81fa-cc8d832858ad.zip
      Description: ''
      MemorySize: 128
      Timeout: 3
      Role: 'arn:aws:iam::■■■■■■:role/service-role/sample_Hello-role-k6eww01p'
```
この設定で問題になるのが、`Role: 'arn:aws:iam::■■■■■■:role/service-role/sample_Hello-role-k6eww01p'`の記述です。
このLambda関数は`sample_Hello-role-k6eww01p`というロールを使う旨が記載されていますが、**このロールは自分のAWSアカウントにはありますが、他のAWSアカウントには無いので、このSAMファイルに従ってデプロイを行うと、この部分でエラーが発生します。**

そこで、`sample_Hello-role-k6eww01p`というロールがどういう内容のものか明記して、他のAWSアカウントでデプロイする際に、ロールも一緒に構築するようにします。

**2. ロールのポリシーの確認**

`sample_Hello-role-k6eww01p`というロールに、どのようなポリシーが付加されているか確認します。

すると、「AWSLambdaBasicExecutionRole-10eb65・・・・」というポリシーが付加されています。
<img width="1159" alt="001.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/9889ef06-92fb-39a6-2ee6-d3c4c304bcdd.png">

これはAWSでデフォルトで用意されているポリシーをコピーして作ったものなので、実質は以下の「AWSLambdaBasicExecutionRole」と同じです。
よって、「AWSLambdaBasicExecutionRole」のポリシーARNをコピーします。
<img width="1154" alt="002.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/54495abc-0ab7-1e84-d814-0d1d4f2cb8f6.png">


**3. SAMファイルにロールの定義を追加**
SAMファイルに、「AWSLambdaBasicExecutionRole」というポリシーを持った、「tsuikaRole」というロールの定義を追記します。

```yaml:sample_Hello.yaml（ロールの定義を追記）
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Serverless Specification template describing your function.
Resources:
# ↓のRole定義を追加
  tsuikaRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          -
            Effect: "Allow"
            Principal:
              Service:
                - "lambda.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
#     Policies: 
#       - 
#         PolicyName: "tsuikaPolicy"
#         PolicyDocument: 
#           Version: "2012-10-17"
#           Statement: 
#             - 
#               Effect: Allow
#               Action: 
#                 - "logs:CreateLogGroup"
#                 - "logs:CreateLogStream"
#                 - "logs:PutLogEvents"
#               Resource: "*"
  sampleHello:
    Type: 'AWS::Serverless::Function'
    Properties:
      Handler: index.handler
      Runtime: nodejs8.10
      CodeUri: s3://sample-hello-bucket/sample_Hello-cba9fc2c-bd5b-407c-81fa-cc8d832858ad.zip
      Description: ''
      MemorySize: 128
      Timeout: 3
#     Role: 'arn:aws:iam::028784405484:role/service-role/sample_Hello-role-k6eww01p'
      Role: !GetAtt tsuikaRole.Arn
```
上記の`tsuikaRole`のブロックが、ロールの定義情報です。
ポリシーの定義情報は、本来はコメントアウトしている`Policies`のように書いたりしますが、今回はAWSが管理している標準のポリシーを使うので、`ManagedPolicyArns`として、先程コピーしたポリシーARNをセットするだけで良いです。

また、`sampleHello`も使用するロールが、今回定義する`tsuikaRole`に変更になるので、`!GetAtt tsuikaRole.Arn`と記載します。
`Fn::GetAtt`は、「このテンプレート内の指定した値（今回は`tsuikaRole`）の属性値を参照する」という記述です。

##🔶 Serverless Application Repositoryに、SAMファイルを再登録
**1. SAMファイルの再登録**
Serverless Application Repositoryの、登録したサーバレスアプリの画面を開き、［新しいバーションを発行］をクリックする。
<img width="1210" alt="003.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/d6ca0ba4-b7d0-2ca6-607a-345ebcb23e15.png">
「セマンティックバージョン」に、新しいバージョンNoを、「SAMテンプレート」に修正したSAMファイルをセットして、［公開バージョン］をクリックします。
<img width="1208" alt="004.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/6d918c16-c25a-55ac-38f3-379d0ce59683.png">
SAMファイルに問題が無ければ、新しいバージョンとして登録されます。

##🔶 アプリを利用させたいAWSアカウントの登録
**1. AWSアカウント番号の登録**
新しいバージョンとして登録できたら、［Add］をクリックします。
<img width="1208" alt="005.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/efcf38a5-d378-04c3-425b-a03e25f1bdd8.png">
アプリを利用させたいAWSアカウント番号をセットして、［Save］をクリックします。
<img width="1210" alt="006.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/0a63331f-d221-a70b-aaff-9e1e59ced23e.png">
問題が無ければ、以下のように登録されます。
<img width="1210" alt="007.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/10d49ab8-397a-f87d-55a2-428fcd22a641.png">

##🔶 動作確認
対象のAWSアカウントで、Serverless Application Repositoryの、Private applicationsを検索します。
今回、IAMの登録もあるので、「Show apps that・・・」のチェックを入れる必要があります。
登録したアプリが見つかれば、デプロイを試してみてください。
<img width="1213" alt="008.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38099/e61e3042-f7a1-7944-16e2-41ab66214164.png">

##🔶 まとめ
以上の手順で、自作のサーバレスアプリを、他のAWSアカウントでも使えるようになります。

やはり難しいポイントはSAMファイルの設定で、慣れないとSAMファイルの登録時や、アプリのデプロイ時にエラーが頻発するので、根気よく頑張ってください。

便利なLambda関数を是非みんなに公開して、生産性をアップしていきましょう。

##🔶 参考
- [AWS CLI で IAM Role を作りつつ、「Assume」や「Principal」について考える
](https://qiita.com/knaka/items/69724ee0b5aaf6108a55)
- [テンプレートリファレンス　Fn::GetAtt](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-getatt.html)