api gateway + samでapiの環境を作る(ip制限)

やったこと
- ip制限(sam)
- api keyの設定(sam)
- route53でドメインの設定
- api gatewayでlambdaとドメインを紐づける

今回紹介する項目
- ip制限(sam)

#前提
AWS::Serverless::Functionでlambdaを作成済みであること。
参考：https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-resource-function.html

作成したlambdaにip制限の設定を行なっていきます。

#ip制限(sam)
samで以下のコードでlambdaを作成しているものとします。

```template.yml
ApiLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: ApiLambdaFunction
      VpcConfig: 略
      CodeUri: ./
      Handler: lambda.handler
      Runtime: nodejs12.x
      Events:
        AnyPath:
          Type: Api 
          Properties:
            Path: /{proxy+}
            Method: ANY
```

次に以下のドキュメントを参考にip制限の設定をしていきます。
https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-property-function-apifunctionauth.html

AWS::Serverless::Apiをsamで書いていないので、これは自動で作成されています。
このままだとRestApiIdを指定することができないので、samにかいてidを指定できるようにします。

以下のsamを追記します。

```
ApiGatewayRestApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
```

次にIpRangeWhitelistの設定をしていきます。

```template.yml
ApiLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: ApiLambdaFunction
      VpcConfig: 略
      CodeUri: ./
      Handler: lambda.handler
      Runtime: nodejs12.x
      Events:
        AnyPath:
          Type: Api 
          Properties:
            Path: /{proxy+}
            Method: ANY
            RestApiId: !Ref ApiGatewayRestApi
            Auth:
              ResourcePolicy:
                IpRangeWhitelist:
                   - ip1
                   - ip2

```

IpRangeWhitelist を追加しました。
これでipのホワイトリストができました。

ただし、注意点があります。
ipを設定するときに環境ごとに変えたい場合があると思います。

以下のようにParameters、Mappingsに環境ごとのipの設定を入れたとします。

```
Parameters:
  Env:
    Type: String
    AllowedValues:
      - develop
      - prod
Mappings:
  Config:
    develop:
      allowIps:
        - ip1
        - ip2
    prod:
      allowIps:
        - ip3
        - ip4
```

その場合、IpRangeWhitelistは以下のようになります。

```
IpRangeWhitelist: !FindInMap [ Config, !Ref Env, allowIps ]
```

しかし、これは機能しませんでした。
なぜか、Mappingでの指定ができなかったので、CustomStatementsで直接指定しました。

```template.yml
Parameters:
  Env:
    Type: String
    AllowedValues:
      - develop
      - prod
Mappings:
  Config:
    develop:
      allowIps:
        - ip1
        - ip2
    prod:
      allowIps:
        - ip3
        - ip4
ApiLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: ApiLambdaFunction
      VpcConfig: 略
      CodeUri: ./
      Handler: lambda.handler
      Runtime: nodejs12.x
      Events:
        AnyPath:
          Type: Api 
          Properties:
            Path: /{proxy+}
            Method: ANY
            RestApiId: !Ref ApiGatewayRestApi
            Auth:
              ResourcePolicy:
                IpRangeWhitelist: !FindInMap [ Config, !Ref Env, allowIps ]
                CustomStatements: [
                  {
                    "Effect": "Allow",
                    "Principal": "*",
                    "Action": "execute-api:Invoke",
                    "Resource": "execute-api:/Prod/*/*"
                  },
                  {
                    "Effect": "Deny",
                    "Principal": "*",
                    "Action": "execute-api:Invoke",
                    "Resource": "execute-api:/Prod/*/*",
                    "Condition": {
                      "NotIpAddress": {
                        "aws:SourceIp": !FindInMap [ Config, !Ref Env, allowIps ]
                      }
                    }
                  }
                ]
```

これでip制限の設定の完了です。
sam deploy後に api gatewayで確認することができます。

#ipの変更
既にdeployした場合、ipを変更するときに注意点があります。
ipリストを変更してsam deployすると変更は反映されますが、実際の挙動には反映されません。

api gatewayのコンソールにてdeployし直す必要があります。
これはResourcePolicyを変更する際の仕様のようです。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-resource-policies-create-attach.html