

# 게이트웨이 엔드포인트에 대한 사용자 지정 도메인 이름 설정
<a name="gateway-custom-domains"></a>

기본적으로 게이트웨이 엔드포인트에는 형식으로 AWS관리형 도메인 이름이 제공됩니다`<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com`. 프로덕션 환경의 경우 또는 보다 사용자 친화적인 환경을 만들기 위해 게이트웨이 엔드포인트에 사용자 지정 도메인 이름을 사용할 수 있습니다. 이 섹션에서는 Amazon CloudFront를 역방향 프록시로 사용하여 사용자 지정 도메인 이름을 설정하는 방법을 안내합니다.

## 사전 조건
<a name="gateway-custom-domains-prereq"></a>

시작하기 전에 다음을 갖추었는지 확인하세요.
+ 작동하는 게이트웨이 엔드포인트
+ DNS 위임(Route 53 도메인에 공개적으로 연결해야 하는 경우)
+  AWS 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 배포에 매핑합니다.

다음 단계는 AWS 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 검증 인증서 생성
<a name="gateway-custom-domains-certificate"></a>

그런 다음 DNS 검증과 함께 Certificate Manager(ACM)를 사용하여 사용자 지정 도메인에 대한 SSL/TLS AWS 인증서를 생성합니다.

```
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
});
```

**중요**  
CloudFront가 동적 API 상호 작용에 중요한 게이트웨이 엔드포인트의 응답을 캐싱하지 않도록 `cachePolicy: CachePolicy.CACHING_DISABLED`를 설정합니다.

`<mymcpserver>`를 게이트웨이 ID로 바꾸고를 AWS 리전(예: `us-east-1` )`<region>`으로 바꿉니다.

### 4단계: Route 53 A 레코드 생성
<a name="gateway-custom-domains-dns-record"></a>

Route 53 사용자 지정 도메인이 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>

커서에서 구성 파일을 업데이트합니다.

```
{
  "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 요금 모델을 검토하여 특정 사용 사례에 대한 비용 영향을 이해합니다.

 **보안 고려 사항**   
다음과 같은 추가 보안 조치를 구현하는 것이 좋습니다.  
+ 엔드포인트를 일반적인 웹 악용으로부터 보호하기 위한 WAF 규칙
+ 특정 지리적 리전에 대한 액세스를 제한하는 지리적 제한
+ 추가 인증 계층을 추가하기 위한 사용자 지정 헤더 또는 요청 서명

 **모니터링 및 로깅**   
CloudFront 액세스 로그를 활성화하고 사용자 지정 도메인 설정의 상태와 성능을 모니터링하도록 CloudWatch 경보를 구성합니다.

 **인증서 갱신**   
DNS 레코드가 그대로 유지되는 한 DNS 검증을 통해 발급된 ACM 인증서는 자동으로 갱신됩니다. 검증 레코드를 삭제하지 않아야 합니다.

 **사용자 지정 도메인이 있는 OAuth 보호 리소스 엔드포인트**   
기본적으로 `/.well-known/oauth-protected-resource` 엔드포인트는 사용자 지정 도메인 대신 게이트웨이 도메인이 포함된 리소스 URL을 반환합니다. 이로 인해 사용자 지정 도메인을 사용할 때 OAuth 클라이언트가 인증에 실패할 수 있습니다.  
이 문제를 해결하기 위해 OAuth 검색 응답을 가로채고 올바른 사용자 지정 도메인 URL을 사용하여 새 응답을 생성하는 Lambda@Edge 함수를 구현할 수 있습니다. 접근 방식은 다음과 같습니다.  
+  **ORIGIN\_RESPONSE 이벤트 유형과 함께 Lambda@Edge 사용**: 오리진 응답에서 트리거하여 OAuth 보호 리소스 엔드포인트 응답을 가로채는 함수를 생성합니다.
+  **새 응답 생성**: Lambda@Edge는 오리진 응답 본문을 읽을 수 없으므로 기존 응답을 수정하는 대신 사용자 지정 도메인을 사용하여 완전히 새로운 JSON 응답을 생성합니다.
+  **CloudFront 동작과 연결**: `/.well-known/oauth-protected-resource` 경로 패턴에 대해 특별히 트리거되도록 Lambda@Edge 함수를 구성합니다.

  이 솔루션을 구현한 후 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).