mcpField
D
deploying-custom-domain-rest-api

deploying-custom-domain-rest-api

github.com/aws云与 DevOps3.3k5.1k 次安装1 天前更新
代码仓库

关于 deploying-custom-domain-rest-api

用于部署 AWS API Gateway REST API 的操作技能,面向需要配置自定义域名和 Lambda 请求授权器的用户。它涵盖 Regional 端点、证书、DNS 和 API 阶段映射;不支持私有端点。

主要功能

  1. 01创建 Regional REST API 与 Lambda 后端
  2. 02配置请求型 Lambda 授权器
  3. 03申请 ACM 证书并配置 TLS 1.2
  4. 04设置自定义域名与阶段映射
  5. 05配置 Route 53 别名记录

适用场景

  1. 01为 GET /example 部署带授权的 API
  2. 02为 API 配置自定义域名与 HTTPS
  3. 03通过 Route 53 将域名指向 API Gateway

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/aws/agent-toolkit-for-aws --skill deploying-custom-domain-rest-api

安装后在 Claude Code 中输入/deploying-custom-domain-rest-api确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

scripts/
authorizer.mjs
dns-record.json
example_function.mjs
lambda-trust-policy.json
validate.sh

详细介绍

使用 Lambda 和 Request Authorizer 的自定义域名 REST API

概述

本 SOP 将部署一个 REST API,其中包含 Regional 自定义域名、Lambda 后端函数和基于请求的 Lambda 授权方。它涵盖 ACM 证书配置、IAM 角色创建、Lambda 函数部署、创建带有自定义授权方的 API Gateway REST API、配置自定义域名、设置基础路径映射以及配置 Route 53 DNS。

该架构包括:

  • 一个端点类型为 REGIONAL 的 API Gateway REST API
  • 一个基于请求的 Lambda 授权方,用于验证标头、查询字符串参数和阶段变量
  • 一个位于 GET /example 的 Lambda 后端函数
  • 一个使用 TLS 1.2 的自定义域名
  • 一个将自定义域名连接到 API 阶段的基础路径映射
  • 一条 Route 53 A 别名记录,将自定义域名指向 API Gateway Regional 端点

重要提示:本 SOP 使用 Regional 端点。如果用户请求私有端点,请告知他们本技能仅涵盖 Regional 端点。私有端点需要配置 VPC 端点。

参数

  • custom_domain_name(必填):API 的完全限定域名(例如,api.example.com)
  • region(必填):所有资源所在的 AWS 区域。对于 Regional 端点,ACM 证书必须位于同一区域
  • hosted_zone_id(必填):该域名的 Route 53 托管区域 ID
  • acm_certificate_arn(可选):覆盖自定义域名的现有 ACM 证书 ARN。如果未提供,步骤 2 将创建证书
  • stage_name(可选,默认值:"dev"):API Gateway 阶段名称

参数获取约束:

  • 你必须在单条提示中一次性询问所有必填参数,而不是逐个询问
  • 你必须支持多种输入方式(直接输入、文件路径、URL)
  • 继续操作前,你必须确认已成功获取所有参数
  • 你必须告知用户,本技能使用硬编码的演示授权值(headerValue1、queryValue1、stageValue1),这些值不适用于生产环境。生产环境应使用 AWS Secrets Manager 或 Systems Manager Parameter Store 管理授权凭据。参见:https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
  • 你必须验证 custom_domain_name 是否为有效的 FQDN

步骤

0. 验证依赖项

约束:

  • 你必须验证以下工具是否可用:aws-cli、python3、sed、node(v22+)
  • 如有任何工具缺失,你必须明确告知用户
  • 你必须询问用户是否希望在工具缺失的情况下继续
  • 你必须尊重客户随时中止操作的决定
  • 你必须向客户说明正在执行哪个步骤、执行原因以及将调用哪个工具
1. 获取 AWS 账户 ID

此步骤必须在所有其他步骤之前执行。

约束:

  • 你必须使用以下命令获取账户 ID:aws sts get-caller-identity --query 'Account' --output text
  • 你必须将结果存储为 {account_id},并在后续所有引用 {account_id} 的步骤中复用
  • 如果尚未配置凭证,你必须中止操作
2. 申请 ACM 证书

如果已提供 acm_certificate_arn,则跳过此步骤。

