AWS SAMでAPIGateway+LambdaをopenAPIで書いてデプロイしたらテストでInternal server errorになったので、解消した話

## APIGatewayとLambdaのtemplate.ymlを分割したら、Internal server errorになった

AWS SAMを使用して、template.ymlファイルを次のように分割し、APIGatewayの定義にopenAPI(swagger?)を利用することで、APIGatewayとLambdaを紐づけていました。

※　筆者は大元のtemplate.ymlにAPIGatewayの定義をしています。

フォルダ構成はざっくりこんな感じ。

```
.
├── template.yml
├── package.json
├── tsconfig.json
└── functions
    └──helloWorld
        ├──index.ts (handler)
        └──lambda-template.yml
```

以下、大元のtemplate.ymlと、Lambda定義のtemplateの中身です。

```yml:template.yml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Resources:
  # functionsディレクトリに保存したlambda-template.yml(後述)で定義したLambdaを読み込む
  HelloWorldFunction:
    Type: AWS::Serverless::Application
    Properties:
      Location: functions/helloWorld/lambda-template.yml # 適宜正しいディレクトリパスに置き換えてください

  API:
    Type: AWS::Serverless::Api
    Properties:
      Name: hello-world-api
      StageName: dev
      DefinitionBody:
        openapi: 3.0.1
        info:
          title: hello-world-api
          version: "2021-10-01"
        paths:
          /hello-world:
            get:
              x-amazon-apigateway-integration:
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:HelloWorldFunction/invocations
                httpMethod: POST
                type: aws_proxy
```

Lambdaのtemplate.yml

```yml:lambda-template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: HelloWorldFunction
      Handler: index.handler
      Runtime: nodejs18.x
```

AWSコンソールからAPIGatewayのテストを実行すると…![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620495/521e13f2-9248-5cc6-7e5a-d6f4287d98ab.png)

で、最終行を見てみると

```
Execution failed due to configuration error: Invalid permissions on Lambda function
```

## 結論(解決方法)

次のように修正

```yml:template.yml
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Application
    Properties:
      Location: functions/helloWorld/lambda-template.yml
      Parameters: # APIの論理IDをLambdaの定義に渡す
        API: !Ref API
        
  API:
    Type: AWS::Serverless::Api
    Properties:
      Name: hello-world-api
      StageName: dev
      DefinitionBody:
        openapi: 3.0.1
        info:
          title: hello-world-api
          version: "2021-10-01"
        paths:
          /hello-world:
            get:
              x-amazon-apigateway-integration:
                uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:HelloWorldFunction/invocations
                httpMethod: POST
                type: aws_proxy
```

```yml:lambda-template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Parameters: # 大元のtemplate.ymlのParametersと紐づけ
  API:
    Type: String

Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: HelloWorldFunction
      Handler: index.handler
      Runtime: nodejs18.x

  LambdaPermission: # LambdaにAPIからの呼び出しを許可する「リソースベースのポリシー」を追加
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt HelloWorldFunction.Arn
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${API}/*/GET/hello-world
```

`AWS::Lambda::Permission`については[こちら](https://qiita.com/mizuno_jin/items/60ba2e8b546d065ebb6b)を見てください。

これでデプロイ⇒APIGatewayでテストを実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620495/237adc17-3833-d6da-ac35-aa236de3b69d.png)

こんにちは！しました。

## 原因

原因はLambdaの設定の「リソースベースのポリシー」が空だったことにあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3620495/b8fda4b3-ca00-2e6e-e0fd-556fde3e6a56.png)

ここに、APIGatewayからの呼び出しを許可するポリシーをくっ付けてやる必要があるのですが、その記述がtemplate.ymlにありませんでした。

## そもそも論

APIGatewayと同じtemplate.ymlにLambdaを定義することで、わざわざ`AWS::Lambda::Permission`の記述をする必要はありません。

例えば[こちら](https://qiita.com/fkooo/items/e08cdea0f73f60dabd3d)のような感じ。

どうやら、SAMの内部的な処理で良しなにやってくれるみたいです。
[こちらの記事](https://dev.classmethod.jp/articles/sam-try-and-error/)も同じ事象みたいなので、掲載します。

てか、本記事よりもリンクの記事の方が正しく書いていただいているので、私と同じ事象になった方は是非参照されたし。

## 最後に

何か補足や間違いがあれば、随時更新しようと思います。
それ以外の感想や、「役に立った」等、何でも良いので、是非コメント頂けると嬉しいです！