「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を利用してください。
template.yaml
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」を返します。
app.py
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を作成して格納しておきます。
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"}