AWS SAMでAPI Gatewayのリソースポリシーを設定してみた
おつかれさまです。サーバーレス開発部の新井です。
今回は、3ヶ月程前に発表されたAPI GatewayのリソースポリシーをAWS SAMから設定する方法を紹介したいと思います。API Gatewayのリソースポリシーでは、 特定のAWSアカウントのユーザーに対するアクセス制限や特定のIPアドレス範囲内でのアクセス制限を設定することことができます。S3のバケットポリシーの設定とほぼ同じと考えれば、イメージがつかみやすいかと思います。
また、前回のブログの一部でカスタムオーソライザーによるIP制限を紹介しましたが、今回紹介するAPI Gatewayのリソースポリシーを利用する方がより簡単に実装することができます。
それでは、早速始めていきたいと思います!
- 今回参考にさせて頂いたサイト
- https://dev.classmethod.jp/cloud/aws/api-gateway-resource-policy/
- https://aws.amazon.com/about-aws/whats-new/2018/04/amazon-api-gateway-supports-resource-policies/
- https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-resource-policies-create-attach.html
構成図
下準備
まずは、SAM CLIから必要なリソースを作成していきます。 使ってるバージョンは以下の通り
$ sam --version SAM CLI, version 0.4.0
例のごとく以下のコマンドを実行
sam init --runtime python3.6
作成されたフォルダの中身はこんな感じ
$ tree -L 1 . ├── hello_world ├── README.md ├── requirements.txt ├── sam-app ├── template.yaml └── tests
hello_world/app.pyでrequestsモジュールを使っているので、インストールしてあげる
pip install -r requirements.txt -t hello_world/
何も考えずデプロイ
aws s3 mb s3:// aws cloudformation package --template-file template.yaml --output-template-file output.yaml --s3-bucket aws cloudformation deploy --template-file output.yaml --stack-name --capabilities CAPABILITY_IAM
※ initで作成したtemplate.yaml
がそのままだとpathの設定がおかしいと怒られたので、CodeUriの部分をhello_world/build/→hello_worldに修正しました。
疎通が出来ることを確認
$curl -v https:///Prod/hello {"message": "hello world", "location": "xxx.xxx.xxx.xxx"}
LambdaのGIPを返してくれているみたいですね。
API Gatewayのリソースポリシーを設定
余談ですが、当初AWS SAMがこの新しい機能をサポートしているのか、そもそもCloud Formationがサポートしてるのか結構あやしい状態で、色々検索してみたのですが、いっこうにそれらしい記事やサンプルなども見つからずほぼ諦めかけていました。
初心に戻り、上記の参考サイト3を上から下までちゃんと読んでみたところ、「API Gateway リソースポリシーをアタッチする Swagger の例」にそれっぽいことが書いてあったので、試してみたらできたというオチでした。一次ソースはちゃんと読まないとダメですね。。。
それでは、本題に入ります。
template.yaml
のAPIをSwagger定義からインポートするように書換えます。変化がわかるように過去の元の部分はコメントアウトして載せています。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello_world Handler: app.lambda_handler Runtime: python3.6 Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object Variables: PARAM1: VALUE # Events: # HelloWorld: # Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api # Properties: # Path: /hello # Method: get HelloWorldLambdaPermission: Type: "AWS::Lambda::Permission" Properties: Action: lambda:InvokeFunction FunctionName: !Ref HelloWorldFunction Principal: apigateway.amazonaws.com HelloWorldApi: Type: AWS::Serverless::Api Properties: StageName: Prod DefinitionBody: swagger: "2.0" info: title: sam-apig-resource-policy-api schemes: - https paths: /hello: get: summary: "hello api" description: "hello api" produces: - "application/json" x-amazon-apigateway-integration: responses: default: statusCode: "200" uri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorldFunction.Arn}/invocations passthroughBehavior: "when_no_match" httpMethod: "POST" contentHandling: "CONVERT_TO_TEXT" type: "aws_proxy" x-amazon-apigateway-policy: Version: "2012-10-17" Statement: - Effect: Allow Principal: "*" Action: execute-api:Invoke Resource: - "execute-api:/*" Condition: IpAddress: aws:SourceIp: - "xxx.xxx.xxx.xxx/32" Outputs: # HelloWorldApi: # Description: "API Gateway endpoint URL for Prod stage for Hello World function" # Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/" HelloWorldFunction: Description: "Hello World Lambda Function ARN" Value: !GetAtt HelloWorldFunction.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn
API Gatewayのポリシードキュメントを設定している箇所は、x-amazon-apigateway-policyになりますが、この記述をDefinitionBodyのSwagger内に書く必要がある関係で、他の部分を修正、追加したりと多少面倒でした。
再度デプロイを行い、今度はIP制限により疎通ができなくなっていることを確認する。
$curl -v https:/// {"Message":"User: anonymous is not authorized to perform: execute-api:Invoke on resource: arn:aws:execute-api:ap-northeast-1::/Prod/GET/hello"}
ちゃんと設定されていますね。
SourceIpの部分に許可したいIPアドレスを入力すれば、ホワイトリスが設定できます。さらに、EffectをDenyにしたり、CondtionをNotIpAddressにするなどして、IPアドレスのブラックリストを設定することも可能です。
まとめ
いかがだったでしょうか。
やっていることは大したことないですが、まだ新しい機能ということもあって情報が少ないかと思いますので、どなたかの参考になれば幸いです。
また、現在サーバーレス開発部では一緒に働くメンバーを募集中です!!ご興味がある方は採用フォームからお問い合わせいただければと思います!