使用无服务器的 WebSockets API 的自定义域名

Custom Domain Name for WebSockets API with Serverless

我正在为一个无服务器应用程序管理 REST API,并希望在同一区域使用 WebSockets API 扩展此设置。一切都应该使用相同的证书处理,但子域不同。

起初我用 sls create_domain --stage=... 创建了一个新的自定义域。 然后我尝试将它添加到新的 WebSockets 堆栈,但以这个错误结束:

Error: Failed to find CloudFormation resources for ...

我在 Github 上发现 CloudFormation 现在似乎不支持它,因此 Serverless 不支持它。

所以我尝试在 UI:

中手动将我的舞台附加到自定义域名

Mixing of REST APIs and HTTP APIs on the same domain name can only be accomplished through API Gateway's V2 DomainName interface. Currently, WebSocket APIs can only be attached to a domain name with other WebSocket APIs. This must also occur through API Gateway's V2 DomainName interface.

更多的混乱出现了,因为在这种情况下它甚至不是同一个域名。新域名为 sockets.<DOMAIN>.com,现有域名为 api.<DOMAIN>.com。或者不同的子域是否属于 'same domain name'?

尽管如此,我还是尝试通过 apigatewayv2 CLI 再次创建自定义域:

aws apigatewayv2 create-domain-name --domain-name <DOMAIN> --domain-name-configurations file://domain-configuration.json --region eu-west-1

域-configuration.json:

[
{
    "ApiGatewayDomainName": "<DOMAIN>",
    "CertificateArn": "arn:aws:acm:us-east-1:<ACCOUNT_ID>:certificate/<CERT_ID>",
    "CertificateName": "<DOMAIN>",
    "DomainNameStatus": "AVAILABLE",
    "EndpointType": "EDGE",
    "SecurityPolicy": "TLS_1_2"
}

]

但这会导致以下错误:

An error occurred (BadRequestException) when calling the CreateDomainName operation: Invalid certificate ARN: arn:aws:acm:us-east-1:924441585974:certificate/b88f0a3f-1393-4a16-a876-9830852b5207. Certificate must be in 'eu-west-1'.

我目前的状态是 API 网关只允许自定义证书位于 us-east-1,所以这个错误让我更加困惑。

总结:我完全不知道如何将自定义域名附加到我的 WebSocket API 阶段。我很高兴每一个正确方向的提示!

找到了具有自定义 CloudFormation 资源模板的解决方案:

resources:
  Resources:
    WebSocketDomainName:
      Type: AWS::ApiGatewayV2::DomainName
      Properties:
        DomainName: <domain-name>
        DomainNameConfigurations:
          - EndpointType: 'REGIONAL'
            CertificateArn: <cert-arn>
    WebSocketMapping:
      Type: AWS::ApiGatewayV2::ApiMapping
      Properties:
        ApiId: <api-id>
        DomainName: !Ref WebSocketDomainName
        Stage: <stage-name>
    DNSRecord:
      Type: AWS::Route53::RecordSet
      Properties:
        HostedZoneName: <hosted-zone-name>.
        TTL: '900'
        ResourceRecords:
          - !GetAtt [ WebSocketDomainName, RegionalDomainName ]
        Name: <domain-name>
        Type: CNAME

编辑:现在正在使用 serverless-domain-manager

custom:
  customDomain:
    rest:
      domainName: rest.serverless.foo.com
      stage: ci
      basePath: api
      certificateName: '*.foo.com'
      createRoute53Record: true
      endpointType: 'regional'
      securityPolicy: tls_1_2
    http:
      domainName: http.serverless.foo.com
      stage: ci
      basePath: api
      certificateName: '*.foo.com'
      createRoute53Record: true
      endpointType: 'regional'
      securityPolicy: tls_1_2
    websocket:
      domainName: ws.serverless.foo.com
      stage: ci
      basePath: api
      certificateName: '*.foo.com'
      createRoute53Record: true
      endpointType: 'regional'
      securityPolicy: tls_1_2

感谢@tpschmidt 的有用回复! 只需添加,如果您想要 BasePathMapping 用于您的 websocket 域,请将 ApiMapping Key 添加到上面提供的 Cloudformation。例如:

WebSocketMapping:
      Type: AWS::ApiGatewayV2::ApiMapping
      Properties:
        ApiId: <api-id>
        DomainName: !Ref WebSocketDomainName
        Stage: <stage-name>
        ApiMappingKey: <stage-name> #(e.g. prod)

我不得不进行一些小的调整,以便在具有 WebSockets 支持和自定义域的私有 VPC 中使用 Lambda。

  1. CertificateArn 必须来自 ACM,不能 是上传到 IAM 的证书。
  2. 我使用了 A 记录而不是 CNAME
WebSocketDomainName:
    Type: AWS::ApiGatewayV2::DomainName
    Properties:
        DomainName: !Ref DomainName
        DomainNameConfigurations:
            - EndpointType: REGIONAL
              CertificateArn: <your-certificate-arn>

# This maps /staging or /prod to just the domain name
WebSocketMapping:
    Type: AWS::ApiGatewayV2::ApiMapping
    Properties:
        ApiId: <your-api-id>
        DomainName: !Ref WebSocketDomainName
        Stage: <your-stage>

Route53DNS:
    Type: AWS::Route53::RecordSetGroup
    Properties:
        HostedZoneName: !Ref Route53HostedZone
        RecordSets:
            - Name: !Ref DomainName
              Type: A
              AliasTarget:
                  HostedZoneId: ZLY8HYME6SFDD # This means eu-west-1 ApiGateWay
                  DNSName:
                      !GetAtt [WebSocketDomainName, RegionalDomainName]

您的 HostedZoneId 检查:https://docs.aws.amazon.com/general/latest/gr/apigateway.html