CloudFrontのオリジンにAPI Gatewayを設定して、CloudFront経由でAPI Gatewayにアクセスしてみる
「Webアプリ」と「Webアプリが使うAPI」を作成しているとき、同一オリジンにしたいことがあります。
- Webアプリ: example.com
- Webアプリが使うAPI: example.com/v1/hello
というわけで、試してみました。
おすすめの方
- CloudFront DistributionをCloudFormationで作成したい方
- CloudFront DistributionのオリジンにAPI Gatewayを設定したい方
APIを作成する
sam init
sam init \ --runtime python3.11 \ --name api-gateway-cloudfront-sample \ --app-template hello-world \ --no-tracing \ --no-application-insights \ --structured-logging \ --package-type Zip
AWS SAMテンプレート
CloudFrontに対して、「S3バケット」と「API Gateway」のオリジンを設定しています。 CloudFrontの各種設定は、必要に応じて変更してください。
今回はシンプルな方法です。Pathをさらにカスタマイズしたい場合は、CloudFront Funstionsを利用してください。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: api-gateway-cloudfront-sample Resources: MyApi: Type: AWS::Serverless::Api Properties: StageName: v1 OpenApiVersion: 3.0.1 HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.11 Timeout: 5 Architectures: - x86_64 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get RestApiId: !Ref MyApi HelloWorldFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${HelloWorldFunction} SampleBucket: Type: AWS::S3::Bucket Properties: BucketName: !Sub api-gateway-sample-${AWS::AccountId}-${AWS::Region} PublicAccessBlockConfiguration: BlockPublicAcls: true BlockPublicPolicy: true IgnorePublicAcls: true RestrictPublicBuckets: true SampleBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref SampleBucket PolicyDocument: Id: SampleBucket-BucketPolicy Statement: - Effect: Allow Action: - s3:GetObject Resource: - !Sub arn:aws:s3:::${SampleBucket}/* Principal: CanonicalUser: !GetAtt SampleBucketCloudFrontOriginAccessIdentity.S3CanonicalUserId SampleBucketCloudFrontOriginAccessIdentity: Type: AWS::CloudFront::CloudFrontOriginAccessIdentity Properties: CloudFrontOriginAccessIdentityConfig: Comment: !Sub Allows CloudFront to reach the ${SampleBucket} SampleDistribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: Enabled: true DefaultRootObject: index.html CustomErrorResponses: - ErrorCachingMinTTL: 300 ErrorCode: 403 ResponseCode: 200 ResponsePagePath: /index.html - ErrorCachingMinTTL: 300 ErrorCode: 404 ResponseCode: 200 ResponsePagePath: /index.html Origins: - Id: !Sub S3-${SampleBucket} DomainName: !GetAtt SampleBucket.RegionalDomainName S3OriginConfig: OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${SampleBucketCloudFrontOriginAccessIdentity} - Id: !Sub API-Gateway-${MyApi} DomainName: !Sub ${MyApi}.execute-api.${AWS::Region}.amazonaws.com CustomOriginConfig: OriginProtocolPolicy: https-only DefaultCacheBehavior: TargetOriginId: !Sub S3-${SampleBucket} AllowedMethods: - GET - HEAD ViewerProtocolPolicy: redirect-to-https # CachingDisabled # https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad CacheBehaviors: - PathPattern: 'v1/*' TargetOriginId: !Sub API-Gateway-${MyApi} AllowedMethods: - GET - HEAD - OPTIONS - PUT - PATCH - POST - DELETE CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad ViewerProtocolPolicy: redirect-to-https HttpVersion: http2 Outputs: HelloWorldApi: Value: !Sub "https://${MyApi}.execute-api.${AWS::Region}.amazonaws.com/v1/hello/"
Lambdaコード
「User-Agent」を返します。
import json def lambda_handler(event, context): return { "statusCode": 200, "body": json.dumps( { "message": "hello world", "userAgent": event["headers"]["User-Agent"], } ), }
デプロイ
sam build sam deploy \ --guided \ --region ap-northeast-1 \ --stack-name api-gateway-cloudfront-sample-stack
動作を確認する
事前準備:S3バケットに適当なindex.htmlを格納する
S3バケットに対するアクセスも確認したいので、適当なindex.htmlを作成して格納しておきます。
this is test file.
まずは、API Gatewayに直接アクセスする
アクセスできました。userAgentはcurlになっています。
$ curl https://xxx.execute-api.ap-northeast-1.amazonaws.com/v1/hello {"message": "hello world", "userAgent": "curl/8.1.2"}
CloudFrontにアクセスする
さきほど格納したindex.htmlが返ってきました。
$ curl https://zzz.cloudfront.net this is test file.
CloudFront経由でAPI Gatewayにアクセスする
アクセスできました。userAgentが「Amazon CloudFront」になっています。
$ curl https://zzz.cloudfront.net/v1/hello {"message": "hello world", "userAgent": "Amazon CloudFront"}