この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
おつかれさまです。サーバーレス開発部の新井です。
今回は、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定義からインポートするように書換えます。変化がわかるように過去の元の部分はコメントアウトして載せています。
template.yaml
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アドレスのブラックリストを設定することも可能です。
まとめ
いかがだったでしょうか。
やっていることは大したことないですが、まだ新しい機能ということもあって情報が少ないかと思いますので、どなたかの参考になれば幸いです。
また、現在サーバーレス開発部では一緒に働くメンバーを募集中です!!ご興味がある方は採用フォームからお問い合わせいただければと思います!