背景・目的
運用中の API Gateway(エッジ最適化エンドポイント)とリージョンタイプに対して、カスタムドメインを設定してみました。
API Gateway のエンドタイプごとに、証明書の発行リージョンやRoute 53設定など複数の考慮点があります。
今回は、CloudFormation を使ってエッジ最適化とリージョンエンドポイントそれぞれの挙動を確認します。
なお、以前も似たようなことを試してみます。
実践
前提
今回、下記の環境で試しています
- Route 53のホストゾーンがある
- Cursor
事前準備
-
新規にプロジェクトを作成します
% gh repo create api-gateway-migration-example --public --clone ✓ Created repository XXXX/api-gateway-migration-example on github.com https://github.com/XXXX/api-gateway-migration-example %
-
上記のプロジェクトをCursorのワークスペースに追加します
バックエンドのLambda
- Lambdaのテンプレートを作成します
AWSTemplateFormatVersion: '2010-09-09' Description: Shared Lambda (creates minimal IAM role) Resources: LambdaBasicRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: { Service: lambda.amazonaws.com } Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole SharedHelloFn: Type: AWS::Lambda::Function Properties: Runtime: python3.11 Handler: index.handler Role: !GetAtt LambdaBasicRole.Arn Code: ZipFile: | def handler(event, context): return {"statusCode": 200, "body": "Hello from Shared Lambda"} Outputs: SharedLambdaArn: Value: !GetAtt SharedHelloFn.Arn Export: Name: SharedLambdaArn
- 実行します。できました
% aws cloudformation deploy \ --template-file lambda-shared.yaml \ --stack-name shared-lambda \ --capabilities CAPABILITY_IAM Waiting for changeset to be created.. Waiting for stack create/update to complete Successfully created/updated stack - shared-lambda %
Edge最適化タイプ
まずは、Edge最適化のAPI Gatewayを作成します。下記のような構成を作成します
ACM証明書の作成
- AWSにサインインします
エッジ最適化用(us-east-1)
-
エッジ最適化のため、us-east-1リージョンに移動します
-
AWS Certificate Manager に移動します
-
「証明書をリクエスト」をクリックします
-
下記を設定し、「リクエスト」をクリックします
レコードの作成
CloudFormationの作成
Edge最適化のREST API、カスタムドメインを作成します
-
テンプレートを作成します
Parameters: HostedZoneId: Type: String DomainName: Type: String EdgeCertArnUsEast1: Type: String LambdaArn: # ★ 共有LambdaのARNを受ける Type: String RecordWeight: Type: Number Default: 100 Resources: Api: Type: AWS::ApiGateway::RestApi Properties: Name: !Sub edge-api-${DomainName} EndpointConfiguration: { Types: [EDGE] } RootGet: Type: AWS::ApiGateway::Method Properties: RestApiId: !Ref Api ResourceId: !GetAtt Api.RootResourceId HttpMethod: GET AuthorizationType: NONE Integration: Type: AWS_PROXY IntegrationHttpMethod: POST Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaArn}/invocations LambdaInvokePermissionForEdgeApi: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref LambdaArn Action: lambda:InvokeFunction Principal: apigateway.amazonaws.com SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${Api}/*/*/* Deployment: Type: AWS::ApiGateway::Deployment DependsOn: RootGet Properties: RestApiId: !Ref Api StageName: prod EdgeDomain: Type: AWS::ApiGateway::DomainName Properties: DomainName: !Ref DomainName CertificateArn: !Ref EdgeCertArnUsEast1 EndpointConfiguration: { Types: [EDGE] } BasePathMapping: Type: AWS::ApiGateway::BasePathMapping Properties: DomainName: !Ref EdgeDomain RestApiId: !Ref Api Stage: prod ApiAliasRecordEdge: Type: AWS::Route53::RecordSet Properties: HostedZoneId: !Ref HostedZoneId Name: !Ref DomainName Type: A SetIdentifier: edge Weight: !Ref RecordWeight AliasTarget: DNSName: !GetAtt EdgeDomain.DistributionDomainName HostedZoneId: !GetAtt EdgeDomain.DistributionHostedZoneId EvaluateTargetHealth: false
-
実行します。できました
% aws cloudformation deploy \ --template-file edge-template.yaml \ --stack-name edge-api-stack \ --region ap-northeast-1 \ --parameter-overrides \ HostedZoneId=$HOSTED_ZONE_ID \ DomainName=$DOMAIN_NAME \ EdgeCertArnUsEast1=$EDGE_CERT_ARN_USEAST1 Waiting for changeset to be created.. Waiting for stack create/update to complete Successfully created/updated stack - edge-api-stack
-
CloudFrontもできていました
% aws apigateway get-domain-name \ --region ap-northeast-1 \ --domain-name XXXXXX { "domainName": "XXXXXX", "domainNameArn": "arn:aws:apigateway:ap-northeast-1::/domainnames/XXXXXX", "certificateArn": "arn:aws:acm:us-east-1:XXXXXX:certificate/XXXXXX", "certificateUploadDate": "2025-08-15T22:06:19+09:00", "distributionDomainName": "XXXXXX.cloudfront.net", "distributionHostedZoneId": "XXXXXX", "endpointConfiguration": { "types": [ "EDGE" ], "ipAddressType": "ipv4" }, "domainNameStatus": "AVAILABLE", "securityPolicy": "TLS_1_2", "tags": {}, "routingMode": "BASE_PATH_MAPPING_ONLY" } %
疎通
- リクエストを送ってみます。想定通りのメッセージが返されました
% curl https://apigw.XXXXXXXXXXXXX Hello from Shared Lambda% %
リージョンタイプ
次に、リージョンタイプのAPI Gatewayを作成し、並行稼働させます。
下記のような構成を作成し、ドメインを分けてアクセスします
リージョン用(ap-northeast-1)
-
リージョン用のため、今回使用するap-northeast-1リージョンに移動します
-
AWS Certificate Manager に移動します
-
「証明書をリクエスト」をクリックします
-
下記を設定し、「リクエスト」をクリックします
-
作成後、保留中になります
レコードの作成
- 上記のACMで作成した証明書の画面で「Route 53でレコードを作成」をクリックします
- 「レコードを作成」をクリックします
- Route 53のホストゾーンに登録されました
- しばらく(5分程度)すると、ステータスが「発行済み」になりました
CloudFormationの作成
-
テンプレートを作成します
AWSTemplateFormatVersion: '2010-09-09' Description: Regional API Gateway using shared Lambda (ImportValue) Parameters: HostedZoneId: Type: String DomainName: Type: String RegionalCertArn: Type: String RecordWeight: Type: Number Default: 100 Resources: Api: Type: AWS::ApiGateway::RestApi Properties: Name: !Sub regional-api-${DomainName} EndpointConfiguration: Types: [REGIONAL] RootGet: Type: AWS::ApiGateway::Method Properties: RestApiId: !Ref Api ResourceId: !GetAtt Api.RootResourceId HttpMethod: GET AuthorizationType: NONE Integration: Type: AWS_PROXY IntegrationHttpMethod: POST Uri: !Sub - arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SharedLambdaArn}/invocations - { SharedLambdaArn: !ImportValue SharedLambdaArn } LambdaInvokePermissionForRegionalApi: Type: AWS::Lambda::Permission Properties: FunctionName: !ImportValue SharedLambdaArn Action: lambda:InvokeFunction Principal: apigateway.amazonaws.com SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${Api}/*/*/* # ← デプロイはステージ名を付けずに作る ApiDeployment: Type: AWS::ApiGateway::Deployment DependsOn: RootGet Properties: RestApiId: !Ref Api Description: Initial deployment # ← ステージを明示的に作る(prod) ApiStage: Type: AWS::ApiGateway::Stage Properties: RestApiId: !Ref Api DeploymentId: !Ref ApiDeployment StageName: prod RegionalDomain: Type: AWS::ApiGateway::DomainName Properties: DomainName: !Ref DomainName RegionalCertificateArn: !Ref RegionalCertArn EndpointConfiguration: Types: [REGIONAL] # ← ステージが完成してからマッピングを作る BasePathMapping: Type: AWS::ApiGateway::BasePathMapping DependsOn: - RegionalDomain - ApiStage Properties: DomainName: !Ref RegionalDomain RestApiId: !Ref Api Stage: prod ApiAliasRecordRegional: Type: AWS::Route53::RecordSet DependsOn: RegionalDomain Properties: HostedZoneId: !Ref HostedZoneId Name: !Ref DomainName Type: A SetIdentifier: regional Weight: !Ref RecordWeight AliasTarget: DNSName: !GetAtt RegionalDomain.RegionalDomainName HostedZoneId: !GetAtt RegionalDomain.RegionalHostedZoneId EvaluateTargetHealth: false
-
実行します。できました
% aws cloudformation deploy \ --region ap-northeast-1 \ --template-file region-template.yaml \ --stack-name regional-api-stack \ --parameter-overrides \ HostedZoneId=$HOSTED_ZONE_ID \ DomainName=$REGIONAL_DOMAIN_NAME \ RegionalCertArn=$REGIONAL_CERT_ARN_APNORTHEAST1 Waiting for changeset to be created.. Waiting for stack create/update to complete Successfully created/updated stack - regional-api-stack %
-
Route 53にAレコードが登録されました
-
リクエストを送ってみます。想定通りのメッセージが返されました(ドメインを伏せているのでわからないですね。)
% curl https://region-apigw.XXXXXXXXXXXXX Hello from Shared Lambda% %
考察
今回は、API Gatewayのエッジ最適化タイプとリージョンタイプについて、カスタムドメインを使って挙動を確認しました。証明書やDNSレコード、CloudFrontの有無などの関係性について、以前より理解が深まったように思います。
参考