约束:

  • 你必须使用以下命令申请证书:aws acm request-certificate --domain-name {custom_domain_name} --validation-method DNS --region {region}
  • 你必须从响应中获取 CertificateArn
  • 你必须使用以下命令获取 DNS 验证记录:aws acm describe-certificate --certificate-arn {cert_arn} --query 'Certificate.DomainValidationOptions[0].ResourceRecord' --region {region}
  • 你必须使用以下命令在 Route 53 中创建验证 CNAME 记录:aws route53 change-resource-record-sets --hosted-zone-id {hosted_zone_id} --change-batch '{"Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"{validation_name}","Type":"CNAME","TTL":300,"ResourceRecords":[{"Value":"{validation_value}"}]}}]}'
  • 你必须使用以下命令等待证书验证通过:aws acm wait certificate-validated --certificate-arn {cert_arn} --region {region}
  • 等待命令最长可能需要 30 分钟。如果超时,请使用以下命令手动检查状态:aws acm describe-certificate --certificate-arn {cert_arn} --query 'Certificate.Status' --region {region};如果状态仍为 PENDING_VALIDATION,请重试等待命令
  • 证书状态为 ISSUED 之前,你不得继续操作
  • 你必须将证书 ARN 保存为 acm_certificate_arn,以便在步骤 7 中使用
3. 创建 IAM 执行角色

约束:

  • 你必须创建两个 IAM 角色:一个用于授权器 Lambda,另一个用于示例函数 Lambda
  • 两个角色都使用 scripts/lambda-trust-policy.json 中的同一信任策略。该信任策略包含一个 aws:SourceAccount 条件,其范围限定为用户的账户 ID
  • 你必须创建信任策略的工作副本,并将 ACCOUNT_ID 占位符替换为步骤 1 中的实际账户 ID。使用:sed 's/ACCOUNT_ID/{account_id}/' scripts/lambda-trust-policy.json > /tmp/lambda-trust-policy.json
  • 你必须使用以下命令创建授权器角色:aws iam create-role --role-name request-authorizer-role --assume-role-policy-document file:///tmp/lambda-trust-policy.json
  • 你必须使用以下命令为授权器角色附加基本执行策略:aws iam attach-role-policy --role-name request-authorizer-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  • 你必须使用以下命令创建示例函数角色:aws iam create-role --role-name example-function-role --assume-role-policy-document file:///tmp/lambda-trust-policy.json
  • 你必须使用以下命令为示例函数角色附加基本执行策略:aws iam attach-role-policy --role-name example-function-role --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
  • 你必须从每个 create-role 响应中获取角色 ARN,以便在步骤 4 中使用
  • 创建角色后,你必须至少等待 10 秒再创建 Lambda 函数,因为 IAM 角色的传播采用最终一致性机制
4. 创建并部署 Lambda 函数

限制:

  • 你必须创建两个 Lambda 函数:请求授权器和示例函数
  • 对于授权器函数:
    • 你必须使用内联代码创建函数。首先将代码写入文件并打包: python3 -c "import zipfile,io,base64; z=io.BytesIO(); f=zipfile.ZipFile(z,'w'); f.writestr('index.mjs', open('scripts/authorizer.mjs').read()); f.close(); open('/tmp/authorizer.zip','wb').write(z.getvalue())"
    • 然后使用以下命令创建函数:aws lambda create-function --function-name request-authorizer --runtime nodejs22.x --handler index.handler --role {authorizer_role_arn} --zip-file fileb:///tmp/authorizer.zip --timeout 10 --region {region}
  • 对于示例函数:
    • 你必须使用内联代码创建函数。首先将代码写入文件并打包: python3 -c "import zipfile,io; z=io.BytesIO(); f=zipfile.ZipFile(z,'w'); f.writestr('index.mjs', open('scripts/example_function.mjs').read()); f.close(); open('/tmp/example_function.zip','wb').write(z.getvalue())"
    • 然后使用以下命令创建函数:aws lambda create-function --function-name example-function --runtime nodejs22.x --handler index.handler --role {example_role_arn} --zip-file fileb:///tmp/example_function.zip --timeout 10 --region {region}
  • 你必须通过调用以下命令验证每个函数均已创建:aws lambda get-function --function-name {function_name} --region {region}
5. 使用请求授权方创建 REST API

