

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 为网关终端节点设置自定义域名
<a name="gateway-custom-domains"></a>

默认情况下，网关终端节点以以下格式`<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com`提供 Amazon-managed 域名。对于生产环境或创建更加用户友好的体验，您可能需要为网关终端节点使用自定义域名。本节指导您使用亚马逊 CloudFront 作为反向代理设置自定义域名。

## 先决条件
<a name="gateway-custom-domains-prereq"></a>

在开始之前，请确保您满足以下条件：
+ 有效的网关终端节点
+ DNS 委托（如果您的 Route 53 域需要可公开访问）
+  Amazon 已安装并配置 CDK（如果遵循 CDK 方法）
+ 创建和管理 CloudFront 分配、Route 53 托管区域和 ACM 证书的适当 IAM 权限

## 解决方案概述
<a name="gateway-custom-domains-overview"></a>

此解决方案包含以下组件：
+  **Route 53 托管区域**：管理您的自定义域的 DNS 记录
+  **ACM 证书**：为您的自定义域提供 SSL/TLS 加密
+  **CloudFront 分发**：充当反向代理，将请求从您的自定义域转发到网关终端节点
+  **Route 53 A Record**：将您的自定义域映射到 CloudFront 分配

以下步骤将指导您使用 Amazon CDK 设置这些组件。

## 实现步骤
<a name="gateway-custom-domains-steps"></a>

### 步骤 1：创建 Route 53 托管区域
<a name="gateway-custom-domains-hosted-zone"></a>

首先，为您的自定义域创建 Route 53 托管区域：

```
import { RemovalPolicy } from 'aws-cdk-lib';
import { PublicHostedZone } from 'aws-cdk-lib/aws-route53';

const domainName = 'my.example.com';

const hostedZone = new PublicHostedZone(this, 'HostedZone', {
    zoneName: domainName,
});
this.hostedZone.applyRemovalPolicy(RemovalPolicy.RETAIN);
```

**注意**  
我们采用的移除政策`RETAIN`来防止在堆栈更新或删除期间意外删除托管区域。

### 第 2 步：创建 DNS-validated 证书
<a name="gateway-custom-domains-certificate"></a>

接下来，使用带有 DNS 验证的 SSL/TLS Amazon 证书管理器 (ACM) 为您的自定义域创建证书：

```
import { RemovalPolicy } from 'aws-cdk-lib';
import { Certificate, CertificateValidation } from 'aws-cdk-lib/aws-certificatemanager';

const certificate = new Certificate(this, 'SSLCertificate', {
    domainName: domainName, // route53 hosted zone domain name from step 1
    validation: CertificateValidation.fromDns(hostedZone), // route53 hosted zone from step 1
});
this.certificate.applyRemovalPolicy(RemovalPolicy.RETAIN);
```

DNS 验证会自动在 Route 53 托管区域中创建必要的验证记录。

### 第 3 步：创建 CloudFront 发行版
<a name="gateway-custom-domains-cloudfront"></a>

创建 CloudFront 分发以充当您的网关终端节点的反向代理：

```
import {
  AllowedMethods,
  CachePolicy,
  Distribution,
  OriginProtocolPolicy,
  ViewerProtocolPolicy
} from 'aws-cdk-lib/aws-cloudfront';
import { HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';

const bedrockAgentCoreGatewayHostName = '<mymcpserver>.gateway.bedrock-agentcore.<region>.amazonaws.com'
const bedrockAgentCoreGatewayPath = '/mcp' // can also be left undefined, depending on your requirement

const distribution = new Distribution(this, 'Distribution', {
    defaultBehavior: {
        origin: new HttpOrigin(bedrockAgentCoreGatewayHostName, {
            protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
            originPath: bedrockAgentCoreGatewayPath,
        }),
        viewerProtocolPolicy: ViewerProtocolPolicy.HTTPS_ONLY,
        cachePolicy: CachePolicy.CACHING_DISABLED, // important since caching is enabled by default and hence is not suitable for a reverse proxy
        allowedMethods: AllowedMethods.ALLOW_ALL,
    },
    domainNames: [domainName], // route53 hosted zone domain name from step 1
    certificate: certificate, // ssl certificate for the route53 domain from step 2
});
```

**重要**  
设置`cachePolicy: CachePolicy.CACHING_DISABLED`为确保 CloudFront 不会缓存来自网关终端节点的响应，这对于动态 API 交互非常重要。

`<mymcpserver>`替换为您的网关 ID `<region>` 和您的 Amazon 区域（例如，`us-east-1`）。

### 步骤 4：创建 Route 53 A 记录
<a name="gateway-custom-domains-dns-record"></a>

创建 Route 53 A 记录，将您的自定义域指向 CloudFront 分配：

```
import { ARecord, RecordTarget } from 'aws-cdk-lib/aws-route53';
import { CloudFrontTarget } from 'aws-cdk-lib/aws-route53-targets';

const aRecord = new ARecord(this, 'AliasRecord', {
    zone: hostedZone, // route53 hosted zone from step 1
    recordName: domainName, // route53 hosted zone domain name from step 1
    target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)), // cloudfront distribution from step 3
});
```

这将创建将您的自定义域映射到 CloudFront 分配的别名记录。

### 第 5 步：部署基础架构
<a name="gateway-custom-domains-deploy"></a>

部署您的 CDK 堆栈来创建资源：

```
cdk deploy
```

