CloudFrontのビューワープロトコルポリシーにRedirect HTTP to HTTPSを設定したときの動作の確認
概要
CloudFrontのドキュメントに、ビューワープロトコルポリシーに Redirect HTTP to HTTPS を設定した時の挙動が書かれています。
Amazon CloudFront デベロッパーガイド ビューワーに HTTPS を要求する
Redirect HTTP to HTTPS
ビューワーは両方のプロトコルを使用できます。HTTP GET および HEAD リクエストは自動的に HTTPS リクエストにリダイレクトされます。CloudFront は新しい HTTPS URL とともに HTTP ステータスコード 301 (Moved Permanently) を返します。ビューワーはこの HTTPS URL を使用して CloudFront にリクエストを再送信します。
このときオリジンプロトコルポリシーに Match Viewer を設定していると、ビューワーがHTTPでCloudFrontにアクセスした場合はHTTPSにリダイレクトされるので、オリジンにはHTTPSでアクセスされます。
この動作を確認しておきたかったので、環境を準備して試してみました。
環境構築用のCloudFormationテンプレート
全体
CFnテンプレート全体
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFront distribution fronting an API Gateway mock integration
Parameters:
StageName:
Type: String
Default: prod
Description: Stage name for the API Gateway deployment referenced by CloudFront.
ApiKeyValue:
Type: String
NoEcho: true
Description: API key shared only with CloudFront (used as X-Api-Key)
Resources:
ApiGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: MockApiWithCloudFront
Description: API Gateway with a mock integration used as a CloudFront origin
EndpointConfiguration:
Types:
- REGIONAL
ApiGatewayResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt ApiGatewayRestApi.RootResourceId
PathPart: mock
RestApiId: !Ref ApiGatewayRestApi
ApiGatewayMethod:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: GET
ResourceId: !Ref ApiGatewayResource
RestApiId: !Ref ApiGatewayRestApi
AuthorizationType: NONE
ApiKeyRequired: true
Integration:
Type: MOCK
RequestTemplates:
application/json: '{"statusCode": 200}'
IntegrationResponses:
- StatusCode: 200
ResponseTemplates:
application/json: '{"message": "This is a mock response"}'
MethodResponses:
- StatusCode: 200
ApiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref ApiGatewayRestApi
Description: Deployment for mock integration
DependsOn: ApiGatewayMethod
ApiGatewayStage:
Type: AWS::ApiGateway::Stage
Properties:
StageName: !Ref StageName
DeploymentId: !Ref ApiGatewayDeployment
RestApiId: !Ref ApiGatewayRestApi
# API キーと使用量プラン(CloudFrontからのみ使用)
ApiKey:
Type: AWS::ApiGateway::ApiKey
Properties:
Name: CloudFrontOnlyKey
Enabled: true
Value: !Ref ApiKeyValue
UsagePlan:
Type: AWS::ApiGateway::UsagePlan
Properties:
UsagePlanName: CloudFrontOnlyUsagePlan
ApiStages:
- ApiId: !Ref ApiGatewayRestApi
Stage: !Ref ApiGatewayStage
UsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
Properties:
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref UsagePlan
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Comment: CloudFront distribution redirecting HTTP viewers to HTTPS and matching origin protocol
DefaultCacheBehavior:
TargetOriginId: ApiGatewayOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # Managed-CachingDisabled
Origins:
- Id: ApiGatewayOrigin
DomainName: !Sub "${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com"
OriginPath: !Sub "/${StageName}"
OriginCustomHeaders:
- HeaderName: X-Api-Key
HeaderValue: !Ref ApiKeyValue
CustomOriginConfig:
OriginProtocolPolicy: match-viewer
OriginSSLProtocols:
- TLSv1.2
HTTPPort: 80
HTTPSPort: 443
PriceClass: PriceClass_200
HttpVersion: http2and3
Outputs:
CloudFrontDomainName:
Description: Domain name of the CloudFront distribution
Value: !GetAtt CloudFrontDistribution.DomainName
ApiInvokeUrl:
Description: Direct invoke URL for the API Gateway stage
Value: !Sub "https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/${StageName}/mock"
今回関係ある部分の抜粋
AWS::CloudFront::Distribution で以下を指定しています。
| プロパティ | 値 |
|---|---|
| ViewerProtocolPolicy | redirect-to-https |
| OriginProtocolPolicy | match-viewer |
また、動作確認用のオリジンとしてAPI Gatewayを設定しています。
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
Comment: CloudFront distribution redirecting HTTP viewers to HTTPS and matching origin protocol
DefaultCacheBehavior:
TargetOriginId: ApiGatewayOrigin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
CachedMethods:
- GET
- HEAD
Compress: true
CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # Managed-CachingDisabled
Origins:
- Id: ApiGatewayOrigin
DomainName: !Sub "${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com"
OriginPath: !Sub "/${StageName}"
OriginCustomHeaders:
- HeaderName: X-Api-Key
HeaderValue: !Ref ApiKeyValue
CustomOriginConfig:
OriginProtocolPolicy: match-viewer
OriginSSLProtocols:
- TLSv1.2
HTTPPort: 80
HTTPSPort: 443
PriceClass: PriceClass_200
HttpVersion: http2and3
動作確認
環境構築
API Gatewayへのアクセスを制限するために、CloudFrontでAPIキーを付与します。
付与するAPIキーを最初に作成し、 ApiKey 変数に格納しておきます。
ApiKey=$(openssl rand -hex 32)
API Gatewayのステージ名を test 、APIキーの値に上記の ApiKey の値を設定し、CloudFormationでCloudFrontとAPI Gatewayをデプロイします。
aws cloudformation create-stack --stack-name TestCloudFront --template-body file://cloudfront-apigw-mock.yaml --parameters ParameterKey=StageName,ParameterValue=test ParameterKey=ApiKeyValue,ParameterValue="${ApiKey}"
CloudFormationでのデプロイが完了すると CloudFrontDomainName にCloudFrontのFQDNが出力されるので、 CloudFront 変数にFQDNを格納します。
CloudFront=$(aws cloudformation describe-stacks --stack-name TestCloudFront --query 'Stacks[0].Outputs[?OutputKey==`CloudFrontDomainName`].OutputValue | [0]' --output text)
ビューワーからHTTPでCloudFrontにアクセスした場合
curl でプロトコルをhttpに設定してCloudFrontにアクセスした場合は、最終的なアクセス先を示す url_effective でプロトコルがhttpsになっていることが確認できました。
curl -s -w "%{http_code} %{url_effective}\n" -L http://${CloudFront}/mock
{"message": "This is a mock response"}200 https://dxclb8f0tip3a.cloudfront.net/mock
ビューワーからHTTPSでCloudFrontにアクセスした場合
curl でプロトコルをhttpsに設定してCloudFrontにアクセスした場合は、リダイレクトされることなくMatch Viewer の設定に従ってhttpsでオリジンにアクセスされています。
curl -s -w "%{http_code} %{url_effective}\n" -L https://${CloudFront}/mock
{"message": "This is a mock response"}200 https://dxclb8f0tip3a.cloudfront.net/mock
GETメソッドでの通信の流れ
今回の設定でのクライアントからオリジンまでの通信の流れをまとめると以下のようになります。
参考
Discussion