约束:

  • 必须使用以下命令创建 REST API:aws apigateway create-rest-api --name custom-domain-api --endpoint-configuration types=REGIONAL --region {region}
  • 必须获取 API ID,并使用以下命令获取根资源 ID:aws apigateway get-resources --rest-api-id {api_id} --region {region}
  • 必须使用以下命令创建基于请求的 Lambda 授权方:aws apigateway create-authorizer --rest-api-id {api_id} --name request-authorizer --type REQUEST --authorizer-uri 'arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/arn:aws:lambda:{region}:{account_id}:function:request-authorizer/invocations' --identity-source 'method.request.header.HeaderAuth1,method.request.querystring.QueryString1,context.stage' --region {region}
  • 必须从响应中获取授权方 ID
  • 必须使用以下命令授予 API Gateway 调用授权方的权限:aws lambda add-permission --function-name request-authorizer --statement-id apigateway-auth-invoke --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn 'arn:aws:execute-api:{region}:{account_id}:{api_id}/authorizers/{authorizer_id}' --region {region}
  • 必须使用以下命令创建 /example 资源:aws apigateway create-resource --rest-api-id {api_id} --parent-id {root_resource_id} --path-part example --region {region}
  • 必须使用以下命令创建 GET 方法:aws apigateway put-method --rest-api-id {api_id} --resource-id {example_resource_id} --http-method GET --authorization-type CUSTOM --authorizer-id {authorizer_id} --region {region}
  • 必须使用以下命令创建 Lambda 代理集成:aws apigateway put-integration --rest-api-id {api_id} --resource-id {example_resource_id} --http-method GET --type AWS_PROXY --integration-http-method POST --uri 'arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/arn:aws:lambda:{region}:{account_id}:function:example-function/invocations' --region {region}
  • 必须使用以下命令授予 API Gateway 调用示例函数的权限:aws lambda add-permission --function-name example-function --statement-id apigateway-invoke --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn 'arn:aws:execute-api:{region}:{account_id}:{api_id}/*/GET/example' --region {region}
  • 在配置好所有资源、方法和集成之前,禁止创建部署
  • 必须配置请求验证,以拒绝格式错误的查询参数和标头:验证 QueryString1 和 HeaderAuth1 是否符合预期模式,并限制其大小
6. 部署 API

约束:

  • 必须使用以下命令创建部署:aws apigateway create-deployment --rest-api-id {api_id} --stage-name {stage_name} --region {region}
  • 必须使用以下命令设置授权方所需的阶段变量:aws apigateway update-stage --rest-api-id {api_id} --stage-name {stage_name} --patch-operations op=replace,path=/variables/StageVar1,value=stageValue1 --region {region}
  • 必须调用以下命令验证部署和阶段变量,并确认变量中存在 StageVar1:aws apigateway get-stage --rest-api-id {api_id} --stage-name {stage_name} --region {region}
  • 必须在阶段启用访问日志记录。首先创建日志组:aws logs create-log-group --log-group-name api-gw-access-logs --region {region}。然后使用以下格式启用日志记录:aws apigateway update-stage --rest-api-id {api_id} --stage-name {stage_name} --patch-operations op=replace,path=/accessLogSettings/destinationArn,value=arn:aws:logs:{region}:{account_id}:log-group:api-gw-access-logs op=replace,path=/accessLogSettings/format,value='{"requestId":"$context.requestId","ip":"$context.identity.sourceIp","requestTime":"$context.requestTime","httpMethod":"$context.httpMethod","resourcePath":"$context.resourcePath","status":"$context.status"}' --region {region}
7. 创建自定义域名和基本路径映射

约束:

  • 必须使用以下命令创建自定义域名:aws apigateway create-domain-name --domain-name {custom_domain_name} --regional-certificate-arn {acm_certificate_arn} --endpoint-configuration types=REGIONAL --security-policy TLS_1_2 --region {region}
  • 必须从响应中捕获 regionalDomainName 和 regionalHostedZoneId,以便在步骤 8 中使用
  • 必须使用以下命令创建基本路径映射:aws apigateway create-base-path-mapping --domain-name {custom_domain_name} --rest-api-id {api_id} --stage {stage_name} --base-path '(none)' --region {region}
  • 必须调用以下命令验证域名是否已创建:aws apigateway get-domain-name --domain-name {custom_domain_name} --region {region}
  • 不得将安全策略降级至 TLS_1_2 以下
8. 创建 Route 53 DNS 记录

约束:

  • 必须创建 scripts/dns-record.json 的工作副本,并替换其中的占位符:sed -e 's/CUSTOM_DOMAIN_NAME/{custom_domain_name}/' -e 's/REGIONAL_DOMAIN_NAME/{regional_domain_name}/' -e 's/REGIONAL_HOSTED_ZONE_ID/{regional_hosted_zone_id}/' scripts/dns-record.json > /tmp/dns-record.json
  • 命令为:aws route53 change-resource-record-sets --hosted-zone-id {hosted_zone_id} --change-batch file:///tmp/dns-record.json
  • 必须对 AliasTarget 使用从步骤 7 捕获的 regionalDomainName 和 regionalHostedZoneId,而不是用户的托管区域 ID
  • 使用 Route 53 作为 DNS 提供商时,必须使用 A 别名记录(而非 CNAME)
  • 建议告知用户,DNS 传播最长可能需要 48 小时
9. 验证最终设置

约束:

  • 建议运行 scripts/validate.sh {custom_domain_name} {api_id} {region} 检查所有资源
  • 必须告知用户使用以下命令进行测试:curl 'https://{custom_domain_name}/example?QueryString1=queryValue1' -H 'HeaderAuth1: headerValue1'
  • 必须说明预期响应为 200,且内容为 {"message": "Hello from the example function!"}
  • 必须说明,缺少正确的 HeaderAuth1 标头或 QueryString1 查询参数的请求会被授权器拒绝
  • 必须提供所有已创建资源的摘要,包括:
    • ACM 证书 ARN
    • IAM 角色 ARN
    • Lambda 函数 ARN
    • REST API ID 和阶段名称
    • 授权器 ID
    • 自定义域名和 Regional 域名
    • Route 53 DNS 记录