部署过程可能需要一些时间，尤其是证书验证和 CloudFront 分发创建。

## 测试您的自定义域名
<a name="gateway-custom-domains-testing"></a>

部署基础设施后，验证您的自定义域配置是否正确：

### 验证 DNS 解析
<a name="gateway-custom-domains-testing-dns"></a>

使用`dig`命令验证您的自定义域是否已解析为 CloudFront 发行版：

```
dig my.example.com
```

输出应显示您的域名解析为 CloudFront IP 地址。

### 验证 SSL 证书
<a name="gateway-custom-domains-testing-ssl"></a>

`curl`用于验证 SSL 证书的配置是否正确：

```
curl -v https://my.example.com
```

输出应显示成功的 SSL 握手且没有证书错误。

## 配置 MCP 客户端
<a name="gateway-custom-domains-client-config"></a>

设置并验证自定义域后，您可以配置 MCP 客户端以使用它：

### 光标配置
<a name="gateway-custom-domains-client-config-cursor"></a>

对于 Cursor，更新您的配置文件：

```
{
  "mcpServers": {
    "my-mcp-server": {
      "url": "https://my.example.com"
    }
  }
}
```

### 其他 MCP 客户端
<a name="gateway-custom-domains-client-config-other"></a>

对于原生不支持可流式传输 HTTP 的 MCP 客户端：

```
{
  "mcpServers": {
    "my-mcp-server": {
      "command": "/path/to/uvx",
        "args": [
            "mcp-proxy",
            "--transport",
            "streamablehttp",
            "https://my.example.com"
        ]
    }
  }
}
```

## 其他注意事项
<a name="gateway-custom-domains-considerations"></a>

 **所涉费用 **   
用 CloudFront 作反向代理会产生额外的数据传输和请求处理费用。查看定 CloudFront 价模型，了解特定用例的成本影响。

 **安全注意事项 **   
考虑实施额外的安全措施，例如：  
+ 保护您的终端节点免受常见 Web 漏洞攻击的 WAF 规则
+ Geo-restrictions 限制对特定地理区域的访问
+ 自定义标头或请求签名以添加额外的身份验证层

 **监控和日志记录**   
启用 CloudFront 访问日志并配置 CloudWatch 警报以监控自定义域设置的运行状况和性能。

 **证书续订 **   
只要 DNS 记录保持不变，通过 DNS 验证颁发的 ACM 证书就会自动续订。确保您没有删除验证记录。

 **带有自定义域的 OAuth 保护资源端点 **   
默认情况下，`/.well-known/oauth-protected-resource`终端节点返回包含网关域的资源 URL，而不是您的自定义域。这可能会导致 OAuth 客户端在使用自定义域时身份验证失败。  
要解决此问题，您可以实现 Lambda @Edge 函数，该函数会拦截 OAuth 发现响应并使用正确的自定义域 URL 生成新的响应。以下是方法：  
+  **使用带有 ORIGIN\_RESPONSE 事件类型的 Lambda @Edge**：创建一个触发源响应的函数，以拦截受保护的 OAuth 资源端点响应。
+  **生成新的响应**：Lambda @Edge 无法读取原始响应正文，因此，与其修改现有响应，不如使用自定义域生成全新的 JSON 响应。
+  **与 CloudFront 行为相关联**：将 Lambda @Edge 函数配置为专门针对`/.well-known/oauth-protected-resource`路径模式触发。

  实施此解决方案后，受保护的 OAuth 资源端点将返回正确的自定义域：

  ```
  curl https://my-custom-domain.com/.well-known/oauth-protected-resource
  {
    "authorization_servers": ["https://my-org.okta.com/oauth2/default"],
    "resource": "https://my-custom-domain.com/mcp"
  }
  ```
**注意**  
虽然 Lambda @Edge 为这个问题提供了解决方案，但在没有内置支持的情况下为 AgentCore Gateway 实现自定义域需要额外的复杂性，这可能不是所有客户的最佳选择。在对带有自定义域的 OAuth 发现提供原生支持之前，可以考虑将这种方法作为一种解决方法。

## 问题排查
<a name="gateway-custom-domains-troubleshooting"></a>

 **DNS 解析问题 **   
如果您的自定义域名无法正确解析：  
+ 确认您的 Route 53 托管区域中的 A 记录配置正确
+ 检查域名注册商处的域名服务器设置是否正确
+ 留出时间进行 DNS 传播（在某些情况下最长可达 48 小时）

 **SSL 证书问题 **   
如果你遇到 SSL 证书错误：  
+ 验证证书是否已颁发并在 ACM 控制台中处于活动状态
+ 检查证书是否与您的 CloudFront 发行版正确关联
+ 确保证书涵盖您正在使用的确切域名

 **网关连接问题 **   
如果您的自定义域未连接到您的网关：  
+ 验证您的 CloudFront 发行版中的源域和路径是否正确
+ 检查您的网关终端节点是否可以直接访问
+ 查看 CloudFront 分发日志中是否存在任何错误

## 结论
<a name="gateway-custom-domains-conclusion"></a>

为 Gateway 终端节点设置自定义域名可以增强应用程序的专业外观，并可以灵活地管理 API 终端节点。按照本指南中概述的步骤，您可以用 CloudFront 作反向代理来创建安全可靠的自定义域配置。

有关网关特性和功能的更多信息，请参阅 [ Amazon Bedrock AgentCore Gateway：将工具和其他资源安全地连接到您的网关](gateway.md)。