CloudFormationでAPI Gateway(REST API)のデフォルトエンドポイントを無効化する

2022.03.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いわさです。

前回の記事で、SAMの場合はDisableExecuteApiEndpointが期待した動作にならない場合があり、直接OpenAPIドキュメント内でdisableExecuteApiEndpointを指定する必要がある場合について触れました。

では、CloudFormationの場合はそもそもDisableExecuteApiEndpointプロパティは動作するのでしょうか。
こちらを確認してみました。

CloudFormationテンプレート

前回の記事で使ったSAMテンプレート(mTLS+カスタムドメインなAPI Gateway)をCloudFormationで再現すると以下のような構成になります。
ハイライト部分が該当のプロパティです。

AWSTemplateFormatVersion: '2010-09-09'
Description: ---
Parameters:
  ApiName:
    Description: API Gateway Name
    Type: String
  HostedZoneId:
    Description: Hosted Zone Id
    Type: String
  CustomDomainName:
    Description: Custom Domain Name
    Type: String
  TrustStoreS3Uri:
    Description: TrustStore S3 URI
    Type: String
    Default: s3://xxx/xxx.pem
Resources:
  Api:
    Type: AWS::ApiGateway::RestApi
    Properties: 
      Name: !Ref ApiName
      Body: 
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: ./openapi.json
      DisableExecuteApiEndpoint: true
      EndpointConfiguration: 
        Types: 
          - REGIONAL

  Deployment:
    Type: AWS::ApiGateway::Deployment
    Properties: 
      RestApiId: !Ref Api
      StageName: iwasa-stage2

  CustomDomain:
    Type: AWS::ApiGateway::DomainName
    Properties: 
      DomainName: !Ref CustomDomainName
      EndpointConfiguration: 
        Types: 
          - REGIONAL
      MutualTlsAuthentication: 
        TruststoreUri: !Ref TrustStoreS3Uri
      RegionalCertificateArn: !Ref Certificate
      SecurityPolicy: TLS_1_2

  BasePathMapping:
    Type: AWS::ApiGateway::BasePathMapping
    DependsOn: CustomDomain
    Properties:
      DomainName: !Ref CustomDomainName
      RestApiId: !Ref Api
      Stage: iwasa-stage2

  DnsWebRecord:
    Type: AWS::Route53::RecordSet
    Properties:
      Name: !Ref CustomDomainName
      Type: A
      AliasTarget:
        DNSName: !GetAtt CustomDomain.RegionalDomainName
        HostedZoneId: !GetAtt CustomDomain.RegionalHostedZoneId
      HostedZoneId: !Ref HostedZoneId

  Certificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: !Ref CustomDomainName
      DomainValidationOptions:
        - DomainName: !Ref CustomDomainName
          HostedZoneId: !Ref HostedZoneId
      ValidationMethod: DNS

それにしても、SAM比較すると随分といろいろなリソースが登場し、また依存関係が複雑ですね。
抽象化してくれるSAMの偉大さを知りました。

cfn-lintでは該当プロパティがエラーになりましたが、無視してデプロイしました。

CloudFormationではDisableExecuteApiEndpointが期待どおり動作する

CloudFormationの場合は、DisableExecuteApiEndpointで制御が出来ていますね。

注意点

上記のテンプレートはエッジ最適化ではなくリージョンのものです。
SAMだとうまくそのあたりも抽象化してくれるのですが、CloudFormationの場合だとREGIONALEDGEかはだいぶ意識して組み立てる必要があります。

また、AWS::ApiGateway::BasePathMappingはカスタムドメイン作成後に作成される必要があります。
よって上記テンプレートでは、DependsOn: CustomDomainを指定しています。

2022-03-18 16:23:01 UTC+0900 BasePathMapping CREATE_FAILED Resource handler returned message: "Invalid domain name identifier specified (Service: ApiGateway, Status Code: 404, Request ID: 809c35ff-c315-4d71-83a9-6f606e6395eb, Extended Request ID: null)" (RequestToken: ffc45dd0-bbe1-1ff2-43ba-3c53046e1e96, HandlerErrorCode: NotFound)

さいごに

CloudFormationだとリソースプロパティで期待どおり動作してくれることが確認できました。

しかし、作成するリソースが多かったり、色々意識したりすることが多いのでSAMはうまいこと抽象化してくれてるんだなというのを実感しました。
今回のDisableExecuteApiEndpointのように一部SAMで対応しきれていないケースもあるとは思うのですが、SAMでシンプルにAPIを表現できるようになるのは捨てがたい。