示例

输入示例
custom_domain_name: api.example.com
region: us-east-2
hosted_zone_id: Z2OJLYMUO9EFXC
stage_name: prod
输出示例
ACM certificate issued for api.example.com
  ARN: arn:aws:acm:us-east-2:123456789012:certificate/abc-123

IAM roles created
  Authorizer: arn:aws:iam::123456789012:role/request-authorizer-role
  Example: arn:aws:iam::123456789012:role/example-function-role

Lambda functions deployed
  Authorizer: arn:aws:lambda:us-east-2:123456789012:function:request-authorizer
  Example: arn:aws:lambda:us-east-2:123456789012:function:example-function

REST API deployed
  API ID: a1b2c3d4e5
  Stage: prod (StageVar1=stageValue1)
  Authorizer: request-authorizer (REQUEST type)

Custom domain configured
  Domain: api.example.com
  Regional endpoint: d-abc123.execute-api.us-east-2.amazonaws.com
  TLS: 1.2

Route 53 DNS record created
  A-alias: api.example.com -> d-abc123.execute-api.us-east-2.amazonaws.com

Test command (authorized):
  curl 'https://api.example.com/example?QueryString1=queryValue1' -H 'HeaderAuth1: headerValue1'

Test command (denied):
  curl 'https://api.example.com/example'

故障排查

证书停留在 PENDING_VALIDATION 状态

运行 aws acm describe-certificate --certificate-arn {arn} --query 'Certificate.DomainValidationOptions',确认 Route 53 中存在 DNS 验证 CNAME 记录。确保 CNAME 是在正确的托管区域中创建的。

API 调用返回 403 Forbidden

请求授权器会检查三个值:HeaderAuth1 标头必须为 headerValue1,QueryString1 查询参数必须为 queryValue1,阶段变量 StageVar1 必须为 stageValue1。确认这三个值均已提供且正确。查看授权器函数的 CloudWatch Logs,了解详细错误消息。

401 Unauthorized

授权器函数无法调用时,API Gateway 会返回 401。确认已添加 Lambda 权限,允许 API Gateway 调用授权器。检查授权器 URI 是否正确。

缺少身份验证令牌(403)

请求路径与已配置的资源不匹配。运行 aws apigateway get-resources --rest-api-id {api_id},确认 /example 资源存在。确保在创建所有资源后已部署 API。

自定义域名未返回响应

DNS 传播最长可能需要 48 小时。使用 dig {custom_domain_name} 检查。确认 A 别名记录指向 create-domain-name 响应中的正确 regionalDomainName 和 regionalHostedZoneId。

未设置阶段变量

如果授权器拒绝所有请求,请使用 aws apigateway get-stage --rest-api-id {api_id} --stage-name {stage_name} --query 'variables' 验证是否已设置阶段变量。必须将 StageVar1 变量设置为 stageValue1。

创建 Lambda 时找不到 IAM 角色

IAM 角色的传播具有最终一致性。创建角色后,至少等待 10 秒再创建 Lambda 函数。使用 aws iam get-role --role-name {role_name} 验证角色 ARN。

基路径映射不起作用

使用 aws apigateway get-base-path-mappings --domain-name {custom_domain_name} 验证。基路径 (none) 会将域名根路径映射到阶段。请确保已成功部署到该阶段。

安全注意事项

  • Lambda 授权器中硬编码的授权值(headerValue1、queryValue1、stageValue1)仅用于演示,不适用于生产环境。部署到生产环境之前,请替换为适当的身份验证机制(JWT 验证、来自 AWS Secrets Manager 的 API 密钥或 OAuth)。
  • 在 API 阶段启用请求限流,以防止滥用。使用以下命令配置速率和突发限制:aws apigateway update-stage --rest-api-id {api_id} --stage-name {stage_name} --patch-operations op=replace,path=/throttle/rateLimit,value=1000 op=replace,path=/throttle/burstLimit,value=2000
  • 为 Lambda 日志组启用 CloudWatch Logs 加密。使用以下命令关联 KMS 密钥:aws logs associate-kms-key --log-group-name /aws/lambda/request-authorizer --kms-key-arn <KMS_KEY_ARN>
  • 使用 AWS WAF 保护公共 API,缓解常见攻击(SQL 注入、XSS、基于速率的规则):aws wafv2 associate-web-acl --web-acl-arn <WAF_ACL_ARN> --resource-arn arn:aws:apigateway:{region}::/restapis/{api_id}/stages/{stage_name}

其他资源

评论

支持 Markdown