

# 보안 액세스 구성 및 콘텐츠에 대한 액세스 제한
<a name="SecurityAndPrivateContent"></a>

CloudFront에서 제공되는 콘텐츠의 보안을 위해 몇 가지 옵션을 사용할 수 있습니다. 다음은 CloudFront에서 콘텐츠에 대한 액세스를 보호하고 제한하는 데 사용할 수 있는 몇 가지 방법입니다.
+ HTTPS 연결 구성
+ 특정 지리적 위치의 사용자가 콘텐츠에 액세스하지 못하도록 차단
+ 사용자가 CloudFront 서명된 URL 또는 서명된 쿠키를 사용하여 콘텐츠에 액세스하도록 요구
+ 특정 콘텐츠 필드에 대한 필드 수준 암호화 설정
+ AWS WAF를 사용하여 콘텐츠에 대한 액세스 제어

또한 인프라 및 애플리케이션을 위한 DDoS 복원력이 있는 아키텍처를 구현해야 합니다. 자세한 내용은 [DDoS 복원력에 대한 AWS 모범 사례](https://docs.aws.amazon.com/whitepapers/latest/aws-best-practices-ddos-resiliency/aws-best-practices-ddos-resiliency.html)를 참조하세요.

추가 정보는 다음을 참조하세요.
+ [CloudFront를 사용하여 콘텐츠 전송 보호](https://aws.amazon.com/cloudfront/security/)
+ [Amazon OpenSearch Service의 SIEM](https://github.com/aws-samples/siem-on-amazon-opensearch-service/blob/main/README.md)

**Topics**
+ [CloudFront에서 HTTPS 사용](using-https.md)
+ [대체 도메인 이름과 HTTPS 사용](using-https-alternate-domain-names.md)
+ [CloudFront에 대한 상호 TLS 인증(뷰어 mTLS)](mtls-authentication.md)
+ [CloudFront에 대한 오리진 상호 TLS](origin-mtls-authentication.md)
+ [서명된 URL과 서명된 쿠키를 사용하여 프라이빗 콘텐츠 제공](PrivateContent.md)
+ [AWS 오리진에 대한 액세스 제한](private-content-restricting-access-to-origin.md)
+ [Application Load Balancer에 대한 액세스 제한](restrict-access-to-load-balancer.md)
+ [콘텐츠의 지리적 배포 제한](georestrictions.md)
+ [필드 수준 암호화를 사용하여 민감한 데이터 보호](field-level-encryption.md)

# CloudFront에서 HTTPS 사용
<a name="using-https"></a>

뷰어가 HTTPS를 사용할 것을 요청하도록 CloudFront를 구성할 수 있습니다. 이렇게 하면 CloudFront가 뷰어와 통신할 때 연결이 암호화됩니다. 또한 CloudFront가 오리진과 HTTPS를 사용하도록 구성할 수 있습니다. 이렇게 하면 CloudFront가 오리진과 통신할 때 연결이 암호화됩니다.

CloudFront가 뷰어와 통신할 때 그리고 오리진과 통신할 때 모두 HTTPS를 요구하도록 구성할 경우, CloudFront에서 요청을 받을 때 다음과 같은 프로세스가 수행됩니다.

1. 최종 사용자가 HTTPS 요청을 CloudFront에 제출합니다. 뷰어와 CloudFront 간에 SSL/TLS 협상이 수행됩니다. 결국에는 최종 사용자가 암호화된 형식을 요청을 제출합니다.

1. CloudFront 엣지 로케이션에 캐시 응답을 포함하는 경우 CloudFront가 응답을 암호화하여 뷰어에게 반환하면 뷰어는 이를 해독합니다.

1. CloudFront 엣지 로케이션에 캐시 응답을 포함하지 않는 경우 CloudFrontnt는 오리진과 SSL/TLS 협상을 수행하며 협상이 완료되면 요청을 암호화된 형식으로 오리진에 전달합니다.

1. 오리진은 요청을 복호화한 후 요청을 처리하여 응답을 생성 및 암호화한 후 CloudFront에 반환합니다.

1. CloudFront는 응답을 복호화한 후 다시 암호화하여 뷰어에게 전달합니다. 또한 CloudFront는 엣지 로케이션에 응답을 캐시하여 다음에 요청할 때 사용할 수 있도록 합니다.

1. 최종 사용자가 응답을 해독합니다.

이 프로세스는 오리진 서버가 Amazon S3 버킷이든, MediaStore이든, HTTP/S 서버와 같은 사용자 지정 오리진이든 상관없이 기본적으로 동일하게 작동합니다.

**참고**  
SSL 재협상 유형 공격을 차단하기 위해 CloudFront는 최종 사용자와 오리진의 요청에 대한 재협상을 지원하지 않습니다.

또는 CloudFront 배포에 대해 상호 인증을 켤 수 있습니다. 자세한 내용은 [CloudFront에 대한 상호 TLS 인증(뷰어 mTLS)CloudFront에 대한 오리진 상호 TLS](mtls-authentication.md) 섹션을 참조하세요.

최종 사용자와 CloudFront 간에 그리고 CloudFront와 오리진 간에 HTTPS를 요청하는 방법을 알아보려면 다음 주제를 참조하세요.

**Topics**
+ [뷰어와 CloudFront 간에 HTTPS 요구](using-https-viewers-to-cloudfront.md)
+ [사용자 지정 오리진에 대해 HTTPS 요구](using-https-cloudfront-to-custom-origin.md)
+ [Amazon S3 오리진에 대해 HTTPS 요구](using-https-cloudfront-to-s3-origin.md)
+ [최종 사용자와 CloudFront 간에 지원되는 프로토콜 및 암호](secure-connections-supported-viewer-protocols-ciphers.md)
+ [CloudFront와 오리진 간에 지원되는 프로토콜 및 암호](secure-connections-supported-ciphers-cloudfront-to-origin.md)

# 뷰어와 CloudFront 간의 통신에 HTTPS 요구
<a name="using-https-viewers-to-cloudfront"></a>

CloudFront 배포에 하나 이상의 캐시 동작을 구성하여 최종 사용자와 CloudFront 간의 통신에 HTTPS를 요구할 수 있습니다. 또한 CloudFront가 일부 객체에 대해서만 HTTPS를 요구하도록 하기 위해 HTTP 및 HTTPS 모두를 허용하는 캐시 동작을 한 개 이상 구성할 수 있습니다. 구성 단계는 객체 URL에 사용하는 도메인 이름에 따라 다릅니다.
+ CloudFront가 배포에 할당한 도메인 이름(예: d111111abcdef8.cloudfront.net)을 사용할 경우 한 개 이상의 캐시 동작에 대해 **최종 사용자 프로토콜 정책(Viewer Protocol Policy)** 설정을 변경하여 HTTPS 통신을 요구하도록 합니다. 이 구성에서 CloudFront는 SSL/TLS 인증서를 제공합니다.

  CloudFront 콘솔을 사용하여 **최종 사용자 프로토콜 정책(Viewer Protocol Policy)** 값을 변경하려면 이 단원의 절차를 참조하세요.

  CloudFront API를 사용하여 `ViewerProtocolPolicy` 요소의 값을 변경하는 방법을 보려면 *Amazon CloudFront API 참조*의 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)을 참조하세요.
+ example.com 등의 자체 도메인 이름을 사용할 경우 몇 가지 CloudFront 설정을 변경해야 합니다. 또한 AWS Certificate Manager(ACM)에서 제공한 SSL/TLS 인증서를 사용하거나, 다른 인증 기관의 인증서를 또는 IAM 인증서 스토어로 가져와야 합니다. 자세한 내용은 [대체 도메인 이름과 HTTPS 사용](using-https-alternate-domain-names.md) 단원을 참조하세요.

**참고**  
CloudFront가 오리진에서 객체를 받을 때 최종 사용자가 CloudFront로부터 받는 객체가 암호화되도록 하려면 CloudFront와 오리진 간에 항상 HTTPS를 사용하세요. 최근에 CloudFront와 오리진 간의 연결을 HTTP에서 HTTPS로 변경한 경우 CloudFront 엣지 로케이션의 객체를 무효화할 것을 권장합니다. CloudFront는 최종 사용자가 사용한 프로토콜(HTTP 또는 HTTPS)이, CloudFront가 객체를 받는 데 사용한 프로토콜과 일치하는지와 상관없이 최종 사용자에게 객체를 반환합니다. 배포에서 객체 제거 또는 대체에 대한 자세한 내용은 [CloudFront가 배포하는 콘텐츠 추가, 제거 또는 교체](AddRemoveReplaceObjects.md) 단원을 참조하십시오.

## 뷰어에 HTTPS 요구
<a name="configure-cloudfront-HTTPS-viewers"></a>

하나 이상의 캐시 동작에 대해 최종 사용자와 CloudFront 간에 HTTPS를 요구하려면 다음과 같이 하세요.<a name="using-https-viewers-to-cloudfront-procedure"></a>

**CloudFront에서 최종 사용자와 CloudFront 간에 HTTPS를 요구하도록 구성하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. CloudFront 콘솔의 상단 창에서 업데이트할 배포의 ID를 선택합니다.

1. **동작** 탭에서 업데이트할 캐시 동작을 선택한 후 **편집**을 선택합니다.

1. **최종 사용자 프로토콜 정책**에 다음 값 중 하나를 지정합니다.  
**Redirect HTTP to HTTPS**  
최종 사용자가 두 프로토콜을 모두 사용할 수 있습니다. HTTP `GET` 및 `HEAD` 요청은 HTTPS 요청으로 자동 리디렉션됩니다. CloudFront는 HTTP 상태 코드 301(영구 이동됨)을 새로운 HTTPS URL과 함께 반환합니다. 그러면 최종 사용자는 HTTPS URL을 사용하여 이 요청을 CloudFront에 다시 제출합니다.  
HTTP를 통해 `POST`, `PUT`, `DELETE`, `OPTIONS` 또는 `PATCH`를 HTTP - HTTPS 캐시 동작 및 HTTP 1.1 이상의 요청 프로토콜 버전으로 보내면, CloudFront는 HTTP 상태 코드 307(임시 리디렉션)과 함께 HTTPS 위치로 요청을 리디렉션합니다. 이렇게 하면 요청이 동일한 메서드와 본문 페이로드를 사용하여 새 위치로 다시 전송됩니다.  
`POST`, `PUT`, `DELETE`, `OPTIONS` 또는 `PATCH` 요청을 HTTP - HTTPS 캐시 동작을 통해 HTTP 1.1 미만인 요청 프로토콜 버전으로 보내면, CloudFront는 HTTP 상태 코드 403(사용할 수 없음)을 반환합니다.
최종 사용자가 HTTPS 요청으로 리디렉션되는 HTTP 요청을 만들 경우 CloudFront에서 두 요청 모두에 대해 요금을 부과합니다. HTTP 요청의 경우에는 CloudFront에서 최종 사용자에게 반환되는 요청 및 헤더에만 요금이 부과됩니다. HTTPS 요청의 경우에는 요청, 헤더, 그리고 오리진에 의해 반환된 객체에 대해 요금이 부과됩니다.  
**HTTPS Only**  
최종 사용자가 HTTPS를 사용할 경우에만 콘텐츠에 액세스할 수 있습니다. 최종 사용자가 HTTPS 요청 대신에 HTTP 요청을 보내면 CloudFront는 HTTP 상태 코드 403(금지됨)을 반환하고 객체는 반환하지 않습니다.

1. **변경 사항 저장**을 선택합니다.

1. 최종 사용자와 CloudFront 간에 HTTPS를 요구하려는 캐시 동작에 대해 3\$15단계를 반복합니다.

1. 업데이트한 구성을 프로덕션 환경에서 사용하기 전에 다음 사항을 확인합니다.
   + 각 캐시 동작의 경로 패턴이 최종 사용자에 HTTPS를 사용하도록 지정한 요청에만 적용되는가.
   + 캐시 동작이 CloudFront에서 평가하도록 할 순서대로 나열되었는가. 자세한 내용은 [경로 패턴](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern) 단원을 참조하세요.
   + 캐시 동작이 올바른 오리진에 요청을 라우팅하는가.

# CloudFront와 사용자 지정 오리진 간의 통신에 HTTPS 요구
<a name="using-https-cloudfront-to-custom-origin"></a>

CloudFront와 오리진 간의 통신에 HTTPS를 요청할 수 있습니다.

**참고**  
오리진이 웹 사이트 엔드포인트로 구성된 Amazon S3 버킷인 경우, Amazon S3에서 웹 사이트 엔드포인트로 HTTPS를 지원하지 않으므로 오리진에 HTTPS를 사용하도록 CloudFront를 구성할 수 없습니다.

CloudFront와 오리진 간에 HTTPS를 요청하려면 이 항목의 절차에 따라 다음을 수행하세요.

1. 배포에서 오리진에 대한 **오리진 프로토콜 정책** 설정을 변경합니다.

1. 오리진 서버에 SSL/TLS 인증서를 설치합니다(Amazon S3 오리진 또는 기타 특정 AWS 오리진을 사용하는 경우 필요 없음).

**Topics**
+ [사용자 지정 오리진에 HTTPS 요구](#using-https-cloudfront-to-origin-distribution-setting)
+ [사용자 지정 오리진에 SSL/TLS 인증서 설치](#using-https-cloudfront-to-origin-certificate)

## 사용자 지정 오리진에 HTTPS 요구
<a name="using-https-cloudfront-to-origin-distribution-setting"></a>

다음 절차는 CloudFront에서 HTTPS를 사용하여 Elastic Load Balancing 로드 밸런서, Amazon EC2 인스턴스 또는 다른 사용자 지정 오리진과 통신하도록 구성하는 방법을 보여 줍니다. CloudFront API를 사용한 배포 업데이트에 대한 자세한 내용은 *Amazon CloudFront API 참조*의 [배포 업데이트](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)를 참조하십시오.<a name="using-https-cloudfront-to-custom-origin-procedure"></a>

**CloudFront에서 CloudFront와 사용자 지정 오리진 간에 HTTPS를 요구하도록 구성하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. CloudFront 콘솔의 상단 창에서 업데이트할 배포의 ID를 선택합니다.

1. **동작** 탭에서 업데이트할 오리진을 선택하고 **편집**을 선택합니다.

1. 다음 설정을 업데이트합니다.  
**오리진 프로토콜 정책**  
배포의 해당 오리진에 대해 **오리진 프로토콜 정책**을 변경합니다.  
   + **HTTPS만(HTTPS Only)** - CloudFront에서 사용자 지정 오리진과 통신할 때 HTTPS만 사용합니다.
   + **최종 사용자와 일치(Match Viewer)** - CloudFront에서 최종 사용자 요청의 프로토콜에 따라 HTTP 또는 HTTPS를 사용하여 사용자 지정 오리진과 통신합니다. 예를 들면 **오리진 프로토콜 정책(Origin Protocol Policy)**에 **최종 사용자와 일치(Match Viewer)**를 선택하고 최종 사용자가 HTTPS를 사용하여 CloudFront에서 객체를 요청하는 경우, CloudFront에서도 HTTPS를 사용하여 해당 요청을 오리진으로 전달합니다.

     **Viewer Protocol Policy**(최종 사용자 프로토콜 정책)에서 **Redirect HTTP to HTTPS**(HTTP를 HTTPS로 재지정) 또는 **HTTPS Only**(HTTPS만 해당)를 지정한 경우에만 **Match Viewer**를 선택합니다.

     최종 사용자가 HTTP 및 HTTPS 프로토콜 모두를 사용하여 요청하더라도 CloudFront에서는 한 번만 객체를 캐싱합니다.  
**오리진 SSL 프로토콜**  
배포의 해당 오리진에 대해 **오리진 SSL 프로토콜**을 선택합니다. SSLv3 프로토콜이 덜 안전하므로 사용자가 TLSv1 이상을 지원하지 않는 경우에만 SSLv3을 선택하는 것이 좋습니다. TLSv1 핸드쉐이크는 SSLv3의 이전 버전 및 이후 버전과 모두 호환되지만, TLSv1.1 이상은 호환되지 않습니다. SSLv3을 선택하면 CloudFront는 SSLv3 핸드셰이크 요청*만* 보냅니다.

1. **변경 사항 저장**을 선택합니다.

1. CloudFront와 사용자 지정 오리진 간에 HTTPS를 요구하려는 다른 오리진에 대해 3\$15단계를 반복합니다.

1. 업데이트한 구성을 프로덕션 환경에서 사용하기 전에 다음 사항을 확인합니다.
   + 각 캐시 동작의 경로 패턴이 최종 사용자에 HTTPS를 사용하도록 지정한 요청에만 적용되는가.
   + 캐시 동작이 CloudFront에서 평가하도록 할 순서대로 나열되었는가. 자세한 내용은 [경로 패턴](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern) 단원을 참조하세요.
   + 캐시 동작은 변경한 **오리진 프로토콜 정책**에 따라 요청을 오리진으로 라우팅합니다.

## 사용자 지정 오리진에 SSL/TLS 인증서 설치
<a name="using-https-cloudfront-to-origin-certificate"></a>

사용자 지정 오리진에서 다음 소스의 SSL/TLS 인증서를 사용할 수 있습니다.
+ 오리진이 Elastic Load Balancing 로드 밸런서인 경우 AWS Certificate Manager(ACM)에서 제공하는 인증서를 사용할 수 있습니다. 또한 신뢰할 수 있는 다른 인증 기관에서 서명한 인증서 및 ACM으로 가져온 인증서를 사용할 수도 있습니다.
+ Elastic Load Balancing 로드 밸런서 외의 오리진에서는 Comodo, DigiCert, Symantec 같이 신뢰할 수 있는 서드 파티 인증 기관(CA)에서 서명한 인증서를 사용해야 합니다.

오리진에서 반환되는 인증서는 다음 도메인 이름 중 하나를 포함하고 있어야 합니다.
+ 오리진의 **오리진 도메인(Origin domain)** 필드(CloudFront API의 `DomainName` 필드)에 있는 도메인 이름.
+ 캐시 동작이 `Host` 헤더를 오리진으로 전달하도록 구성된 경우, `Host` 헤더의 도메인 이름.

CloudFront가 HTTPS를 사용하여 오리진과 통신하면 CloudFront는 인증서가 신뢰할 수 있는 인증 기관에 의해 발급되었는지 확인합니다. CloudFront는 Mozilla가 지원하는 것과 동일한 인증 기관을 지원합니다. 최신 목록은 [Mozilla에 포함된 CA 인증서 목록](https://wiki.mozilla.org/CA/Included_Certificates)을 참조하십시오. CloudFront와 오리진 간의 HTTPS 통신에는 자체 서명한 인증서를 사용할 수 없습니다.

**중요**  
오리진 서버에서 만료된 인증서, 잘못된 인증서 또는 자체 서명된 인증서를 반환하는 경우 또는 오리진 서버에서 잘못된 순서로 인증서 체인을 반환하는 경우에는 CloudFront에서 TCP 연결을 끊고 HTTP 상태 코드 502(잘못된 게이트웨이)를 뷰어로 반환하며 `X-Cache` 헤더를 `Error from cloudfront`로 설정합니다. 또한 중간 인증서를 포함하여 인증서의 전체 체인이 없는 경우, CloudFront는 TCP 연결을 끊습니다.

# CloudFront와 Amazon S3 오리진 간의 통신에 HTTPS 요구
<a name="using-https-cloudfront-to-s3-origin"></a>

오리진이 Amazon S3 버킷인 경우 CloudFront와 통신을 위해 HTTPS를 사용하는 옵션은 버킷을 사용하는 방식에 따라 달라집니다. 웹 사이트 엔드포인트로 Amazon S3 버킷이 구성되어 있는 경우, Amazon S3에서 해당 구성으로 HTTPS 연결을 지원하지 않으므로 HTTPS를 사용하여 오리진과 통신하도록 CloudFront를 구성할 수 없습니다.

오리진이 HTTPS 통신을 지원하는 Amazon S3 버킷일 경우 CloudFront는 뷰어가 요청을 전송하는 데 사용된 프로토콜을 사용하여 S3로 요청을 전달합니다. [프로토콜(사용자 지정 오리진만 해당)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy) 설정의 기본 설정은 **최종 사용자와 일치(Match Viewer)**이며 변경할 수 없습니다. 그러나 Amazon S3 오리진에 대해 오리진 액세스 제어(OAC)를 사용 설정하면 CloudFront와 Amazon S3 간에 사용되는 통신은 사용자가 어떻게 설정하는지에 따라 달라집니다. 자세한 내용은 [새 오리진 액세스 제어 생성](private-content-restricting-access-to-s3.md#create-oac-overview-s3) 섹션을 참조하세요.

CloudFront와 Amazon S3 간의 통신에 HTTPS를 요구하려면, **최종 사용자 프로토콜 정책(Viewer Protocol Policy)** 값을 **Redirect HTTP to HTTPS(HTTP를 HTTPS로 재지정)** 또는 **HTTPS Only(HTTPS만)**로 변경해야 합니다. 이 단원의 나머지 절차에서는 CloudFront 콘솔을 사용하여 **최종 사용자 프로토콜 정책(Viewer Protocol Policy)** 값을 변경하는 방법을 설명합니다. CloudFront API를 사용하여 배포용 `ViewerProtocolPolicy` 요소를 업데이트하는 자세한 내용은 *Amazon CloudFront API 참조*의 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)을 참조하세요.

HTTPS 통신을 지원하는 Amazon S3 버킷과 함께 HTTPS를 사용하면 Amazon S3가 SSL/TLS 인증서를 제공하므로 사용자가 제공할 필요가 없습니다.

## Amazon S3 오리진에 대해 HTTPS 요구
<a name="configure-cloudfront-HTTPS-S3-origin"></a>

다음 절차에서는 CloudFront에서 Amazon S3 오리진에 대해 HTTPS를 요구하도록 구성하는 방법을 알아봅니다.<a name="using-https-cloudfront-to-s3-origin-procedure"></a>

**CloudFront에서 Amazon S3 오리진에 대해 HTTPS를 요구하도록 구성하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. CloudFront 콘솔의 상단 창에서 업데이트할 배포의 ID를 선택합니다.

1. **동작** 탭에서 업데이트할 캐시 동작을 선택한 후 **편집**을 선택합니다.

1. **최종 사용자 프로토콜 정책**에 다음 값 중 하나를 지정합니다.  
**Redirect HTTP to HTTPS**  
최종 사용자가 두 프로토콜 모두 사용할 수 있지만, HTTP 요청은 자동으로 HTTPS 요청으로 리디렉션됩니다. CloudFront는 HTTP 상태 코드 301(영구 이동됨)을 새로운 HTTPS URL과 함께 반환합니다. 그러면 최종 사용자는 HTTPS URL을 사용하여 이 요청을 CloudFront에 다시 제출합니다.  
CloudFront는 HTTP에서 HTTPS로 `DELETE`, `OPTIONS`, `PATCH`, `POST` 또는 `PUT` 요청을 리디렉션하지 않습니다. HTTPS에 리디렉션할 캐시 동작을 구성하는 경우, CloudFront는 해당 캐시 동작에 대한 HTTP `DELETE`, `OPTIONS`, `PATCH`, `POST`, 또는 `PUT` 요청에 HTTP 상태 코드 403(금지됨)으로 응답합니다.
최종 사용자가 HTTPS 요청으로 리디렉션되는 HTTP 요청을 만들 경우 CloudFront에서 두 요청 모두에 대해 요금을 부과합니다. HTTP 요청의 경우에는 CloudFront에서 최종 사용자에게 반환되는 요청 및 헤더에만 요금이 부과됩니다. HTTPS 요청의 경우에는 요청, 헤더, 그리고 오리진에 의해 반환된 객체 모두에 요금이 부과됩니다.  
**HTTPS Only**  
최종 사용자가 HTTPS를 사용할 경우에만 콘텐츠에 액세스할 수 있습니다. 최종 사용자가 HTTPS 요청 대신에 HTTP 요청을 보내면 CloudFront는 HTTP 상태 코드 403(금지됨)을 반환하고 객체는 반환하지 않습니다.

1. **예, 편집합니다**를 선택합니다.

1. 최종 사용자와 CloudFront 간에 그리고 CloudFront와 S3 간에 HTTPS를 요구하려는 캐시 동작에 대해 3\$15단계를 반복합니다.

1. 업데이트한 구성을 프로덕션 환경에서 사용하기 전에 다음 사항을 확인합니다.
   + 각 캐시 동작의 경로 패턴이 최종 사용자에 HTTPS를 사용하도록 지정한 요청에만 적용되는가.
   + 캐시 동작이 CloudFront에서 평가하도록 할 순서대로 나열되었는가. 자세한 내용은 [경로 패턴](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern) 단원을 참조하세요.
   + 캐시 동작이 올바른 오리진에 요청을 라우팅하는가.

# 최종 사용자와 CloudFront 간에 지원되는 프로토콜 및 암호
<a name="secure-connections-supported-viewer-protocols-ciphers"></a>

[최종 사용자와 CloudFront 배포 간에 HTTPS가 필요](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy)한 경우 [보안 정책](DownloadDistValuesGeneral.md#DownloadDistValues-security-policy)을 선택해야 하며 이는 다음 설정을 결정합니다.
+ CloudFront가 최종 사용자와 통신하는 데 사용하는 최소 SSL/TLS 프로토콜.
+ CloudFront가 최종 사용자와의 통신을 암호화할 때 사용할 수 있는 암호

보안 정책을 선택하려면 [보안 정책(최소 SSL/TLS 버전)](DownloadDistValuesGeneral.md#DownloadDistValues-security-policy)에 해당 값을 지정합니다. 다음 표에는 CloudFront가 각 보안 정책에 사용할 수 있는 프로토콜 및 암호가 나와 있습니다.

최종 사용자는 지원되는 암호 중 하나 이상을 지원하여 CloudFront와의 HTTPS 연결을 설정해야 합니다. CloudFront에서는 최종 사용자가 지원하는 암호 중에서 나열된 순서대로 암호를 선택합니다. 또한 [OpenSSL, s2n 및 RFC 암호 이름](#secure-connections-openssl-rfc-cipher-names) 단원도 참조하십시오.


|  | 보안 정책 |  | SSLv3 | TLSv1 | TLSv1\$12016 | TLSv1.1\$12016 | TLSv1.2\$12018 | TLSv1.2\$12019 | TLSv1.2\$12021 | TLSv1.2\$12025 | TLSv1.3\$12025 | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| 지원되는 SSL/TLS 프로토콜 | 
| TLSv1.3 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLSv1.2 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| TLSv1.1 | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| TLSv1 | ♦ | ♦ | ♦ |  |  |  |  |  |  | 
| SSLv3 | ♦ |  |  |  |  |  |  |  |  | 
| 지원되는 TLSv1.3 암호 | 
| TLS\$1AES\$1128\$1GCM\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1AES\$1256\$1GCM\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1CHACHA20\$1POLY1305\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | ♦ | 
| 지원되는 ECDSA 암호 | 
| ECDHE-ECDSA-AES128-GCM-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-ECDSA-AES128-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-ECDSA-AES128-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| ECDHE-ECDSA-AES256-GCM-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-ECDSA-CHACHA20-POLY1305 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| ECDHE-ECDSA-AES256-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-ECDSA-AES256-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| 지원되는 RSA 암호 | 
| ECDHE-RSA-AES128-GCM-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-RSA-AES128-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-RSA-AES128-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| ECDHE-RSA-AES256-GCM-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-RSA-CHACHA20-POLY1305 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| ECDHE-RSA-AES256-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-RSA-AES256-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| AES128-GCM-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  |  | 
| AES256-GCM-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  |  | 
| AES128-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  |  | 
| AES256-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| AES128-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| DES-CBC3-SHA | ♦ | ♦ |  |  |  |  |  |  |  | 
| RC4-MD5 | ♦ |  |  |  |  |  |  |  |  | 

## OpenSSL, s2n 및 RFC 암호 이름
<a name="secure-connections-openssl-rfc-cipher-names"></a>

OpenSSL 및 [s2n](https://github.com/awslabs/s2n)은 TLS 표준에서 사용하는 암호 이름과 다른 이름을 사용합니다([RFC 2246](https://tools.ietf.org/html/rfc2246), [RFC 4346](https://tools.ietf.org/html/rfc4346), [RFC 5246](https://tools.ietf.org/html/rfc5246) 및 [RFC 8446](https://tools.ietf.org/html/rfc8446)). 다음 표에는 각 암호의 RFC 이름에 OpenSSL 및 s2n 이름이 매핑되어 있습니다.

CloudFront는 클래식 키 교환과 양자 보안 키 교환을 모두 지원합니다. 타원 곡선을 사용하는 클래식 키 교환의 경우 CloudFront는 다음을 지원합니다.
+ `prime256v1`
+ `X25519`
+ `secp384r1`

양자 보안 키 교환의 경우 CloudFront는 다음을 지원합니다.
+ `X25519MLKEM768`
+ `SecP256r1MLKEM768`
**참고**  
양자 보안 키 교환은 TLS 1.3에서만 지원됩니다. TLS 1.2 및 이전 버전은 양자 보안 키 교환을 지원하지 않습니다.

  자세한 내용은 다음 항목을 참조하세요.
  + [양자 내성 암호](https://aws.amazon.com/security/post-quantum-cryptography/)
  + [암호화 알고리즘 및 AWS 서비스](https://docs.aws.amazon.com/prescriptive-guidance/latest/encryption-best-practices/aws-cryptography-services.html#algorithms)
  + [TLS 1.3의 하이브리드 키 교환](https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/)

CloudFront의 인증서 요구 사항에 대한 자세한 내용은 [CloudFront에서 SSL/TLS 인증서를 사용하기 위한 요구 사항](cnames-and-https-requirements.md) 섹션을 참조하시기 바랍니다.


| OpenSSL 및 s2n 암호 이름 | RFC 암호화 이름 | 
| --- | --- | 
| 지원되는 TLSv1.3 암호 | 
| TLS\$1AES\$1128\$1GCM\$1SHA256 | TLS\$1AES\$1128\$1GCM\$1SHA256 | 
| TLS\$1AES\$1256\$1GCM\$1SHA384 | TLS\$1AES\$1256\$1GCM\$1SHA384 | 
| TLS\$1CHACHA20\$1POLY1305\$1SHA256 | TLS\$1CHACHA20\$1POLY1305\$1SHA256 | 
| 지원되는 ECDSA 암호 | 
| ECDHE-ECDSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| ECDHE-ECDSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| ECDHE-ECDSA-CHACHA20-POLY1305 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 | 
| ECDHE-ECDSA-AES256-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384 | 
| ECDHE-ECDSA-AES256-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| 지원되는 RSA 암호 | 
| ECDHE-RSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-RSA-AES128-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256  | 
| ECDHE-RSA-AES128-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| ECDHE-RSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384  | 
| ECDHE-RSA-CHACHA20-POLY1305 | TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 | 
| ECDHE-RSA-AES256-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384  | 
| ECDHE-RSA-AES256-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| AES128-GCM-SHA256 | TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| AES256-GCM-SHA384 | TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| AES128-SHA256 | TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| AES256-SHA | TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| AES128-SHA | TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| DES-CBC3-SHA  | TLS\$1RSA\$1WITH\$13DES\$1EDE\$1CBC\$1SHA  | 
| RC4-MD5 | TLS\$1RSA\$1WITH\$1RC4\$1128\$1MD5 | 

## 최종 사용자와 CloudFront 간에 지원되는 서명 체계
<a name="secure-connections-viewer-signature-schemes"></a>

CloudFront에서는 최종 사용자와 CloudFront 간의 연결을 위해 다음과 같은 서명 체계를 지원합니다.


|  | 보안 정책 | 서명 스키마 | SSLv3 | TLSv1 | TLSv1\$12016 | TLSv1.1\$12016 | TLSv1.2\$12018 | TLSv1.2\$12019 |  TLSv1.2\$12021 | TLSv1.2\$12025 | TLSv1.3\$12025 | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1PSS\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1PSS\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1PSS\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1RSAE\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1RSAE\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1RSAE\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA224 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA224 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SECP256R1\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SECP384R1\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA1 | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA1 | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 

# CloudFront와 오리진 간에 지원되는 프로토콜 및 암호
<a name="secure-connections-supported-ciphers-cloudfront-to-origin"></a>

[CloudFront와 오리진 간에 HTTPS 필요(require HTTPS between CloudFront and your origin)](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesOriginProtocolPolicy)를 선택하면 보안 연결을 [허용하기 위한 SSL/TLS 프로토콜](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesOriginSSLProtocols)을 결정할 수 있으며 CloudFront가 아래 표에 나열된 ECDSA 또는 RSA 암호를 사용하여 오리진에 연결할 수 있습니다. 오리진에 대해 HTTPS 연결을 설정하려면 오리진이 CloudFront에 대해 이들 암호 중 하나 이상을 지원해야 합니다.

OpenSSL 및 [s2n](https://github.com/awslabs/s2n)은 TLS 표준에서 사용하는 암호 이름과 다른 이름을 사용합니다([RFC 2246](https://tools.ietf.org/html/rfc2246), [RFC 4346](https://tools.ietf.org/html/rfc4346), [RFC 5246](https://tools.ietf.org/html/rfc5246) 및 [RFC 8446](https://tools.ietf.org/html/rfc8446)). 다음 표에는 각 암호의 OpenSSL 및 s2n 이름, RFC 이름이 포함되어 있습니다.

타원 곡선 키 교환 알고리즘이 포함된 암호의 경우 CloudFront는 다음과 같은 타원 곡선을 지원합니다.
+ prime256v1
+ secp384r1
+ X25519


| OpenSSL 및 s2n 암호 이름 | RFC 암호화 이름 | 
| --- | --- | 
| 지원되는 ECDSA 암호 | 
| ECDHE-ECDSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| ECDHE-ECDSA-AES256-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384 | 
| ECDHE-ECDSA-AES256-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| ECDHE-ECDSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| 지원되는 RSA 암호 | 
| ECDHE-RSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| ECDHE-RSA-AES256-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384 | 
| ECDHE-RSA-AES256-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| ECDHE-RSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-RSA-AES128-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| ECDHE-RSA-AES128-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| AES256-SHA | TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| AES128-SHA | TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| DES-CBC3-SHA | TLS\$1RSA\$1WITH\$13DES\$1EDE\$1CBC\$1SHA | 
| RC4-MD5 | TLS\$1RSA\$1WITH\$1RC4\$1128\$1MD5 | 

**CloudFront와 오리진 간에 지원되는 서명 체계**

CloudFront에서는 CloudFront와 오리진 간의 연결을 위해 다음과 같은 서명 체계를 지원합니다.
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA256
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA384
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA512
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA224
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA256
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA384
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA512
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA224
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA1
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA1

# 대체 도메인 이름과 HTTPS 사용
<a name="using-https-alternate-domain-names"></a>

파일의 URL에 자체 도메인 이름(예: `https://www.example.com/image.jpg`)을 사용하고 최종 사용자가 HTTPS를 사용하게 하려면 다음 주제에 나온 단계를 수행해야 합니다. (기본 CloudFront 배포 도메인 이름을 URL에 사용하는 경우에는(예: `https://d111111abcdef8.cloudfront.net/image.jpg`) [뷰어와 CloudFront 간의 통신에 HTTPS 요구](using-https-viewers-to-cloudfront.md) 주제의 지침을 따르세요.)

**중요**  
인증서를 배포에 추가하는 경우 CloudFront는 인증서를 모든 엣지 로케이션으로 즉시 전파합니다. 새 엣지 로케이션을 사용할 수 있게 되면 CloudFront에서는 인증서를 그러한 새 위치로도 전파합니다. CloudFront에서 인증서를 전파하는 엣지 로케이션을 제한할 수는 없습니다.

**Topics**
+ [CloudFront에서 HTTPS 요청을 제공하는 방식 선택](cnames-https-dedicated-ip-or-sni.md)
+ [CloudFront에서 SSL/TLS 인증서를 사용하기 위한 요구 사항](cnames-and-https-requirements.md)
+ [CloudFront에서 SSL/TLS 인증서 사용 시의 할당량(뷰어와 CloudFront 간의 HTTPS만 해당)](cnames-and-https-limits.md)
+ [대체 도메인 이름과 HTTPS 구성](cnames-and-https-procedures.md)
+ [SSL/TLS RSA 인증서에서 퍼블릭 키 크기 확인](cnames-and-https-size-of-public-key.md)
+ [SSL/TLS 인증서에 대한 할당량 증가](increasing-the-limit-for-ssl-tls-certificates.md)
+ [SSL/TLS 인증서 교체](cnames-and-https-rotate-certificates.md)
+ [사용자 지정 SSL/TLS 인증서에서 기본 CloudFront 인증서로 되돌리기](cnames-and-https-revert-to-cf-certificate.md)
+ [사용자 지정 SSL/TLS 인증서를 전용 IP 주소 사용에서 SNI 사용으로 전환](cnames-and-https-switch-dedicated-to-sni.md)

# CloudFront에서 HTTPS 요청을 제공하는 방식 선택
<a name="cnames-https-dedicated-ip-or-sni"></a>

최종 사용자가 HTTPS를 사용하고 파일에 대체 도메인 이름을 사용하게 하려면 CloudFront에서 HTTPS 요청을 제공하는 방식에 대해 다음 옵션 중 하나를 선택합니다.
+ [서버 이름 표시(SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) 사용 – 권장
+ 각 엣지 로케이션에서 전용 IP 주소 사용

이 단원에서는 각 옵션이 어떻게 작동하는지를 설명합니다.

## SNI를 사용하여 HTTPS 요청 제공(대부분 클라이언트에 적용)
<a name="cnames-https-sni"></a>

[서버 이름 표시(SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication)는 2010년 이후 출시된 브라우저와 클라이언트에서 지원되는 TLS 프로토콜의 확장 기능입니다. SNI를 사용하여 HTTPS 요청을 제공하도록 CloudFront를 구성한 경우, CloudFront에서는 대체 도메인 이름을 각 엣지 로케이션의 IP 주소와 연결합니다. 최종 사용자가 HTTPS 콘텐츠 요청을 제출하면 DNS는 이 요청을 올바른 엣지 로케이션의 IP 주소로 라우팅합니다. 도메인 이름의 IP 주소는 SSL/TLS 핸드셰이크 협상 중에 결정됩니다(IP 주소는 배포 전용이 아님).

HTTPS 연결 설정 과정 초기에 SSL/TLS 협상이 발생합니다. CloudFront에서 요청과 관련된 도메인을 즉시 확인할 수 없으면 연결이 끊어집니다. SNI를 지원하는 최종 사용자가 콘텐츠에 대해 HTTPS 요청을 전송할 경우 다음과 같은 작업이 수행됩니다.

1. 최종 사용자는 요청 URL에서 도메인 이름을 자동으로 가져와서 SNI 확장 또는 TLS 클라이언트 hello 메시지에 추가합니다.

1. CloudFront가 TLS 클라이언트 hello를 수신하면 SNI 확장의 도메인 이름을 사용하여 일치하는 CloudFront 배포를 찾고 연결된 TLS 인증서를 다시 보냅니다.

1. 최종 사용자와 CloudFront는 SSL/TLS 협상을 수행합니다.

1. CloudFront;가 요청된 콘텐츠를 최종 사용자에 반환합니다.

SNI를 지원하는 최신 브라우저 목록은 Wikipedia 항목인 [Server Name Indication](https://en.wikipedia.org/wiki/Server_Name_Indication)을 참조하세요.

SNI를 사용하고자 하지만 사용자 브라우저 중 일부에서 SNI가 지원되지 않는 경우 몇 가지 옵션 중 하나를 사용할 수 있습니다.
+ SNI 대신에 전용 IP 주소를 사용하여 HTTPS 요청을 제공하도록 CloudFront;를 구성합니다. 자세한 내용은 [전용 IP 주소를 사용하여 HTTPS 요청 제공(모든 클라이언트에 적용)](#cnames-https-dedicated-ip) 단원을 참조하세요.
+ 사용자 지정 인증서 대신에 CloudFront SSL/TLS 인증서를 사용합니다. 그러기 위해서는 파일에 대한 URL에서 배포의 CloudFront 도메인 이름을 사용해야 합니다. 예: `https://d111111abcdef8.cloudfront.net/logo.png`.

  기본 CloudFront 인증서를 사용할 경우 최종 사용자가 SSL 프로토콜 TLSv1 또는 그 이상 버전을 지원해야 합니다. CloudFront는 기본 CloudFront 인증서로 SSLv3를 지원하지 않습니다.

  또한 CloudFront에서 사용 중인 SSL/TLS 인증서를 사용자 지정 인증서에서 기본 CloudFront 인증서로 다음과 같이 변경해야 합니다.
  + 배포를 사용하여 콘텐츠를 배포하지 않은 경우에는 구성을 변경하면 됩니다. 자세한 내용은 [배포 업데이트](HowToUpdateDistribution.md) 단원을 참조하세요.
  + 배포를 사용하여 콘텐츠를 배포한 경우에는 새 CloudFront 배포를 생성하고 파일에 대한 URL을 변경하여 콘텐츠를 사용할 수 없는 시간을 줄이거나 없애야 합니다. 자세한 내용은 [사용자 지정 SSL/TLS 인증서에서 기본 CloudFront 인증서로 되돌리기](cnames-and-https-revert-to-cf-certificate.md) 단원을 참조하세요.
+ 사용자가 사용하는 브라우저를 개발자가 제어할 수 있는 경우 사용자가 해당 브라우저를 SNI가 지원되는 브라우저로 업그레이드하게 합니다.
+ HTTPS 대신에 HTTP를 사용합니다.

## 전용 IP 주소를 사용하여 HTTPS 요청 제공(모든 클라이언트에 적용)
<a name="cnames-https-dedicated-ip"></a>

서버 이름 표시(SNI)는 요청을 도메인과 연결하는 한 가지 방법입니다. 또 다른 방법으로는 전용 IP 주소 사용을 들 수 있습니다. 2010년 이후 출시 브라우저나 클라이언트로 업그레이드가 불가한 사용자가 있다면 전용 IP 주소를 사용하여 HTTPS 요청을 제공할 수 있습니다. SNI를 지원하는 최신 브라우저 목록은 Wikipedia 항목인 [Server Name Indication](https://en.wikipedia.org/wiki/Server_Name_Indication)을 참조하세요.

**중요**  
전용 IP 주소를 사용하여 HTTPS 요청을 제공하도록 CloudFront를 구성하면 추가 월별 요금이 발생합니다. 요금 발생은 SSL/TLS 인증서를 배포와 연결하고 배포를 활성화할 때 시작됩니다. CloudFront 요금에 대한 자세한 내용은 [Amazon CloudFront 요금](https://aws.amazon.com/cloudfront/pricing)을 참조하세요. 또한 [Using the Same Certificate for Multiple CloudFront Distributions](cnames-and-https-limits.md#cnames-and-https-same-certificate-multiple-distributions) 단원을 참조하세요.

전용 IP 주소를 사용하여 HTTPS 요청을 제공하도록 CloudFront를 구성한 경우 CloudFront에서는 인증서를 각 CloudFront 엣지 로케이션의 전용 IP 주소와 연결합니다. 최종 사용자가 콘텐츠에 대해 HTTPS 요청을 전송할 경우 다음과 같은 작업이 수행됩니다.

1. DNS에서 배포의 해당 엣지 로케이션에 대한 IP 주소로 요청을 라우팅합니다.

1. 클라이언트 요청이 `ClientHello` 메시지에 SNI 확장을 제공하는 경우 CloudFront는 해당 SNI와 연결된 배포를 검색합니다.
   + 일치하는 항목이 있는 경우 CloudFront는 SSL/TLS 인증서를 사용하여 요청에 응답합니다.
   + 일치하는 항목이 없는 경우, CloudFront에서는 대신 이 IP 주소를 사용하여 배포를 식별하고 최종 사용자에게 반환할 SSL/TLS 인증서를 결정합니다.

1. 최종 사용자와 CloudFront가 SSL/TLS 인증서를 사용하여 SSL/TLS 협상을 수행합니다.

1. CloudFront;가 요청된 콘텐츠를 최종 사용자에 반환합니다.

이 방법은 사용자가 사용 중인 브라우저나 기타 최종 사용자와 상관없이 모든 HTTPS 요청에 작동합니다.

**참고**  
전용 IP는 고정 IP가 아니며 시간이 지남에 따라 변경될 수 있습니다. 엣지 로케이션에 대해 반환되는 IP 주소는 [CloudFront 엣지 서버 목록](LocationsOfEdgeServers.md)의 IP 주소 범위에서 동적으로 할당됩니다.  
CloudFront 엣지 서버의 IP 주소 범위는 변경될 수 있습니다. IP 주소 변경 사항에 대한 알림을 받으려면 [Amazon SNS를 통해 AWS 퍼블릭 IP 주소 변경 사항을 구독](https://aws.amazon.com/blogs/aws/subscribe-to-aws-public-ip-address-changes-via-amazon-sns/)하세요.

## 3개 이상의 전용 IP SSL/TLS 인증서를 사용할 수 있는 권한 요청
<a name="cnames-and-https-multiple-certificates"></a>

CloudFront에 3개 이상의 SSL/TLS 전용 IP 인증서를 영구적으로 연결할 수 있는 권한이 필요할 경우 다음과 같이 합니다. HTTPS 요청에 대한 자세한 내용은 [CloudFront에서 HTTPS 요청을 제공하는 방식 선택](#cnames-https-dedicated-ip-or-sni) 단원을 참조하세요.

**참고**  
이 절차는 CloudFront 배포에 3개 이상의 전용 IP 인증서를 사용하는 경우에 사용됩니다. 기본값은 2입니다. 배포에 2개 이상의 SSL 인증서를 바인딩할 수 없다는 점에 유의하세요.  
한 번에 하나의 SSL/TLS 인증서만 CloudFront 배포에 연결할 수 있습니다. 이 수치는 모든 CloudFront 배포에서 사용할 수 있는 전용 IP SSL 인증서의 총 개수에 해당됩니다.<a name="cnames-and-https-multiple-certificates-procedure"></a>

**CloudFront 배포에 3개 이상의 인증서를 사용할 수 있는 권한을 요청하려면**

1. [지원 센터](https://console.aws.amazon.com/support/home?#/case/create?issueType=service-limit-increase&limitType=service-code-cloudfront-distributions)로 이동하여 사례를 생성합니다.

1. 사용 권한이 필요한 인증서 수를 지정하고 요청 상황을 설명하세요. 그러고 나면 귀하의 계정을 가능한 빨리 업데이트하겠습니다.

1. 다음 절차로 진행합니다.

# CloudFront에서 SSL/TLS 인증서를 사용하기 위한 요구 사항
<a name="cnames-and-https-requirements"></a>

SSL/TLS 인증서에 대한 요구 사항은 이 주제에 설명되어 있습니다. 별도로 명시되지 않는 한, 다음 두 가지에 모두 적용됩니다.
+ 최종 사용자와 CloudFront 간에 HTTPS를 사용하기 위한 인증서 
+ CloudFront와 오리진 간에 HTTPS를 사용하기 위한 인증서

**Topics**
+ [인증서 발행자](#https-requirements-certificate-issuer)
+ [AWS 리전 for AWS Certificate Manager](#https-requirements-aws-region)
+ [인증서 형식](#https-requirements-certificate-format)
+ [중간 인증서](#https-requirements-intermediate-certificates)
+ [키 유형](#https-requirements-key-type)
+ [프라이빗 키](#https-requirements-private-key)
+ [권한](#https-requirements-permissions)
+ [인증서 키의 크기](#https-requirements-size-of-public-key)
+ [지원되는 인증서 유형](#https-requirements-supported-types)
+ [인증서 만료 날짜 및 갱신](#https-requirements-cert-expiration)
+ [CloudFront 배포 및 인증서의 도메인 이름](#https-requirements-domain-names-in-cert)
+ [최소 SSL/TLS 프로토콜 버전](#https-requirements-minimum-ssl-protocol-version)
+ [지원되는 HTTP 버전](#https-requirements-supported-http-versions)

## 인증서 발행자
<a name="https-requirements-certificate-issuer"></a>

[AWS Certificate Manager(ACM)](https://aws.amazon.com/certificate-manager/)에서 발급된 퍼블릭 인증서를 사용하는 것이 좋습니다. ACM에서 인증서를 받는 방법에 대한 자세한 내용은 *[AWS Certificate Manager 사용 설명서](https://docs.aws.amazon.com/acm/latest/userguide/)*를 참조하세요. CloudFront 배포에서 ACM 인증서를 사용하려면 미국 동부(버지니아 북부) 리전(`us-east-1`)에서 인증서를 요청하거나 가져와야 합니다.

 CloudFront는 Mozilla와 동일한 인증 기관(CA)를 지원하므로 ACM을 사용하지 않는 경우[Mozilla Included CA Certificate List](https://wiki.mozilla.org/CA/Included_Certificates)에 등록된 CA에서 발행한 인증서를 사용하세요.

CloudFront 배포에 지정한 오리진에서 사용하는 TLS 인증서도 Mozilla 포함 CA 인증서 목록의 CA에서 발급해야 합니다.

인증서 가져오기 및 설치에 대한 자세한 내용은 HTTP 서버 소프트웨어 설명서와 CA 설명서를 참조하세요.

## AWS 리전 for AWS Certificate Manager
<a name="https-requirements-aws-region"></a>

최종 사용자와 CloudFront 간에 HTTPS를 요구하기 위해 AWS Certificate Manager(ACM) 인증서를 사용하려면 미국 동부(버지니아 북부) 리전(`us-east-1`)에서 인증서를 요청하거나 가져와야 합니다.

CloudFront와 오리진 간에 HTTPS가 필요하고 오리진으로 Elastic Load Balancing 로드 밸런서를 사용하는 경우 모든 AWS 리전에서 인증서를 요청하거나 가져올 수 있습니다.

## 인증서 형식
<a name="https-requirements-certificate-format"></a>

인증서는 X.509 PEM 형식이어야 합니다. AWS Certificate Manager를 사용할 경우 이 형식이 기본 형식입니다.

## 중간 인증서
<a name="https-requirements-intermediate-certificates"></a>

서드 파티 인증 기관(CA)을 사용할 경우, 도메인 인증서에 서명한 CA 관련 인증서부터, `.pem` 파일에 있는 인증서 체인의 모든 중간 인증서를 나열합니다. 일반적으로 올바른 체인 순서대로 중간 및 루트 인증서를 나열하는 파일이 CA 웹 사이트에 있습니다.

**중요**  
루트 인증서, 신뢰 경로에 없는 중간 인증서 또는 CA의 퍼블릭 키 인증서는 포함하지 마세요.

다음은 그 예입니다:

```
-----BEGIN CERTIFICATE-----
Intermediate certificate 2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
Intermediate certificate 1
-----END CERTIFICATE-----
```

## 키 유형
<a name="https-requirements-key-type"></a>

CloudFront는 RSA 및 ECDSA 퍼블릭/프라이빗 키 페어를 지원합니다.

CloudFront는 RSA 및 ECDSA 인증서를 사용하여 최종 사용자와 오리진 모두에 대한 HTTPS 연결을 지원합니다. [AWS Certificate Manager(ACM)](https://console.aws.amazon.com/acm)을 사용하면 RSA 인증서 및 ECDSA 인증서를 요청하고 가져올 수 있으며 그 다음 CloudFront 배포와 연결할 수 있습니다.

HTTPS 연결에서 협상할 수 있는 RSA 및 ECDSA 암호 목록(CloudFront 지원)은 [최종 사용자와 CloudFront 간에 지원되는 프로토콜 및 암호](secure-connections-supported-viewer-protocols-ciphers.md) 및 [CloudFront와 오리진 간에 지원되는 프로토콜 및 암호](secure-connections-supported-ciphers-cloudfront-to-origin.md) 단원을 참조하세요.

## 프라이빗 키
<a name="https-requirements-private-key"></a>

다른 인증 기관(CA)의 인증서를 사용할 경우 다음 사항에 유의하세요.
+ 프라이빗 키는 인증서에 있는 퍼블릭 키와 일치해야 합니다.
+ 프라이빗 키는 PEM 형식이어야 합니다.
+ 프라이빗 키는 암호로 암호화할 수 없습니다.

AWS Certificate Manager(ACM)에서 인증서를 제공할 경우 ACM은 프라이빗 키를 공개하지 않습니다. 이 프라이빗 키는 ACM과 통합된 AWS 서비스에서 사용하기 위해 ACM에 저장됩니다.

## 권한
<a name="https-requirements-permissions"></a>

SSL/TLS 인증서를 사용하고 가져올 수 있는 권한이 있어야 합니다. AWS Certificate Manager(ACM)를 사용하는 경우, AWS Identity and Access Management 권한을 사용하여 인증서에 대한 액세스를 제한하는 것이 좋습니다. 자세한 내용은 *AWS Certificate Manager 사용 설명서*에서 [자격 증명 및 액세스 관리](https://docs.aws.amazon.com/acm/latest/userguide/security-iam.html)를 참조하세요.

## 인증서 키의 크기
<a name="https-requirements-size-of-public-key"></a>

CloudFront에서 지원하는 인증서 키 크기는 키 및 인증서 유형에 따라 다릅니다.

**RSA 인증서의 경우:**  
CloudFront가 1,024비트, 2,048비트, 3,072비트, 4,096비트 RSA 키를 지원합니다. CloudFront에서 사용하는 RSA 인증서의 최대 키 길이는 4,096비트입니다.  
 참고로 ACM은 최대 2048비트 키로 RSA 인증서를 발급합니다. 3,072비트 또는 4,096비트 RSA 인증서를 사용하려면 인증서를 외부에서 얻어 ACM으로 가져와야 합니다. 그러면 CloudFront에서 사용할 수 있습니다.  
RSA 키의 크기를 확인하는 방법에 대한 자세한 내용은 [SSL/TLS RSA 인증서에서 퍼블릭 키 크기 확인](cnames-and-https-size-of-public-key.md) 단원을 참조하세요.

**ECDSA 인증서의 경우:**  
CloudFront는 256비트 키를 지원합니다. 최종 사용자와 CloudFront 간에 HTTPS를 요구하기 위해 ACM의 ECDSA 인증서를 사용하려면 prime256v1 타원 곡선을 사용합니다.

## 지원되는 인증서 유형
<a name="https-requirements-supported-types"></a>

CloudFront는 신뢰할 수 있는 인증 기관에서 발급한 모든 유형의 인증서를 지원합니다.

## 인증서 만료 날짜 및 갱신
<a name="https-requirements-cert-expiration"></a>

서드 파티 인증 기관(CA)에서 받은 인증서를 사용할 경우, 인증서 만료 날짜를 직접 모니터링하여 인증서가 만료되기 전에 AWS Certificate Manager(ACM)에 가져온 인증서를 갱신하거나 AWS Identity and Access Management 인증서 스토어에 업로드해야 합니다.

**중요**  
인증서 만료 문제를 방지하려면 현재 인증서의 `NotAfter` 값보다 최소 24시간 전에 인증서를 갱신하거나 다시 가져옵니다. 인증서가 24시간 이내에 만료되는 경우 ACM에서 새 인증서를 요청하거나 ACM으로 새 인증서를 가져옵니다. 그런 다음 새 인증서를 CloudFront 배포에 연결합니다.  
인증서 갱신 또는 다시 가져오기가 진행되는 동안 CloudFront에서 이전 인증서를 계속 사용할 수 있습니다. 이는 CloudFront에서 변경 사항을 표시하기까지 최대 24시간이 걸릴 수 있는 비동기 프로세스입니다.

ACM에서 제공한 인증서를 사용할 경우 ACM에서 인증서 갱신을 관리해 줍니다. 자세한 내용은 *AWS Certificate Manager 사용 설명서*에서 [관리형 갱신](https://docs.aws.amazon.com/acm/latest/userguide/managed-renewal.html)을 참조하세요.

## CloudFront 배포 및 인증서의 도메인 이름
<a name="https-requirements-domain-names-in-cert"></a>

사용자 지정 오리진을 사용하는 경우 오리진의 SSL/TLS 인증서에는 **일반 이름(Common Name)** 필드에 도메인 이름이 포함되며 **대체 도메인 이름(Subject Alternative Names)** 필드에도 몇 번 더 포함될 수 있습니다. CloudFront는 인증서 도메인 이름 내 와일드카드 문자 사용을 지원합니다.

인증서의 도메인 이름 중 하나는 오리진 도메인 이름으로 지정하는 도메인 이름과 일치해야 합니다. 일치하는 도메인 이름이 없는 경우 CloudFront는 최종 사용자에게 HTTP 상태 코드 `502 (Bad Gateway)`를 반환합니다.

**중요**  
배포에 대체 도메인 이름을 추가하면, CloudFront는 해당 대체 도메인 이름이 연결한 인증서에 포함되어 있는지 확인합니다. 인증서의 SAN(주체 대체 이름) 필드에 대체 도메인 이름이 있어야 합니다. 즉, SAN 필드에는 대체 도메인 이름과 정확히 일치하는 항목이 포함되거나 추가할 대체 도메인 이름과 동일한 수준에서 와일드카드가 포함되어야 합니다.  
자세한 내용은 [대체 도메인 이름 사용과 관련된 요구 사항](CNAMEs.md#alternate-domain-names-requirements) 섹션을 참조하세요.

## 최소 SSL/TLS 프로토콜 버전
<a name="https-requirements-minimum-ssl-protocol-version"></a>

전용 IP 주소를 사용할 경우 보안 정책을 선택하여 최종 사용자와 CloudFront 간의 연결을 위한 최소 SSL/TLS 프로토콜 버전을 설정합니다.

자세한 내용은 [모든 배포 설정 참조](distribution-web-values-specify.md) 주제에서 [보안 정책(최소 SSL/TLS 버전)](DownloadDistValuesGeneral.md#DownloadDistValues-security-policy) 단원을 참조하세요.

## 지원되는 HTTP 버전
<a name="https-requirements-supported-http-versions"></a>

한 인증서를 둘 이상의 CloudFront 배포와 연결하는 경우, 인증서와 연결된 모든 배포에서 [지원되는 HTTP 버전](DownloadDistValuesGeneral.md#DownloadDistValuesSupportedHTTPVersions)에 대해 동일한 옵션을 사용해야 합니다. CloudFront 배포를 생성 또는 업데이트할 때 이 옵션을 지정합니다.

# CloudFront에서 SSL/TLS 인증서 사용 시의 할당량(뷰어와 CloudFront 간의 HTTPS만 해당)
<a name="cnames-and-https-limits"></a>

CloudFront에서 SSL/TLS 인증서 사용 시 다음 할당량에 유의하시기 바랍니다. 이러한 할당량은 AWS Certificate Manager(ACM)를 사용하여 프로비저닝하거나, ACM으로 가져오거나, 뷰어와 CloudFront 간의 HTTPS 통신을 위해 IAM 인증서 스토어에 업로드하는 SSL/TLS 인증서에만 적용됩니다.

자세한 내용은 [SSL/TLS 인증서에 대한 할당량 증가](increasing-the-limit-for-ssl-tls-certificates.md) 섹션을 참조하세요.

**CloudFront 배포당 최대 인증서 수**  
각 CloudFront 배포에 최대 한 개의 SSL/TLS 인증서를 연결할 수 있습니다.

**ACM으로 가져오거나 IAM 인증서 스토어로 업로드할 수 있는 인증서의 최대 수**  
서드 파티 인증 기관에서 SSL/TLS 인증서를 구입한 경우 다음 위치 중 하나에 인증서를 저장해야 합니다.  
+ **AWS Certificate Manager** – ACM 인증서 수의 현재 할당량은 *AWS Certificate Manager 사용 설명서*의 [할당량](https://docs.aws.amazon.com/acm/latest/userguide/acm-limits.html)을 참조하세요. 명시된 할당량은 ACM을 사용하여 프로비저닝한 인증서와 ACM으로 가져온 인증서를 모두 포함한 총 개수입니다.
+ **IAM 인증서 스토어** – 하나의 AWS 계정에서 IAM 인증서 스토어에 업로드할 수 있는 인증서 수의 현재 할당량(이전에는 제한이라고 함)은 *IAM 사용 설명서*의 [IAM 및 STS 제한](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html)을 참조하세요. Service Quotas 콘솔을 사용하여 더 높은 할당량을 요청할 수 있습니다.

**AWS 계정당 인증서 최대 수(전용 IP 주소만 해당)**  
전용 IP 주소를 사용하여 HTTPS 요청을 처리하려는 경우 다음 사항에 유의하세요.  
+ 기본적으로 CloudFront는 AWS 계정에 두 인증서를 사용할 수 있는 권한(일일 사용을 위한 인증서와 여러 배포용으로 인증서를 교체해야 할 때 사용할 인증서)을 부여합니다.
+ AWS 계정에 사용자 지정 SSL/TLS 인증서가 두 개 이상 필요한 경우 Service Quotas 콘솔에서 더 높은 할당량을 요청할 수 있습니다.

**다른 AWS 계정을 사용하여 생성된 CloudFront 배포에 동일한 인증서 사용**  
다른 인증 기관을 사용할 경우 그리고 서로 다른 AWS 계정으로 생성된 여러 CloudFront 배포에서 동일한 인증서를 사용하려면 각 AWS 계정마다 한 번씩 해당 인증서를 ACM으로 가져오거나 IAM 인증서 스토어로 업로드해야 합니다.  
ACM에서 제공한 인증서를 사용하는 경우, 다른 AWS 계정이 생성한 인증서를 사용하도록 CloudFront를 구성할 수 없습니다.

**CloudFront 및 다른 AWS 서비스에 동일한 인증서 사용**  
신뢰할 수 있는 인증 기관(예: Comodo, DigiCert, Symantec 등)에서 인증서를 구입한 경우, CloudFront 및 기타 AWS 서비스에서 동일한 인증서를 사용할 수 있습니다. ACM으로 인증서를 가져올 경우 한 번만 가져와서 여러 AWS 서비스에 사용해야 합니다.  
ACM에서 제공한 인증서를 사용할 경우 인증서가 ACM에 저장됩니다.

**다중 CloudFront 배포에 동일한 인증서 사용**  
HTTPS 요청을 처리하는 데 사용하는 임의의 또는 모든 CloudFront 배포에서 동일한 인증서를 사용할 수 있습니다. 다음을 참조하세요.  
+ 전용 IP 주소를 사용한 요청 제공과 SNI를 사용한 요청 제공에 동일한 인증서를 사용할 수 있습니다.
+ 단 한 개의 인증서를 각각의 배포와 연결할 수 있습니다.
+ 각각의 배포에 하나 이상의 대체 도메인 이름이 포함되어야 하며, 이 이름은 인증서의 **Common Name(일반 이름)** 필드나 **Subject Alternative Names(주체 대체 이름)** 필드에도 표시됩니다.
+ 전용 IP 주소를 사용하여 HTTPS 요청을 제공하고 동일한 AWS 계정을 사용해 모든 배포를 생성한 경우, 모든 배포에 동일한 인증서를 사용함으로써 비용을 크게 절감할 수 있습니다. CloudFront는 배포가 아닌 인증서별로 요금을 청구합니다.

  예를 들어, 동일한 AWS 계정을 사용하여 세 개의 배포를 생성하고, 이 세 개의 배포에 모두 동일한 인증서를 사용한다고 가정하겠습니다. 이 경우, 전용 IP 주소 사용에 대한 단 한 건의 수수료만 청구됩니다.

  하지만 전용 IP 주소를 사용하여 HTTPS 요청을 제공하고 서로 다른 AWS 계정에서 동일한 인증서를 사용해 CloudFront 배포를 생성할 경우, 각각의 계정에 전용 IP 주소 사용에 대한 요금이 청구됩니다. 예를 들어, 세 개의 AWS 계정을 사용하여 세 개의 배포를 생성하고 이 세 배포에 동일한 인증서를 사용할 경우, 각 계정에 전용 IP 주소 사용에 대한 수수료 전액이 청구됩니다.

# 대체 도메인 이름과 HTTPS 구성
<a name="cnames-and-https-procedures"></a>

파일의 URL에 대체 도메인 이름을 사용하고, 최종 사용자와 CloudFront 간에 HTTPS를 사용하려면 해당 절차를 수행합니다.

**Topics**
+ [SSL/TLS 인증서 받기](#cnames-and-https-getting-certificates)
+ [SSL/TLS 인증서 가져오기](#cnames-and-https-uploading-certificates)
+ [CloudFront 배포 업데이트](#cnames-and-https-updating-cloudfront)

## SSL/TLS 인증서 받기
<a name="cnames-and-https-getting-certificates"></a>

SSL/TLS 인증서를 받습니다(아직 없는 경우). 자세한 내용은 다음과 같이 해당 문서를 참조하세요.
+ AWS Certificate Manager(ACM)에서 제공하는 인증서를 사용하려면 [AWS Certificate Manager 사용 설명서](https://docs.aws.amazon.com/acm/latest/userguide/)를 참조하세요. [CloudFront 배포 업데이트](#cnames-and-https-updating-cloudfront) 단원을 참조하세요.
**참고**  
AWS 관리형 리소스에 대해 SSL/TLS 인증서를 프로비저닝 및 관리하고 배포할 때 ACM을 사용하는 것이 좋습니다. 미국 동부(버지니아 북부) 리전에서 ACM 인증서를 요청해야 합니다.
+ 다른 인증 기관(CA)의 인증서를 받으려면 인증 기관에서 제공한 설명서를 참조하세요. 인증서가 있으면 다음 절차로 진행합니다.

## SSL/TLS 인증서 가져오기
<a name="cnames-and-https-uploading-certificates"></a>

다른 인증 기관의 인증서를 받았을 경우 ACM으로 가져오거나 IAM 인증서 스토어에 업로드합니다.

**ACM(권장)**  
ACM에서 ACM 콘솔을 사용하거나 프로그래밍 방식으로 타사 인증서를 가져올 수 있습니다. 인증서를 ACM으로 가져오는 방법에 대한 자세한 내용은 *AWS Certificate Manager 사용 설명서*의 [AWS Certificate Manager로 인증서 가져오기](https://docs.aws.amazon.com/acm/latest/userguide/import-certificate.html) 섹션을 참조하세요. 미국 동부(버지니아 북부) 리전에서 인증서를 가져와야 합니다.

**IAM 인증서 스토어**  
(권장하지 않음) 다음 AWS CLI 명령을 사용하여 서드 파티 인증서를 IAM 인증서 스토어에 업로드합니다.  

```
aws iam upload-server-certificate \
        --server-certificate-name CertificateName \
        --certificate-body file://public_key_certificate_file \
        --private-key file://privatekey.pem \
        --certificate-chain file://certificate_chain_file \
        --path /cloudfront/path/
```
다음을 참조하세요.  
+ **AWS 계정** – CloudFront 배포를 생성하는 데 사용한 것과 동일한 AWS 계정을 사용하여 인증서를 IAM 인증서 스토어로 업로드해야 합니다.
+ **--path 파라미터** – 인증서를 IAM으로 업로드할 때 `--path` 파라미터(인증서 경로) 값은 `/cloudfront/`로 시작해야 합니다(예: `/cloudfront/production/` 또는 `/cloudfront/test/`). 경로는 /로 끝나야 합니다.
+ **기존 인증서** – `--server-certificate-name` 및 `--path` 파라미터에, 기존 인증서와 연결되어 있는 값과 다른 값을 지정해야 합니다.
+ **CloudFront 콘솔 사용** – AWS CLI에서 `--server-certificate-name` 파라미터에 지정하는 값(예: `myServerCertificate`)은 CloudFront 콘솔의 **SSL 인증서** 목록에 나타납니다.
+ **CloudFront API 사용** – AWS CLI에서 반환하는 영숫자 문자열(예:`AS1A2M3P4L5E67SIIXR3J`)을 메모해 둡니다. 이 문자열은 `IAMCertificateId` 요소에서 지정하는 값입니다. IAM ARN은 필요하지 않습니다. CLI에서도 반환되기 때문입니다.
AWS CLI에 대한 자세한 내용은 [AWS Command Line Interface 사용 설명서](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html) 및 [AWS CLI 명령 참조](https://docs.aws.amazon.com/cli/latest/reference/)를 참조하세요.

## CloudFront 배포 업데이트
<a name="cnames-and-https-updating-cloudfront"></a>

배포의 설정을 업데이트하려면 다음과 같이 합니다.<a name="cnames-and-https-updating-cloudfront-procedure"></a>

**대체 도메인 이름을 사용하도록 CloudFront 배포를 구성하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 업데이트하려는 배포의 ID를 선택합니다.

1. [**General**] 탭에서 [**Edit**]를 선택합니다.

1. 다음 값을 업데이트합니다.  
**대체 도메인 이름(CNAME)(Alternate domain names(CNAME))**  
**항목 추가**를 선택하여 해당 대체 도메인 이름을 추가합니다. 도메인 이름을 쉼표로 구분하거나 각각의 이름을 새 줄에 입력합니다.  
**Custom SSL Certificate(사용자 정의 SSL 인증서)**  
드롭다운 목록에서 인증서를 선택합니다.  
최대 100개의 인증서가 여기에 나열됩니다. 100개 이상의 인증서가 있고 추가할 인증서가 보이지 않는 경우에는 해당 필드에 인증서 ARN을 입력하여 선택할 수 있습니다.  
IAM 인증서 스토어에 인증서를 업로드했는데 목록에 나타나지 않아서 필드에 이름을 입력하는 방법으로 선택을 할 수 없는 경우에는 [SSL/TLS 인증서 가져오기](#cnames-and-https-uploading-certificates) 절차를 검토하여 인증서를 올바르게 업로드했는지 확인합니다.  
SSL/TLS 인증서를 CloudFront 배포와 연결한 후에 모든 배포에서 인증서를 제거하고 모든 배포판이 배포될 때까지 ACM 또는 IAM 인증서 스토어에서 인증서를 삭제하지 않습니다.

1. **변경 사항 저장**을 선택합니다.

1. CloudFront에서 최종 사용자와 CloudFront 간에 HTTPS를 요구하도록 구성:

   1. **동작** 탭에서 업데이트할 캐시 동작을 선택하고 **편집**을 선택합니다.

   1. **Viewer Protocol Policy**(최종 사용자 프로토콜 정책)에 다음 값 중 하나를 지정합니다.  
**Redirect HTTP to HTTPS**  
최종 사용자가 두 프로토콜 모두 사용할 수 있지만, HTTP 요청은 자동으로 HTTPS 요청으로 리디렉션됩니다. CloudFront는 HTTP 상태 코드 `301 (Moved Permanently)`을 새로운 HTTPS URL과 함께 반환합니다. 그러면 최종 사용자는 HTTPS URL을 사용하여 이 요청을 CloudFront에 다시 제출합니다.  
CloudFront는 HTTP에서 HTTPS로 `DELETE`, `OPTIONS`, `PATCH`, `POST` 또는 `PUT` 요청을 리디렉션하지 않습니다. HTTPS에 리디렉션할 캐시 동작을 구성하는 경우, CloudFront는 해당 캐시 동작에 대한 HTTP `DELETE`, `OPTIONS`, `PATCH`, `POST`, 또는 `PUT` 요청에 HTTP 상태 코드 `403 (Forbidden)`으로 응답합니다.
최종 사용자가 HTTPS 요청으로 리디렉션되는 HTTP 요청을 만들 경우 CloudFront에서 두 요청 모두에 대해 요금을 부과합니다. HTTP 요청의 경우에는 CloudFront에서 최종 사용자에게 반환되는 요청 및 헤더에만 요금이 부과됩니다. HTTPS 요청의 경우에는 요청, 헤더, 그리고 오리진에 의해 반환된 파일을 모두 처리합니다.  
**HTTPS Only**  
최종 사용자가 HTTPS를 사용할 경우에만 콘텐츠에 액세스할 수 있습니다. 최종 사용자가 HTTPS 요청 대신에 HTTP 요청을 보내면 CloudFront는 HTTP 상태 코드 `403 (Forbidden)`을 반환하고 파일은 반환하지 않습니다.

   1. **예, 편집합니다**를 선택합니다.

   1. 최종 사용자와 CloudFront 간에 HTTPS를 요구하려는 추가적인 캐시 동작 각각에 대해 단계 a부터 c까지 반복합니다.

1. 업데이트한 구성을 프로덕션 환경에서 사용하기 전에 다음 사항을 확인합니다.
   + 각 캐시 동작의 경로 패턴이 최종 사용자에 HTTPS를 사용하도록 지정한 요청에만 적용되는가.
   + 캐시 동작이 CloudFront에서 평가하도록 할 순서대로 나열되었는가. 자세한 내용은 [경로 패턴](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern) 단원을 참조하세요.
   + 캐시 동작이 올바른 오리진에 요청을 라우팅하는가.

# SSL/TLS RSA 인증서에서 퍼블릭 키 크기 확인
<a name="cnames-and-https-size-of-public-key"></a>

CloudFront 대체 도메인 이름 및 HTTPS를 사용하는 경우, SSL/TLS RSA 인증서 퍼블릭 키의 최대 크기는 4,096비트입니다. (이는 퍼블릭 키의 문자 수가 아니라 키 크기입니다.) 인증서에서 AWS Certificate Manager를 사용하는 경우에는 ACM이 더 큰 RSA 키를 지원하더라도 CloudFront에서 더 큰 키를 사용할 수 없습니다.

다음 OpenSSL 명령을 실행하여 RSA 퍼블릭 키의 크기를 확인할 수 있습니다.

```
openssl x509 -in path and filename of SSL/TLS certificate -text -noout 
```

여기서 각 항목은 다음과 같습니다.
+ `-in`은 SSL/TLS RSA 인증서의 경로 및 파일 이름을 지정합니다.
+ `-text`를 지정하면 OpenSSL에서 RSA 퍼블릭 키 길이를 비트로 표시합니다.
+ `-noout`를 지정하면 OpenSSL에서 퍼블릭 키가 표시되지 않습니다.

출력 예:

```
Public-Key: (2048 bit)
```

# SSL/TLS 인증서에 대한 할당량 증가
<a name="increasing-the-limit-for-ssl-tls-certificates"></a>

AWS Certificate Manager(ACM)로 가져오거나 AWS Identity and Access Management(IAM)에 업로드할 수 있는 SSL/TLS 인증서 수에는 할당량이 있습니다. 또한 전용 IP 주소를 사용하여 HTTPS 요청을 제공하도록 CloudFront를 구성할 경우 AWS 계정에서 사용할 수 있는 SSL/TLS 인증서 개수에도 할당량이 있습니다. 하지만 더 높은 할당량을 요청할 수 있습니다.

**Topics**
+ [ACM으로 가져오는 인증서의 할당량 증가](#certificates-to-import-into-acm)
+ [IAM에 업로드하는 인증서의 할당량 늘리기](#certificates-to-upload-into-iam)
+ [전용 IP 주소와 함께 사용되는 인증서의 할당량 증가](#certificates-using-dedicated-ip-address)

## ACM으로 가져오는 인증서의 할당량 증가
<a name="certificates-to-import-into-acm"></a>

ACM으로 가져올 수 있는 인증서 개수에 대한 할당량은 *AWS Certificate Manager 사용 설명서*의 [할당량](https://docs.aws.amazon.com/acm/latest/userguide/acm-limits.html)을 참조하세요.

더 높은 할당량을 요청하려면 Service Quotas 콘솔을 사용하세요. 자세한 내용은* Service Quotas 사용 설명서*의 [할당량 증가 요청](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html)을 참조하세요.

## IAM에 업로드하는 인증서의 할당량 늘리기
<a name="certificates-to-upload-into-iam"></a>

IAM에 업로드할 수 있는 인증서 개수에 대한 할당량(이전에는 제한이라고 함)은 *IAM 사용 설명서*의 [IAM 및 STS 제한](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html)을 참조하세요.

더 높은 할당량을 요청하려면 Service Quotas 콘솔을 사용하세요. 자세한 내용은* Service Quotas 사용 설명서*의 [할당량 증가 요청](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html)을 참조하세요.

## 전용 IP 주소와 함께 사용되는 인증서의 할당량 증가
<a name="certificates-using-dedicated-ip-address"></a>

전용 IP 주소를 사용하여 HTTPS 요청을 제공할 경우 각 AWS 계정에서 사용할 수 있는 SSL 인증서 개수에 대한 할당량은 [SSL 인증서의 할당량](cloudfront-limits.md#limits-ssl-certificates) 섹션을 참조하세요.

더 높은 할당량을 요청하려면 Service Quotas 콘솔을 사용하세요. 자세한 내용은* Service Quotas 사용 설명서*의 [할당량 증가 요청](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html)을 참조하세요.

# SSL/TLS 인증서 교체
<a name="cnames-and-https-rotate-certificates"></a>

SSL/TLS 인증서가 만료될 때 배포의 보안을 보장하고 뷰어의 서비스 중단을 방지하려면 인증서를 교체해야 합니다. 다음과 같은 방법으로 인증서를 교체할 수 있습니다.
+ AWS Certificate Manager(ACM)에서 제공하는 SSL/TLS 인증서의 경우 인증서를 교체할 필요가 없습니다. ACM에서 *자동으로* 인증서 갱신을 관리합니다. 자세한 내용은 *AWS Certificate Manager 사용 설명서*의 [Managed certificate renewal](https://docs.aws.amazon.com/acm/latest/userguide/acm-renewal.html)을 참조하시기 바랍니다.
+ 서드 파티 인증 기관을 사용하여 인증서를 ACM으로 가져오거나(권장) IAM 인증서 스토어에 업로드한 경우 필요에 따라 인증서를 교체해야 합니다.

  

**중요**  
ACM은 서드 파티 인증 기관에서 확보하여 ACM으로 가져온 인증서에 대해서는 갱신을 관리하지 않습니다.
전용 IP 주소를 사용하여 HTTPS 요청을 제공하도록 CloudFront를 구성한 경우 인증서를 교체하는 동안은 하나 이상의 추가 인증서 사용에 대한 비례 할당으로 계산된 추가 요금이 발생할 수 있습니다. 추가 요금을 최소화하기 위해 배포를 업데이트할 것을 권장합니다.

## SSL/TLS 인증서 교체
<a name="rotate-ssl-tls-certificate"></a>

인증서를 교체하려면 다음 절차를 수행합니다. 최종 사용자는 인증서를 교체하는 동안은 물론, 프로세스가 완료된 후에도 콘텐츠에 계속 액세스할 수 있습니다.<a name="rotate-ssl-tls-certificates-proc"></a>

**SSL/TLS 인증서를 교체하려면**

1. [SSL/TLS 인증서에 대한 할당량 증가](increasing-the-limit-for-ssl-tls-certificates.md)는 추가 SSL 인증서를 사용하기 위한 권한이 필요한지 여부를 확인합니다. 권한이 필요한 경우 권한을 요청하고 기다렸다 권한이 부여되면 2단계로 넘어갑니다.

1. 새 인증서를 ACM으로 가져오거나 IAM에 업로드합니다. 자세한 내용은 *Amazon CloudFront 개발자 안내서*의 [SSL/TLS 인증서 가져오기](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-procedures.html#cnames-and-https-uploading-certificates)를 참조하세요.

1. (IAM 인증서만 해당) 새 인증서를 사용하도록 한 번에 하나씩 배포를 업데이트합니다. 자세한 내용은 [배포 업데이트](HowToUpdateDistribution.md) 섹션을 참조하세요.

1. (선택 사항) ACM 또는 IAM에서 이전 인증서를 삭제합니다.
**중요**  
모든 배포에서 해당 인증서가 제거되고 업데이트된 배포의 상태가 `Deployed`로 변경될 때까지는 SSL/TLS 인증서를 삭제하지 않습니다.

# 사용자 지정 SSL/TLS 인증서에서 기본 CloudFront 인증서로 되돌리기
<a name="cnames-and-https-revert-to-cf-certificate"></a>

CloudFront에서 최종 사용자와 CloudFront 간에 HTTPS를 사용하도록 구성했으며 CloudFront에서 사용자 지정 SSL/TLS 인증서를 사용하도록 구성한 경우, 기본 CloudFront SSL/TLS 인증서를 사용하도록 구성을 변경할 수 있습니다. 이 절차는 콘텐츠를 배포하는 데 배포를 사용했는지 여부에 따라 다릅니다.
+ 배포를 사용하여 콘텐츠를 배포하지 않은 경우에는 구성을 변경하면 됩니다. 자세한 내용은 [배포 업데이트](HowToUpdateDistribution.md) 단원을 참조하세요.
+ 배포를 사용하여 콘텐츠를 배포한 경우에는 새 CloudFront 배포를 생성하고 파일에 대한 URL을 변경하여 콘텐츠를 사용할 수 없는 시간을 줄이거나 없애야 합니다. 이렇게 하려면 다음과 같이 합니다.

## 기본 CloudFront 인증서로 되돌리기
<a name="revert-default-cloudfront-certificate"></a>

다음 절차에서는 사용자 지정 SSL/TLS 인증서에서 기본 CloudFront 인증서로 되돌리는 방법을 보여줍니다.<a name="cnames-and-https-revert-to-cf-certificate-proc"></a>

**기본 CloudFront 인증서로 되돌리려면**

1. 원하는 구성을 사용하여 새 CloudFront 배포를 생성합니다. **SSL 인증서(SSL Certificate)**에서 **기본 CloudFront 인증서(Default CloudFront Certificate)(\$1.cloudfront.net)**를 선택합니다.

   자세한 내용은 [배포 생성](distribution-web-creating-console.md) 섹션을 참조하세요.

1. CloudFront를 사용하여 배포하고 있는 파일의 경우에는 CloudFront에서 새 배포에 할당한 도메인 이름이 사용되도록 애플리케이션에서 URL을 업데이트합니다. 예를 들면 `https://www.example.com/images/logo.png`를 `https://d111111abcdef8.cloudfront.net/images/logo.png`로 변경합니다.

1. 사용자 지정 SSL/TLS 인증서와 연결된 배포를 삭제하거나, **SSL 인증서(SSL Certificate)** 값이 **기본 CloudFront 인증서(Default CloudFront Certificate)(\$1.cloudfront.net)**로 변경되도록 배포를 업데이트합니다. 자세한 내용은 [배포 업데이트](HowToUpdateDistribution.md) 단원을 참조하세요.
**중요**  
이 단계를 완료하지 않으면 AWS에서 사용자 지정 SSL/TLS 인증서 사용에 요금을 계속 부과합니다.

1. (선택 사항) 사용자 지정 SSL/TLS 인증서를 삭제합니다.

   1. AWS CLI 명령 `list-server-certificates`를 실행하여 삭제할 인증서의 인증서 ID를 확인합니다. 자세한 내용은 *AWS CLI 명령 참조*의 [list-server-certificates](https://docs.aws.amazon.com/cli/latest/reference/iam/list-server-certificates.html)를 참조하세요.

   1. AWS CLI 명령 `delete-server-certificate`를 실행하여 인증서를 삭제합니다. 자세한 내용은 AWS CLI 명령 참조의 [delete-server-certificate](https://docs.aws.amazon.com/cli/latest/reference/iam/delete-server-certificate.html)를 참조합니다.**

# 사용자 지정 SSL/TLS 인증서를 전용 IP 주소 사용에서 SNI 사용으로 전환
<a name="cnames-and-https-switch-dedicated-to-sni"></a>

사용자 지정 SSL/TLS 인증서에 전용 IP 주소를 사용하도록 CloudFront를 구성한 경우 SSL/TLS 인증서에 SNI를 대신 사용하고 전용 IP 주소와 연결된 요금이 청구되지 않도록 전환할 수 있습니다.

**중요**  
이 CloudFront 구성 업데이트는 SNI를 지원하는 최종 사용자에는 영향을 미치지 않습니다. 최종 사용자는 변경 전후뿐만 아니라 변경 사항이 CloudFront 엣지 로케이션에 전파되는 동안에도 콘텐츠에 액세스할 수 있습니다. SNI를 지원하지 않는 뷰어는 변경 후에 콘텐츠에 액세스할 수 없습니다. 자세한 내용은 [CloudFront에서 HTTPS 요청을 제공하는 방식 선택](cnames-https-dedicated-ip-or-sni.md) 섹션을 참조하세요.

## 사용자 지정 인증서에서 SNI로 전환
<a name="cloudfront-switch-custom-cert-sni"></a>

다음 절차에서는 사용자 지정 SSL/TLS 인증서를 전용 IP 주소 사용에서 SNI 사용으로 전환하는 방법을 보여줍니다.<a name="cnames-and-https-switch-dedicated-to-sni-proc"></a>

**사용자 지정 SSL/TLS 인증서를 전용 IP 주소 사용에서 SNI 사용으로 전환하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 보거나 업데이트하려는 배포의 ID를 선택합니다.

1. **Distribution Settings**(배포 설정)를 선택합니다.

1. [**General**] 탭에서 [**Edit**]를 선택합니다.

1. **사용자 지정 SSL 인증 - *선택 사항***에서 **레거시 클라이언트 지원**을 선택 해제합니다.

1. **예, 편집합니다**를 선택합니다.

# CloudFront에 대한 상호 TLS 인증(뷰어 mTLS)
<a name="mtls-authentication"></a>

상호 TLS 인증(상호 전송 계층 보안 인증 - mTLS)은 양방향 인증서 기반 인증을 요구하여 표준 TLS 인증을 확장하는 보안 프로토콜로, 클라이언트와 서버 모두 보안 연결을 설정하기 전에 자격 증명을 증명해야 합니다. 상호 TLS를 사용하면 신뢰할 수 있는 TLS 인증서를 제공하는 클라이언트만 CloudFront 배포에 액세스할 수 있습니다.

## 작동 방식
<a name="how-mtls-works"></a>

표준 TLS 핸드셰이크에서는 서버만 클라이언트에 자격 증명을 증명하는 인증서를 제공합니다. 상호 TLS를 사용하면 인증 프로세스가 양방향이 됩니다. 클라이언트가 CloudFront 배포에 연결을 시도하면 CloudFront는 TLS 핸드셰이크 중에 클라이언트 인증서를 요청합니다. 클라이언트는 보안 연결을 설정하기 전에 CloudFront가 구성된 트러스트 스토어에 대해 검증하는 유효한 X.509 인증서를 제시해야 합니다.

CloudFront는 AWS 엣지 로케이션에서 이 인증서 검증을 수행하여 오리진 서버에서 인증 복잡성을 오프로드하는 동시에 CloudFront의 글로벌 성능 이점을 유지합니다. 확인 모드(모든 클라이언트가 유효한 인증서를 제시해야 함) 또는 선택적 모드(제공 시 인증서를 검증하지만 인증서 없는 연결도 허용함)의 두 가지 모드로 mTLS를 구성할 수 있습니다.

## 사용 사례
<a name="mtls-use-cases"></a>

CloudFront를 사용한 상호 TLS 인증은 기존 인증 방법이 충분하지 않은 몇 가지 중요한 보안 시나리오를 해결합니다.
+ **콘텐츠 캐싱을 사용한 디바이스 인증** - 펌웨어 업데이트, 게임 다운로드 또는 내부 리소스에 대한 액세스를 허용하기 전에 게임 콘솔, IoT 디바이스 또는 회사 하드웨어를 인증할 수 있습니다. 각 디바이스에는 CloudFront의 캐싱 기능을 활용하면서 신뢰성을 입증하는 고유한 인증서가 포함되어 있습니다.
+ **API-to-API 인증** - 신뢰할 수 있는 비즈니스 파트너, 결제 시스템 또는 마이크로 서비스 간의 시스템 대 시스템 통신을 보호할 수 있습니다. 인증서 기반 인증을 사용하면 공유 보안 암호 또는 API 키를 사용할 필요 없이 자동 데이터 교환을 위한 강력한 자격 증명 확인을 제공합니다.

**Topics**
+ [작동 방식](#how-mtls-works)
+ [사용 사례](#mtls-use-cases)
+ [트러스트 스토어 및 인증서 관리](trust-stores-certificate-management.md)
+ [CloudFront 배포에 상호 TLS 활성화](enable-mtls-distributions.md)
+ [CloudFront 연결 함수 연결](connection-functions.md)
+ [추가 설정 구성](configuring-additional-settings.md)
+ [오리진으로 전달된 캐시 정책에 대한 뷰어 mTLS 헤더](viewer-mtls-headers.md)
+ [CloudFront 연결 함수 및 KVS를 사용한 해지](revocation-connection-function-kvs.md)
+ [연결 로그를 사용한 관찰성](connection-logs.md)

# 트러스트 스토어 및 인증서 관리
<a name="trust-stores-certificate-management"></a>

트러스트 스토어를 생성하고 구성하는 것은 CloudFront와의 상호 TLS 인증을 구현하기 위한 필수 요구 사항입니다. 트러스트 스토어에는 CloudFront가 인증 프로세스 중에 클라이언트 인증서를 검증하는 데 사용하는 인증 기관(CA) 인증서가 포함되어 있습니다.

## 트러스트 스토어란 무엇인가요?
<a name="what-is-trust-store"></a>

트러스트 스토어는 CloudFront가 상호 TLS 인증 중에 클라이언트 인증서를 검증하는 데 사용하는 CA 인증서의 리포지토리입니다. 트러스트 스토어에는 클라이언트 인증서를 인증하기 위한 신뢰 체인을 구성하는 루트 및 중간 CA 인증서가 포함되어 있습니다.

CloudFront와 상호 TLS를 구현하면 트러스트 스토어는 유효한 클라이언트 인증서를 발급하기 위해 신뢰할 수 있는 인증 기관을 정의합니다. CloudFront는 TLS 핸드셰이크 중에 트러스트 스토어에 대해 각 클라이언트 인증서를 검증합니다. 트러스트 스토어의 CA 중 하나에 연결된 인증서를 제공하는 클라이언트만 성공적으로 인증됩니다.

CloudFront의 트러스트 스토어는 여러 배포와 연결할 수 있는 계정 수준 리소스입니다. 이를 통해 CA 인증서 관리를 간소화하면서 전체 CloudFront 배포에서 일관된 인증서 검증 정책을 유지할 수 있습니다.

## 인증 기관 지원
<a name="ca-support"></a>

CloudFront는 AWS 프라이빗 인증 기관과 타사 프라이빗 인증 기관에서 발급한 인증서를 지원합니다. 이러한 유연성을 통해 기존 인증서 인프라를 사용하거나 조직 요구 사항에 따라 AWS 관리형 인증서 서비스를 활용할 수 있습니다.
+ **AWS 프라이빗 인증 기관:** 관리형 프라이빗 인증 기관 서비스를 제공하는 AWS Private CA에서 발급한 인증서를 사용할 수 있습니다. 이 통합은 인증서 수명 주기 관리를 간소화하고 다른 AWS 서비스와의 원활한 통합을 제공합니다.
+ **타사 프라이빗 인증 기관:** 엔터프라이즈 CA 또는 기타 타사 인증서 공급자를 포함하여 기존 프라이빗 인증 기관 인프라의 인증서를 사용할 수도 있습니다. 이렇게 하면 CloudFront의 mTLS 기능을 추가하면서 현재 인증서 관리 프로세스를 유지할 수 있습니다.

## 인증서 요구 사항 및 사양
<a name="certificate-requirements"></a>

트러스트 스토어에는 포함된 CA 인증서에 대한 특정 요구 사항이 있습니다.

### CA 인증서 형식 요구 사항
<a name="ca-cert-format-requirements"></a>
+ **형식:** PEM(Privacy Enhanced Mail) 형식
+ **콘텐츠 경계:** 인증서는 -----BEGIN CERTIFICATE----- 및 -----END CERTIFICATE----- 경계 내에 묶여야 합니다.
+ **주석:** 앞에는 \$1 문자를 붙여야 하며 - 문자를 포함할 수 없습니다.
+ **줄 바꿈:** 인증서 사이에 빈 줄이 허용되지 않습니다.

### 지원되는 인증서 사양
<a name="supported-cert-specs"></a>
+ **인증서 유형:** X.509v3
+ **퍼블릭 키 유형:**
  + RSA 2048, RSA 3072, RSA 4096
  + ECDSA: secp256r1, secp384r1
+ **서명 알고리즘:**
  + RSA를 사용하는 SHA256, SHA384, SHA512
  + EC를 사용하는 SHA256, SHA384, SHA512
  + MGF1 지원 RSASSA-PSS를 사용하는 SHA256, SHA384, SHA512

### 예제 인증서 번들 형식
<a name="example-cert-bundle"></a>

여러 인증서(PEM 인코딩):

```
# Root CA Certificate
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKoK/OvD/XqiMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTcwNzEyMTU0NzQ4WhcNMjcwNzEwMTU0NzQ4WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAuuExKvY1xzHFylsHiuowqpmzs7rEcuuylOuEszpFp+BtXh0ZuEtts9LP
-----END CERTIFICATE-----
# Intermediate CA Certificate
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKoK/OvD/XqjMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTcwNzEyMTU0NzQ4WhcNMjcwNzEwMTU0NzQ4WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAuuExKvY1xzHFylsHiuowqpmzs7rEcuuylOuEszpFp+BtXh0ZuEtts9LP
-----END CERTIFICATE-----
```

## 트러스트 스토어 생성
<a name="create-trust-store"></a>

트러스트 스토어를 생성하기 전에 PEM 형식의 CA 인증서 번들을 Amazon S3 버킷에 업로드해야 합니다. 인증서 번들에는 클라이언트 인증서를 검증하는 데 필요한 신뢰할 수 있는 모든 루트 및 중간 CA 인증서가 포함되어야 합니다.

CA 인증서 번들은 트러스트 스토어를 생성할 때 S3에서 한 번만 읽습니다. CA 인증서 번들을 나중에 변경하는 경우 트러스트 스토어를 수동으로 업데이트해야 합니다. 트러스트 스토어와 S3 CA 인증서 번들 간에 동기화가 유지되지 않습니다.

### 사전 조건
<a name="trust-store-prerequisites"></a>
+ Amazon S3 버킷에 업로드된 인증 기관(CA)의 인증서 번들
+ CloudFront 리소스를 생성하는 데 필요한 권한

### 트러스트 스토어를 생성하려면(콘솔)
<a name="create-trust-store-console"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **트러스트 스토어**를 선택합니다.

1. **트러스트 스토어 생성**을 선택합니다.

1. **트러스트 스토어 이름**에 트러스트 스토어의 이름을 입력합니다.

1. **인증 기관(CA) 번들**의 경우 PEM 형식 CA 인증서 번들에 Amazon S3 경로를 입력합니다.

1. **트러스트 스토어 생성**을 선택합니다.

### 트러스트 스토어를 생성하려면(AWS CLI)
<a name="create-trust-store-cli"></a>

```
aws cloudfront create-trust-store \
  --name MyTrustStore \
  --certificate-authority-bundle-s3-location Bucket=my-bucket,Key=ca-bundle.pem \
  --tags Items=[{Key=Environment,Value=Production}]
```

## 트러스트 스토어를 배포와 연결
<a name="associate-trust-store"></a>

트러스트 스토어를 생성한 후에는 이를 CloudFront 배포와 연결하여 상호 TLS 인증을 활성화해야 합니다.

### 사전 조건
<a name="associate-prerequisites"></a>
+ HTTPS 전용 뷰어 프로토콜 정책이 활성화되고 HTTP3 지원이 비활성화된 기존 CloudFront 배포입니다.

### 트러스트 스토어를 연결하려면(콘솔)
<a name="associate-trust-store-console"></a>

CloudFront 콘솔 내에서 트러스트 스토어 세부 정보 페이지 또는 배포 설정 페이지를 통해 트러스트 스토어를 연결할 수 있는 두 가지 방법이 있습니다.

**트러스트 스토어 세부 정보 페이지를 통해 트러스트 스토어 연결:**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **트러스트 스토어**를 선택합니다.

1. 연결할 트러스트 스토어의 이름을 선택합니다.

1. **배포에 연결**을 선택합니다.

1. 사용 가능한 뷰어 mTLS 옵션을 구성합니다.
   + **클라이언트 인증서 검증 모드:** 필수 모드와 선택 모드 중에서 선택합니다. 필수 모드에서는 모든 클라이언트가 인증서를 제시해야 합니다. 선택적 모드에서는 인증서를 제공하는 클라이언트가 검증되는 반면, 인증서를 제공하지 않는 클라이언트는 액세스가 허용됩니다.
   + **트러스트 스토어 CA 이름 알림:** TLS 핸드셰이크 중에 트러스트 스토어의 CA 이름을 클라이언트에 알릴지 여부를 선택합니다.
   + **인증서 만료 날짜 무시:** 만료된 인증서와의 연결을 허용할지 여부를 선택합니다(다른 검증 기준은 계속 적용됨).
   + **연결 함수:** 선택적 연결 함수를 연결하여 다른 사용자 지정 기준에 따라 연결을 허용/거부할 수 있습니다.

1. 트러스트 스토어와 연결할 배포를 하나 이상 선택합니다. HTTP3가 비활성화되고 HTTPS 전용 캐시 동작이 있는 배포만 뷰어 mTLS를 지원할 수 있습니다.

1. **연결**을 선택합니다.

**배포 설정 페이지를 통해 트러스트 스토어 연결:**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 연결하려는 배포를 선택합니다.

1. **일반** 탭의 **설정** 컨테이너에서 오른쪽 상단 모서리에 있는 **편집**을 선택합니다.

1. 페이지 하단까지 아래로 스크롤하여 **연결** 컨테이너 내에서 **뷰어 mTLS** 스위치를 켭니다.

1. 사용 가능한 뷰어 mTLS 옵션을 구성합니다.
   + **클라이언트 인증서 검증 모드:** 필수 모드와 선택 모드 중에서 선택합니다. 필수 모드에서는 모든 클라이언트가 인증서를 제시해야 합니다. 선택적 모드에서는 인증서를 제공하는 클라이언트가 검증되는 반면, 인증서를 제공하지 않는 클라이언트는 액세스가 허용됩니다.
   + **트러스트 스토어 CA 이름 알림:** TLS 핸드셰이크 중에 트러스트 스토어의 CA 이름을 클라이언트에 알릴지 여부를 선택합니다.
   + **인증서 만료 날짜 무시:** 만료된 인증서와의 연결을 허용할지 여부를 선택합니다(다른 검증 기준은 계속 적용됨).
   + **연결 함수:** 선택적 연결 함수를 연결하여 다른 사용자 지정 기준에 따라 연결을 허용/거부할 수 있습니다.

1. 오른쪽 하단 모서리에서 **변경 사항 저장**을 선택합니다.

### 트러스트 스토어를 연결하려면(AWS CLI)
<a name="associate-trust-store-cli"></a>

트러스트 스토어는 DistributionConfig.ViewerMtlsConfig 속성을 통해 배포에 연결할 수 있습니다. 즉, 먼저 배포 구성을 가져온 다음 후속 UpdateDistribution 요청에서 ViewerMtlsConfig를 제공해야 합니다.

```
// First fetch the distribution
aws cloudfront get-distribution {DISTRIBUTION_ID}

// Update the distribution config, for example:
Distribution config, file://distConf.json: 
{
  ...other fields,
  ViewerMtlsConfig: {
    Mode: 'required',
    TrustStoreConfig: {
        AdvertiseTrustStoreCaNames: false,
        IgnoreCertificateExpiry: true,
        TrustStoreId: {TRUST_STORE_ID}
    }
  }
}

aws cloudfront update-distribution \
   --id {DISTRIBUTION_ID} \
   --if-match {ETAG} \
   --distribution-config file://distConf.json
```

## 트러스트 스토어 관리
<a name="manage-trust-stores"></a>

### 트러스트 스토어 세부 정보 보기
<a name="view-trust-store-details"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **트러스트 스토어**를 선택합니다.

1. 트러스트 스토어 이름을 선택하여 세부 정보 페이지를 봅니다.

세부 정보 페이지에는 다음이 표시됩니다.
+ 트러스트 스토어 이름 및 ID
+ CA 인증서 수
+ 생성 날짜 및 마지막 수정 날짜
+ 연결된 배포
+ Tags

### 트러스트 스토어 수정
<a name="modify-trust-store"></a>

CA 인증서 번들을 교체하려면:

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **트러스트 스토어**를 선택합니다.

1. 트러스트 스토어의 이름을 선택합니다.

1. **작업**을 선택한 다음 **편집**을 선택합니다.

1. **인증 기관(CA) 번들**에 업데이트된 CA 번들 PEM 파일의 Amazon S3 위치를 입력합니다.

1. **트러스트 스토어 업데이트**를 선택합니다.

### 트러스트 스토어 삭제
<a name="delete-trust-store"></a>

**사전 조건:** 먼저 모든 CloudFront 배포에서 트러스트 스토어의 연결을 해제해야 합니다.

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **트러스트 스토어**를 선택합니다.

1. 트러스트 스토어의 이름을 선택합니다.

1. **트러스트 스토어 삭제**를 선택합니다.

1. [**삭제**]를 선택하여 확인합니다.

### 다음 단계
<a name="trust-store-next-steps"></a>

트러스트 스토어를 생성하고 CloudFront 배포와 연결한 후 배포에서 상호 TLS 인증을 활성화하고 인증서 헤더를 오리진에 전달하는 등의 추가 설정을 구성할 수 있습니다. 배포에서 mTLS를 활성화하는 방법에 대한 자세한 지침은 [CloudFront 배포에 상호 TLS 활성화](enable-mtls-distributions.md) 섹션을 참조하세요.

# CloudFront 배포에 상호 TLS 활성화
<a name="enable-mtls-distributions"></a>

## 사전 조건 및 요구 사항
<a name="mtls-prerequisites-requirements"></a>

CloudFront의 상호 TLS 확인 모드에서는 모든 클라이언트가 TLS 핸드셰이크 중에 유효한 인증서를 제시하고 유효한 인증서가 없는 연결을 거부해야 합니다. CloudFront 배포에서 상호 TLS를 활성화하기 전에 다음을 확인해야 합니다.
+ 인증 기관 인증서로 트러스트 스토어를 생성함
+ 트러스트 스토어가 CloudFront 배포와 연결됨
+ 모든 배포 캐시 동작이 HTTPS 전용 뷰어 프로토콜 정책을 사용함
+ 배포에서 HTTP/2를 사용하고 있음(기본 설정, HTTP/3에서는 뷰어 mTLS가 지원되지 않음)

**참고**  
상호 TLS 인증에는 뷰어와 CloudFront 간의 HTTPS 연결이 필요합니다. HTTP 연결을 지원하는 캐시 동작이 있는 배포에서는 mTLS를 활성화할 수 없습니다.

## 상호 TLS 활성화(콘솔)
<a name="enable-mtls-console"></a>

### 새 배포의 경우
<a name="enable-mtls-new-distributions"></a>

CloudFront 콘솔에서 새 배포를 생성하는 과정에서는 뷰어 mTLS를 구성할 수 없습니다. 먼저 모든 방법(콘솔, CLI, API)으로 배포를 생성한 다음 배포 설정을 편집하여 아래 기존 배포 지침에 따라 뷰어 mTLS를 활성화합니다.

### 기존 배포의 경우
<a name="enable-mtls-existing-distributions"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 배포 목록에서 수정하려는 배포를 선택합니다.

1. 모든 캐시 동작의 뷰어 프로토콜 정책을 **HTTP를 HTTPS로 리디렉션** 또는 **HTTPS 전용**으로 설정해야 합니다. (**캐시 동작** 탭을 선택하여 HTTP 프로토콜 정책으로 캐시 동작을 보고 업데이트할 수 있습니다.)

1. **일반** 탭을 선택합니다.

1. **설정** 섹션에서 **편집**을 선택합니다.

1. **연결성** 섹션에서 **뷰어 상호 인증(mTLS)**을 찾습니다.

1. **상호 인증 활성화**를 켜기로 전환합니다.

1. **클라이언트 인증서 검증 모드**에서 **필수**(모든 클라이언트가 인증서를 제시해야 함) 또는 **선택 사항**(클라이언트가 선택적으로 인증서를 제공할 수 있음)을 선택합니다.

1. **트러스트 스토어**에서 이전에 생성한 트러스트 스토어를 선택합니다.

1. (선택 사항) TLS 핸드셰이크 중에 CloudFront가 클라이언트에 CA 이름을 보내도록 하려면 **트러스트 스토어 CA 이름 알리기**를 전환합니다.

1. (선택 사항) 만료된 인증서와의 연결을 허용하려면 **인증서 만료 날짜 무시**를 전환합니다.

1. **변경 사항 저장**을 선택합니다.

## 상호 TLS 활성화(AWS CLI)
<a name="enable-mtls-cli"></a>

### 새 배포의 경우
<a name="enable-mtls-cli-new"></a>

다음 예제에서는 mTLS 설정을 포함하는 배포 구성 파일(distribution-config.json)을 생성하는 방법을 보여줍니다.

```
{
  "CallerReference": "cli-example-1",
  "Origins": {
    "Quantity": 1,
    "Items": [
      {
        "Id": "my-origin",
        "DomainName": "example.com",
        "CustomOriginConfig": {
          "HTTPPort": 80,
          "HTTPSPort": 443,
          "OriginProtocolPolicy": "https-only"
        }
      }
    ]
  },
  "DefaultCacheBehavior": {
    "TargetOriginId": "my-origin",
    "ViewerProtocolPolicy": "https-only",
    "MinTTL": 0,
    "ForwardedValues": {
      "QueryString": false,
      "Cookies": {
        "Forward": "none"
      }
    }
  },
  "ViewerCertificate": {
    "CloudFrontDefaultCertificate": true
  },
  "ViewerMtlsConfig": {
    "Mode": "required", 
    "TrustStoreConfig": {
        "TrustStoreId": {TRUST_STORE_ID},
        "AdvertiseTrustStoreCaNames": true,
        "IgnoreCertificateExpiry": true
    }
  },
  "Enabled": true
}
```

다음 예제 명령을 사용하여 mTLS가 활성화된 배포를 생성합니다.

```
aws cloudfront create-distribution --distribution-config file://distribution-config.json
```

### 기존 배포의 경우
<a name="enable-mtls-cli-existing"></a>

다음 예제 명령을 사용하여 현재 배포 구성을 가져옵니다.

```
aws cloudfront get-distribution-config --id E1A2B3C4D5E6F7 --output json > dist-config.json
```

파일을 편집하여 mTLS 설정을 추가합니다. 배포 구성에 다음 예제 섹션을 추가합니다.

```
"ViewerMtlsConfig": {
    "Mode": "required", 
    "TrustStoreConfig": {
        "TrustStoreId": {TRUST_STORE_ID},
        "AdvertiseTrustStoreCaNames": true,
        "IgnoreCertificateExpiry": true
    }
}
```

파일에서 ETag 필드를 제거하되 값을 별도로 저장합니다.

다음 예제 명령을 사용하여 배포를 새 구성으로 업데이트합니다.

```
aws cloudfront update-distribution \
    --id E1A2B3C4D5E6F7 \
    --if-match YOUR-ETAG-VALUE \
    --distribution-config file://dist-config.json
```

## 뷰어 프로토콜 정책
<a name="viewer-protocol-policies"></a>

상호 TLS를 사용하는 경우 모든 배포 캐시 동작을 HTTPS 전용 뷰어 프로토콜 정책으로 구성해야 합니다.
+ **HTTP를 HTTPS로 리디렉션** - 인증서 검증을 수행하기 전에 HTTP 요청을 HTTPS로 리디렉션합니다.
+ **HTTPS 전용** - HTTPS 요청만 수락하고 인증서 검증을 수행합니다.

**참고**  
HTTP 연결은 인증서 검증을 수행할 수 없으므로 HTTP 및 HTTPS 뷰어 프로토콜 정책은 상호 TLS에서 지원되지 않습니다.

## 다음 단계
<a name="enable-mtls-next-steps"></a>

CloudFront 배포에서 뷰어 TLS를 활성화한 후 연결 함수를 연결하여 사용자 지정 인증서 검증 로직을 구현할 수 있습니다. 연결 함수를 사용하면 사용자 지정 검증 규칙, 인증서 해지 확인 및 로깅을 통해 기본 제공 mTLS 인증 기능을 확장할 수 있습니다. 연결 함수 생성 및 연결에 대한 자세한 내용은 [CloudFront 연결 함수 연결](connection-functions.md) 섹션을 참조하세요.

# CloudFront 연결 함수 연결
<a name="connection-functions"></a>

CloudFront 연결 함수를 사용하면 TLS 핸드셰이크 중에 사용자 지정 인증서 검증 로직을 구현하여 내장 mTLS 인증 기능을 확장할 수 있습니다.

## 연결 함수란 무엇입니까?
<a name="what-are-connection-functions"></a>

연결 함수는 클라이언트 인증서가 검증된 후 TLS 핸드셰이크 중에 실행되는 JavaScript 함수입니다. 검증된 클라이언트 인증서는 연결 함수로 전달되며, 이 시점에서 연결 함수는 액세스 권한 부여 여부를 추가로 결정할 수 있습니다. 연결 함수에 대한 자세한 내용은 [CloudFront Functions를 사용하여 엣지에서 사용자 지정](cloudfront-functions.md) 섹션을 참조하세요.

## 연결 함수가 mTLS에서 작동하는 방식
<a name="how-connection-functions-work"></a>

클라이언트가 CloudFront 배포에 대한 mTLS 연결을 설정하려고 하면 다음 시퀀스가 발생합니다.

1. 클라이언트가 CloudFront 엣지 로케이션으로 TLS 핸드셰이크를 시작합니다.

1. CloudFront가 클라이언트 인증서를 요청하고 수신합니다.

1. CloudFront가 트러스트 스토어에 대해 표준 인증서 검증을 수행합니다.

1. 인증서가 표준 검증을 통과하면 CloudFront는 연결 함수를 간접적으로 호출합니다. **ViewerMtlsConfig** 내에서 **IgnoreCertificateExpiry**가 활성화된 경우 만료되었지만 유효한 인증서도 연결 함수로 전달됩니다. 클라이언트 인증서가 유효하지 않으면 연결 함수가 간접 호출되지 않습니다.

1. 연결 함수는 구문 분석된 인증서 정보와 연결 세부 정보를 수신합니다.

1. 함수는 사용자 지정 로직을 기반으로 허용/거부 결정을 내립니다.

1. CloudFront는 사용자의 결정에 따라 TLS 연결을 완료하거나 종료합니다.

연결 함수는 확인 모드와 선택적 모드(클라이언트가 인증서를 제공하는 경우) 모두에 대해 간접적으로 호출됩니다.

## 연결 함수 생성
<a name="create-connection-function"></a>

CloudFront 콘솔 또는 AWS CLI를 사용하여 연결 함수를 생성할 수 있습니다.

### 연결 함수를 생성하려면(콘솔)
<a name="create-connection-function-console"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **함수**를 선택합니다.

1. **연결 함수** 탭을 선택한 다음 **연결 함수 생성**을 선택합니다.

1. AWS 계정 내에서 고유한 함수 이름을 입력합니다.

1. **계속**을 선택합니다.

1. 함수 편집기에서 인증서 검증을 위한 JavaScript 코드를 작성합니다. 함수 핸들러는 허용 또는 거부를 직접 호출해야 합니다.

1. 선택 사항: KeyValue 스토어를 연결 함수에 연결하여 해지 제어를 구현할 수 있습니다.

1. **변경 사항 저장**을 선택합니다.

### 연결 함수를 생성하려면(AWS CLI)
<a name="create-connection-function-cli"></a>

다음 예제에서는 연결 함수를 생성하는 방법을 보여줍니다.

code.js와 같은 별도의 파일에 함수 코드를 작성합니다.

```
function connectionHandler(connection) {
  connection.allow();
}
```

```
aws cloudfront create-connection-function \
  --name "certificate-validator" \
  --connection-function-config '{
      "Comment": "Client certificate validation function",
      "Runtime": "cloudfront-js-2.0"
  }' \
  --connection-function-code fileb://code.js
```

## 연결 함수 코드 구조
<a name="connection-function-code-structure"></a>

연결 함수는 인증서 및 연결 정보가 포함된 연결 객체를 수신하는 connectionHandler 함수를 구현합니다. 함수는 `connection.allow()` 또는 `connection.deny()`를 사용하여 연결에 대한 결정을 내려야 합니다.

### 기본 연결 함수 예제
<a name="basic-connection-function-example"></a>

다음 예제는 클라이언트 인증서의 제목 필드를 확인하는 간단한 연결 함수를 보여줍니다.

```
function connectionHandler(connection) {
    // Only process if a certificate was presented
    if (!connection.clientCertificate) {
        console.log("No certificate presented");
        connection.deny();
    }
    
    // Check the subject field for specific organization
    const subject = connection.clientCertificate.certificates.leaf.subject;
    if (!subject.includes("O=ExampleCorp")) {
        console.log("Certificate not from authorized organization");
       connection.deny();
    } else {
        // All checks passed
        console.log("Certificate validation passed");
        connection.allow();
    }
}
```

연결 객체에서 사용할 수 있는 클라이언트 인증서 속성의 전체 사양은 여기에서 확인할 수 있습니다.

```
{
  "connectionId": "Fdb-Eb7L9gVn2cFakz7wWyBJIDAD4-oNO6g8r3vXDV132BtnIVtqDA==", // Unique identifier for this TLS connection
  "clientIp": "203.0.113.42", // IP address of the connecting client (IPv4 or IPv6)
  "clientCertificate": {
    "certificates": {
      "leaf": {
        "subject": "CN=client.example.com,O=Example Corp,C=US", // Distinguished Name (DN) of the certificate holder
        "issuer": "CN=Example Corp Intermediate CA,O=Example Corp,C=US", // Distinguished Name (DN) of the certificate authority that issued this certificate
        "serialNumber": "4a:3f:5c:92:d1:e8:7b:6c", // Unique serial number assigned by the issuing CA (hexadecimal)
        "validity": {
          "notBefore": "2024-01-15T00:00:00Z", // Certificate validity start date (ISO 8601 format)
          "notAfter": "2025-01-14T23:59:59Z"   // Certificate expiration date (ISO 8601 format)
        },
        "sha256Fingerprint": "a1b2c3d4e5f6...abc123def456", // SHA-256 hash of the certificate (64 hex characters)
      },
    },
  },
}
```

## 연결 함수 연결
<a name="associate-connection-function-section"></a>

연결 함수를 생성한 후에는 이를 라이브 단계에 게시하고 배포와 연결해야 합니다.

### 연결 함수를 게시하고 연결하려면(콘솔)
<a name="publish-associate-console"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **함수**를 선택합니다.

1. **연결 함수** 탭을 선택하고 연결 함수를 선택합니다.

1. **게시**를 선택하여 라이브 단계로 이동합니다.

1. 게시 섹션 아래의 연결된 배포 테이블에서 **연결 추가**를 선택합니다.

1. 연결하려는 뷰어 mTLS가 활성화된 배포를 선택합니다.

또는 배포 세부 정보 페이지에서 게시된 연결 함수를 연결할 수도 있습니다.

1. 모든 배포가 나열된 콘솔 홈 페이지로 이동합니다.

1. 연결하려는 배포를 선택합니다.

1. **일반** 탭을 선택합니다.

1. **설정** 섹션에서 **편집**을 선택합니다.

1. **연결성** 섹션에서 **뷰어 상호 인증(mTLS)**을 찾습니다.

1. **연결 함수**에서 함수를 선택합니다.

1. **변경 사항 저장**을 선택합니다.

### 연결 함수를 연결하려면(AWS CLI)
<a name="associate-connection-function-cli"></a>

다음 예제에서는 연결 함수를 배포와 연결하는 방법을 보여줍니다.

```
// DistributionConfig:
{
   ...other settings,
    "ConnectionFunctionAssociation": {
        "Id": "cf_30c2CV2elHwCoInb3LtcaUJkZeD"
    }
}
```

## 연결 함수 사용 사례
<a name="connection-function-use-cases"></a>

연결 함수를 사용하면 다음과 같은 여러 고급 mTLS 사용 사례를 사용할 수 있습니다.
+ **인증서 속성 검증** - 조직 단위 요구 사항 또는 주체 대체 이름 패턴과 같은 클라이언트 인증서의 특정 필드를 확인합니다.
+ **인증서 해지 확인** - KeyValueStore를 사용하여 해지된 인증서 일련 번호를 저장하는 사용자 지정 인증서 해지 확인을 구현합니다.
+ **IP 기반 인증서 정책** - 클라이언트 IP 주소 또는 지리적 제한에 따라 다른 인증서 정책을 적용합니다.
+ **다중 테넌트 검증** - 호스트 이름 또는 인증서 속성에 따라 다양한 인증서 요구 사항이 적용되는 테넌트별 검증 규칙을 구현합니다.

**참고**  
연결 함수는 TLS 핸드셰이크 중에 클라이언트 연결당 한 번 실행됩니다.  
연결 함수는 HTTP 요청/응답을 수정하지 않고 연결만 허용하거나 거부할 수 있습니다.  
라이브 단계 함수(게시됨)만 배포와 연결할 수 있습니다.  
각 배포에는 최대 하나의 연결 함수가 있을 수 있습니다.

## 다음 단계
<a name="connection-function-next-steps"></a>

연결 함수를 CloudFront 배포와 연결한 후 선택적 설정을 구성하여 mTLS 구현의 동작을 사용자 지정할 수 있습니다. 선택적 클라이언트 인증서 검증 모드와 같은 추가 설정을 구성하는 방법에 대한 자세한 지침은 [추가 설정 구성](configuring-additional-settings.md) 섹션을 참조하세요.

# 추가 설정 구성
<a name="configuring-additional-settings"></a>

기본 상호 TLS 인증을 활성화한 후 특정 사용 사례 및 요구 사항에 맞게 인증 동작을 사용자 지정하도록 추가 설정을 구성할 수 있습니다.

## 클라이언트 인증서 검증 선택적 모드
<a name="optional-mode"></a>

CloudFront는 제공된 클라이언트 인증서를 검증하지만 인증서를 제시하지 않는 클라이언트에 대한 액세스를 허용하는 선택적 클라이언트 인증서 검증 모드를 제공합니다.

### 선택적 모드 동작
<a name="optional-mode-behavior"></a>
+ 유효한 인증서가 있는 클라이언트에 대한 연결을 부여합니다(잘못된 인증서는 거부됨).
+ 인증서 없이 클라이언트에 연결 허용
+ 단일 배포를 통해 혼합 클라이언트 인증 시나리오를 허용합니다.

선택적 모드는 mTLS 인증으로 점진적으로 마이그레이션하거나, 인증서가 있는 클라이언트 및 인증서가 없는 클라이언트를 지원하거나, 레거시 클라이언트와의 이전 버전 호환성을 유지하는 데 적합합니다.

**참고**  
선택적 모드에서는 클라이언트가 인증서를 제시하지 않더라도 연결 함수가 계속 간접 호출됩니다. 이를 통해 클라이언트 IP 주소 로깅 또는 인증서 제시 여부에 따라 다른 정책 적용과 같은 사용자 지정 로직을 구현할 수 있습니다.

### 선택적 모드를 구성하려면(콘솔)
<a name="configure-optional-mode-console"></a>

1. 배포 설정에서 **일반** 탭으로 이동하여 **편집**을 선택합니다.

1. **연결성** 컨테이너 내의 **뷰어 상호 인증(mTLS)** 섹션으로 스크롤합니다.

1. **클라이언트 인증서 검증 모드**에서 **선택 사항**을 선택합니다.

1. 변경 내용을 저장합니다.

### 선택적 모드를 구성하려면(AWS CLI)
<a name="configure-optional-mode-cli"></a>

다음 예제에서는 선택적 모드를 구성하는 방법을 보여줍니다.

```
"ViewerMtlsConfig": {
   "Mode": "optional",
   ...other settings
}
```

## 인증 기관 광고
<a name="ca-advertisement"></a>

AdvertiseTrustStoreCaNames 필드는 TLS 핸드셰이크 중에 CloudFront가 신뢰할 수 있는 CA 이름 목록을 클라이언트에 전송할지 여부를 제어하여 클라이언트가 적절한 인증서를 선택할 수 있도록 지원합니다.

### CA 광고를 구성하려면(콘솔)
<a name="configure-ca-advertisement-console"></a>

1. 배포 설정에서 **일반** 탭으로 이동하여 **편집**을 선택합니다.

1. **연결성** 컨테이너 내의 **뷰어 상호 인증(mTLS)** 섹션으로 스크롤합니다.

1. **트러스트 스토어 CA 이름 광고** 확인란을 선택하거나 선택 취소합니다.

1. **변경 사항 저장**을 선택합니다.

### CA 광고를 구성하려면(AWS CLI)
<a name="configure-ca-advertisement-cli"></a>

다음 예제에서는 CA 광고를 활성화하는 방법을 보여줍니다.

```
"ViewerMtlsConfig": {
   "Mode": "required", // or "optional"
   "TrustStoreConfig": {
      "AdvertiseTrustStoreCaNames": true,
      ...other settings
   } 
}
```

## 인증서 만료 처리
<a name="certificate-expiration-handling"></a>

IgnoreCertificateExpiry 속성은 CloudFront가 만료된 클라이언트 인증서에 응답하는 방법을 결정합니다. 기본적으로 CloudFront는 만료된 클라이언트 인증서를 거부하지만 필요할 때 수락하도록 구성할 수 있습니다. 이는 일반적으로 즉시 업데이트할 수 없는 인증서가 만료된 디바이스를 대상으로 활성화됩니다.

### 인증서 만료 처리를 구성하려면(콘솔)
<a name="configure-expiration-console"></a>

1. 배포 설정에서 **일반** 탭으로 이동하여 **편집**을 선택합니다.

1. **연결성** 컨테이너의 **뷰어 상호 인증(mTLS)** 섹션으로 스크롤합니다.

1. **인증서 만료 날짜 무시** 확인란을 선택하거나 선택 취소합니다.

1. **변경 사항 저장**을 선택합니다.

### 인증서 만료 처리를 구성하려면(AWS CLI)
<a name="configure-expiration-cli"></a>

다음 예제에서는 인증서 만료를 무시하는 방법을 보여줍니다.

```
"ViewerMtlsConfig": {
  "Mode": "required", // or "optional"
  "TrustStoreConfig": {
     "IgnoreCertificateExpiry": false,
     ...other settings
  }
}
```

**참고**  
**IgnoreCertificateExpiry**는 인증서 검증 날짜에만 적용됩니다. 다른 모든 인증서 검증 검사(신뢰 체인, 서명 검증)는 계속 적용됩니다.

## 다음 단계
<a name="additional-settings-next-steps"></a>

추가 설정을 구성한 후 헤더 전달을 설정하여 인증서 정보를 오리진에 전달하고, 연결 함수 및 KeyValueStore를 사용하여 인증서 해지를 구현하고, 모니터링을 위해 연결 로그를 활성화할 수 있습니다. 오리진에 인증서 정보를 전달하는 방법에 대한 자세한 내용은 [오리진에 헤더 전달](viewer-mtls-headers.md)을 참조하세요.

# 오리진으로 전달된 캐시 정책에 대한 뷰어 mTLS 헤더
<a name="viewer-mtls-headers"></a>

상호 TLS 인증을 사용하는 경우, CloudFront는 클라이언트 인증서에서 정보를 추출하여 오리진에 HTTP 헤더로 전달할 수 있습니다. 이렇게 하면 오리진 서버가 인증서 검증 로직을 구현하지 않고도 인증서 세부 정보에 액세스할 수 있습니다.

캐시 동작을 생성하는 데 사용할 수 있는 헤더는 다음과 같습니다.


| 헤더 이름 | 설명 | 예시 값 | 
| --- | --- | --- | 
| CloudFront-Viewer-Cert-Serial-Number | 인증서 일련 번호의 16진수 표현 | 4a:3f:5c:92:d1:e8:7b:6c | 
| CloudFront-Viewer-Cert-Issuer | 발급자 고유 이름(DN)의 RFC2253 문자열 표현 | CN=rootcamtls.com,OU=rootCA,O=mTLS,L=Seattle,ST=Washington,C=US | 
| CloudFront-Viewer-Cert-Subject | 주체 고유 이름(DN)의 RFC2253 문자열 표현 | CN=client\$1.com,OU=client-3,O=mTLS,ST=Washington,C=US | 
| CloudFront-Viewer-Cert-Present | 인증서가 있는지 여부를 나타내는 1(존재) 또는 0(존재하지 않음)입니다. 이 값은 필수 모드에서 항상 1입니다. | 1 | 
| CloudFront-Viewer-Cert-Sha256 | 클라이언트 인증서의 SHA256 해시 | 01fbf94fef5569753420c349f49adbfd80af5275377816e3ab1fb371b29cb586 | 

오리진 요청의 경우 캐시 동작에 사용할 수 있는 위의 헤더 외에도 두 개의 추가 헤더가 제공됩니다.


| 헤더 이름 | 설명 | 예시 값 | 
| --- | --- | --- | 
| CloudFront-Viewer-Cert-Validity | notBefore 및 notAfter 날짜의 ISO8601 형식 | CloudFront-Viewer-Cert-Validity: NotBefore=2023-09-21T01:50:17Z;NotAfter=2024-09-20T01:50:17Z | 
| CloudFront-Viewer-Cert-Pem | 리프 인증서의 URL 인코딩 PEM 형식 | CloudFront-Viewer-Cert-Pem: -----BEGIN%20CERTIFICATE-----%0AMIIG<...reduced...>NmrUlw%0A-----END%20CERTIFICATE-----%0A | 

## 헤더 전달 구성
<a name="configure-header-forwarding"></a>

### 콘솔
<a name="configure-headers-console"></a>

확인 모드에서 CloudFront는 모든 뷰어 요청에 CloudFront-Viewer-Cert-\$1 헤더를 자동으로 추가합니다. 이러한 헤더를 오리진에 전달하려면 다음을 수행합니다.

1. 기본 목록 배포 페이지에서 뷰어 mTLS가 활성화된 배포를 선택하고 **동작** 탭으로 이동합니다.

1. 캐시 동작을 선택한 다음 **편집**을 선택합니다.

1. **오리진 요청 정책** 섹션에서 **정책 생성**을 선택하거나 기존 정책을 선택합니다.

1. 오리진 요청 정책에 다음 헤더가 포함되어 있는지 확인합니다.
   + CloudFront-Viewer-Cert-Serial-Number
   + CloudFront-Viewer-Cert-Issuer
   + CloudFront-Viewer-Cert-Subject
   + CloudFront-Viewer-Cert-Present
   + Cloudfront-Viewer-Cert-Sha256
   + CloudFront-Viewer-Cert-Validity
   + CloudFront-Viewer-Cert-Pem

1. **생성**(새 정책의 경우) 또는 **변경 사항 저장**(기존 정책의 경우)을 선택합니다.

1. 캐시 동작 내에서 정책을 선택하고 변경 사항을 저장합니다.

### AWS CLI 사용
<a name="configure-headers-cli"></a>

다음 예제에서는 확인 모드를 위한 mTLS 헤더가 포함된 오리진 요청 정책을 생성하는 방법을 보여줍니다.

```
aws cloudfront create-origin-request-policy \
  --origin-request-policy-config '{
    "Name": "MTLSHeadersPolicy",
    "HeadersConfig": {
      "HeaderBehavior": "whitelist",
      "Headers": {
        "Quantity": 5,
        "Items": [
          "CloudFront-Viewer-Cert-Serial-Number",
          "CloudFront-Viewer-Cert-Issuer",
          "CloudFront-Viewer-Cert-Subject",
          "CloudFront-Viewer-Cert-Validity",
          "CloudFront-Viewer-Cert-Pem"
        ]
      }
    },
    "CookiesConfig": {
      "CookieBehavior": "none"
    },
    "QueryStringsConfig": {
      "QueryStringBehavior": "none"
    }
  }'
```

## 헤더 처리 고려 사항
<a name="header-processing-considerations"></a>

인증서 헤더로 작업할 때는 다음 모범 사례를 고려하세요.
+ **헤더 검증:** 추가 보안 조치로 오리진의 인증서 헤더 값을 확인합니다.
+ **헤더 크기 제한:** 오리진 서버가 처리할 수 있도록 PEM 인증서 헤더의 크기를 키울 수 있습니다.
+ **캐시 고려 사항:** 캐시 키에서 인증서 헤더를 사용하면 캐시 조각화가 증가합니다.
+ **교차 오리진 요청:** 애플리케이션에서 CORS를 사용하는 경우 인증서 헤더를 허용하도록 구성해야 할 수 있습니다.

## 다음 단계
<a name="headers-next-steps"></a>

헤더 전달을 구성한 후 CloudFront 연결 함수 및 KeyValueStore를 사용하여 인증서 해지 확인을 구현할 수 있습니다. 해지 확인 구현에 대한 자세한 내용은 [CloudFront 연결 함수 및 KVS를 사용한 해지](revocation-connection-function-kvs.md) 섹션을 참조하세요.

# CloudFront 연결 함수 및 KVS를 사용한 해지
<a name="revocation-connection-function-kvs"></a>

CloudFront 연결 함수를 KeyValueStore와 결합하여 상호 TLS 인증에 대한 인증서 해지 확인을 구현할 수 있습니다. 이 접근 방식은 CloudFront의 기본 제공 인증서 검증을 보완하는 확장형 실시간 인증서 해지 메커니즘을 제공합니다.

연결 함수는 CloudFront 엣지 로케이션에서 TLS 연결 설정 중에 실행되는 JavaScript 함수로, mTLS 인증을 위한 사용자 지정 인증서 검증 로직을 구현할 수 있습니다. 연결 함수에 대한 자세한 내용은 [CloudFront 연결 함수 연결](connection-functions.md) 섹션을 참조하세요.

## 연결 함수에서 인증서 해지 작동 방식
<a name="how-revocation-works"></a>

CloudFront의 표준 인증서 검증은 인증서 체인, 서명 및 만료를 확인하지만 내장 인증서 해지 확인은 포함하지 않습니다. 연결 함수를 사용하면 TLS 핸드셰이크 중에 사용자 지정 해지 확인을 구현할 수 있습니다.

인증서 해지 프로세스는 다음과 같이 작동합니다.

1. 해지된 인증서 일련 번호를 CloudFront KeyValueStore에 저장합니다.

1. 클라이언트가 인증서를 제시하면 연결 함수가 간접 호출됩니다.

1. 함수는 KeyValueStore에 대해 인증서의 일련 번호를 확인합니다.

1. 스토어에서 일련 번호를 찾으면 인증서가 해지됩니다.

1. 함수는 해지된 인증서에 대한 연결을 거부합니다.

이 접근 방식은 CloudFront의 글로벌 엣지 네트워크에서 해지 확인을 실시간에 가깝게 제공합니다.

## 해지된 인증서에 대한 KeyValueStore 설정
<a name="setup-kvs-revoked-certs"></a>

먼저 KeyValueStore를 생성하여 해지된 인증서의 일련 번호를 저장합니다.

### KeyValueStore를 생성하는 방법(콘솔)
<a name="create-kvs-console"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **키 값 스토어**를 선택합니다.

1. **키 값 스토어 생성**을 선택합니다.

1. 키 값 스토어의 이름(예: revoked-certificates)을 입력합니다.

1. (선택 사항) 설명을 추가합니다.

1. **키 값 스토어 생성**을 선택합니다.

### KeyValueStore를 생성하려면(AWS CLI)
<a name="create-kvs-cli"></a>

다음 예제에서는 KeyValueStore를 생성하는 방법을 보여줍니다.

```
aws cloudfront create-key-value-store \
  --name "revoked-certificates" \
  --comment "Store for revoked certificate serial numbers"
```

## 해지된 인증서 일련 번호 가져오기
<a name="import-revoked-serials"></a>

KeyValueStore를 생성한 후 해지된 인증서의 일련 번호를 가져와야 합니다.

### 해지 데이터 준비
<a name="prepare-revocation-data"></a>

해지된 인증서 일련 번호를 사용하여 JSON 파일을 생성합니다.

```
{
  "data": [
    {
      "key": "ABC123DEF456",
      "value": ""
    },
    {
      "key": "789XYZ012GHI",
      "value": ""
    }
  ]
}
```

### S3에서 가져오기
<a name="import-from-s3"></a>

1. 이 JSON 파일을 S3 버킷에 업로드합니다.

1. 파일을 KeyValueStore로 가져옵니다.

   ```
   aws cloudfront create-key-value-store \
     --name "revoked-certificates" \
     --import-source '{
       "SourceType": "S3",
       "SourceARN": "arn:aws:s3:::amzn-s3-demo-bucket1/revoked-serials.json"
     }'
   ```

## 해지 확인을 위한 연결 함수 생성
<a name="create-revocation-connection-function"></a>

KeyValueStore에 대해 인증서 일련 번호를 확인하는 연결 함수를 생성합니다.

### 연결 함수 코드 예제
<a name="revocation-function-example"></a>

다음 예제에서는 인증서 해지 확인을 수행하는 연결 함수를 보여줍니다.

```
import cf from 'cloudfront';

async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    
    // Get client certificate serial number
    const clientSerialNumber = connection.clientCertificate.certificates.leaf.serialNumber;
    
    // Check if the serial number exists in the KeyValueStore
    const isRevoked = await kvsHandle.exists(clientSerialNumber.replaceAll(':', ''));
    
    if (isRevoked) {
        console.log(`Certificate ${clientSerialNumber} is revoked. Denying connection.`);
        connection.logCustomData(`REVOKED:${clientSerialNumber}`);
        connection.deny();
    } else {
        console.log(`Certificate ${clientSerialNumber} is valid. Allowing connection.`);
        connection.allow();
    }
    
}
```

### 연결 함수를 생성하려면(AWS CLI)
<a name="create-revocation-function-cli"></a>

다음 예제에서는 KeyValueStore 연결을 사용하여 연결 함수를 생성하는 방법을 보여줍니다.

```
aws cloudfront create-connection-function \
  --name "revocation-checker" \
  --connection-function-config '{
      "Comment": "Certificate revocation checking function",
      "Runtime": "cloudfront-js-2.0",
      "KeyValueStoreAssociations": {
          "Quantity": 1,
          "Items": [
              {
                  "KeyValueStoreARN": "arn:aws:cloudfront::123456789012:key-value-store/revoked-certificates"
              }
          ]
      }
  }' \
  --connection-function-code fileb://revocation-checker.js
```

## 함수를 배포에 연결합니다.
<a name="associate-revocation-function"></a>

연결 함수를 생성하고 게시한 후 [CloudFront 연결 함수 연결](connection-functions.md) 섹션에 설명된 대로 mTLS 지원 CloudFront 배포와 연결합니다.

# 연결 로그를 사용한 관찰성
<a name="connection-logs"></a>

CloudFront 연결 로그는 상호 TLS 인증 이벤트에 대한 자세한 가시성을 제공하므로 인증서 검증을 모니터링하고, 연결 시도를 추적하고, 인증 문제를 해결할 수 있습니다.

## 연결 로그란 무엇인가요?
<a name="what-are-connection-logs"></a>

연결 로그는 상호 TLS 지원 배포의 TLS 핸드셰이크 및 인증서 검증에 대한 자세한 정보를 캡처합니다. HTTP 요청 정보를 기록하는 표준 액세스 로그와 달리 연결 로그는 특히 다음을 포함한 TLS 연결 설정 단계에 중점을 둡니다.
+ 연결 상태(성공/실패)
+ 클라이언트 인증서 세부 정보
+ TLS 프로토콜 및 암호 정보
+ 연결 타이밍 지표
+ 연결 함수의 사용자 지정 데이터

이러한 로그는 인증서 기반 인증 이벤트에 대한 포괄적인 가시성을 제공하여 보안을 모니터링하고 문제를 해결하며 규정 준수 요구 사항을 충족하는 데 도움이 됩니다.

## 연결 로그 활성화
<a name="enable-connection-logs"></a>

연결 로그는 상호 TLS 인증이 활성화된 배포에만 사용할 수 있습니다. CloudWatch Logs, Amazon Data Firehose 및 Amazon S3를 비롯한 여러 대상으로 연결 로그를 전송할 수 있습니다.

### 사전 조건
<a name="connection-logs-prerequisites"></a>

연결 로그를 활성화하기 전에:
+ CloudFront 배포에 대한 상호 TLS 구성
+ CloudFront 배포에 대한 연결 로그 활성화
+ 선택한 로깅 대상에 필요한 권한이 있는지 확인합니다.
+ 교차 계정 전송의 경우 적절한 IAM 정책을 구성합니다.

### 연결 로그를 활성화하려면(콘솔)
<a name="enable-connection-logs-console"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 배포 목록에서 mTLS 지원 배포를 선택합니다.

1. **Logging**(로깅) 탭을 선택합니다.

1. **추가**를 선택합니다.

1. 로그를 수신할 서비스를 선택합니다.
   + **CloudWatch 로그**
   + **Firehose** – 
   + **Amazon S3**

1. **대상**에서 선택한 서비스의 리소스를 선택합니다.
   + CloudWatch Logs에서 **로그 그룹 이름**을 입력합니다.
   + Firehose의 경우 **Firehose 전송 스트림**을 선택합니다.
   + Amazon S3의 경우 **버킷 이름**을 입력합니다(접두사 포함은 선택 사항).

1. (선택 사항) 추가 설정 구성:
   + **필드 선택:** 포함할 특정 로그 필드를 선택합니다.
   + **출력 형식:** JSON, 일반, w3c, 원시 또는 Parquet(S3만 해당) 중에서 선택합니다.
   + **필드 구분 기호:** 로그 필드를 구분하는 방법을 지정합니다.

1. **변경 사항 저장**을 선택합니다

### 연결 로그를 활성화하려면(AWS CLI)
<a name="enable-connection-logs-cli"></a>

다음 예제에서는 CloudWatch API를 사용하여 연결 로그를 활성화하는 방법을 보여줍니다.

```
# Step 1: Create a delivery source
aws logs put-delivery-source \
  --name "cf-mtls-connection-logs" \
  --resource-arn "arn:aws:cloudfront::123456789012:distribution/E1A2B3C4D5E6F7" \
  --log-type CONNECTION_LOGS

# Step 2: Create a delivery destination
aws logs put-delivery-destination \
  --name "s3-destination" \
  --delivery-destination-configuration \
  "destinationResourceArn=arn:aws:s3:::amzn-s3-demo-bucket1"

# Step 3: Create the delivery
aws logs create-delivery \
  --delivery-source-name "cf-mtls-connection-logs" \
  --delivery-destination-arn "arn:aws:logs:us-east-1:123456789012:delivery-destination:s3-destination"
```

**참고**  
CloudWatch API를 사용하는 경우 로그를 다른 리전으로 전송할 때도 미국 동부(버지니아 북부) 리전(us-east-1)을 지정해야 합니다.

## 연결 로그 필드
<a name="connection-log-fields"></a>

연결 로그에는 각 TLS 연결 시도에 대한 세부 정보가 포함됩니다.


| 필드 | 설명 | 예제 | 
| --- | --- | --- | 
| eventTimestamp | 연결이 설정되거나 실패한 경우 ISO 8601 타임스탬프 | 1731620046814 | 
| connectionId | TLS 연결의 고유 식별자 | oLHiEKbQSn8lkvJfA3D4gFowK3\$1iZ0g4i5nMUjE1Akod8TuAzn5nzg== | 
| connectionStatus |  mTLS 연결 시도의 상태입니다.  | Success 또는 Failed | 
| clientIp | 연결 클라이언트의 IP 주소 | 2001:0db8:85a3:0000:0000:8a2e:0370:7334 | 
| clientPort | 클라이언트에서 사용하는 포트 | 12137 | 
| serverIp | CloudFront 엣지 서버의 IP 주소 | 99.84.71.136 | 
| distributionId | CloudFront 배포 ID | E2DX1SLDPK0123 | 
| distributionTenantId | CloudFront 배포 테넌트 ID(해당하는 경우) | dt\$12te1Ura9X3R2iCGNjW123 | 
| tlsProtocol | 사용된 TLS 프로토콜 버전 | TLSv1.3 | 
| tlsCipher | 연결에 사용되는 TLS 암호 제품군 | TLS\$1AES\$1128\$1GCM\$1SHA256 | 
| tlsHandshakeDuration | TLS 핸드셰이크 기간(밀리초) | 153 | 
| tlsSni | TLS 핸드셰이크의 서버 이름 표시 값 | d111111abcdef8.cloudfront.net | 
| clientLeafCertSerialNumber | 클라이언트 인증서의 일련 번호 | 00:b1:43:ed:93:d2:d8:f3:9d | 
| clientLeafCertSubject | 클라이언트 인증서의 제목 필드 | C=US, ST=WA, L=Seattle, O=Amazon.com, OU=CloudFront, CN=client.test.mtls.net | 
| clientLeafCertIssuer | 클라이언트 인증서의 발급자 필드 | C=US, ST=WA, L=Seattle, O=Amazon.com, OU=CloudFront, CN=test.mtls.net | 
| clientLeafCertValidity | 클라이언트 인증서의 유효 기간 | NotBefore=2025-06-05T23:28:21Z;NotAfter=2125-05-12T23:28:21Z | 
| connectionLogCustomData | 연결 함수를 통해 추가된 사용자 지정 데이터 | REVOKED:00:b1:43:ed:93:d2:d8:f3:9d | 

## 연결 오류 코드
<a name="connection-error-codes"></a>

```
Failed:ClientCertMaxChainDepthExceeded
Failed:ClientCertMaxSizeExceeded
Failed:ClientCertUntrusted
Failed:ClientCertNotYetValid
Failed:ClientCertExpired
Failed:ClientCertTypeUnsupported
Failed:ClientCertInvalid
Failed:ClientCertIntentInvalid
Failed:ClientCertRejected
Failed:ClientCertMissing
Failed:TcpError
Failed:TcpTimeout
Failed:ConnectionFunctionError
Failed:ConnectionFunctionDenied
Failed:Internal
Failed:UnmappedConnectionError
```

연결이 실패하면 CloudFront는 특정 사유 코드를 기록합니다.


| 코드 | 설명 | 
| --- | --- | 
| ClientCertMaxChainDepthExceeded | 최대 인증서 체인 깊이 초과 | 
| ClientCertMaxSizeExceeded | 최대 인증서 크기 초과 | 
| ClientCertUntrusted | 클라이언트 인증서를 신뢰할 수 없음 | 
| ClientCertNotYetValid | 인증서가 아직 유효하지 않음 | 
| ClientCertExpired | 인증서가 만료됨 | 
| ClientCertTypeUnsupported | 클라이언트 인증서 유형이 지원되지 않음 | 
| ClientCertInvalid | 인증서가 잘못됨 | 
| ClientCertIntentInvalid | 인증서 의도가 잘못됨 | 
| ClientCertRejected | 사용자 지정 검증에서 거부된 인증서 | 
| ClientCertMissing | 인증서 누락 | 
| TcpError |  연결을 설정하는 동안 오류 발생  | 
| TcpTimeout |  제한 시간 내에 연결을 설정할 수 없음  | 
| ConnectionFunctionError |  연결 함수 실행 중에 발견되지 않은 예외 발생  | 
| 내부 |  내부 서비스 오류 발생  | 
| UnmappedConnectionError |  다른 범주에 속하지 않는 오류 발생  | 

# CloudFront에 대한 오리진 상호 TLS
<a name="origin-mtls-authentication"></a>

상호 TLS 인증(상호 전송 계층 보안 인증 - mTLS)은 양방향 인증서 기반 인증을 요구하여 표준 TLS 인증을 확장하는 보안 프로토콜로, 클라이언트와 서버 모두 보안 연결을 설정하기 전에 자격 증명을 증명해야 합니다.

## 뷰어 mTLS와 오리진 mTLS 비교
<a name="viewer-mtls-vs-origin-mtls"></a>

뷰어와 CloudFront 배포(뷰어 mTLS) 간에 또는 CloudFront 배포와 오리진(오리진 mTLS) 간에 상호 인증(mTLS)을 활성화할 수 있습니다. 이 문서는 오리진 mTLS 구성에 관한 것입니다. 뷰어 mTLS 구성은 [CloudFront에 대한 상호 TLS 인증(뷰어 mTLS)CloudFront에 대한 오리진 상호 TLS](mtls-authentication.md) 섹션을 참조하세요.

오리진 mTLS를 통해 CloudFront가 클라이언트 인증서를 사용하여 오리진 서버에 자체 인증을 수행할 수 있습니다. 오리진 mTLS를 사용하면 승인된 CloudFront 배포만 애플리케이션 서버와의 연결을 설정할 수 있으므로 무단 액세스 시도가 방지됩니다.

**참고**  
오리진 mTLS 연결에서 CloudFront는 클라이언트 역할을 하며 TLS 핸드셰이크 중에 오리진 서버에 클라이언트 인증서를 제시합니다. CloudFront는 클라이언트 인증서의 유효성 또는 해지 상태에 대한 검증을 수행하지 않습니다. 이는 오리진 서버의 책임입니다. 오리진 인프라는 보안 요구 사항에 따라 트러스트 스토어와 대조하여 클라이언트 인증서를 검증하고, 인증서 만료를 확인하고, 해지 확인(예: CRL 또는 OCSP 검증)을 수행하도록 구성되어야 합니다. CloudFront의 역할은 인증서를 제공하는 것에 국한됩니다. 모든 인증서 검증 로직 및 보안 정책은 오리진 서버에서 적용됩니다.

## 작동 방식
<a name="how-origin-mtls-works"></a>

CloudFront와 오리진 사이의 표준 TLS 핸드셰이크에서는 오리진 서버만 CloudFront에 ID를 증명하는 인증서를 제공합니다. 오리진 mTLS를 사용하면 인증 프로세스가 양방향으로 이루어집니다. CloudFront가 오리진 서버에 연결을 시도할 때 CloudFront는 TLS 핸드셰이크 중에 클라이언트 인증서를 요청합니다. 오리진 서버는 보안 연결을 설정하기 전에 트러스트 스토어와 대조하여 이 인증서를 검증합니다.

## 사용 사례
<a name="origin-mtls-use-cases"></a>

오리진 mTLS는 기존 인증 방법으로 운영 오버헤드가 발생하는 몇 가지 중요한 보안 시나리오를 해결합니다.
+ **하이브리드 및 멀티 클라우드 보안** - CloudFront와 AWS 외부에서 호스팅되는 오리진 또는 AWS에 있는 퍼블릭 오리진 간의 연결을 보호할 수 있습니다. 따라서 IP 허용 목록 또는 사용자 지정 헤더 솔루션을 관리할 필요가 없으므로 AWS, 온프레미스 데이터 센터 및 서드파티 공급자 간에 일관된 인증서 기반 인증을 제공할 수 있습니다. 분산 인프라를 운영하는 미디어 회사, 소매업체 및 기업은 전체 인프라에서 표준화된 보안 제어를 활용할 수 있습니다.
+ **B2B API 및 백엔드 보안** - CloudFront의 성능 이점을 유지하면서 직접 액세스 시도로부터 백엔드 API 및 마이크로서비스를 보호할 수 있습니다. 인증 요구 사항이 엄격한 SaaS 플랫폼, 결제 처리 시스템 및 엔터프라이즈 애플리케이션은 API 요청이 승인된 CloudFront 배포에서만 시작되는지 확인하여 중간자 공격 및 무단 액세스 시도를 방지할 수 있습니다.

## 중요: 오리진 서버 요구 사항
<a name="important-origin-server-requirements"></a>

오리진 mTLS를 사용하려면 상호 TLS 인증을 지원하도록 오리진 서버를 구성해야 합니다. 오리진 인프라는 다음을 수행할 수 있어야 합니다.
+ TLS 핸드셰이크 중 클라이언트 인증서 요청 및 검증
+ CloudFront의 클라이언트 인증서를 발급한 인증 기관 인증서로 트러스트 스토어 유지 관리
+ 상호 TLS 연결 이벤트 로깅 및 모니터링
+ 인증서 검증 정책 관리 및 인증 실패 처리

CloudFront가 클라이언트 측 인증서 제시를 처리하지만, 이러한 인증서를 검증하고 상호 TLS 연결을 관리할 책임은 오리진 서버에 있습니다. CloudFront에서 오리진 mTLS를 활성화하기 전에 오리진 인프라가 올바르게 구성되어 있는지 확인합니다.

## 시작하기
<a name="how-origin-mtls-getting-started"></a>

CloudFront에 오리진 mTLS를 구현하려면 AWS Certificate Manager에서 클라이언트 인증서를 가져오고, 상호 TLS를 요구하도록 오리진 서버를 구성하고, CloudFront 배포에서 오리진 mTLS를 활성화해야 합니다. 다음 섹션에서는 각 구성 작업에 대한 단계별 지침을 제공합니다.

**Topics**
+ [뷰어 mTLS와 오리진 mTLS 비교](#viewer-mtls-vs-origin-mtls)
+ [작동 방식](#how-origin-mtls-works)
+ [사용 사례](#origin-mtls-use-cases)
+ [중요: 오리진 서버 요구 사항](#important-origin-server-requirements)
+ [시작하기](#how-origin-mtls-getting-started)
+ [AWS Certificate Manager를 사용한 인증서 관리](origin-certificate-management-certificate-manager.md)
+ [CloudFront 배포에 오리진 상호 TLS 활성화](origin-enable-mtls-distributions.md)
+ [오리진 상호 TLS와 함께 CloudFront Functions 사용](origin-mtls-cloudfront-functions.md)

# AWS Certificate Manager를 사용한 인증서 관리
<a name="origin-certificate-management-certificate-manager"></a>

[AWS Certificate Manager(ACM)](https://aws.amazon.com/certificate-manager/)는 오리진 상호 TLS 인증 중에 CloudFront가 오리진 서버에 제시하는 클라이언트 인증서를 저장합니다.

## 인증 기관 지원
<a name="origin-ca-support"></a>

CloudFront 오리진 mTLS는 TLS 클라이언트 인증을 위해 확장 키 사용(EKU)이 포함된 클라이언트 인증서를 필요로 합니다. 이 요구 사항으로 인해 인증 기관에서 인증서를 발급하고 AWS Certificate Manager로 가져와야 합니다. 오리진 mTLS 클라이언트 인증서에는 ACM의 자동 인증서 프로비저닝 및 갱신 기능을 사용할 수 없습니다. CloudFront 오리진 mTLS는 다음 두 소스의 클라이언트 인증서를 지원합니다.
+ **AWS 프라이빗 인증 기관:** 확장 키 사용 필드에 TLS 클라이언트 인증이 포함된 인증서 템플릿(예: EndEntityClientAuthCertificate 템플릿)을 사용하여 AWS Private CA에서 인증서를 발급할 수 있습니다. AWS Private CA에서 인증서를 발급한 후에는 미국 동부(버지니아 북부) 리전(us-east-1)의 ACM으로 인증서를 가져와야 합니다. 이 접근 방식을 사용하면 인증서 수명 주기 관리에 대한 제어력을 유지하면서 AWS Private CA의 보안 이점을 누릴 수 있습니다.
+ **서드파티 프라이빗 인증 기관:** 기존 프라이빗 인증 기관 인프라에서 인증서를 발급하고 ACM으로 가져올 수도 있습니다. 이렇게 하면 CloudFront의 오리진 mTLS 기능을 활용하면서 현재 인증서 관리 프로세스를 유지할 수 있습니다. 인증서는 확장 키 사용 필드에 TLS 클라이언트 인증을 포함해야 하며 인증서, 프라이빗 키 및 인증서 체인이 포함된 PEM 형식이어야 합니다.

**중요**  
AWS 프라이빗 CA와 서드파티 CA 모두에 대해 인증서 만료 날짜를 모니터링하고 만료 전에 갱신된 인증서를 ACM으로 가져오는 것은 사용자의 책임입니다. ACM의 자동 갱신 기능은 오리진 mTLS에 사용되는 가져온 인증서에는 적용되지 않습니다.

## 인증서 요구 사항 및 사양
<a name="origin-certificate-requirements"></a>

### 클라이언트 인증서 요구 사항
<a name="origin-ca-cert-format-requirements"></a>
+ **형식:** PEM(Privacy Enhanced Mail) 형식
+ **구성 요소:** 인증서, 프라이빗 키 및 인증서 체인
+ **최대 인증서 체인 깊이:** 3(리프 인증서 \$1 중간 인증서 \$1 루트 인증서)
+ **최대 인증서 체인 크기**: 64KB
+ **인증서 크기:** 96KB를 초과할 수 없음
+ **최대 프라이빗 키 크기:** 5KB(ACM 제한)
+ **CloudFront 배포 생성 또는 업데이트 API 직접 호출당 추가하거나 수정할 수 있는 최대 고유 오리진 mTLS 인증서 ARN 수:** 5
+ **리전:** 인증서는 미국 동부(버지니아 북부) 리전(us-east-1)의 ACM에 저장되어야 합니다.

### 지원되는 인증서 사양
<a name="origin-supported-cert-specs"></a>
+ **인증서 유형:** X.509v3
+ **퍼블릭 키 알고리즘:**
  + RSA: 2048비트
  + ECDSA: P-256
+ **서명 알고리즘:**
  + RSA를 사용하는 SHA256, SHA384, SHA512
  + ECDSA를 사용하는 SHA256, SHA384, SHA512
  + MGF1 지원 RSASSA-PSS를 사용하는 SHA256, SHA384, SHA512
+ **확장 키 사용(필수):** 인증서는 mTLS 용도로 사용하기 위해 TLS 클라이언트 인증으로 설정된 확장 키 사용(EKU) 확장 기능을 필요로 합니다.

### 서버 인증서 요구 사항
<a name="origin-server-certificate-requirements"></a>

오리진 서버는 상호 TLS 핸드셰이크 중에 공개적으로 신뢰할 수 있는 인증 기관의 인증서를 제시해야 합니다. 오리진 서버 인증서 요구 사항에 대한 자세한 내용은 [CloudFront에서 SSL/TLS 인증서를 사용하기 위한 요구 사항](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-https-cloudfront-to-custom-origin.html#using-https-cloudfront-to-origin-certificate)을 참조하세요.

### 인증서 요청 또는 가져오기
<a name="origin-request-import-certificate"></a>

오리진 mTLS를 활성화하기 전에 ACM에서 사용할 수 있는 클라이언트 인증서가 있어야 합니다.

#### AWS Private CA에서 인증서 요청 및 가져오기
<a name="request-certificate-aws-private-ca"></a>

사전 조건:
+ 계정에 구성된 AWS Private Certificate Authority
+ AWS Private CA에서 인증서를 발급할 수 있는 권한
+ ACM으로 인증서를 가져올 수 있는 권한
+ 사용 사례에 적합한 `Extended key usage:TLS web client authentication`이 포함된 [인증서 템플릿](https://docs.aws.amazon.com/privateca/latest/userguide/UsingTemplates.html) ARN
+ OpenSSL, AWS CLI 및 jq(JSON 구문 분석용)를 설치합니다.

##### PCA에서 인증서를 요청하고 ACM으로 가져오는 방법(AWS CLI)
<a name="request-certificate-cli"></a>

1. 쉽게 재사용할 수 있도록 변수에 프라이빗 CA ARN을 설정합니다.

   ```
   PCA_ARN="arn:aws:acm-pca:region:account:certificate-authority/12345678..."
   ```

1. OpenSSL을 사용하여 ECDSA P-256 프라이빗 키(prime256v1 곡선) 및 인증서 서명 요청(CSR)을 생성하고, ACM 가져오기에 필요한 대로 프라이빗 키를 암호화되지 않은 상태로 유지하기 위해 -node 플래그를 사용합니다.

   ```
   openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes \
       -keyout private.key \
       -out request.csr \
       -subj "/CN=client.example.com"
   ```

1. AWS Private CA에 CSR을 제출하여 인증서를 발급하면 새로 발급된 인증서의 ARN이 반환됩니다.

   ```
   CERT_ARN=$(aws acm-pca issue-certificate \
       --certificate-authority-arn "$PCA_ARN" \
       --csr fileb://request.csr \
       --signing-algorithm "SHA256WITHECDSA" \
       --validity Value=365,Type="DAYS" \
       --template-arn arn:aws:acm-pca:::template/EndEntityCertificate/V1 \
       --query 'CertificateArn' --output text)
   ```

1. get-certificate 명령을 사용하여 AWS PCA에서 인증서 번들을 검색합니다. 이 명령은 리프 인증서와 체인을 모두 반환합니다. 그런 다음 jq를 사용하여 이들을 별도의 파일로 분리합니다.

   ```
   # Retrieve the full certificate bundle in JSON format
   aws acm-pca get-certificate \
       --certificate-authority-arn "$PCA_ARN" \
       --certificate-arn "$CERT_ARN" \
       --output json > full_cert.json
   
   # Split into Leaf and Chain
   jq -r '.Certificate' full_cert.json > leaf_cert.pem
   jq -r '.CertificateChain' full_cert.json > cert_chain.pem
   ```

1. CLI에서 이진 파일 데이터를 올바르게 처리하도록 fileb:// 프로토콜을 사용하여 암호화되지 않은 프라이빗 키, 리프 인증서 및 인증서 체인을 AWS ACM으로 가져옵니다.

   ```
   aws acm import-certificate \
       --certificate fileb://leaf_cert.pem \
       --private-key fileb://private.key \
       --certificate-chain fileb://cert_chain.pem \
       --region us-east-1 \
       --query 'CertificateArn' \
       --output text
   ```

#### 서드파티 CA에서 인증서 가져오기
<a name="import-certificate-third-party-ca"></a>

사전 조건:
+ 인증 기관에서 발급한 인증서, 암호화되지 않은 프라이빗 키 및 인증서 체인(PEM 형식)
+ 인증서에는 TLS 클라이언트 인증을 위한 확장 키 사용이 포함되어야 함
+ ACM으로 인증서를 가져올 수 있는 권한

##### 인증서를 ACM으로 가져오는 방법(AWS CLI)
<a name="import-certificate-cli"></a>

```
aws acm import-certificate \
  --certificate fileb://certificate.pem \
  --private-key fileb://private-key.pem \
  --certificate-chain fileb://certificate-chain.pem \
  --region us-east-1 \
  --query 'CertificateArn' \
  --output text
```

#### 다음 단계
<a name="certificate-next-steps"></a>

ACM에서 클라이언트 인증서를 획득하거나 가져온 후에는 오리진 서버에서 상호 TLS 인증을 요구하도록 구성하고 CloudFront 배포에서 오리진 mTLS를 활성화할 수 있습니다. CloudFront에서 오리진 mTLS를 활성화하는 방법에 대한 지침은 다음 섹션인 "CloudFront 배포에 오리진 상호 TLS 활성화"를 참조하세요.

# CloudFront 배포에 오리진 상호 TLS 활성화
<a name="origin-enable-mtls-distributions"></a>

AWS Certificate Manager를 통해 클라이언트 인증서를 획득하고 상호 TLS를 요구하도록 오리진 서버를 구성한 후 CloudFront 배포에서 오리진 mTLS를 활성화할 수 있습니다.

## 사전 조건 및 요구 사항
<a name="origin-mtls-prerequisites-requirements"></a>

CloudFront 배포에서 오리진 mTLS를 활성화하기 전에 다음을 확인해야 합니다.
+ 미국 동부(버지니아 북부) 리전(us-east-1)의 AWS Certificate Manager에 저장된 클라이언트 인증서
+ 상호 TLS 인증을 요구하고 클라이언트 인증서를 검증하도록 구성된 오리진 서버
+ 공개적으로 신뢰할 수 있는 인증 기관의 인증서를 제시하는 오리진 서버
+ CloudFront 배포를 수정할 수 있는 권한
+ 오리진 mTLS는 비즈니스, 프리미엄 또는 종량제 요금제에서만 사용할 수 있습니다.

**참고**  
사용자 지정 오리진(AWS 외부에서 호스팅되는 오리진 포함)과 Application Load Balancer 및 API Gateway와 같은 상호 TLS를 지원하는 AWS 오리진에 대해 오리진 mTLS를 구성할 수 있습니다.

**중요**  
다음 CloudFront 기능은 오리진 mTLS에서 지원되지 않습니다.  
**gRPC 트래픽:** 오리진 mTLS가 활성화된 오리진에는 gRPC 프로토콜이 지원되지 않습니다.
**WebSocket 연결:** 오리진 mTLS가 활성화된 오리진에는 WebSocket 프로토콜이 지원되지 않습니다.
**VPC 오리진:** 오리진 mTLS는 VPC 오리진과 함께 사용할 수 없습니다.
**Lambda@Edge를 사용한 오리진 요청 및 오리진 응답 트리거:** 오리진 요청 및 오리진 응답 위치의 Lambda@Edge 함수는 오리진 mTLS에서 지원되지 않습니다.
**임베디드 POP:** 임베디드 POP에는 오리진 mTLS가 지원되지 않습니다.

## 오리진 mTLS 활성화
<a name="origin-enable-mtls-per-origin"></a>

오리진별 구성을 사용하면 동일한 배포 내에서 오리진별로 서로 다른 클라이언트 인증서를 지정할 수 있습니다. 이 접근 방식은 오리진별로 인증 요구 사항이 다를 때 유연성을 극대화합니다.

### 새 배포의 경우(콘솔)
<a name="origin-enable-mtls-new-distributions"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. **배포 생성**을 선택합니다.

1. 요금제 선택: **비즈니스** 또는 **프리미엄** 또는 **종량제**를 선택합니다(오리진 mTLS는 무료 요금제로 사용할 수 없음).

1. 오리진 설정 섹션에서 오리진 유형을 기타로 선택합니다.

1. **오리진 설정** 섹션에서 **오리진 설정 사용자 지정**을 선택합니다.

1. 첫 번째 오리진(도메인 이름, 프로토콜 등)을 구성합니다.

1. 오리진 구성에서 **mTLS**를 찾습니다.

1. **mTLS**를 켜기로 전환합니다.

1. **클라이언트 인증서**의 경우 Certificate Manager에서 AWS 인증서를 선택합니다.

1. (선택 사항) 자체 오리진 mTLS 구성으로 오리진을 더 추가합니다.

1. 나머지 배포 설정을 완료한 다음 **배포 생성**을 선택합니다.

### 기존 배포의 경우(콘솔)
<a name="origin-enable-mtls-existing-distributions"></a>

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 배포 목록에서 수정하려는 배포를 선택합니다. (참고: 해당 배포가 **프로 또는 프리미엄 또는 종량제** 요금제에 포함되어 있는지 확인하세요. 포함되지 않은 경우 오리진 mTLS를 활성화하기 전에 요금제를 업그레이드해야 합니다.)

1. **오리진** 탭을 선택합니다.

1. 구성하려는 오리진을 선택하고 **편집**을 선택합니다.

1. 오리진 설정에서 **mTLS**를 찾습니다.

1. **mTLS**를 켜기로 전환합니다.

1. **클라이언트 인증서**의 경우 AWS Certificate Manager에서 인증서를 선택합니다. (참고: EKU(확장 키 사용) 속성이 "TLS 클라이언트 인증"으로 설정된 클라이언트 인증서만 나열됩니다.)

1. **변경 사항 저장**을 선택합니다

1. 필요에 따라 추가 오리진에 대해 이 과정을 반복합니다.

## AWS CLI 사용
<a name="origin-enable-mtls-cli"></a>

오리진별 구성의 경우 각 오리진의 구성 내에서 오리진 mTLS 설정을 지정합니다.

```
{
  "Origins": {
    "Quantity": 2,
    "Items": [
      {
        "Id": "origin-1",
        "DomainName": "api.example.com",
        "CustomOriginConfig": {
          "HTTPSPort": 443,
          "OriginProtocolPolicy": "https-only"
        },
        "OriginMtlsConfig": {
          "ClientCertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/cert-1"
        }
      },
      {
        "Id": "origin-2",
        "DomainName": "backend.example.com",
        "CustomOriginConfig": {
          "HTTPSPort": 443,
          "OriginProtocolPolicy": "https-only"
        },
        "OriginMtlsConfig": {
          "CertificateArn": "arn:aws:acm:us-east-1:123456789012:certificate/cert-2"
        }
      }
    ]
  }
}
```

**참고**  
서버에서 요청하지 않으면 CloudFront가 클라이언트 인증서를 제공하지 않고 연결이 정상적으로 진행될 수 있습니다.

## 다음 단계
<a name="origin-enable-mtls-next-steps"></a>

CloudFront 배포에서 오리진 mTLS를 활성화한 후 CloudFront 액세스 로그를 사용하여 인증 이벤트를 모니터링할 수 있습니다.

# 오리진 상호 TLS와 함께 CloudFront Functions 사용
<a name="origin-mtls-cloudfront-functions"></a>

CloudFront Functions는 콘텐츠 전송을 사용자 지정하도록 엣지에서 경량 서버리스 컴퓨팅을 제공합니다. CloudFront Functions와 함께 오리진 상호 TLS를 사용하는 경우 오리진 선택 및 조작과 관련하여 알아야 할 특정 동작 및 제한 사항이 있습니다.

## 지원되는 CloudFront Functions 작업
<a name="supported-cloudfront-functions-operations"></a>

CloudFront Functions는 다음과 같은 방법으로 mTLS가 활성화된 오리진과 상호 작용할 수 있습니다.

### updateRequestOrigin()
<a name="update-request-origin-function"></a>

updateRequestOrigin() 함수는 mTLS가 활성화된 오리진을 사용하여 작업할 때 제한적인 수정을 지원합니다.
+ **오리진 mTLS 오리진 간 전환:** 두 오리진이 **동일한 클라이언트 인증서**를 사용하는 경우 오리진 mTLS를 사용하는 다른 오리진으로 라우팅하도록 요청을 업데이트할 수 있습니다. 이를 통해 상호 TLS 인증을 유지하면서 사용자 지정 라우팅 로직을 구현할 수 있습니다.
+ **오리진 mTLS 비활성화:** 함수에서 `mTLSConfig: 'off'`를 설정하여 mTLS가 활성화된 오리진에서 비 mTLS 오리진으로 전환할 수 있습니다. 이렇게 하면 요청 특성에 따라 상호 TLS 인증을 조건부로 비활성화할 수 있는 유연성이 제공됩니다.

#### 예: 동일한 인증서를 사용하여 오리진 mTLS 오리진 간 전환
<a name="example-switching-mtls-origins"></a>

```
function handler(event) {
    var request = event.request;

    // Route to different origin based on request path
    if (request.uri.startsWith('/api/v2')) {
        request.origin = {
            domainName: 'api-v2.example.com',
            customHeaders: {},
            // Both origins must use the same certificate
        };
    }

    return request;
}
```

#### 예: 조건부로 오리진 mTLS 비활성화
<a name="example-disabling-mtls"></a>

```
function handler(event) {
    var request = event.request;

    // Disable mTLS for specific paths
    if (request.uri.startsWith('/public')) {
        request.origin = {
            domainName: 'public-origin.example.com',
            customHeaders: {},
            mTLSConfig: 'off'
        };
    }

    return request;
}
```

## 지원되지 않는 CloudFront Functions 작업
<a name="unsupported-cloudfront-functions-operations"></a>

다음 CloudFront Functions 작업은 정식 출시 시점에 mTLS가 활성화된 오리진을 지원하지 않습니다.

### selectRequestOriginById()
<a name="select-request-origin-by-id-function"></a>

`selectRequestOriginById()` 함수는 오리진 mTLS가 활성화된 오리진을 선택할 수 없습니다. 이 함수를 사용하여 mTLS가 활성화된 오리진을 선택하려고 하면 검증 오류가 발생합니다.

사용 사례에 따라 오리진 mTLS를 사용한 동적 오리진 선택이 필요한 경우, 모든 대상 오리진이 동일한 클라이언트 인증서를 사용하도록 `updateRequestOrigin()`을 대신 사용하세요.

### createRequestOriginGroup()
<a name="create-request-origin-group-function"></a>

`createRequestOriginGroup()` 함수는 mTLS가 활성화된 오리진을 포함하는 오리진 그룹 생성을 지원하지 않습니다. 오리진 mTLS 오리진이 있는 오리진 그룹은 CloudFront Functions를 통해 동적으로 생성할 수 없습니다.

오리진 mTLS를 사용한 오리진 장애 조치 기능이 필요한 경우 함수에서 동적으로 생성하는 대신 CloudFront 배포 설정에서 오리진 그룹을 직접 구성하세요.

# 서명된 URL과 서명된 쿠키를 사용하여 프라이빗 콘텐츠 제공
<a name="PrivateContent"></a>

인터넷을 통해 콘텐츠를 배포하는 많은 기업에서는 유료 사용자 등 일부 사용자용으로 제작된 각종 문서, 비즈니스 데이터, 미디어 스트림 또는 콘텐츠에 대한 액세스를 제한하고자 합니다. CloudFront를 통해 이러한 프라이빗 콘텐츠를 안전하게 제공하려면 다음과 같이 하세요.
+ 사용자가 특별한 CloudFront 서명된 URL 또는 서명된 쿠키를 사용하여 프라이빗 콘텐츠에 액세스하도록 합니다.
+ 사용자가 오리진 서버(예: Amazon S3 또는 프라이빗 HTTP 서버)에서 직접 콘텐츠에 액세스하는 URL이 아닌 CloudFront URL을 사용하여 콘텐츠에 액세스해야 합니다. 반드시 CloudFront URL을 사용해야 하는 것은 아니지만, 서명된 URL 또는 서명된 쿠키에 지정한 제약 조건을 사용자가 우회하지 못하도록 하려면 사용하는 것이 좋습니다.

자세한 내용은 [파일에 대한 액세스 제한](private-content-overview.md) 섹션을 참조하세요.

## 프라이빗 콘텐츠를 제공하는 방법
<a name="private-content-task-list"></a>

프라이빗 콘텐츠를 제공하도록 CloudFront를 구성하려면 다음 작업을 수행하세요.

1. (권장 선택 사항) 사용자가 CloudFront를 통해서만 콘텐츠에 액세스하도록 요구합니다. 사용하는 방식은 Amazon S3 또는 사용자 지정 오리진 중 어떤 것을 사용하는지에 따라 다릅니다.
   + **Amazon S3** – [Amazon S3 오리진에 대한 액세스 제한](private-content-restricting-access-to-s3.md) 단원을 참조하세요.
   + **사용자 지정 오리진** – [사용자 지정 오리진의 파일에 대한 액세스 제한](private-content-overview.md#forward-custom-headers-restrict-access) 단원을 참조하세요.

   사용자 지정 오리진은 Amazon EC2, 웹 사이트 엔드포인트로 구성된 Amazon S3 버킷, Elastic Load Balancing, 자체 HTTP 웹 서버를 포함합니다.

1. 서명된 URL 또는 서명된 쿠키를 생성할 때 사용할 *신뢰할 수 있는 키 그룹* 또는 *신뢰할 수 있는 서명자*를 지정합니다. 신뢰할 수 있는 키 그룹을 사용하는 것이 좋습니다. 자세한 내용은 [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md) 단원을 참조하세요.

1. 서명된 쿠키를 설정하는 `Set-Cookie` 헤더 또는 서명된 URL을 보유한 권한 있는 사용자의 요청에 응답하는 애플리케이션을 작성합니다. 다음 주제 중 하나에 있는 단계를 따릅니다.
   + [서명된 URL 사용](private-content-signed-urls.md)
   + [서명된 쿠키 사용](private-content-signed-cookies.md)

   어떤 방법을 사용할지 확실하지 않은 경우 [서명된 URL 또는 서명된 쿠키 사용 결정](private-content-choosing-signed-urls-cookies.md) 단원을 참조하세요.

**Topics**
+ [프라이빗 콘텐츠를 제공하는 방법](#private-content-task-list)
+ [파일에 대한 액세스 제한](private-content-overview.md)
+ [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md)
+ [서명된 URL 또는 서명된 쿠키 사용 결정](private-content-choosing-signed-urls-cookies.md)
+ [서명된 URL 사용](private-content-signed-urls.md)
+ [서명된 쿠키 사용](private-content-signed-cookies.md)
+ [base64 인코딩 및 암호화를 위한 Linux 명령 및 OpenSSL](private-content-linux-openssl.md)
+ [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)

# 파일에 대한 액세스 제한
<a name="private-content-overview"></a>

프라이빗 콘텐츠에 대한 사용자 액세스를 두 가지 방법으로 제어할 수 있습니다.
+ [CloudFront 캐시에 있는 파일에 대한 액세스를 제한합니다](#private-content-overview-edge-caches).
+ 다음 중 하나를 수행하여 오리진의 파일에 대한 액세스를 제한합니다.
  + [Amazon S3 버킷의 오리진 액세스 제어(OAC)를 설정합니다](private-content-restricting-access-to-s3.md).
  + [프라이빗 HTTP 서버(사용자 지정 오리진)에 대한 사용자 지정 헤더를 구성합니다.](#forward-custom-headers-restrict-access)

## CloudFront 캐시에 있는 파일에 대한 액세스 제한
<a name="private-content-overview-edge-caches"></a>

사용자가 *서명된 URL* 또는 *서명된 쿠키*를 사용하여 파일에 액세스할 것을 요구하도록 CloudFront를 구성할 수 있습니다. 그런 다음 서명된 URL을 만들어 인증된 사용자에게 배포하거나 인증된 사용자를 위해 `Set-Cookie` 헤더를 보내 서명된 쿠키를 설정하도록 하는 애플리케이션을 개발합니다. (사용자 몇 명에게 적은 수의 파일에 대한 장기 액세스 권한을 부여하려면 서명된 URL을 수동으로 만드는 방법도 있습니다.) 

서명된 URL 또는 서명된 쿠키를 만들어 파일 액세스를 제어할 때 다음과 같은 제약 조건을 지정할 수 있습니다.
+ URL의 효력이 사라지는 종료 날짜 및 시간 
+ (선택 사항) URL의 효력이 발생하는 날짜 및 시간
+ (선택 사항) 콘텐츠에 액세스할 때 사용할 수 있는 컴퓨터의 IP 주소 또는 주소 범위 

퍼블릭–프라이빗 키 페어의 프라이빗 키를 사용하여 서명된 URL 또는 서명된 쿠키의 일부분을 해시 및 서명합니다. 누군가 서명된 URL 또는 서명된 쿠키를 사용하여 파일에 액세스하면 CloudFront는 URL 또는 쿠키의 서명된 부분과 서명되지 않은 부분을 비교합니다. 양쪽이 일치하지 않으면 CloudFront는 파일을 제공하지 않습니다.

URL 또는 쿠키에 서명하려면 RSA 2048 또는 ECDSA 256 프라이빗 키를 사용해야 합니다.

## Amazon S3 버킷에 있는 파일에 대한 액세스 제한
<a name="private-content-overview-s3"></a>

사용자가 지정된 CloudFront 배포를 통해 액세스할 수는 있지만 Amazon S3 URL을 사용하여 직접 액세스할 수는 없도록 Amazon S3 버킷의 콘텐츠를 선택적으로 보호할 수 있습니다. 이렇게 하면 CloudFront를 우회하고 Amazon S3 URL을 사용하여 액세스 제한 콘텐츠에 접근하는 사람을 막을 수 있습니다. 서명된 URL을 사용하기 위해 꼭 필요한 단계는 아니지만 이렇게 하는 것이 좋습니다.

사용자가 CloudFront URL을 통해 콘텐츠에 액세스하도록 요구하려면 다음 작업을 수행합니다.
+ CloudFront에 S3 버킷의 파일을 읽을 수 있는 *오리진 액세스 제어* 권한을 부여합니다.
+ 오리진 액세스 제어를 생성하고 CloudFront 배포와 연결합니다.
+ 나머지 모든 사람으로부터 Amazon S3 URL을 사용하여 파일을 읽을 수 있는 권한을 제거합니다.

자세한 내용은 [Amazon S3 오리진에 대한 액세스 제한](private-content-restricting-access-to-s3.md) 섹션을 참조하세요.

## 사용자 지정 오리진의 파일에 대한 액세스 제한
<a name="forward-custom-headers-restrict-access"></a>

사용자 지정 오리진을 사용하는 경우 선택적으로 사용자 지정 헤더를 설정하여 액세스를 제한할 수 있습니다. CloudFront가 사용자 지정 오리진에서 파일을 가져오려면 표준 HTTP(또는 HTTPS) 요청을 사용하여 CloudFront에서 해당 파일에 액세스할 수 있어야 합니다. 그러나 사용자 지정 헤더를 사용하면 사용자가 직접 액세스할 수 없고 CloudFront를 통해서만 액세스할 수 있도록 콘텐츠에 대한 액세스를 추가로 제한할 수 있습니다. 서명된 URL을 사용하기 위해 꼭 필요한 단계는 아니지만 이렇게 하는 것이 좋습니다.

사용자가 CloudFront를 통해 콘텐츠에 액세스하도록 하려면 CloudFront 배포의 다음 설정을 변경합니다.

**오리진 사용자 지정 헤더**  
오리진에 사용자 지정 헤더를 전달하도록 CloudFront를 구성합니다. [사용자 지정 헤더를 오리진 요청에 추가하도록 CloudFront 구성](add-origin-custom-headers.md#add-origin-custom-headers-configure)을(를) 참조하세요.

**Viewer Protocol Policy**  
최종 사용자가 HTTPS를 사용하여 CloudFront에 액세스하도록 배포를 구성합니다. [뷰어 프로토콜 정책](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy)을(를) 참조하세요.

**오리진 프로토콜 정책**  
CloudFront가 최종 사용자와 같은 프로토콜을 사용하여 오리진에 요청을 전달하도록 배포를 구성합니다. [프로토콜(사용자 지정 오리진만 해당)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy)을(를) 참조하세요.

이러한 변경을 수행한 후에는 CloudFront에서 전송하도록 구성한 사용자 지정 헤더를 포함하는 요청만 수락하도록 사용자 지정 오리진에서 애플리케이션을 업데이트합니다.

**최종 사용자 프로토콜 정책**(Viewer Protocol Policy)과 **오리진 프로토콜 정책**(Origin Protocol Policy)의 조합을 통해 사용자 지정 헤더가 전송 중에 암호화되도록 합니다. 하지만 주기적으로 다음을 수행하여 CloudFront가 오리진에 전달하는 사용자 지정 헤더를 교체하는 것이 좋습니다.

1. CloudFront 배포를 업데이트하여 사용자 지정 오리진에 새 헤더 전달을 시작합니다.

1. 요청이 CloudFront에서 온다는 확인으로 애플리케이션을 업데이트하여 새 헤더를 허용합니다.

1. 요청에 더 이상 교체하는 헤더가 포함되지 않는 경우, 요청이 CloudFront에서 온다는 확인으로 애플리케이션을 업데이트하여 새 헤더를 허용합니다.

# 서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정
<a name="private-content-trusted-signers"></a>

**Topics**
+ [신뢰할 수 있는 키 그룹(권장)과 AWS 계정 사이에서 선택](#choosing-key-groups-or-AWS-accounts)
+ [서명자에 대해 키 페어 생성](#private-content-creating-cloudfront-key-pairs)
+ [프라이빗 키 재포맷(.NET 및 Java만 해당)](#private-content-reformatting-private-key)
+ [배포에 서명자 추가](#private-content-adding-trusted-signers)
+ [키 페어 교체](#private-content-rotating-key-pairs)

서명된 URL 또는 서명된 쿠키를 만들려면 *서명자*가 필요합니다. 서명자는 CloudFront에 생성하는 신뢰할 수 있는 키 그룹이거나, CloudFront 키 페어가 포함된 AWS 계정입니다. 서명된 URL 및 서명된 쿠키와 함께 신뢰할 수 있는 키 그룹을 사용하는 것이 좋습니다. 자세한 내용은 [신뢰할 수 있는 키 그룹(권장)과 AWS 계정 사이에서 선택](#choosing-key-groups-or-AWS-accounts) 단원을 참조하세요.

서명자에는 두 가지 목적이 있습니다.
+ 배포에 서명자를 추가하는 즉시 CloudFront에서는 파일에 액세스할 때 서명된 URL 또는 서명된 쿠키를 사용할 것을 최종 사용자에게 요구하기 시작합니다.
+ 서명된 URL 또는 서명된 쿠키를 만들 때는 서명자의 키 페어에서 프라이빗 키를 사용하여 URL 또는 쿠키의 일부분에 서명합니다. 제한된 객체에 대한 요청이 들어오면 CloudFront는 URL 또는 쿠키의 서명을 서명되지 않은 URL 또는 쿠키와 비교하여 URL 또는 쿠키가 변조되지 않았는지 확인합니다. 또한 CloudFront는 URL 또는 쿠키가 유효한지, 의미가 있는지를 확인합니다(예: 만료 날짜 및 시간 이전인지 확인).

서명자를 지정할 때 서명자를 캐시 동작에 추가하여 서명된 URL 또는 서명된 쿠키가 필요한 파일을 간접적으로 지정합니다. 배포에 캐시 동작이 한 개뿐이라면 최종 사용자는 반드시 서명된 URL 또는 서명된 쿠키를 사용하여 해당 배포의 파일에 액세스해야 합니다. 여러 가지 캐시 동작을 만들고 일부 캐시 동작에만 서명자를 추가하는 경우, 일부 파일에 액세스할 때만 서명된 URL 또는 서명된 쿠키를 사용하도록 최종 사용자에게 요구할 수 있습니다.

서명된 URL 또는 서명된 쿠키를 만들고 CloudFront 배포에 서명자를 추가할 수 있는 서명자(프라이빗 키)를 지정하려면 다음 작업을 수행하세요.

1. 신뢰할 수 있는 키 그룹 또는 AWS 계정을 서명자로 사용할지 결정합니다. 신뢰할 수 있는 키 그룹을 사용하는 것이 좋습니다. 자세한 내용은 [신뢰할 수 있는 키 그룹(권장)과 AWS 계정 사이에서 선택](#choosing-key-groups-or-AWS-accounts) 단원을 참조하세요.

1. 1단계에서 선택한 서명자에 대해 퍼블릭–프라이빗 키 페어를 만듭니다. 자세한 내용은 [서명자에 대해 키 페어 생성](#private-content-creating-cloudfront-key-pairs) 단원을 참조하세요.

1. .NET 또는 Java를 사용하여 서명된 URL 또는 서명된 쿠키를 만드는 경우, 프라이빗 키를 다시 포맷해야 합니다. 자세한 내용은 [프라이빗 키 재포맷(.NET 및 Java만 해당)](#private-content-reformatting-private-key) 단원을 참조하세요.

1. 서명된 URL 또는 서명된 쿠키를 만들려는 배포에서 서명자를 지정합니다. 자세한 내용은 [배포에 서명자 추가](#private-content-adding-trusted-signers) 섹션을 참조하세요.

## 신뢰할 수 있는 키 그룹(권장)과 AWS 계정 사이에서 선택
<a name="choosing-key-groups-or-AWS-accounts"></a>

서명된 URL 또는 서명된 쿠키를 사용하려면 *서명자*가 필요합니다. 서명자는 CloudFront에 생성하는 신뢰할 수 있는 키 그룹이거나, CloudFront 키 페어가 포함된 AWS 계정입니다. 다음과 같은 이유로 신뢰할 수 있는 키 그룹을 사용하는 것이 좋습니다.
+ CloudFront 키 그룹을 사용하면 CloudFront 서명된 URL 및 서명된 쿠키에 대한 퍼블릭 키를 관리하기 위해 AWS 계정 루트 사용자를 사용할 필요가 없습니다. [AWS 모범 사례](https://docs.aws.amazon.com/general/latest/gr/root-vs-iam.html#aws_tasks-that-require-root)에서는 필요하지 않은 경우 루트 사용자를 사용하지 않는 것을 권장합니다.
+ CloudFront 키 그룹을 사용하면 CloudFront API를 사용하여 퍼블릭 키, 키 그룹 및 신뢰할 수 있는 서명자를 관리할 수 있습니다. API를 사용하여 키 생성 및 키 회전을 자동화할 수 있습니다. AWS 루트 사용자를 사용할 때는 AWS Management Console을 사용하여 CloudFront 키 페어를 관리해야 하므로 프로세스를 자동화할 수 없습니다.
+ CloudFront API를 사용하여 키 그룹을 관리할 수 있으므로 AWS Identity and Access Management(IAM) 권한 정책을 사용하여 다른 사용자가 수행할 수 있는 작업을 제한할 수도 있습니다. 예를 들어 사용자가 퍼블릭 키를 업로드하되 삭제할 수는 없도록 할 수 있습니다. 또는 멀티 팩터 인증을 사용하거나 특정 네트워크에서 요청을 보내거나 특정 날짜 및 시간 범위 내에서 요청을 보내는 등 특정 조건을 충족하는 경우에만 사용자가 퍼블릭 키를 삭제하도록 허용할 수 있습니다.
+ CloudFront 키 그룹을 사용하면 더 많은 수의 퍼블릭 키를 CloudFront 배포와 연결할 수 있으므로 퍼블릭 키를 더 유연하게 사용하고 관리할 수 있습니다. 기본적으로 단일 배포에 최대 4개의 키 그룹을 연결할 수 있으며 키 그룹에 최대 5개의 퍼블릭 키를 포함할 수 있습니다.

  AWS 계정 루트 사용자를 사용하여 CloudFront 키 페어를 관리하는 경우 AWS 계정당 최대 두 개의 활성 CloudFront 키 페어만 가질 수 있습니다.

## 서명자에 대해 키 페어 생성
<a name="private-content-creating-cloudfront-key-pairs"></a>

CloudFront 서명된 URL 또는 서명된 쿠키를 만드는 데 사용하는 각 서명자에게는 퍼블릭–프라이빗 키 페어가 있어야 합니다. 서명자는 프라이빗 키를 사용하여 URL 또는 쿠키에 서명하고 CloudFront는 퍼블릭 키를 사용하여 서명을 확인합니다.

키 페어를 생성하는 방법은 신뢰할 수 있는 키 그룹을 서명자(권장)로 사용하는지 또는 CloudFront 키 페어로 사용하는지에 따라 다릅니다. 자세한 내용은 다음 단원을 참조하세요. 생성하는 키 페어는 다음 요구 사항을 충족해야 합니다.
+ SSH-2 RSA 2048 또는 ECDSA 256 키 페어여야 합니다.
+ base64로 인코딩된 PEM 형식이어야 합니다.

애플리케이션 보안을 위해 키 페어를 주기적으로 교체하는 것이 좋습니다. 자세한 내용은 [키 페어 교체](#private-content-rotating-key-pairs) 단원을 참조하세요.

### 신뢰할 수 있는 키 그룹에 대한 키 페어 생성(권장)
<a name="create-key-pair-and-key-group"></a>

신뢰할 수 있는 키 그룹에 대한 키 페어를 생성하려면 다음 단계를 수행합니다.

1. 퍼블릭–프라이빗 키 페어를 생성합니다.

1. CloudFront에 퍼블릭 키를 업로드합니다.

1. CloudFront 키 그룹에 퍼블릭 키를 추가합니다.

자세한 내용은 다음 절차를 참조하세요.<a name="private-content-uploading-cloudfront-public-key-procedure"></a>

**키 페어를 생성하려면**
**참고**  
다음 단계에서는 키 페어를 생성하는 방법의 예시로 OpenSSL을 사용합니다. RSA 또는 ECDSA 키 페어를 생성하는 방법에는 여러 가지가 있습니다.

1. 다음 예제 명령 중 하나를 실행합니다.
   + 다음 예제 명령은 OpenSSL을 사용하여 길이가 2048비트인 RSA 키 페어를 생성하고 `private_key.pem`이라는 파일에 저장합니다.

     ```
     openssl genrsa -out private_key.pem 2048
     ```
   + 다음 예제 명령어는 OpenSSL을 사용하여 `prime256v1` 곡선을 가진 ECDSA 키 쌍을 생성하고 `private_key.pem`이라는 이름의 파일에 저장합니다.

     ```
     openssl ecparam -name prime256v1 -genkey -noout -out privatekey.pem
     ```

1. 이렇게 만들어진 파일은 퍼블릭 키와 프라이빗 키를 모두 포함합니다. 다음 예제 명령은 `private_key.pem`이라는 파일에서 퍼블릭 키를 추출합니다.

   ```
   openssl rsa -pubout -in private_key.pem -out public_key.pem
   ```

   나중에 다음 절차에서 `public_key.pem` 파일의 퍼블릭 키를 업로드합니다.

**퍼블릭 키를 CloudFront에 업로드하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 메뉴에서 **퍼블릭 키**를 선택합니다.

1. **퍼블릭 키 생성**을 선택합니다.

1. **퍼블릭 키 생성** 창에서 다음을 수행합니다.

   1. **키 이름**에 퍼블릭 키를 식별할 이름을 입력합니다.

   1. **키 값**에 퍼블릭 키를 붙여 넣습니다. 이전 절차의 단계를 수행한 경우 퍼블릭 키는 `public_key.pem`이라는 파일에 있습니다. 퍼블릭 키의 내용을 복사하여 붙여 넣으려면 다음과 같이 하면 됩니다.
      + 다음과 같이 macOS 또는 Linux 명령줄에서 **cat** 명령을 사용합니다.

        ```
        cat public_key.pem
        ```

        해당 명령의 출력을 복사한 다음 **키 값**(Key value) 필드에 붙여 넣습니다.
      + 메모장(Windows) 또는 TextEdit(macOS)와 같은 일반 텍스트 편집기로 `public_key.pem` 파일을 엽니다. 파일의 내용을 복사한 다음 **키 값**(Key value) 필드에 붙여 넣습니다.

   1. (선택 사항) **설명**(Comment)에 퍼블릭 키에 대한 설명을 추가합니다.

   완료되면 **추가**(Add)를 선택합니다.

1. 퍼블릭 키 ID를 적어 둡니다. 나중에 서명된 URL 또는 서명된 쿠키를 만들 때 `Key-Pair-Id` 필드 값으로 이를 사용합니다.

**키 그룹에 퍼블릭 키를 추가하려면**

1. 에서 CloudFront 콘솔을 엽니다[https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)

1. 탐색 메뉴에서 **키 그룹**(Key groups)을 선택합니다.

1. **키 그룹 추가**(Add key group)를 선택합니다.

1. **키 그룹 만들기**(Create key group) 페이지에서 다음을 수행합니다.

   1. **키 그룹 이름**(Key group name)에 키 그룹을 식별할 이름을 입력합니다.

   1. (선택 사항) **설명**(Comment)에 키 그룹에 대한 설명을 입력합니다.

   1. **퍼블릭 키**(Public keys)에서 키 그룹에 추가할 퍼블릭 키를 선택한 다음 **추가**(Add)를 선택합니다. 키 그룹에 추가할 각 퍼블릭 키에 대해 이 단계를 반복합니다.

1. **키 그룹 만들기**(Create Key Pair)를 선택합니다.

1. 키 그룹 이름을 적어 둡니다. 나중에 키 그룹을 CloudFront 배포의 캐시 동작과 연결하는 데 이를 사용합니다. CloudFront API에서 키 그룹 ID를 사용하여 키 그룹을 캐시 동작과 연결합니다.

### CloudFront 키 페어 생성(권장되지 않음, AWS 계정 루트 사용자 필요)
<a name="create-key-pair-aws-account"></a>

**중요**  
다음 단계를 수행하는 대신 신뢰할 수 있는 키 그룹에 대한 퍼블릭 키를 만드는 것이 좋습니다. 서명된 URL 및 서명된 쿠키에 대한 퍼블릭 키를 만드는 권장 방법은 [신뢰할 수 있는 키 그룹에 대한 키 페어 생성(권장)](#create-key-pair-and-key-group) 단원을 참조하세요.

CloudFront 키 페어를 만드는 방법은 다음과 같습니다.
+ AWS Management Console에서 키 페어를 만들고 프라이빗 키를 다운로드합니다. 다음 절차를 참조하세요.
+ OpenSSL과 같은 애플리케이션을 사용하여 RSA 키 페어를 만든 후 퍼블릭 키를 에 업로드합니다AWS Management Console RSA 키 페어 생성에 대한 자세한 내용은 [신뢰할 수 있는 키 그룹에 대한 키 페어 생성(권장)](#create-key-pair-and-key-group) 단원을 참조하세요.<a name="private-content-creating-cloudfront-key-pairs-procedure"></a>

**에서 CloudFront 키 페어 생성AWS Management Console**

1. AWS 계정 루트 사용자의 자격 증명을 사용하여 AWS Management Console에 로그인합니다.
**중요**  
IAM 사용자는 CloudFront 키 페어를 만들 수 없습니다. 키 페어를 만들려면 루트 사용자 자격 증명을 사용하여 로그인해야 합니다.

1. 계정 이름을 선택한 다음 **내 보안 자격 증명**을 선택합니다.

1. **CloudFront 키 페어(CloudFront key pairs)**를 선택합니다.

1. 활성 키 페어가 하나만 있는지 확인합니다. 활성 키 페어가 이미 두 개라면 키 페어를 만들 수 없습니다.

1. **새 키 페어 생성**을 선택합니다.
**참고**  
사용자 고유의 키 페어를 만들고 퍼블릭 키를 업로드하도록 선택할 수도 있습니다. CloudFront 키 페어는 1024, 2048 또는 4096비트 키를 지원합니다.

1. **키 페어 생성** 대화 상자에서 **프라이빗 키 파일 다운로드**를 선택한 다음 컴퓨터에 파일을 저장합니다.
**중요**  
CloudFront 키 페어의 프라이빗 키를 안전한 위치에 저장하고 파일에 대한 권한을 설정하여 원하는 관리자만 읽을 수 있도록 합니다. 다른 사람이 프라이빗 키를 가지게 되면 이들이 유효한 서명된 URL과 서명된 쿠키를 만들어 콘텐츠를 다운로드할 수 있게 됩니다. 프라이빗 키는 다시 가져올 수 없기 때문에 이를 잃어버리거나 삭제한 경우 새 CloudFront 키 페어를 만들어야 합니다.

1. 키 페어의 키 페어 ID를 기록합니다. (AWS Management Console에서는 **액세스 키 ID**라고 합니다.) 서명된 URL 또는 서명된 쿠키를 만들 때 이것을 사용합니다.

## 프라이빗 키 재포맷(.NET 및 Java만 해당)
<a name="private-content-reformatting-private-key"></a>

.NET 또는 Java를 사용하여 서명된 URL 또는 서명된 쿠키를 만드는 경우, 기본 PEM 형식의 키 페어에서 프라이빗 키를 사용하여 서명을 만들 수 없습니다. 대신 다음을 수행합니다.
+ **.NET 프레임워크** – 프라이빗 키를 .NET 프레임워크에서 사용하는 XML 형식으로 변환합니다. 몇 가지 도구를 사용할 수 있습니다.
+ **Java** – 프라이빗 키를 DER 형식으로 변환합니다. 이 작업을 수행하는 한 가지 방법은 다음 OpenSSL 명령을 사용하는 것입니다. 다음 명령에서 `private_key.pem`은 PEM 형식의 프라이빗 키가 들어 있는 파일의 이름이며, `private_key.der`은 명령을 실행한 후 DER 형식의 프라이빗 키가 들어 있는 파일의 이름입니다.

  ```
  openssl pkcs8 -topk8 -nocrypt -in private_key.pem -inform PEM -out private_key.der -outform DER
  ```

  인코더가 정확하게 작동하려면 Bouncy Castle Java 암호화 API에 대한 JAR을 프로젝트에 추가한 다음 Bouncy Castle 공급자를 추가합니다.

## 배포에 서명자 추가
<a name="private-content-adding-trusted-signers"></a>

서명자는 배포에 대해 서명된 URL 및 서명된 쿠키를 만들 수 있는 신뢰할 수 있는 키 그룹(권장) 또는 CloudFront 키 페어입니다. CloudFront 배포와 함께 서명된 URL 또는 서명된 쿠키를 사용하려면 서명자를 지정해야 합니다.

서명자는 캐시 동작과 연결됩니다. 이렇게 하면 같은 배포의 일부 파일에 대해서만 서명된 URL 또는 서명된 쿠키를 요구할 수 있습니다. 배포에는 해당 캐시 동작과 연결된 파일에 대해서만 서명된 URL 또는 쿠키가 필요합니다.

마찬가지로 서명자는 해당 캐시 동작과 연결된 파일에 대해서만 URL 또는 쿠키에 서명할 수 있습니다. 예를 들어, 캐시 동작 하나당 서명자가 하나씩 있고 다른 캐시 동작에는 다른 서명자가 있다면 양쪽의 서명자 모두 상대편의 캐시 동작과 연결된 파일에 대해 서명된 URL 또는 쿠키를 만들 수 없습니다.

**중요**  
배포에 서명자를 추가하기 전에 다음을 수행합니다.  
캐시 동작의 경로 패턴과 캐시 동작 순서를 신중하게 정의하여 콘텐츠 액세스 권한을 실수로 사용자에게 부여하거나 일부 공개 콘텐츠에 사용자가 액세스하는 일이 없도록 해야 합니다.  
예를 들어, 하나의 요청이 두 캐시 동작의 경로 패턴과 일치한다고 가정합니다. 첫 번째 캐시 동작에는 서명된 URL 또는 서명된 쿠키가 필요하지 않고, 두 번째 캐시 동작에는 필요합니다. CloudFront에서는 첫 번째와 연결된 캐시 동작을 처리하므로 사용자는 서명된 URL 또는 서명된 쿠키 없이도 파일에 액세스할 수 있습니다.  
경로 패턴에 대한 자세한 내용은 [경로 패턴](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern)을 참조하세요.
콘텐츠를 배포하는 데 이미 사용하고 있는 배포의 경우 서명자를 추가하기 전에 서명된 URL 및 서명된 쿠키를 생성할 준비가 되어 있어야 합니다. 서명자를 추가하면 CloudFront는 유효한 서명된 URL 또는 서명된 쿠키를 포함하지 않는 요청을 거부합니다.

CloudFront 콘솔 또는 CloudFront API를 사용하여 배포에 서명자를 추가할 수 있습니다.

------
#### [ Console ]

다음 단계에서는 신뢰할 수 있는 키 그룹을 서명자로 추가하는 방법을 보여 줍니다. AWS 계정을 신뢰할 수 있는 서명자로 추가할 수도 있지만 권장하지 않습니다.<a name="private-content-adding-trusted-signers-console-procedure"></a>

**콘솔을 사용하여 배포에 서명자를 추가하려면**

1. 신뢰할 수 있는 서명자로 사용할 키 그룹의 키 그룹 ID를 적어 둡니다. 자세한 내용은 [신뢰할 수 있는 키 그룹에 대한 키 페어 생성(권장)](#create-key-pair-and-key-group) 섹션을 참조하세요.

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다

1. 서명된 URL 또는 서명된 쿠키로 보호하려는 파일의 배포를 선택합니다.
**참고**  
새 배포에 서명자를 추가하려면 배포를 만들 때 6단계에서 설명하는 것과 동일한 설정을 지정합니다.

1. **동작** 탭을 선택합니다.

1. 경로 패턴이 서명된 URL 또는 서명된 쿠키로 보호하려는 파일과 일치하는 캐시 동작을 선택한 다음 **편집**을 선택합니다.

1. **동작 편집**(Edit Behavior) 페이지에서 다음을 수행합니다.

   1. **최종 사용자 액세스 제한(서명된 URL 또는 서명된 쿠키 사용)**(Restrict Viewer Access (Use Signed URLs or Signed Cookies)에서 **예**를 클릭합니다.

   1. **신뢰할 수 있는 키 그룹 또는 신뢰할 수 있는 서명자**(Trusted Key Groups or Trusted Signer)에서 **신뢰할 수 있는 키 그룹**(Trusted Key Groups)을 선택합니다.

   1. **신뢰할 수 있는 키 그룹**(Trusted Key Groups)에서 추가할 키 그룹을 선택한 다음 **추가**를 선택합니다. 두 개 이상의 키 그룹을 추가하려면 이 과정을 반복합니다.

1. **예, 편집합니다**를 선택하여 캐시 동작을 업데이트합니다.

------
#### [ API ]

CloudFront API를 사용하여 신뢰할 수 있는 키 그룹을 서명자로 추가할 수 있습니다. 기존 배포 또는 새 배포에 서명자를 추가할 수 있습니다. 두 경우 모두 `TrustedKeyGroups` 요소에 값을 지정합니다.

AWS 계정을 신뢰할 수 있는 서명자로 추가할 수도 있지만 권장하지 않습니다.

*Amazon CloudFront API 참조*에서 다음 주제를 참조하세요.
+ **기존 배포 업데이트** – [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)
+ **새로운 배포 생성** – [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html)

------

## 키 페어 교체
<a name="private-content-rotating-key-pairs"></a>

서명된 URL 및 서명된 쿠키에 대한 키 페어를 주기적으로 교체(변경)하는 것이 좋습니다. 아직 만료되지 않은 서명된 URL 또는 서명된 쿠키를 무효화하지 않고 URL 또는 쿠키를 만들기 위해 사용 중인 키 페어를 교체하려면 다음 작업을 수행하세요.

1. 새 키 페어를 만들고 키 그룹에 퍼블릭 키를 추가합니다. 자세한 내용은 [신뢰할 수 있는 키 그룹에 대한 키 페어 생성(권장)](#create-key-pair-and-key-group) 단원을 참조하세요.

1. 이전 단계에서 새 키 그룹을 만든 경우 [키 그룹을 배포에 서명자로 추가](#private-content-adding-trusted-signers)합니다.
**중요**  
키 그룹에서 기존 퍼블릭 키를 제거하거나 배포에서 키 그룹을 제거하지 마세요. 새것만 추가하세요.

1. 새로운 키 페어의 프라이빗 키를 사용하여 서명을 만들도록 애플리케이션을 업데이트합니다. 새 프라이빗 키로 서명된 URL 또는 서명된 쿠키가 작동하는지 확인합니다.

1. 이전 프라이빗 키로 서명한 URL 또는 쿠키의 만료 날짜가 지날 때까지 기다립니다. 그런 다음 키 그룹에서 이전 프라이빗 키를 제거합니다. 2단계에서 새 키 그룹을 만든 경우 배포에서 이전 키 그룹을 제거합니다.

# 서명된 URL 또는 서명된 쿠키 사용 결정
<a name="private-content-choosing-signed-urls-cookies"></a>

CloudFront 서명된 URL 및 서명된 쿠키는 기본 기능이 같습니다. 바로 콘텐츠에 액세스할 수 있는 대상을 제어하는 기능입니다. CloudFront를 통해 프라이빗 콘텐츠를 제공 중이며 서명된 URL 또는 서명된 쿠키 중 하나를 결정해야 하는 경우, 다음 사항을 고려하세요.

다음과 같은 경우 서명된 URL을 사용합니다.
+ 애플리케이션 설치 파일을 다운로드하는 등 개별 파일에 대한 액세스를 제한하고 싶은 경우
+ 사용자가 쿠키를 지원하지 않는 클라이언트(예: 사용자 지정 HTTP 클라이언트)를 사용하는 경우

다음과 같은 경우 서명된 쿠키를 사용합니다.
+ HLS 형식의 비디오 파일 전체 또는 웹 사이트의 구독자 영역에 있는 파일 전체 등 제한된 파일 여러 개에 대한 액세스 권한을 제공하려는 경우
+ 현재의 URL을 변경하고 싶지 않은 경우

현재 서명된 URL을 사용하지 않는데 (서명되지 않은) URL에 다음과 같은 쿼리 문자열 파라미터가 들어 있다면 서명된 URL 또는 서명된 쿠키를 사용할 수 없습니다.
+ `Expires`
+ `Policy`
+ `Signature`
+ `Key-Pair-Id`

CloudFront는 이러한 쿼리 문자열 파라미터가 포함된 URL을 서명된 URL로 간주하기 때문에 서명된 쿠키를 살펴보지 않을 것입니다.

## 서명된 URL과 서명된 쿠키 모두 사용
<a name="private-content-using-signed-urls-and-cookies"></a>

서명된 URL은 서명된 쿠키보다 우선합니다. 같은 파일에 대한 액세스를 제어할 때 서명된 URL과 서명된 쿠키를 모두 사용하고 최종 사용자는 서명된 URL로 파일을 요청하는 경우, CloudFront는 서명된 URL만을 기준으로 최종 사용자에게 파일을 반환할지 여부를 판단합니다.

# 서명된 URL 사용
<a name="private-content-signed-urls"></a>

서명된 URL에는 만료 날짜 및 시간 같은 추가 정보가 포함되므로 콘텐츠에 대한 액세스를 보다 세부적으로 제어할 수 있습니다. 이러한 추가 정보는 미리 준비된(canned) 정책 또는 사용자 지정 정책에 따라 정책 설명에 나타납니다. 미리 준비된(canned) 정책과 사용자 지정 정책 간의 차이점은 이어지는 두 단원에 설명되어 있습니다.

**참고**  
같은 배포에 대해 미리 준비된(canned) 정책과 사용자 지정 정책으로 각각 서명된 URL을 만들 수 있습니다.

**Topics**
+ [서명된 URL에 대해 미리 준비된 정책 또는 사용자 지정 정책 사용 결정](#private-content-choosing-canned-custom-policy)
+ [서명된 URL의 작동 방식](#private-content-how-signed-urls-work)
+ [서명된 URL의 유효 기간 결정](#private-content-overview-choosing-duration)
+ [CloudFront가 서명된 URL에서 만료 날짜 및 시간을 확인하는 시기](#private-content-check-expiration)
+ [예제 코드 및 타사 도구](#private-content-overview-sample-code)
+ [미리 준비된 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-canned-policy.md)
+ [사용자 지정 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-custom-policy.md)

## 서명된 URL에 대해 미리 준비된 정책 또는 사용자 지정 정책 사용 결정
<a name="private-content-choosing-canned-custom-policy"></a>

서명된 URL을 만들 때 JSON 형식의 정책 설명을 작성하여 서명된 URL의 제약 조건(예: URL의 유효 기간)을 지정합니다. 미리 준비된(canned) 정책 또는 사용자 지정 정책을 사용할 수 있습니다. 다음은 미리 준비된(canned) 정책과 사용자 지정 정책을 비교한 것입니다.


****  

| 설명 | 미리 준비된 정책 | 사용자 정의 정책 | 
| --- | --- | --- | 
| 정책 설명은 여러 파일에 재사용할 수 있습니다. 정책 설명을 재사용하려면 `Resource` 객체에 와일드카드 문자를 사용해야 합니다. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명에서 지정한 값](private-content-creating-signed-url-custom-policy.md#private-content-custom-policy-statement-values) 섹션을 참조하세요.)  | 아니요 | 예 | 
| 날짜 및 시간을 지정하여 사용자가 콘텐츠에 액세스를 시작할 수 있습니다. | 아니요 | 예(선택 사항) | 
| 사용자의 콘텐츠 액세스를 중단할 날짜 및 시간을 지정할 수 있습니다. | 예 | 예 | 
| 콘텐츠에 액세스할 수 있는 사용자의 IP 주소 또는 IP 주소 범위를 지정할 수 있습니다. | 아니요 | 예(선택 사항) | 
| 서명된 URL에는 base64 인코딩 버전의 정책이 포함되므로 URL 길이가 더 깁니다. | 아니요 | 예 | 

*미리 준비된(canned)* 정책으로 서명된 URL을 만드는 방법에 대한 자세한 내용은 [미리 준비된 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-canned-policy.md) 단원을 참조하세요.

*사용자 지정* 정책으로 서명된 URL을 만드는 방법에 대한 자세한 내용은 [사용자 지정 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-custom-policy.md) 단원을 참조하세요.

## 서명된 URL의 작동 방식
<a name="private-content-how-signed-urls-work"></a>

여기서는 서명된 URL에 알맞게 CloudFront 및 Amazon S3를 구성하는 방법과 사용자가 서명된 URL로 파일을 요청할 때 CloudFront가 대응하는 방식을 살펴봅니다.

1. CloudFront 배포에서 CloudFront가 URL 서명을 확인하는 데 사용할 수 있는 퍼블릭 키가 포함된 신뢰할 수 있는 키 그룹을 하나 이상 지정합니다. 해당 프라이빗 키를 사용하여 URL에 서명합니다.

   CloudFront는 RSA 2048 및 ECDSA 256 키 서명을 사용하여 서명된 URL을 지원합니다.

   자세한 내용은 [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md) 섹션을 참조하세요.

1. 애플리케이션을 개발하여 사용자에게 콘텐츠 액세스를 허용할지 여부를 판단하고, 액세스를 제한할 애플리케이션 부분 또는 파일에 대해 서명된 URL을 만듭니다. 자세한 정보는 다음 주제를 참조하세요.
   + [미리 준비된 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-canned-policy.md)
   + [사용자 지정 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-custom-policy.md)

1. 사용자가 서명된 URL이 필요한 파일을 요청합니다.

1. 애플리케이션은 해당 사용자에게 파일 액세스 권한이 있는지 확인합니다. 사용자가 로그인했는지, 콘텐츠 액세스 비용을 지불했는지, 기타 액세스 요구 사항을 충족했는지 등을 확인합니다.

1. 애플리케이션은 서명된 URL을 만들어 사용자에게 반환합니다.

1. 사용자는 서명된 URL을 통해 콘텐츠를 다운로드하거나 스트리밍할 수 있습니다.

   이 단계는 자동으로 진행되기 때문에 사용자는 콘텐츠에 액세스하기 위해 아무것도 하지 않아도 됩니다. 예를 들어, 사용자가 웹 브라우저에서 콘텐츠에 액세스한다면 애플리케이션은 서명된 URL을 브라우저에 반환합니다. 브라우저는 즉시 서명된 URL을 사용하여 사용자 개입 없이 CloudFront 엣지 캐시의 파일에 액세스합니다.

1. CloudFront는 퍼블릭 키를 사용하여 서명을 확인하고 URL이 아직 변조되지 않았음을 확인합니다. 유효하지 않은 서명인 경우 요청을 거부합니다.

   서명이 유효한 경우, CloudFront는 URL의 정책 설명을 보고 아직 유효한 정책임을 확인합니다. 미리 준비된(canned) 정책을 사용하는 경우에는 정책 설명을 구성합니다. 예를 들어, URL의 시작 및 종료 날짜와 시간을 지정했다면 CloudFront는 액세스를 허용하려는 기간 동안 사용자가 콘텐츠에 액세스를 시도하고 있음을 확인합니다.

   요청이 정책 설명의 요구 사항을 충족하는 경우, CloudFront는 스탠다드 작업을 수행합니다. 다시 말해 파일이 이미 엣지 캐시에 있는지 여부를 판단하고, 필요에 따라 요청을 오리진으로 전달하고, 사용자에게 파일을 반환합니다.

**참고**  
서명되지 않은 URL에 쿼리 문자열 파라미터가 포함된 경우 서명하는 URL 부분에 이를 포함시켜야 합니다. 서명된 URL에 서명한 후 서명된 URL에 쿼리 문자열을 추가하면 해당 URL이 HTTP 403 상태를 반환합니다.

## 서명된 URL의 유효 기간 결정
<a name="private-content-overview-choosing-duration"></a>

단시간(최소 몇 분) 동안만 유효한 서명된 URL을 사용하여 프라이빗 콘텐츠를 배포할 수 있습니다. 이렇게 단시간 동안 유효한 서명된 URL은 영화 대여 또는 음악 다운로드 등을 주문 방식으로 고객에게 제공하는 등 특정 목적으로 즉석에서 콘텐츠를 배포할 때 유용합니다. 서명된 URL의 효력을 단시간 동안만 유지하려는 경우, 이를 자동으로 만드는 애플리케이션을 개발할 수 있습니다. 사용자가 파일을 다운로드하거나 미디어 파일을 재생하기 시작하면 CloudFront는 URL의 만료 시간을 현재 시간과 비교하여 URL이 아직 유효한지 파악합니다.

또한 장시간(몇 년 정도) 동안 유효한 서명된 URL을 사용하여 프라이빗 콘텐츠를 배포할 수도 있습니다. 장시간 동안 유효한 서명된 URL은 알려진 사용자에게 프라이빗 콘텐츠를 배포할 때 유용합니다. 투자자에게 사업 계획을 배포하거나 직원에게 교육 자료를 배포하는 경우가 여기에 해당합니다. 이러한 장기 서명 URL을 생성하는 애플리케이션을 개발할 수 있습니다.

## CloudFront가 서명된 URL에서 만료 날짜 및 시간을 확인하는 시기
<a name="private-content-check-expiration"></a>

CloudFront는 HTTP 요청이 있을 때 서명된 URL의 만료 날짜 및 시간을 확인합니다. 클라이언트가 만료 시간 직전에 대용량 파일을 다운로드하기 시작한 경우, 다운로드 도중 만료 시간이 지나도 다운로드는 완료됩니다. TCP 연결이 끊어진 경우, 클라이언트가 만료 시간 이후에 다운로드를 다시 시작하는 것은 불가능합니다.

클라이언트가 범위 GET을 사용하여 파일을 작은 조각으로 가져오는 경우, 만료 시간 이후의 GET 요청은 실패합니다. 범위 GET에 대한 자세한 내용은 [CloudFront에서 객체에 대한 부분적인 요청을 처리하는 방법(범위 GET)](RangeGETs.md)을 참조하세요.

## 예제 코드 및 타사 도구
<a name="private-content-overview-sample-code"></a>

서명된 URL의 해시 및 서명된 부분을 만드는 예제 코드에 대해서는 다음 주제를 참조하세요.
+ [Perl을 사용한 URL 서명 생성](CreateURLPerl.md)
+ [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md)
+ [C\$1 및 .NET Framework를 사용한 URL 서명 생성](CreateSignatureInCSharp.md)
+ [Java를 사용한 URL 서명 생성](CFPrivateDistJavaDevelopment.md)

# 미리 준비된 정책을 사용하여 서명된 URL 생성
<a name="private-content-creating-signed-url-canned-policy"></a>

미리 준비된 정책을 사용하여 서명된 URL을 만들려면 다음 단계를 수행합니다.<a name="private-content-creating-signed-url-canned-policy-procedure"></a>

**미리 준비된 정책을 사용하여 서명된 URL을 만들려면**

1. .NET 또는 Java를 사용하여 서명된 URL을 만드는 중인데 키 페어의 프라이빗 키를 기본 .pem 형식에서 .NET 또는 Java와 상환되는 형식으로 다시 포맷하지 않았다면 지금 포맷하세요. 자세한 내용은 [프라이빗 키 재포맷(.NET 및 Java만 해당)](private-content-trusted-signers.md#private-content-reformatting-private-key) 섹션을 참조하세요.

1. 다음 값을 연결합니다. 이 예제의 서명된 URL의 형식을 사용할 수 있습니다.

   ```
   https://d111111abcdef8.cloudfront.net/image.jpg?color=red&size=medium&Expires=1767290400&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~-ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmatEXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6&Key-Pair-Id=K2JCJMDEHXQW5F
   ```

   모든 빈 공백(탭과 줄바꿈 문자 포함)을 제거합니다. 애플리케이션 코드의 문자열에 이스케이프 문자를 포함해야 할 수도 있습니다. 모든 값에는 일종의 `String`이 있습니다.  
**1. *파일의 기본 URL***  
기본 URL이란 서명된 URL을 사용하지 않고 파일에 액세스할 때 사용할 CloudFront URL을 말합니다. 자체 쿼리 문자열 파라미터가 있는 경우 여기에 포함됩니다. 이전 예제에서 기본 URL은 `https://d111111abcdef8.cloudfront.net/image.jpg`입니다. 웹 배포의 URL 형식에 대한 자세한 내용은 [CloudFront에서 파일에 대한 URL 형식 사용자 지정](LinkFormat.md)을 참조하세요.  
   + 다음 CloudFront URL은 배포의 이미지 파일을 위한 것입니다(CloudFront 도메인 이름 사용). `image.jpg`는 `images` 디렉터리에 있습니다. URL에 있는 파일의 경로는 HTTP 서버 또는 Amazon S3 버킷의 파일 경로와 일치해야 합니다.

     `https://d111111abcdef8.cloudfront.net/images/image.jpg`
   + 다음 CloudFront URL은 쿼리 문자열을 포함합니다.

     `https://d111111abcdef8.cloudfront.net/images/image.jpg?size=large`
   + 다음 CloudFront URL은 배포의 이미지 파일을 위한 것입니다. 모두 대체 도메인 이름을 사용합니다. 두 번째는 쿼리 문자열을 포함합니다.

     `https://www.example.com/images/image.jpg`

     `https://www.example.com/images/image.jpg?color=red`
   + 다음 CloudFront URL은 대체 도메인 이름과 HTTPS 프로토콜을 사용하는 배포의 이미지 파일을 위한 것입니다.

     `https://www.example.com/images/image.jpg`  
** 2. `?` **  
`?`는 기본 URL 뒤에 쿼리 파라미터가 있음을 나타냅니다. 쿼리 파라미터를 지정하지 않은 경우에도 `?`를 포함합니다.  
순서에 관계없이 다음 쿼리 파라미터를 지정할 수 있습니다.  
**3. *자체 쿼리 문자열 파라미터(있는 경우*`&`**  
(선택 사항) 자체 쿼리 문자열 파라미터를 입력할 수 있습니다. 이렇게 하려면 `color=red&size=medium`처럼 각 문자열 파라미터 간에 앰퍼샌드(`&`)를 추가합니다. 쿼리 문자열 파라미터는 URL 내에서 원하는 순서로 지정할 수 있습니다.  
쿼리 문자열 파라미터의 이름은 `Expires`, `Signature`, `Key-Pair-Id`로 지정할 수 없습니다.  
** 4. `Expires=`*Unix 시간 형식(초) 및 협정 세계시(UTC) 기준의 날짜 및 시간***  
URL에서 파일에 대한 액세스 허용을 중지하게 할 날짜 및 시간입니다.  
Unix 시간 형식(초) 및 협정 세계시(UTC) 기준의 URL 만료 날짜 및 시간을 지정합니다. 예를 들면 2026년 1월 1일 오전 10시(UTC)를 이 주제의 시작 부분에 있는 예와 같이 Unix 시간 형식의 `1767290400`으로 변환합니다.  
에포크 시간을 사용하려면 `9223372036854775807`(금요일, 2262년 4월 11일 23:47:16.854 UTC) 이전 날짜에 대한 64비트 정수를 지정합니다.  
  
UTC에 대한 자세한 내용은 [RFC 3339, 인터넷의 날짜 및 시간: 타임스탬프](https://tools.ietf.org/html/rfc3339)를 참조하세요.  
** 5. `&Signature=`*정책 설명의 해시 및 서명된 버전***  
JSON 정책 설명을 해시, 서명 및 base64로 인코딩한 버전입니다. 자세한 내용은 [미리 준비된 정책을 사용하는 서명된 URL에 대한 서명 생성](#private-content-canned-policy-creating-signature) 섹션을 참조하세요.  
** 6. `&Key-Pair-Id=`*서명을 생성하는 데 사용 중인 해당 프라이빗 키가 있는 CloudFront 퍼블릭 키의 퍼블릭 키 ID***  
CloudFront 퍼블릭 키의 ID입니다(예: `K2JCJMDEHXQW5F`). CloudFront는 서명된 URL을 확인할 때 사용할 퍼블릭 키를 퍼블릭 키 ID로 판단합니다. CloudFront는 서명의 정보를 정책 설명의 정보와 비교하고 URL이 변조되지 않았음을 확인합니다.  
이 퍼블릭 키는 배포에서 신뢰할 수 있는 서명자인 키 그룹에 속해야 합니다. 자세한 내용은 [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md) 섹션을 참조하세요.

## 미리 준비된 정책을 사용하는 서명된 URL에 대한 서명 생성
<a name="private-content-canned-policy-creating-signature"></a>

미리 준비된 정책을 사용하는 서명된 URL의 서명을 만들려면 다음 절차를 완료하세요.

**Topics**
+ [미리 준비된 정책을 사용하는 서명된 URL의 정책 설명 생성](#private-content-canned-policy-creating-policy-statement)
+ [미리 준비된 정책을 사용하는 서명된 URL에 대한 서명 생성](#private-content-canned-policy-signing-policy-statement)

### 미리 준비된 정책을 사용하는 서명된 URL의 정책 설명 생성
<a name="private-content-canned-policy-creating-policy-statement"></a>

미리 준비된 정책을 사용하여 서명된 URL을 만드는 경우, `Signature` 파라미터는 정책 설명의 해시 및 서명된 버전입니다. 미리 준비된 정책을 사용하는 서명된 URL의 경우, 사용자 지정 정책을 사용하는 서명된 URL과 마찬가지로 URL에 정책 설명을 포함하지 않습니다. 정책 설명을 만들려면 다음 절차를 수행하세요.<a name="private-content-canned-policy-creating-policy-statement-procedure"></a>

**미리 준비된 정책을 사용하는 서명된 URL에 대한 정책 설명을 만들려면**

1. 다음 JSON 형식과 UTF-8 문자 인코딩을 사용하여 정책 설명을 구성합니다. 지정된 모든 문장 부호 및 기타 리터럴 값을 정확히 포함해야 합니다. `Resource` 및 `DateLessThan` 파라미터에 대한 내용은 [미리 준비된 정책을 사용하는 서명된 URL에 대한 정책 설명에서 지정한 값](#private-content-canned-policy-statement-values)를 참조하세요.

   ```
   {
       "Statement": [
           {
               "Resource": "base URL or stream name",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime": ending date and time in Unix time format and UTC
                   }
               }
           }
       ]
   }
   ```

1. 정책 설명에서 모든 공백(탭과 줄바꿈 문자 포함)을 제거합니다. 애플리케이션 코드의 문자열에 이스케이프 문자를 포함해야 할 수도 있습니다.

#### 미리 준비된 정책을 사용하는 서명된 URL에 대한 정책 설명에서 지정한 값
<a name="private-content-canned-policy-statement-values"></a>

미리 준비된 정책에 대한 정책 설명을 만들 때 다음 값을 지정합니다.

**리소스**  
`Resource`에 대해 값을 하나만 지정할 수 있습니다.
쿼리 문자열(있는 경우)을 포함하지만 CloudFront `Expires`, `Signature` 및 `Key-Pair-Id` 파라미터를 제외한 기본 URL입니다. 예를 들면 다음과 같습니다.  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
다음을 참조하세요.  
+ **프로토콜(Protocol)** – 값은 `http://` 또는 `https://`로 시작해야 합니다.
+ **쿼리 문자열 파라미터(Query string parameters)** – 쿼리 문자열 파라미터가 없는 경우, 물음표를 생략합니다.
+ **대체 도메인 이름(Alternate domain names)** – URL에 대체 도메인 이름(CNAME)을 지정하는 경우, 웹 페이지 또는 애플리케이션의 파일을 참조할 때 대체 도메인 이름을 지정해야 합니다. 객체에 대한 Amazon S3 URL을 지정하지 마세요.

**DateLessThan**  
Unix 시간 형식(초) 및 협정 세계시(UTC) 기준의 URL 만료 날짜 및 시간. 예를 들면 2026년 1월 1일 오전 10시(UTC)를 Unix 시간 형식의 1767290400으로 변환합니다.  
이 값은 서명된 URL의 `Expires` 쿼리 문자열 파라미터 값과 일치해야 합니다. 값을 인용 부호로 묶지 마세요.  
자세한 내용은 [CloudFront가 서명된 URL에서 만료 날짜 및 시간을 확인하는 시기](private-content-signed-urls.md#private-content-check-expiration) 단원을 참조하세요.

#### 미리 준비된 정책을 사용하는 서명된 URL에 대한 정책 설명 예제
<a name="private-content-canned-policy-creating-policy-statement-example"></a>

서명된 URL에 다음 예제의 정책 설명을 사용할 경우, 사용자는 UTC 기준 2026년 1월 1일 오전 10시까지 `https://d111111abcdef8.cloudfront.net/horizon.jpg` 파일에 액세스할 수 있습니다.

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/horizon.jpg?size=large&license=yes",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

### 미리 준비된 정책을 사용하는 서명된 URL에 대한 서명 생성
<a name="private-content-canned-policy-signing-policy-statement"></a>

서명된 URL의 `Signature` 파라미터 값을 만들려면 [미리 준비된 정책을 사용하는 서명된 URL의 정책 설명 생성](#private-content-canned-policy-creating-policy-statement)에서 만든 정책 설명을 해시하고 서명합니다.

다음을 참조하여 정책 설명을 해시, 서명 및 인코딩하는 방법에 대한 추가적인 내용과 예제를 확인하세요.
+ [base64 인코딩 및 암호화를 위한 Linux 명령 및 OpenSSL](private-content-linux-openssl.md)
+ [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)<a name="private-content-canned-policy-creating-signature-download-procedure"></a>

**옵션 1: 미리 준비된 정책을 사용하여 서명을 만들려면**

1. SHA-1 해시 함수와 생성된 RSA 또는 ECDSA 프라이빗 키를 사용하여 [미리 준비된 정책을 사용하는 서명된 URL에 대한 정책 설명을 만들려면](#private-content-canned-policy-creating-policy-statement-procedure) 절차에서 만든 정책 설명을 해시하고 서명합니다. 공백이 삭제된 버전의 정책 설명을 사용합니다.

   해시 함수에 필요한 프라이빗 키의 경우 배포에 대해 신뢰할 수 있는 활성 키 그룹에 퍼블릭 키가 있는 프라이빗 키를 사용합니다.
**참고**  
정책 설명을 해시 및 서명하는 방법은 프로그래밍 언어와 플랫폼에 따라 달라집니다. 샘플 코드에 대한 내용은 [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)를 참조하세요.

1. 해시 및 서명된 문자열에서 공백(탭과 줄바꿈 문자 포함)을 제거합니다.

1. MIME base64 인코딩 기준으로 문자열을 base64로 인코딩합니다. 자세한 내용은 *RFC 2045, MIME(Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*의 [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)을 참조하세요.

1. URL 쿼리 문자열에서 사용할 수 없는 문자를 유효한 문자로 교체합니다. 아래 표에 사용할 수 없는 문자와 유효한 문자가 나열되어 있습니다.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-canned-policy.html)

1. 서명된 URL의 `&Signature=` 뒤에 결과 값을 추가하고 [미리 준비된 정책을 사용하여 서명된 URL을 만들려면](#private-content-creating-signed-url-canned-policy-procedure)로 돌아가서 서명된 URL 부분을 마저 연결합니다.

# 사용자 지정 정책을 사용하여 서명된 URL 생성
<a name="private-content-creating-signed-url-custom-policy"></a>

사용자 지정 정책을 사용하여 서명된 URL을 만들려면 다음 절차를 완료합니다.<a name="private-content-creating-signed-url-custom-policy-procedure"></a>

**사용자 지정 정책을 사용하여 서명된 URL을 만들려면**

1. .NET 또는 Java를 사용하여 서명된 URL을 만드는 중인데 키 페어의 프라이빗 키를 기본 .pem 형식에서 .NET 또는 Java와 상환되는 형식으로 다시 포맷하지 않았다면 지금 포맷하세요. 자세한 내용은 [프라이빗 키 재포맷(.NET 및 Java만 해당)](private-content-trusted-signers.md#private-content-reformatting-private-key) 섹션을 참조하세요.

1. 다음 값을 연결합니다. 이 예제의 서명된 URL의 형식을 사용할 수 있습니다.

   

   ```
   https://d111111abcdef8.cloudfront.net/image.jpg?color=red&size=medium&Policy=eyANCiAgICEXAMPLEW1lbnQiOiBbeyANCiAgICAgICJSZXNvdXJjZSI6Imh0dHA6Ly9kemJlc3FtN3VuMW0wLmNsb3VkZnJvbnQubmV0L2RlbW8ucGhwIiwgDQogICAgICAiQ29uZGl0aW9uIjp7IA0KICAgICAgICAgIklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIyMDcuMTcxLjE4MC4xMDEvMzIifSwNCiAgICAgICAgICJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTI5Njg2MDE3Nn0sDQogICAgICAgICAiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjEyOTY4NjAyMjZ9DQogICAgICB9IA0KICAgfV0gDQp9DQo&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~-ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmatEXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6&Key-Pair-Id=K2JCJMDEHXQW5F
   ```

   모든 빈 공백(탭과 줄바꿈 문자 포함)을 제거합니다. 애플리케이션 코드의 문자열에 이스케이프 문자를 포함해야 할 수도 있습니다. 모든 값에는 일종의 `String`이 있습니다.  
**1. *파일의 기본 URL***  
기본 URL이란 서명된 URL을 사용하지 않고 파일에 액세스할 때 사용할 CloudFront URL을 말합니다. 자체 쿼리 문자열 파라미터가 있는 경우 여기에 포함됩니다. 이전 예제에서 기본 URL은 `https://d111111abcdef8.cloudfront.net/image.jpg`입니다. 웹 배포의 URL 형식에 대한 자세한 내용은 [CloudFront에서 파일에 대한 URL 형식 사용자 지정](LinkFormat.md)을 참조하세요.  
다음 예는 배포에 대해 지정하는 값을 보여줍니다.  
   + 다음 CloudFront URL은 배포의 이미지 파일을 위한 것입니다(CloudFront 도메인 이름 사용). `image.jpg`는 `images` 디렉터리에 있습니다. URL에 있는 파일의 경로는 HTTP 서버 또는 Amazon S3 버킷의 파일 경로와 일치해야 합니다.

     `https://d111111abcdef8.cloudfront.net/images/image.jpg`
   + 다음 CloudFront URL은 쿼리 문자열을 포함합니다.

     `https://d111111abcdef8.cloudfront.net/images/image.jpg?size=large`
   + 다음 CloudFront URL은 배포의 이미지 파일을 위한 것입니다. 둘 다 대체 도메인 이름을 사용하며 두 번째는 쿼리 문자열을 포함합니다.

     `https://www.example.com/images/image.jpg`

     `https://www.example.com/images/image.jpg?color=red`
   + 다음 CloudFront URL은 대체 도메인 이름과 HTTPS 프로토콜을 사용하는 배포의 이미지 파일을 위한 것입니다.

     `https://www.example.com/images/image.jpg`  
**2. `?` **  
`?`는 기본 URL 뒤에 쿼리 문자열 파라미터가 있음을 나타냅니다. 쿼리 파라미터를 지정하지 않은 경우에도 `?`를 포함합니다.  
순서에 관계없이 다음 쿼리 파라미터를 지정할 수 있습니다.  
**3. *자체 쿼리 문자열 파라미터(있는 경우*`&`**  
(선택 사항) 자체 쿼리 문자열 파라미터를 입력할 수 있습니다. 이렇게 하려면 `color=red&size=medium`처럼 각 문자열 파라미터 간에 앰퍼샌드(&)를 추가합니다. 쿼리 문자열 파라미터는 URL 내에서 원하는 순서로 지정할 수 있습니다.  
쿼리 문자열 파라미터의 이름은 `Policy`, `Signature`, `Key-Pair-Id`로 지정할 수 없습니다.
자체 파라미터를 추가하는 경우, 마지막 파라미터를 포함하여 각 파라미터 뒤에 `&`를 추가합니다.  
**4. `Policy=`*정책 설명의 base64 인코딩 버전***  
공백이 제거된 JSON 형식의 정책 설명은 base64로 인코딩합니다. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명 생성](#private-content-custom-policy-statement) 섹션을 참조하세요.  
정책 설명은 서명된 URL이 사용자에게 부여하는 액세스를 제어합니다. 여기에는 파일의 URL, 만료 날짜 및 시간, URL의 효력이 발생하는 날짜 및 시간(선택 사항), 파일에 액세스할 수 있는 IP 주소 또는 IP 주소 범위(선택 사항)가 포함됩니다.  
**5. `&Signature=`*정책 설명의 해시 및 서명된 버전***  
JSON 정책 설명을 해시, 서명 및 base64로 인코딩한 버전입니다. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 서명 생성](#private-content-custom-policy-creating-signature) 섹션을 참조하세요.  
**6. `&Key-Pair-Id=`*서명을 생성하는 데 사용 중인 해당 프라이빗 키가 있는 CloudFront 퍼블릭 키의 퍼블릭 키 ID***  
CloudFront 퍼블릭 키의 ID입니다(예: `K2JCJMDEHXQW5F`). CloudFront는 서명된 URL을 확인할 때 사용할 퍼블릭 키를 퍼블릭 키 ID로 판단합니다. CloudFront는 서명의 정보를 정책 설명의 정보와 비교하고 URL이 변조되지 않았음을 확인합니다.  
이 퍼블릭 키는 배포에서 신뢰할 수 있는 서명자인 키 그룹에 속해야 합니다. 자세한 내용은 [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md) 섹션을 참조하세요.

## 사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명 생성
<a name="private-content-custom-policy-statement"></a>

다음 단계를 완료하여 사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 명령문을 만듭니다.

다양한 방법으로 파일에 대한 액세스를 제어하는 예시 정책 명령문에 대한 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 예제 정책 설명](#private-content-custom-policy-statement-examples) 섹션을 참조하세요.<a name="private-content-custom-policy-creating-policy-procedure"></a>

**사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명을 만들려면**

1. 다음 JSON 형식을 사용하여 정책 설명을 구성하세요. 다음 보다 작음(`<`) 및 다음보다 큼(`>`) 기호 및 해당 기호 내의 설명을 사용자 지정 값으로 바꿉니다. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명에서 지정한 값](#private-content-custom-policy-statement-values) 섹션을 참조하세요.

   ```
   {
       "Statement": [
           {
               "Resource": "<Optional but recommended: URL of the file>",
               "Condition": {
                   "DateLessThan": {
   	                "AWS:EpochTime": <Required: ending date and time in Unix time format and UTC>
                   },
                   "DateGreaterThan": {
   	                "AWS:EpochTime": <Optional: beginning date and time in Unix time format and UTC>
                   },
                   "IpAddress": {
   	                "AWS:SourceIp": "<Optional: IP address>"
                   }
               }
           }
       ]
   }
   ```

   유의할 사항:
   + 정책에는 명령문을 하나만 포함할 수 있습니다.
   + UTF-8 문자 인코딩을 사용하세요.
   + 지정된 대로 정확하게 모든 문장 부호 및 파라미터 이름을 포함하세요. 파라미터 이름의 약어는 허용되지 않습니다.
   + `Condition` 섹션의 파라미터 순서는 중요하지 않습니다.
   + `Resource`, `DateLessThan`, `DateGreaterThan`, `IpAddress`에 대한 값 관련 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명에서 지정한 값](#private-content-custom-policy-statement-values)을 참조하세요.

1. 정책 설명에서 모든 공백(탭과 줄바꿈 문자 포함)을 제거합니다. 애플리케이션 코드의 문자열에 이스케이프 문자를 포함해야 할 수도 있습니다.

1. MIME base64 인코딩 기준으로 정책 설명을 Base64로 인코딩합니다. 자세한 내용은 *RFC 2045, MIME(Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*의 [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)을 참조하세요.

1. URL 쿼리 문자열에서 사용할 수 없는 문자를 유효한 문자로 교체합니다. 아래 표에 사용할 수 없는 문자와 유효한 문자가 나열되어 있습니다.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html)

1. 서명된 URL의 `Policy=` 뒤에 결과 값을 추가하세요.

1. 정책 설명을 해시, 서명 및 base64로 인코딩하여 서명된 URL에 대한 서명을 만드세요. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 서명 생성](#private-content-custom-policy-creating-signature) 섹션을 참조하세요.

### 사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명에서 지정한 값
<a name="private-content-custom-policy-statement-values"></a>

사용자 지정 정책에 대한 정책 설명을 생성할 때 다음 값을 지정합니다.

**리소스**  
있는 경우 쿼리 문자열은 포함하지만 CloudFront `Policy`, `Signature` 및 `Key-Pair-Id` 파라미터는 제외한 기본 URL입니다. 예제:  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg\?size=large&license=yes`  
`Resource`에 대해 값을 하나만 지정할 수 있습니다.  
정책에서 `Resource` 파라미터를 생략할 수 있지만 생략하는 경우 서명된 URL을 가진 사람은 누구나 서명된 URL을 만드는 데 사용한 키 페어와 연결된 어떠한 배포에서든 모든 파일에 액세스할 수 있다는 뜻이 됩니다.****
유의할 사항:  
+ **프로토콜(Protocol)** – 값은 `http://`, `https://` 또는 `*://`로 시작해야 합니다.
+ **쿼리 문자열 파라미터** - URL에 쿼리 문자열 파라미터가 있는 경우 백슬래시 문자(`\`)를 사용하지 않고 쿼리 문자열을 시작하는 물음표 문자(`?`)를 이스케이프 처리합니다. 예제:

  `https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`
+ **와일드카드 문자** - 정책의 URL에 와일드카드 문자를 사용할 수 있습니다. 다음 와일드카드 문자가 지원됩니다.
  + 별표(`*`). 0개 이상의 문자와 매칭됩니다.
  + 물음표(`?`). 정확히 한 문자와 매칭됩니다.

  CloudFront가 정책의 URL을 HTTP 요청의 URL과 매칭하면 정책의 URL은 네 개의 섹션, 즉 프로토콜, 도메인, 경로, 쿼리 문자열로 구분됩니다.

  `[protocol]://[domain]/[path]\?[query string]`

  정책의 URL에 와일드카드 문자를 사용하는 경우 와일드카드 매칭은 와일드카드가 포함된 섹션의 경계 내에서만 적용됩니다. 예를 들어, 다음 정책에서 이 URL을 고려해 보세요.

  `https://www.example.com/hello*world`

  이 예시에서 별표 와일드카드(`*`)는 경로 섹션 내에만 적용되므로 URL `https://www.example.com/helloworld` 및 `https://www.example.com/hello-world`와는 매칭되지만 URL `https://www.example.net/hello?world`와는 매칭되지 않습니다.

  와일드카드 매칭을 위한 섹션 경계에는 다음과 같은 예외가 적용됩니다.
  + 경로 섹션의 후행 별표는 쿼리 문자열 섹션의 별표를 의미합니다. 예를 들어, `http://example.com/hello*`은 `http://example.com/hello*\?*`과 같습니다.
  + 도메인 섹션의 후행 별표는 경로와 쿼리 문자열 섹션의 별표를 의미합니다. 예를 들어, `http://example.com*`은 `http://example.com*/*\?*`과 같습니다.
  + 정책의 URL은 프로토콜 섹션을 생략하고 도메인 섹션에서 별표로 시작할 수 있습니다. 이 경우 프로토콜 섹션은 암시적으로 별표로 설정됩니다. 예를 들어, 정책의 `*example.com` URL은 `*://*example.com/`에 해당합니다.
  + 별표(`"Resource": "*"`)는 그 자체로 모든 URL과 매칭됩니다.

  예를 들어, 정책의 `https://d111111abcdef8.cloudfront.net/*game_download.zip*` 값은 다음 URL 모두와 매칭됩니다.
  + `https://d111111abcdef8.cloudfront.net/game_download.zip`
  + `https://d111111abcdef8.cloudfront.net/example_game_download.zip?license=yes`
  + `https://d111111abcdef8.cloudfront.net/test_game_download.zip?license=temp`
+ **대체 도메인 이름** – 정책의 URL에 대체 도메인 이름(CNAME)을 지정하는 경우, 웹 페이지 또는 애플리케이션에서 HTTP 요청이 대체 도메인 이름을 사용해야 합니다. 정책의 파일에 Amazon S3 URL을 지정하지 마시기 바랍니다.

**DateLessThan**  
Unix 시간 형식(초) 및 협정 세계시(UTC) 기준의 URL 만료 날짜 및 시간. 정책에서 값을 인용 부호로 묶지 마세요. UTC에 대한 자세한 내용은 [인터넷의 날짜 및 시간: 타임스탬프](https://tools.ietf.org/html/rfc3339)를 참조하세요.  
예를 들면 2023년 1월 31일 오전 10시(UTC)를 Unix 시간 형식의 1675159200으로 변환합니다.  
`Condition` 섹션에서 유일한 필수 파라미터입니다. CloudFront는 이 값을 통해 프라이빗 콘텐츠에 대한 영구적인 액세스를 방지합니다.  
자세한 내용은 [CloudFront가 서명된 URL에서 만료 날짜 및 시간을 확인하는 시기](private-content-signed-urls.md#private-content-check-expiration) 섹션을 참조하세요.

**DateGreaterThan(선택 사항)**  
Unix 시간 형식(초)과 협정 세계시(UTC)의 URL에 대한 선택적 시작 날짜 및 시간. 사용자는 지정된 날짜 및 시간 이전에 파일에 액세스할 수 없습니다. 값을 인용 부호로 묶지 마세요.

**IpAddress(선택 사항)**  
HTTP 요청을 수행하는 클라이언트의 IP 주소입니다. 다음 사항에 유의하세요.  
+ 파일에 액세스하는 IP 주소를 허용하려면 `IpAddress` 파라미터를 생략합니다.
+ 하나의 IP 주소 또는 하나의 IP 주소 범위를 지정할 수 있습니다. 클라이언트의 IP 주소가 두 개의 다른 범위 중 하나에 있는 경우, 정책을 사용하여 액세스를 허용할 수 없습니다.
+ 단일 IP 주소에서 액세스를 허용하기 위해 다음을 지정합니다.

  `"`*IPv4 IP 주소*`/32"`
+ IP 주소 범위는 스탠다드 IPv4 CIDR 형식(예: `192.0.2.0/24`)을 지정해야 합니다. 자세한 내용은 [Classless Inter-domain Routing(CIDR): 인터넷 주소 할당 및 집계 계획](https://tools.ietf.org/html/rfc4632)을 참조하세요.
**중요**  
IPv6 형식의 IP 주소(예: 2001:0db8:85a3::8a2e:0370:7334)는 지원되지 않습니다.

  `IpAddress`를 포함하는 사용자 지정 정책을 사용할 경우 배포에 대해 IPv6를 사용하도록 설정하지 마세요. IP 주소로 일부 콘텐츠에 대한 액세스를 제한하고, 다른 콘텐츠에 대해서는 IPv6 요청을 지원하려면 두 가지 배포를 만들면 됩니다. 자세한 내용은 [IPv6 활성화(뷰어 요청)](DownloadDistValuesGeneral.md#DownloadDistValuesEnableIPv6) 주제에서 [모든 배포 설정 참조](distribution-web-values-specify.md) 단원을 참조하세요.

## 사용자 지정 정책을 사용하는 서명된 URL에 대한 예제 정책 설명
<a name="private-content-custom-policy-statement-examples"></a>

다음 예제 정책 설명은 특정 파일, 디렉터리의 모든 파일 또는 키 페어 ID에 연결된 모든 파일의 액세스 제어 방법을 보여줍니다. 예제는 또한 개별 IP 주소 또는 IP 주소 범위에서 액세스를 제어하는 방법과 지정된 날짜 및 시간 이후 사용자의 서명된 URL 사용 방지 방법을 보여줍니다.

이러한 예시를 복사하여 붙여 넣는 경우, 공백(탭과 줄바꿈 문자 포함)을 제거하고 값을 자체 값과 교체한 후 닫는 괄호(`}`)뒤에 줄바꿈 문자를 포함합니다.

자세한 내용은 [사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명에서 지정한 값](#private-content-custom-policy-statement-values) 섹션을 참조하세요.

**Topics**
+ [예제 정책 설명: IP 주소 범위에서 하나의 파일에 액세스](#private-content-custom-policy-statement-example-one-object)
+ [예제 정책 설명: IP 주소 범위에서 디렉터리의 모든 파일에 액세스](#private-content-custom-policy-statement-example-all-objects)
+ [예제 정책 설명: 하나의 IP 주소에서 키 페어 ID에 연결된 모든 파일에 액세스](#private-content-custom-policy-statement-example-one-ip)

### 예제 정책 설명: IP 주소 범위에서 하나의 파일에 액세스
<a name="private-content-custom-policy-statement-example-one-object"></a>

다음 서명된 URL의 예시 사용자 지정 정책은 UTC 기준 2023년 1월 31일 오전 10시까지 `192.0.2.0/24` 범위의 IP 주소에서 `https://d111111abcdef8.cloudfront.net/game_download.zip` 파일에 액세스할 수 있는 사용자를 지정합니다.

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/game_download.zip",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675159200
                }
            }
        }
    ]
}
```

### 예제 정책 설명: IP 주소 범위에서 디렉터리의 모든 파일에 액세스
<a name="private-content-custom-policy-statement-example-all-objects"></a>

다음 예시 사용자 지정 정책은 `Resource` 파라미터의 와일드카드 문자(`*`)로 표시된 바와 같이 `training` 디렉터리의 파일에 대한 서명된 URL을 만들 수 있도록 허용합니다. 사용자는 UTC 기준 2023년 1월 31일 오전 10시까지 `192.0.2.0/24` 범위의 IP 주소에서 파일에 액세스할 수 있습니다.

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/training/*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675159200
                }
            }
        }
    ]
}
```

이 정책과 함께 사용하는 서명된 URL에는 다음과 같이 특정 파일을 식별하는 URL이 있습니다.

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

### 예제 정책 설명: 하나의 IP 주소에서 키 페어 ID에 연결된 모든 파일에 액세스
<a name="private-content-custom-policy-statement-example-one-ip"></a>

다음 예시 사용자 지정 정책은 `Resource` 파라미터의 와일드카드 문자(`*`)로 표시된 대로 배포와 연결된 파일에 대한 서명된 URL을 만들 수 있도록 허용합니다. 서명된 URL은 `http://` 프로토콜이 아닌 `https://` 프로토콜을 사용해야 합니다. 사용자는 IP 주소 `192.0.2.10/32`를 사용해야 합니다. CIDR 표기법의 `192.0.2.10/32` 값은 단일 IP 주소 `192.0.2.10`을 가리킵니다. 파일은 UTC 기준 2023년 1월 31일 오전 10시에서 2023년 2월 2일 오전 10시까지만 사용할 수 있습니다.

```
{
    "Statement": [
       {
            "Resource": "https://*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.10/32"
                },
                "DateGreaterThan": {
                    "AWS:EpochTime": 1675159200
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675332000
                }
            }
        }
    ]
}
```

이 정책과 사용하는 서명된 URL에는 다음과 같이 특정 CloudFront 배포의 특정 파일을 식별하는 URL이 있습니다.

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

또한 서명된 URL은 키 페어 ID를 포함하고 이는 URL에서 지정한 배포(d111111abcdef8.cloudfront.net)의 신뢰할 수 있는 키 그룹과 연결되어야 합니다.

## 사용자 지정 정책을 사용하는 서명된 URL에 대한 서명 생성
<a name="private-content-custom-policy-creating-signature"></a>

서명된 URL에 대한 서명은 정책 설명의 해시, 서명 및 base64로 인코딩된 버전의 사용자 지정 정책을 사용합니다. 사용자 지정 정책에 대한 서명을 만들려면 다음 단계를 수행합니다.

다음을 참조하여 정책 설명을 해시, 서명 및 인코딩하는 방법에 대한 추가적인 내용과 예제를 확인하세요.
+ [base64 인코딩 및 암호화를 위한 Linux 명령 및 OpenSSL](private-content-linux-openssl.md)
+ [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)<a name="private-content-custom-policy-creating-signature-download-procedure"></a>

**옵션 1: 사용자 지정 정책을 사용하여 서명을 만들려면**

1. SHA-1 해시 함수와 생성된 RSA 또는 ECDSA 프라이빗 키를 사용하여 [사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명을 만들려면](#private-content-custom-policy-creating-policy-procedure) 절차에서 만든 JSON 정책 설명을 해시하고 서명합니다. 더 이상 공백을 포함하지 않지만 base64로 인코딩되지 않은 정책 설명 버전을 사용합니다.

   해시 함수에 필요한 프라이빗 키의 경우 배포에 대해 신뢰할 수 있는 활성 키 그룹에 퍼블릭 키가 있는 프라이빗 키를 사용합니다.
**참고**  
정책 설명을 해시 및 서명하는 방법은 프로그래밍 언어와 플랫폼에 따라 달라집니다. 샘플 코드에 대한 내용은 [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)를 참조하세요.

1. 해시 및 서명된 문자열에서 공백(탭과 줄바꿈 문자 포함)을 제거합니다.

1. MIME base64 인코딩 기준으로 문자열을 base64로 인코딩합니다. 자세한 내용은 *RFC 2045, MIME(Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*의 [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)을 참조하세요.

1. URL 쿼리 문자열에서 사용할 수 없는 문자를 유효한 문자로 교체합니다. 아래 표에 사용할 수 없는 문자와 유효한 문자가 나열되어 있습니다.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html)

1. 서명된 URL의 `&Signature=` 뒤에 결과 값을 추가하고 [사용자 지정 정책을 사용하여 서명된 URL을 만들려면](#private-content-creating-signed-url-custom-policy-procedure)로 돌아가서 서명된 URL 부분을 마저 연결합니다.

# 서명된 쿠키 사용
<a name="private-content-signed-cookies"></a>

현재의 URL을 변경하지 않으려는 경우나 여러 제한된 파일(예: 웹 사이트의 구독자 영역에 있는 전체 파일)에 대한 액세스 권한을 제공하려는 경우, CloudFront 서명된 쿠키를 사용하여 콘텐츠 액세스를 제어할 수 있습니다. 이 주제에서는 서명된 쿠키를 사용할 때 고려해야 할 사항과 미리 준비된 정책 및 사용자 지정 정책을 사용하여 서명된 쿠키를 설정하는 방법을 다룹니다.

**Topics**
+ [서명된 쿠키에 대해 미리 준비된 정책 또는 사용자 지정 정책 사용 결정](#private-content-choosing-canned-custom-cookies)
+ [서명된 쿠키 작동 방식](#private-content-how-signed-cookies-work)
+ [서명된 쿠키 악용 방지](#private-content-signed-cookie-misuse)
+ [CloudFront가 서명된 쿠키의 만료 날짜 및 시간을 확인하는 시기](#private-content-check-expiration-cookie)
+ [샘플 코드 및 타사 도구](#private-content-overview-sample-code-cookies)
+ [미리 준비된 정책을 사용하여 서명된 쿠키 설정](private-content-setting-signed-cookie-canned-policy.md)
+ [사용자 지정 정책을 사용하여 서명된 쿠키 설정](private-content-setting-signed-cookie-custom-policy.md)
+ [PHP를 사용하여 서명된 쿠키 생성](signed-cookies-PHP.md)

## 서명된 쿠키에 대해 미리 준비된 정책 또는 사용자 지정 정책 사용 결정
<a name="private-content-choosing-canned-custom-cookies"></a>

서명된 쿠키를 만들 때 JSON 형식의 정책 설명을 작성하여 서명된 쿠키의 제약 조건(예: 쿠키의 유효 기간)을 지정합니다. 미리 준비된 정책 또는 사용자 지정 정책을 사용할 수 있습니다. 다음 테이블은 미리 준비된 정책과 사용자 지정 정책을 비교합니다.


****  

| 설명 | 미리 준비된 정책 | 사용자 정의 정책 | 
| --- | --- | --- | 
| 정책 설명은 여러 파일에 재사용할 수 있습니다. 정책 설명을 재사용하려면 `Resource` 객체에 와일드카드 문자를 사용해야 합니다. 자세한 내용은 [서명된 쿠키에서 사용자 지정 정책을 위한 정책 설명에서 지정한 값](private-content-setting-signed-cookie-custom-policy.md#private-content-custom-policy-statement-cookies-values) 섹션을 참조하세요.)  | 아니요 | 예 | 
| 날짜 및 시간을 지정하여 사용자가 콘텐츠에 액세스를 시작할 수 있습니다. | 아니요 | 예(선택 사항) | 
| 사용자의 콘텐츠 액세스를 중단할 날짜 및 시간을 지정할 수 있습니다. | 예 | 예 | 
| 콘텐츠에 액세스할 수 있는 사용자의 IP 주소 또는 IP 주소 범위를 지정할 수 있습니다. | 아니요 | 예(선택 사항) | 

미리 준비된(canned) 정책으로 서명된 쿠키를 만드는 방법에 대한 자세한 내용은 [미리 준비된 정책을 사용하여 서명된 쿠키 설정](private-content-setting-signed-cookie-canned-policy.md)을 참조하세요.

사용자 지정 정책으로 서명된 쿠키를 만드는 방법에 대한 자세한 내용은 [사용자 지정 정책을 사용하여 서명된 쿠키 설정](private-content-setting-signed-cookie-custom-policy.md)을 참조하세요.

## 서명된 쿠키 작동 방식
<a name="private-content-how-signed-cookies-work"></a>

서명된 쿠키에 대한 CloudFront 구성 방법과 사용자가 서명된 쿠키를 포함한 요청을 제출할 때 CloudFront 반응에 대한 개요가 있습니다.

1. CloudFront 배포에서 CloudFront가 URL 서명을 확인하는 데 사용할 수 있는 퍼블릭 키가 포함된 신뢰할 수 있는 키 그룹을 하나 이상 지정합니다. 해당 프라이빗 키를 사용하여 URL에 서명합니다.

   자세한 내용은 [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md) 단원을 참조하세요.

1. 사용자가 콘텐츠에 액세스해야 하는지 여부를 파악하고, 필요하면 최종 사용자에게 `Set-Cookie` 헤더 세 개를 보내도록 애플리케이션을 개발합니다. (각 `Set-Cookie` 헤더는 이름-값 페어를 하나만 포함할 수 있고 CloudFront 서명된 쿠키에는 이름-값 페어 3개가 필요합니다.) 최종 사용자가 프라이빗 콘텐츠를 요청하기 전에 `Set-Cookie` 헤더를 최종 사용자에게 보내야 합니다. 쿠키의 만료 시간을 짧게 설정한 경우, 사용자가 계속 액세스할 수 있도록 후속 요청에 대해 `Set-Cookie` 헤더 세 개를 더 보낼 수 있습니다.

   일반적으로 CloudFront 배포에는 캐시 동작이 2개 이상 있는데 하나는 인증이 필요 없고 다른 하나는 필요합니다. 사이트 보안에 대한 오류 페이지에는 로그인 페이지로 가는 리디렉터 또는 링크가 있습니다.

   쿠키를 기반으로 파일을 캐시하도록 배포를 구성하는 경우, CloudFront는 서명된 쿠키의 속성을 기반으로 별도의 파일을 캐시하지 않습니다.

1. 사용자가 웹 사이트에 로그인하여 콘텐츠에 대한 비용을 지불하거나 액세스에 필요한 자격 요건을 충족합니다.

1. 애플리케이션은 응답을 통해 `Set-Cookie` 헤더를 반환하고 최종 사용자는 이름-값 페어를 저장합니다.

1. 사용자가 파일을 요청합니다.

   사용자의 브라우저 또는 기타 최종 사용자는 4단계의 이름-값 페어를 불러와서 이를 `Cookie` 헤더의 요청에 추가합니다. 이것이 서명된 쿠키입니다.

1. CloudFront는 퍼블릭 키를 사용하여 서명된 쿠키의 서명을 확인하고 쿠키가 아직 변조되지 않았음을 확인합니다. 유효하지 않은 서명인 경우 요청을 거부합니다.

   쿠키의 서명이 유효한 경우, CloudFront는 쿠키의 정책 설명을 보거나 미리 준비된(canned) 정책을 사용하는 경우, 정책 설명을 구성하여 요청이 아직 유효함을 확인합니다. 예를 들어, 쿠키의 시작 및 종료 날짜와 시간을 지정하는 경우, CloudFront는 액세스가 허용된 시간 동안 콘텐츠 액세스를 시도한 사용자를 확인합니다.

   요청이 정책 설명의 요구 사항을 충족하는 경우, CloudFront는 제한되지 않은 콘텐츠와 같은 방식으로 콘텐츠를 제공합니다. 다시 말해 파일이 이미 엣지 캐시에 있는지 여부를 판단하고, 필요에 따라 요청을 오리진으로 전달하고, 사용자에게 파일을 반환합니다.

## 서명된 쿠키 악용 방지
<a name="private-content-signed-cookie-misuse"></a>

`Domain` 헤더에 `Set-Cookie` 파라미터를 지정할 때는 루트 도메인 이름을 가진 사용자의 액세스 가능성을 줄이도록 최대한 정확한 값을 지정하세요. 예를 들자면 example.com보다 app.example.com이 더 좋고, example.com을 제어하지 않을 때는 특히 그렇습니다. 이렇게 하면 www.example.com을 통한 콘텐츠 액세스를 방지할 수 있습니다.

이런 유형의 공격을 방지하려면 다음을 수행하세요.
+ `Expires` 및 `Max-Age` 쿠키 속성을 제외하여 `Set-Cookie` 헤더에서 세션 쿠키를 만들도록 합니다. 세션 쿠키는 사용자가 브라우저를 닫을 때 자동으로 삭제되며, 따라서 권한 없는 제3자가 콘텐츠에 액세스할 가능성을 줄여 줍니다.
+ `Secure` 속성을 포함하여 최종 사용자가 이를 요청할 때 쿠키가 암호화되도록 하세요.
+ 가능하면 사용자 지정 정책을 사용하고 최종 사용자의 IP 주소를 포함합니다.
+ `CloudFront-Expires` 속성에서 사용자의 콘텐츠 액세스를 허용할 기간을 기준으로 하여 가장 짧고 합리적인 만료 시간을 지정하세요.

## CloudFront가 서명된 쿠키의 만료 날짜 및 시간을 확인하는 시기
<a name="private-content-check-expiration-cookie"></a>

CloudFront는 서명된 쿠키가 아직 유효한지 파악하기 위해 HTTP 요청 시 쿠키의 만료 날짜 및 시간을 확인합니다. 클라이언트가 만료 시간 직전에 대용량 파일을 다운로드하기 시작한 경우, 다운로드 도중 만료 시간이 지나도 다운로드는 완료됩니다. TCP 연결이 끊어진 경우, 클라이언트가 만료 시간 이후에 다운로드를 다시 시작하는 것은 불가능합니다.

클라이언트가 범위 GET을 사용하여 파일을 작은 조각으로 가져오는 경우, 만료 시간 이후의 GET 요청은 실패합니다. 범위 GET에 대한 자세한 내용은 [CloudFront에서 객체에 대한 부분적인 요청을 처리하는 방법(범위 GET)](RangeGETs.md)을 참조하세요.

## 샘플 코드 및 타사 도구
<a name="private-content-overview-sample-code-cookies"></a>

프라이빗 콘텐츠에 대한 샘플 코드는 서명된 URL에 대한 서명을 만드는 방법만 보여줍니다. 그러나 서명된 쿠키에 대한 서명 생성 프로세스도 이와 유사하기 때문에 대부분의 샘플 코드는 여전히 관계가 있습니다. 자세한 내용은 다음 항목을 참조하세요.
+ [Perl을 사용한 URL 서명 생성](CreateURLPerl.md)
+ [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md)
+ [C\$1 및 .NET Framework를 사용한 URL 서명 생성](CreateSignatureInCSharp.md)
+ [Java를 사용한 URL 서명 생성](CFPrivateDistJavaDevelopment.md)

# 미리 준비된 정책을 사용하여 서명된 쿠키 설정
<a name="private-content-setting-signed-cookie-canned-policy"></a>

미리 준비된 정책을 사용하여 서명된 쿠키를 설정하려면 다음 단계를 완료하세요. 서명을 만들려면 [미리 준비된 정책을 사용하는 서명된 쿠키에 대한 서명 생성](#private-content-canned-policy-signature-cookies) 단원을 참조하세요.<a name="private-content-setting-signed-cookie-canned-policy-procedure"></a>

**미리 준비된 정책을 사용하여 서명된 쿠키를 설정하려면**

1. .NET 또는 Java를 사용하여 서명된 쿠키를 생성하는 중인데 키 페어의 프라이빗 키를 기본 .pem 형식에서 .NET 또는 Java와 상환되는 형식으로 다시 포맷하지 않았다면 지금 포맷하세요. 자세한 내용은 [프라이빗 키 재포맷(.NET 및 Java만 해당)](private-content-trusted-signers.md#private-content-reformatting-private-key) 단원을 참조하세요.

1. `Set-Cookie` 헤더 세 개를 승인된 최종 사용자에게 보내도록 애플리케이션을 프로그래밍합니다. 각 `Set-Cookie` 헤더는 이름-값 페어를 하나만 포함할 수 있고 CloudFront 서명된 쿠키에는 이름-값 페어 3개가 필요하기 때문에 `Set-Cookie` 헤더가 3개 있어야 합니다. 이름-값 페어는 `CloudFront-Expires`, `CloudFront-Signature`, `CloudFront-Key-Pair-Id`입니다. 액세스가 제한되는 파일에 대해 사용자가 첫 번째 요청을 하려면 최종 사용자에게 값이 있어야 합니다.
**참고**  
일반적으로 `Expires` 및 `Max-Age` 속성을 제외하는 것이 좋습니다. 이러한 속성을 제외하면 사용자가 브라우저를 닫을 때 쿠키가 삭제되므로 권한 없는 사람이 콘텐츠에 액세스할 가능성이 줄어듭니다. 자세한 내용은 [서명된 쿠키 악용 방지](private-content-signed-cookies.md#private-content-signed-cookie-misuse) 단원을 참조하세요.

   **쿠키 속성의 이름은 대소문자를 구분합니다**.

   줄바꿈은 속성의 가독성을 높이기 위해서만 사용됩니다.

   ```
   Set-Cookie: 
   CloudFront-Expires=date and time in Unix time format (in seconds) and Coordinated Universal Time (UTC); 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Signature=hashed and signed version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Key-Pair-Id=public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   ```  
**(선택 사항) `Domain`**  
요청된 파일의 도메인 이름입니다. `Domain` 속성을 지정하지 않는 경우, 기본값은 URL의 도메인 이름이고 이는 하위 도메인이 아닌 지정된 도메인 이름에만 적용됩니다. `Domain` 속성을 지정하는 경우, 하위 도메인에도 적용됩니다. 도메인 이름 앞의 점(예: `Domain=.example.com`)은 선택 사항입니다. 또한 `Domain` 속성을 지정하는 경우, URL의 도메인 이름과 `Domain` 속성의 값이 일치해야 합니다.  
CloudFront가 배포에 할당하는 도메인 이름을 d111111abcdef8.cloudfront.net과 같이 지정할 수 있으나, \$1.cloudfront.net을 도메인 이름으로 지정할 수는 없습니다.  
URL에 example.com과 같은 대체 도메인 이름을 사용하려면 `Domain` 속성 지정 여부와 상관없이 대체 도메인 이름을 배포에 추가해야 합니다. 자세한 내용은 [대체 도메인 이름(CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) 주제에서 [모든 배포 설정 참조](distribution-web-values-specify.md) 단원을 참조하세요.  
**(선택 사항) `Path`**  
요청된 파일의 경로입니다. `Path` 속성을 지정하지 않는 경우, 기본값은 URL의 경로입니다.  
**`Secure`**  
요청을 보내기 전 최종 사용자에게 쿠키의 암호화를 요청하세요. 쿠키 속성이 MITM(중간자 공격)을 당하지 않도록 HTTPS 연결을 통해 `Set-Cookie` 헤더를 보내는 것이 좋습니다.  
**`HttpOnly`**  
브라우저(지원되는 경우)가 쿠키 값과 상호 작용하는 방식을 정의합니다. `HttpOnly`를 사용하면 JavaScript에서 쿠키 값에 액세스할 수 없습니다. 이 예방 조치는 크로스 사이트 스크립팅(XSS) 공격을 완화하는 데 도움이 될 수 있습니다. 자세한 내용은 [HTTP 쿠키 사용](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)을 참조하세요.  
**`CloudFront-Expires`**  
Unix 시간 형식(초) 및 협정 세계시(UTC) 기준의 URL 만료 날짜 및 시간을 지정합니다. 예를 들면 2026년 1월 1일 오전 10시(UTC)를 Unix 시간 형식의 1767290400으로 변환합니다.  
에포크 시간을 사용하려면 `9223372036854775807`(금요일, 2262년 4월 11일 23:47:16.854 UTC) 이전 날짜에 대한 64비트 정수를 지정합니다.  
UTC에 대한 자세한 내용은 *RFC 3339, 인터넷의 날짜 및 시간: 타임스탬프*, [https://tools.ietf.org/html/rfc3339](https://tools.ietf.org/html/rfc3339)를 참조하세요.  
**`CloudFront-Signature`**  
JSON 정책 설명의 해시, 서명 및 base64 인코딩 버전입니다. 자세한 내용은 [미리 준비된 정책을 사용하는 서명된 쿠키에 대한 서명 생성](#private-content-canned-policy-signature-cookies) 단원을 참조하세요.  
**`CloudFront-Key-Pair-Id`**  
CloudFront 퍼블릭 키의 ID입니다(예: `K2JCJMDEHXQW5F`). CloudFront는 서명된 URL을 확인할 때 사용할 퍼블릭 키를 퍼블릭 키 ID로 판단합니다. CloudFront는 서명의 정보를 정책 설명의 정보와 비교하고 URL이 변조되지 않았음을 확인합니다.  
이 퍼블릭 키는 배포에서 신뢰할 수 있는 서명자인 키 그룹에 속해야 합니다. 자세한 내용은 [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md) 단원을 참조하세요.

다음 예제는 배포와 연결된 도메인 이름을 파일의 URL에 사용할 때 서명된 쿠키 한 개의 `Set-Cookie` 헤더를 보여줍니다.

```
Set-Cookie: CloudFront-Expires=1426500000; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=yXrSIgyQoeE4FBI4eMKF6ho~CA8_; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
```

다음 예제는 파일에 대한 URL의 example.org 대체 도메인 이름을 사용할 때 하나의 서명된 쿠키에 대한 예제 `Set-Cookie` 헤더를 보여줍니다.

```
Set-Cookie: CloudFront-Expires=1426500000; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=yXrSIgyQoeE4FBI4eMKF6ho~CA8_; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/images/*; Secure; HttpOnly
```

URL에 example.com과 같은 대체 도메인 이름을 사용하려면 `Domain` 속성 지정 여부와 상관없이 대체 도메인 이름을 배포에 추가해야 합니다. 자세한 내용은 [대체 도메인 이름(CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) 주제에서 [모든 배포 설정 참조](distribution-web-values-specify.md) 단원을 참조하세요.

## 미리 준비된 정책을 사용하는 서명된 쿠키에 대한 서명 생성
<a name="private-content-canned-policy-signature-cookies"></a>

미리 준비된 정책을 사용하는 서명된 쿠키의 서명을 만들려면 다음 절차를 완료하세요.

**Topics**
+ [미리 준비된 정책을 사용하는 서명된 쿠키에 대한 정책 설명 생성](#private-content-canned-policy-statement-cookies)
+ [정책 설명에 서명하여 미리 준비된 정책을 사용하는 서명된 쿠키에 대한 서명 생성](#private-content-canned-policy-cookies-signing-policy-statement)

### 미리 준비된 정책을 사용하는 서명된 쿠키에 대한 정책 설명 생성
<a name="private-content-canned-policy-statement-cookies"></a>

미리 준비된 정책을 사용하는 서명된 쿠키를 설정할 때 `CloudFront-Signature` 속성은 정책 설명의 해시 및 서명된 버전입니다. 미리 준비된 정책을 사용하는 서명된 쿠키의 경우, 사용자 지정 정책을 사용하는 서명된 쿠키와 마찬가지로 `Set-Cookie` 헤더에 정책 설명을 포함하지 않습니다. 정책 설명을 만들려면 다음 단계를 수행합니다.<a name="private-content-canned-policy-statement-cookies-procedure"></a>

**미리 준비된 정책을 사용하는 서명된 쿠키에 대한 정책 설명을 만들려면**

1. 다음 JSON 형식과 UTF-8 문자 인코딩을 사용하여 정책 설명을 구성합니다. 지정된 모든 문장 부호 및 기타 리터럴 값을 정확히 포함해야 합니다. `Resource` 및 `DateLessThan` 파라미터에 대한 내용은 [서명된 쿠키에서 미리 준비된 정책을 위한 정책 설명에서 지정한 값](#private-content-canned-policy-statement-cookies-values)를 참조하세요.

   ```
   {
       "Statement": [
           {
               "Resource": "base URL or stream name",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime": ending date and time in Unix time format and UTC
                   }
               }
           }
       ]
   }
   ```

1. 정책 설명에서 모든 공백(탭과 줄바꿈 문자 포함)을 제거합니다. 애플리케이션 코드의 문자열에 이스케이프 문자를 포함해야 할 수도 있습니다.

#### 서명된 쿠키에서 미리 준비된 정책을 위한 정책 설명에서 지정한 값
<a name="private-content-canned-policy-statement-cookies-values"></a>

미리 준비된 정책에 대한 정책 설명을 만들 때 다음 값을 지정합니다.

**리소스**  
쿼리 문자열을 포함하는 기본 URL(있는 경우)은 다음과 같습니다.  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
`Resource`에 대해 값을 하나만 지정할 수 있습니다.  
다음을 참조하세요.  
+ **프로토콜(Protocol)** – 값은 `http://` 또는 `https://`로 시작해야 합니다.
+ **쿼리 문자열 파라미터(Query string parameters)** – 쿼리 문자열 파라미터가 없는 경우, 물음표를 생략합니다.
+ **대체 도메인 이름(Alternate domain names)** – URL에 대체 도메인 이름(CNAME)을 지정하는 경우, 웹 페이지 또는 애플리케이션의 파일을 참조할 때 대체 도메인 이름을 지정해야 합니다. 파일에 대한 Amazon S3 URL을 지정하지 마시기 바랍니다.

**DateLessThan**  
Unix 시간 형식(초) 및 협정 세계시(UTC) 기준의 URL 만료 날짜 및 시간. 값을 인용 부호로 묶지 마세요.  
예를 들면 2015년 3월 16일 오전 10시(UTC)를 Unix 시간 형식인 1426500000으로 변환합니다.  
이 값은 `CloudFront-Expires` 헤더의 `Set-Cookie` 속성 값과 일치해야 합니다. 값을 인용 부호로 묶지 마세요.  
자세한 내용은 [CloudFront가 서명된 쿠키의 만료 날짜 및 시간을 확인하는 시기](private-content-signed-cookies.md#private-content-check-expiration-cookie) 단원을 참조하세요.

#### 미리 준비된 정책에 대한 정책 설명 예제
<a name="private-content-canned-policy-cookies-sample-policy-statement"></a>

서명된 쿠키에 다음 예제의 정책 설명을 사용할 경우, 사용자는 UTC 기준 2015년 3월 16일 오전 10시까지 `https://d111111abcdef8.cloudfront.net/horizon.jpg` 파일에 액세스할 수 있습니다.

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/horizon.jpg?size=large&license=yes",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1426500000
                }
            }
        }
    ]
}
```

### 정책 설명에 서명하여 미리 준비된 정책을 사용하는 서명된 쿠키에 대한 서명 생성
<a name="private-content-canned-policy-cookies-signing-policy-statement"></a>

`CloudFront-Signature` 헤더의 `Set-Cookie` 속성의 값을 만들려면 [미리 준비된 정책을 사용하는 서명된 쿠키에 대한 정책 설명을 만들려면](#private-content-canned-policy-statement-cookies-procedure)에서 만든 정책 설명을 해시하고 서명합니다.

다음 주제를 참조하여 정책 설명을 해시, 서명 및 인코딩하는 방법에 대한 추가적인 내용과 예제를 확인하세요.
+ [base64 인코딩 및 암호화를 위한 Linux 명령 및 OpenSSL](private-content-linux-openssl.md)
+ [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)<a name="private-content-canned-policy-cookie-creating-signature-procedure"></a>

**미리 준비된 정책을 사용하는 서명된 쿠키에 대한 서명을 만들려면**

1. SHA-1 해시 함수 및 RSA를 사용하여 [미리 준비된 정책을 사용하는 서명된 쿠키에 대한 정책 설명을 만들려면](#private-content-canned-policy-statement-cookies-procedure) 절차에서 만든 RSA 정책 설명을 해시하고 서명합니다. 공백이 삭제된 버전의 정책 설명을 사용합니다.

   해시 함수에 필요한 프라이빗 키의 경우 배포에 대해 신뢰할 수 있는 활성 키 그룹에 퍼블릭 키가 있는 프라이빗 키를 사용합니다.
**참고**  
정책 설명을 해시 및 서명하는 방법은 프로그래밍 언어와 플랫폼에 따라 달라집니다. 샘플 코드에 대한 내용은 [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)를 참조하세요.

1. 해시 및 서명된 문자열에서 공백(탭과 줄바꿈 문자 포함)을 제거합니다.

1. MIME base64 인코딩 기준으로 문자열을 base64로 인코딩합니다. 자세한 내용은 *RFC 2045, MIME(Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*의 [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)을 참조하세요.

1. URL 쿼리 문자열에서 사용할 수 없는 문자를 유효한 문자로 교체합니다. 아래 표에 사용할 수 없는 문자와 유효한 문자가 나열되어 있습니다.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-canned-policy.html)

1. 결과로 얻은 값을 `Set-Cookie` 이름-값 페어의 `CloudFront-Signature` 헤더에 포함하세요. 그런 다음, [미리 준비된 정책을 사용하여 서명된 쿠키를 설정하려면](#private-content-setting-signed-cookie-canned-policy-procedure) 절차로 돌아가서 `Set-Cookie`에 대한 `CloudFront-Key-Pair-Id` 헤더를 추가합니다.

# 사용자 지정 정책을 사용하여 서명된 쿠키 설정
<a name="private-content-setting-signed-cookie-custom-policy"></a>

사용자 지정 정책을 사용하는 서명된 쿠키를 설정하려면 다음 단계를 수행합니다.<a name="private-content-setting-signed-cookie-custom-policy-procedure"></a>

**사용자 지정 정책을 사용하여 서명된 쿠키를 설정하려면**

1. .NET 또는 Java를 사용하여 서명된 URL을 만드는 중인데 키 페어의 프라이빗 키를 기본 .pem 형식에서 .NET 또는 Java와 상환되는 형식으로 다시 포맷하지 않았다면 지금 포맷하세요. 자세한 내용은 [프라이빗 키 재포맷(.NET 및 Java만 해당)](private-content-trusted-signers.md#private-content-reformatting-private-key) 단원을 참조하세요.

1. `Set-Cookie` 헤더 세 개를 승인된 최종 사용자에게 보내도록 애플리케이션을 프로그래밍합니다. 각 `Set-Cookie` 헤더는 이름-값 페어를 하나만 포함할 수 있고 CloudFront 서명된 쿠키에는 이름-값 페어 3개가 필요하기 때문에 `Set-Cookie` 헤더가 3개 있어야 합니다. 이름-값 페어는 `CloudFront-Policy`, `CloudFront-Signature`, `CloudFront-Key-Pair-Id`입니다. 액세스가 제한되는 파일에 대해 사용자가 첫 번째 요청을 하려면 최종 사용자에게 값이 있어야 합니다.
**참고**  
일반적으로 `Expires` 및 `Max-Age` 속성을 제외하는 것이 좋습니다. 이렇게 하면 사용자가 브라우저를 닫을 때 쿠키가 삭제되므로 권한 없는 사람이 콘텐츠에 액세스할 가능성이 줄어듭니다. 자세한 내용은 [서명된 쿠키 악용 방지](private-content-signed-cookies.md#private-content-signed-cookie-misuse) 단원을 참조하세요.

   **쿠키 속성의 이름은 대소문자를 구분합니다**.

   줄바꿈은 속성의 가독성을 높이기 위해서만 사용됩니다.

   ```
   Set-Cookie: 
   CloudFront-Policy=base64 encoded version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   
   Set-Cookie: 
   CloudFront-Signature=hashed and signed version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Key-Pair-Id=public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   ```  
**(선택 사항) `Domain`**  
요청된 파일의 도메인 이름입니다. `Domain` 속성을 지정하지 않는 경우, 기본값은 URL의 도메인 이름이고 이는 하위 도메인이 아닌 지정된 도메인 이름에만 적용됩니다. `Domain` 속성을 지정하는 경우, 하위 도메인에도 적용됩니다. 도메인 이름 앞의 점(예: `Domain=.example.com`)은 선택 사항입니다. 또한 `Domain` 속성을 지정하는 경우, URL의 도메인 이름과 `Domain` 속성의 값이 일치해야 합니다.  
CloudFront가 배포에 할당하는 도메인 이름을 d111111abcdef8.cloudfront.net과 같이 지정할 수 있으나, \$1.cloudfront.net을 도메인 이름으로 지정할 수는 없습니다.  
URL에 example.com과 같은 대체 도메인 이름을 사용하려면 `Domain` 속성 지정 여부와 상관없이 대체 도메인 이름을 배포에 추가해야 합니다. 자세한 내용은 [대체 도메인 이름(CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) 주제에서 [모든 배포 설정 참조](distribution-web-values-specify.md) 단원을 참조하세요.  
**(선택 사항) `Path`**  
요청된 파일의 경로입니다. `Path` 속성을 지정하지 않는 경우, 기본값은 URL의 경로입니다.  
**`Secure`**  
요청을 보내기 전 최종 사용자에게 쿠키의 암호화를 요청하세요. 쿠키 속성이 MITM(중간자 공격)을 당하지 않도록 HTTPS 연결을 통해 `Set-Cookie` 헤더를 보내는 것이 좋습니다.  
**`HttpOnly`**  
HTTP 또는 HTTPS 요청에 한해 최종 사용자에게 쿠키를 요구하세요.  
**`CloudFront-Policy`**  
공백이 제거된 JSON 형식의 정책 설명은 base64로 인코딩합니다. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 쿠키에 대한 서명 생성](#private-content-custom-policy-signature-cookies) 섹션을 참조하세요.  
정책 설명은 서명된 쿠키가 사용자에게 부여하는 액세스를 제어합니다. 여기에는 사용자가 액세스할 수 있는 파일, 만료 날짜 및 시간, URL의 효력이 발생하는 날짜 및 시간(선택 사항), 파일에 액세스할 수 있는 IP 주소 또는 IP 주소 범위(선택 사항)가 포함됩니다.  
**`CloudFront-Signature`**  
JSON 정책 설명을 해시, 서명 및 base64로 인코딩한 버전입니다. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 쿠키에 대한 서명 생성](#private-content-custom-policy-signature-cookies) 단원을 참조하세요.  
**`CloudFront-Key-Pair-Id`**  
CloudFront 퍼블릭 키의 ID입니다(예: `K2JCJMDEHXQW5F`). CloudFront는 서명된 URL을 확인할 때 사용할 퍼블릭 키를 퍼블릭 키 ID로 판단합니다. CloudFront는 서명의 정보를 정책 설명의 정보와 비교하고 URL이 변조되지 않았음을 확인합니다.  
이 퍼블릭 키는 배포에서 신뢰할 수 있는 서명자인 키 그룹에 속해야 합니다. 자세한 내용은 [서명된 URL 및 서명된 쿠키를 생성할 수 있는 서명자 지정](private-content-trusted-signers.md) 섹션을 참조하세요.

## 사용자 지정 정책의 예제 헤더 `Set-Cookie`
<a name="example-set-cookie-headers-custom-policy"></a>

`Set-Cookie` 헤더 쌍의 다음 예를 참조하십시오.

URL에 example.org와 같은 대체 도메인 이름을 사용하려면 `Domain` 속성 지정 여부와 상관없이 대체 도메인 이름을 배포에 추가해야 합니다. 자세한 내용은 [대체 도메인 이름(CNAME)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) 주제에서 [모든 배포 설정 참조](distribution-web-values-specify.md) 섹션을 참조하세요.

**Example 예 1**  
파일 URL에 배포와 연결된 도메인 이름을 사용하는 경우 서명된 쿠키 하나에 `Set-Cookie` 헤더를 사용할 수 있습니다.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
```

**Example 예제 2**  
파일의 URL에 대체 도메인 이름(example.org)을 사용하는 경우 서명된 쿠키 하나에 `Set-Cookie` 헤더를 사용할 수 있습니다.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/; Secure; HttpOnly
```

**Example 예 3**  
파일의 URL에 배포와 연결된 도메인 이름을 사용하는 경우 서명된 요청에 `Set-Cookie` 헤더 쌍을 사용할 수 있습니다.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=dd111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
```

**Example 예 4**  
파일 URL에 배포와 연결된 대체 도메인 이름(example.org)을 사용하는 경우 서명된 요청 하나에 `Set-Cookie` 헤더 쌍을 사용할 수 있습니다.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/; Secure; HttpOnly
```

## 사용자 지정 정책을 사용하는 서명된 쿠키에 대한 정책 설명 생성
<a name="private-content-custom-policy-statement-cookies"></a>

사용자 지정 정책에 대한 정책 설명을 만들려면 다음 단계를 수행합니다. 다양한 방법으로 파일에 대한 액세스를 제어하는 몇 가지 예제 정책 설명에 대한 내용은 [사용자 지정 정책을 사용하는 서명된 쿠키에 대한 예제 정책 설명](#private-content-custom-policy-statement-signed-cookies-examples) 단원을 참조하세요.<a name="private-content-custom-policy-statement-cookies-procedure"></a>

**사용자 지정 정책을 사용하는 서명된 쿠키에 대한 정책 설명을 만들려면**

1. 다음 JSON 형식을 사용하여 정책 설명을 구성하세요.

   ```
   {
       "Statement": [
           {
               "Resource": "URL of the file",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime":required ending date and time in Unix time format and UTC
                   },
                   "DateGreaterThan": {
                       "AWS:EpochTime":optional beginning date and time in Unix time format and UTC
                   },
                   "IpAddress": {
                       "AWS:SourceIp": "optional IP address"
                   }
               }
           }
       ]
   }
   ```

   다음을 참조하세요.
   + 단 한 개의 명령문만 포함시킬 수 있습니다.
   + UTF-8 문자 인코딩을 사용하세요.
   + 지정된 대로 정확하게 모든 문장 부호 및 파라미터 이름을 포함하세요. 파라미터 이름의 약어는 허용되지 않습니다.
   + `Condition` 섹션의 파라미터 순서는 중요하지 않습니다.
   + `Resource`, `DateLessThan`, `DateGreaterThan`, `IpAddress`에 대한 값 관련 내용은 [서명된 쿠키에서 사용자 지정 정책을 위한 정책 설명에서 지정한 값](#private-content-custom-policy-statement-cookies-values)을 참조하세요.

1. 정책 설명에서 모든 공백(탭과 줄바꿈 문자 포함)을 제거합니다. 애플리케이션 코드의 문자열에 이스케이프 문자를 포함해야 할 수도 있습니다.

1. MIME base64 인코딩 기준으로 정책 설명을 Base64로 인코딩합니다. 자세한 내용은 *RFC 2045, MIME(Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*의 [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)을 참조하세요.

1. URL 쿼리 문자열에서 사용할 수 없는 문자를 유효한 문자로 교체합니다. 아래 표에 사용할 수 없는 문자와 유효한 문자가 나열되어 있습니다.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html)

1. `Set-Cookie` 뒤 `CloudFront-Policy=` 헤더의 결과 값을 포함하세요.

1. 정책 설명을 해시, 서명 및 base64로 인코딩하여 `Set-Cookie`의 `CloudFront-Signature` 헤더에 대한 서명을 만드세요. 자세한 내용은 [사용자 지정 정책을 사용하는 서명된 쿠키에 대한 서명 생성](#private-content-custom-policy-signature-cookies) 단원을 참조하세요.

### 서명된 쿠키에서 사용자 지정 정책을 위한 정책 설명에서 지정한 값
<a name="private-content-custom-policy-statement-cookies-values"></a>

사용자 지정 정책에 대한 정책 설명을 생성할 때 다음 값을 지정합니다.

**리소스**  
쿼리 문자열을 포함하는 기본 URL(있는 경우):  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
`Resource` 파라미터를 생략하는 경우, 사용자는 서명된 URL을 만들 때 사용하는 키 페어에 연결된 배포 관련 모든 파일에 액세스할 수 있습니다.
`Resource`에 대해 값을 하나만 지정할 수 있습니다.  
다음을 참조하세요.  
+ **프로토콜(Protocol)** – 값은 `http://` 또는 `https://`로 시작해야 합니다.
+ **쿼리 문자열 파라미터(Query string parameters)** – 쿼리 문자열 파라미터가 없는 경우, 물음표를 생략합니다.
+ **와일드카드(Wildcards)** – 0개 이상의 문자(\$1)에 해당하거나 문자열 내 정확히 1문자(?)에 해당하는 와일드카드를 문자열 내 모든 곳에 사용할 수 있습니다. 예를 들어 값은

  `https://d111111abcdef8.cloudfront.net/*game_download.zip*`

  다음 파일을 포함합니다.
  + `https://d111111abcdef8.cloudfront.net/game_download.zip`
  + `https://d111111abcdef8.cloudfront.net/example_game_download.zip?license=yes`
  + `https://d111111abcdef8.cloudfront.net/test_game_download.zip?license=temp`
+ **대체 도메인 이름** – URL에 대체 도메인 이름(CNAME)을 지정하는 경우, 웹 페이지 또는 애플리케이션의 파일을 참조할 때 대체 도메인 이름을 지정해야 합니다. 파일에 대한 Amazon S3 URL을 지정하지 마시기 바랍니다.

**DateLessThan**  
Unix 시간 형식(초) 및 협정 세계시(UTC) 기준의 URL 만료 날짜 및 시간. 값을 인용 부호로 묶지 마세요.  
예를 들면 2015년 3월 16일 오전 10시(UTC)를 Unix 시간 형식인 1426500000으로 변환합니다.  
자세한 내용은 [CloudFront가 서명된 쿠키의 만료 날짜 및 시간을 확인하는 시기](private-content-signed-cookies.md#private-content-check-expiration-cookie) 단원을 참조하세요.

**DateGreaterThan(선택 사항)**  
Unix 시간 형식(초)과 협정 세계시(UTC)의 URL에 대한 선택적 시작 날짜 및 시간. 사용자는 지정된 날짜 및 시간 이전에 파일에 액세스할 수 없습니다. 값을 인용 부호로 묶지 마세요.

**IpAddress(선택 사항)**  
클라이언트의 IP 주소는 GET 요청을 합니다. 다음을 참조하세요.  
+ 파일에 액세스하는 IP 주소를 허용하려면 `IpAddress` 파라미터를 생략합니다.
+ 하나의 IP 주소 또는 하나의 IP 주소 범위를 지정할 수 있습니다. 예를 들면, 클라이언트의 IP 주소가 두 개의 다른 범위 중 하나에 있는 경우, 정책을 설정하여 액세스를 허용할 수 없습니다.
+ 단일 IP 주소에서 액세스를 허용하기 위해 다음을 지정합니다.

  `"`*IPv4 IP 주소*`/32"`
+ IP 주소 범위는 스탠다드 IPv4 CIDR 형식(예: `192.0.2.0/24`)을 지정해야 합니다. 자세한 내용은 *RFC 4632, Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan*, [https://tools.ietf.org/html/rfc4632](https://tools.ietf.org/html/rfc4632)를 참조하세요.
**중요**  
IPv6 형식의 IP 주소(예: 2001:0db8:85a3::8a2e:0370:7334)는 지원되지 않습니다.

  `IpAddress`를 포함하는 사용자 지정 정책을 사용할 경우 배포에 대해 IPv6를 사용하도록 설정하지 마세요. IP 주소로 일부 콘텐츠에 대한 액세스를 제한하고, 다른 콘텐츠에 대해서는 IPv6 요청을 지원하려면 두 가지 배포를 만들면 됩니다. 자세한 내용은 [IPv6 활성화(뷰어 요청)](DownloadDistValuesGeneral.md#DownloadDistValuesEnableIPv6) 주제에서 [모든 배포 설정 참조](distribution-web-values-specify.md) 단원을 참조하세요.

## 사용자 지정 정책을 사용하는 서명된 쿠키에 대한 예제 정책 설명
<a name="private-content-custom-policy-statement-signed-cookies-examples"></a>

다음 예제 정책 설명은 특정 파일, 디렉터리의 모든 파일 또는 키 페어 ID에 연결된 모든 파일의 액세스 제어 방법을 보여줍니다. 예제는 또한 개별 IP 주소 또는 IP 주소 범위에서 액세스를 제어하는 방법과 지정된 날짜 및 시간 이후 사용자의 서명된 쿠키 사용 방지 방법을 보여줍니다.

이러한 예제를 복사하여 붙여 넣는 경우, 공백(탭과 줄바꿈 문자 포함)을 제거하고 값을 자체 값과 교체한 후 닫는 괄호(\$1)뒤에 줄바꿈 문자를 포함합니다.

자세한 내용은 [서명된 쿠키에서 사용자 지정 정책을 위한 정책 설명에서 지정한 값](#private-content-custom-policy-statement-cookies-values) 섹션을 참조하세요.

**Topics**
+ [예제 정책 설명: IP 주소 범위에서 하나의 파일에 액세스](#private-content-custom-policy-statement-signed-cookies-example-one-object)
+ [예제 정책 설명: IP 주소 범위에서 디렉터리의 모든 파일에 액세스](#private-content-custom-policy-statement-signed-cookies-example-all-objects)
+ [예제 정책 설명: 하나의 IP 주소에서 키 페어 ID에 연결된 모든 파일에 액세스](#private-content-custom-policy-statement-signed-cookies-example-one-ip)

### 예제 정책 설명: IP 주소 범위에서 하나의 파일에 액세스
<a name="private-content-custom-policy-statement-signed-cookies-example-one-object"></a>

다음 서명된 쿠키의 예제 사용자 지정 정책은 UTC 기준 2023년 1월 1일 오전 10시까지 `https://d111111abcdef8.cloudfront.net/game_download.zip` 범위의 IP 주소에서 `192.0.2.0/24` 파일에 액세스할 수 있는 사용자를 지정합니다.

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/game_download.zip",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

### 예제 정책 설명: IP 주소 범위에서 디렉터리의 모든 파일에 액세스
<a name="private-content-custom-policy-statement-signed-cookies-example-all-objects"></a>

다음 예제 사용자 지정 정책은 `training` 파라미터의 \$1 와일드카드 문자에 표시된 바와 같이 `Resource` 디렉터리의 파일에 대한 서명된 쿠키를 만들 수 있도록 허용합니다. 사용자는 UTC 기준 2013년 1월 1일 오전 10시까지 `192.0.2.0/24` 범위의 IP 주소에서 파일에 액세스할 수 있습니다.

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/training/*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

이 정책을 사용하는 서명된 쿠키는 각자 특정 파일을 식별하는 다음과 같은 기본 URL을 포함합니다.

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

### 예제 정책 설명: 하나의 IP 주소에서 키 페어 ID에 연결된 모든 파일에 액세스
<a name="private-content-custom-policy-statement-signed-cookies-example-one-ip"></a>

다음 샘플 사용자 지정 정책은 `Resource` 파라미터의 \$1 와일드카드 문자 표시된 바와 같이 배포와 연결된 파일에 대한 서명된 쿠키를 설정할 수 있도록 허용합니다. 사용자는 IP 주소 `192.0.2.10/32`를 사용해야 합니다. CIDR 표기법의 `192.0.2.10/32` 값은 단일 IP 주소 `192.0.2.10`을(를) 가리킵니다. 파일은 UTC 기준 2013년 1월 1일 오전 10시에서 2013년 1월 2일 오전 10시까지만 사용할 수 있습니다.

```
{
    "Statement": [
        {
            "Resource": "https://*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.10/32"
                },
                "DateGreaterThan": {
                    "AWS:EpochTime": 1767290400
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767376800
                }
            }
        }
    ]
}
```

이 정책을 사용하는 서명된 쿠키는 각각 특정 CloudFront 배포의 특정 파일을 식별하는 다음과 같은 기본 URL을 포함합니다.

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

또한 서명된 쿠키는 키 페어 ID를 포함하고 이는 기본 URL에서 지정한 배포(d111111abcdef8.cloudfront.net)의 신뢰할 수 있는 키 그룹과 연결되어야 합니다.

## 사용자 지정 정책을 사용하는 서명된 쿠키에 대한 서명 생성
<a name="private-content-custom-policy-signature-cookies"></a>

서명된 쿠키에 대한 서명은 정책 설명의 해시, 서명 및 base64로 인코딩된 버전의 사용자 지정 정책을 사용합니다.

다음을 참조하여 정책 설명을 해시, 서명 및 인코딩하는 방법에 대한 추가적인 내용과 예제를 확인하세요.
+ [base64 인코딩 및 암호화를 위한 Linux 명령 및 OpenSSL](private-content-linux-openssl.md)
+ [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)<a name="private-content-custom-policy-signature-cookies-procedure"></a>

**사용자 지정 정책으로 서명된 쿠키에 대한 서명을 만들려면**

1. SHA-1 해시 함수 및 RSA를 사용하여 [사용자 지정 정책을 사용하는 서명된 URL에 대한 정책 설명을 만들려면](private-content-creating-signed-url-custom-policy.md#private-content-custom-policy-creating-policy-procedure) 절차에서 만든 JSON 정책 설명을 해시하고 서명합니다. 더 이상 공백을 포함하지 않지만 base64로 인코딩되지 않은 정책 설명 버전을 사용합니다.

   해시 함수에 필요한 프라이빗 키의 경우 배포에 대해 신뢰할 수 있는 활성 키 그룹에 퍼블릭 키가 있는 프라이빗 키를 사용합니다.
**참고**  
정책 설명을 해시 및 서명하는 방법은 프로그래밍 언어와 플랫폼에 따라 달라집니다. 샘플 코드에 대한 내용은 [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)를 참조하세요.

1. 해시 및 서명된 문자열에서 공백(탭과 줄바꿈 문자 포함)을 제거합니다.

1. MIME base64 인코딩 기준으로 문자열을 base64로 인코딩합니다. 자세한 내용은 *RFC 2045, MIME(Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*의 [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8)을 참조하세요.

1. URL 쿼리 문자열에서 사용할 수 없는 문자를 유효한 문자로 교체합니다. 아래 표에 사용할 수 없는 문자와 유효한 문자가 나열되어 있습니다.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html)

1. `Set-Cookie` 이름-값 페어에 대한 `CloudFront-Signature=` 헤더의 결과 값을 포함하고 [사용자 지정 정책을 사용하여 서명된 쿠키를 설정하려면](#private-content-setting-signed-cookie-custom-policy-procedure)으로 돌아가서 `Set-Cookie`에 대한 `CloudFront-Key-Pair-Id` 헤더를 추가하세요.

# PHP를 사용하여 서명된 쿠키 생성
<a name="signed-cookies-PHP"></a>

다음 코드 예제는 동영상에 대한 링크를 만드는 [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md)의 예제와 유사합니다. 그러나 이 예제에서는 코드의 URL에 서명하는 대신 `create_signed_cookies()` 함수를 사용하여 쿠키에 서명합니다. 클라이언트 측 플레이어는 쿠키를 사용하여 CloudFront 배포에 대한 각 요청을 인증합니다.

이 접근 방식은 클라이언트가 매니페스트, 세그먼트 및 관련 재생 자산을 검색하기 위해 여러 요청을 해야 하는 HLS(HTTP Live Streaming) 또는 DASH(Dynamic Adaptive Streaming over HTTP)와 같은 콘텐츠를 스트리밍하는 데 유용합니다. 클라이언트는 서명된 쿠키를 사용하여 각 세그먼트에 대해 서명된 새 URL을 만들 필요 없이 각 요청을 인증할 수 있습니다.

**참고**  
URL 서명을 만드는 것은 서명된 쿠키를 사용해 프라이빗 콘텐츠를 제공하는 프로세스의 한 부분에 불과합니다. 자세한 내용은 [서명된 쿠키 사용](private-content-signed-cookies.md) 섹션을 참조하세요.



**Topics**
+ [RSA SHA-1 서명 생성](#create-rsa-sha-1signature-cookies)
+ [서명된 쿠키 생성](#create-the-signed-cookie)
+ [전체 코드](#full-code-signed-cookies)

다음 섹션에서는 코드 예제를 각 부분으로 나눕니다. 아래에서 전체 [코드 샘플](#full-code-signed-cookies)을 확인할 수 있습니다.

## RSA SHA-1 서명 생성
<a name="create-rsa-sha-1signature-cookies"></a>

이 코드 예제에서는 다음을 수행합니다.

1. `rsa_sha1_sign` 함수는 정책 문을 해시하고 서명합니다. 필요한 인수는 배포의 신뢰할 수 있는 키 그룹에 있는 퍼블릭 키에 해당하는 프라이빗 키와 정책 설명입니다.

1. 다음으로 `url_safe_base64_encode` 함수는 서명의 안전한 URL 버전을 만듭니다.

   ```
   function rsa_sha1_sign($policy, $private_key_filename) {
       $signature = "";
       $fp = fopen($private_key_filename, "r");
       $priv_key = fread($fp, 8192);
       fclose($fp);
       $pkeyid = openssl_get_privatekey($priv_key);
       openssl_sign($policy, $signature, $pkeyid);
       openssl_free_key($pkeyid);
       return $signature;
   }
   
   function url_safe_base64_encode($value) {
       $encoded = base64_encode($value);
       return str_replace(
           array('+', '=', '/'),
           array('-', '_', '~'),
           $encoded);
   }
   ```

## 서명된 쿠키 생성
<a name="create-the-signed-cookie"></a>

다음 코드는 다음 쿠키 속성(예: `CloudFront-Expires`, `CloudFront-Signature`, `CloudFront-Key-Pair-Id`)을 사용하여 서명된 쿠키를 만듭니다. 코드는 사용자 지정 정책을 사용합니다.

```
function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null) {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    $encoded_signature = url_safe_base64_encode($signature);

    return array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );
}
```

자세한 내용은 [사용자 지정 정책을 사용하여 서명된 쿠키 설정](private-content-setting-signed-cookie-custom-policy.md) 섹션을 참조하세요.

## 전체 코드
<a name="full-code-signed-cookies"></a>

다음 예제 코드는 PHP로 CloudFront 서명 쿠키를 만드는 전체 데모를 제공합니다. [demo-php.zip](samples/demo-php.zip) 파일에서 전체 예제를 다운로드할 수 있습니다.

다음 예제에서는 IPv4 및 IPv6 주소 범위를 모두 허용하도록 `$policy Condition` 요소를 수정할 수 있습니다. 예제는 Amazon Simple Storage Service 사용 설명서의 [IAM 정책에서 IPv6 주소 사용](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ipv6-access.html#ipv6-access-iam)을 참조합니다.**

```
<?php

function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);
    openssl_sign($policy, $signature, $pkeyid);
    openssl_free_key($pkeyid);
    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}

function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null) {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    $encoded_signature = url_safe_base64_encode($signature);

    return array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );
}



$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';
$base_url = 'https://d1234.cloudfront.net';

$expires = time() + 3600; // 1 hour from now

// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];


// For HLS manifest and segments (using wildcard)
$hls_resource = $base_url . '/sign/*';
$signed_cookies = create_signed_cookies($hls_resource, $private_key_filename, $key_pair_id, $expires, $client_ip);

// Set the cookies
$cookie_domain = parse_url($base_url, PHP_URL_HOST);
foreach ($signed_cookies as $name => $value) {
    setcookie($name, $value, $expires, '/', $cookie_domain, true, true);
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>CloudFront Signed HLS Stream with Cookies</title>
</head>
<body>
    <h1>Amazon CloudFront Signed HLS Stream with Cookies</h1>
    <h2>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h2>
    
    <div id='hls-video'>
        <video id="video" width="640" height="360" controls></video>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <script>
        var video = document.getElementById('video');
        var manifestUrl = '<?php echo $base_url; ?>/sign/manifest.m3u8';
        
        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(manifestUrl);
            hls.attachMedia(video);
        }
        else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = manifestUrl;
        }
    </script>
</body>
</html>
```

서명된 쿠키를 사용하는 대신 서명된 URL을 사용할 수 있습니다. 자세한 내용은 [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md) 섹션을 참조하세요.

# base64 인코딩 및 암호화를 위한 Linux 명령 및 OpenSSL
<a name="private-content-linux-openssl"></a>

다음 Linux 명령줄 명령과 OpenSSL을 사용하여 정책 설명을 해시 및 서명한 후, 서명을 base64로 인코딩하여 URL 쿼리 문자열 파라미터에서 사용할 수 없는 문자를 유효한 문자와 교체하세요.

OpenSSL에 대한 자세한 내용은 를 참조하세요[https://www.openssl.org](https://www.openssl.org)

```
cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha1 -sign private_key.pem | openssl base64 -A | tr -- '+=/' '-_~'
```

앞의 명령에서:
+ `cat` 은 `policy` 파일을 읽습니다.
+ `tr -d "\n" | tr -d " \t\n\r"`은 `cat`에 의해 추가된 공백과 줄 바꿈 문자를 제거합니다.
+ OpenSSL은 SHA-1을 사용하여 파일을 해시하고 프라이빗 키 파일 `private_key.pem`을 사용하여 서명합니다. 프라이빗 키 서명은 RSA 2048 또는 ECDSA 256일 수 있습니다.
+ OpenSSL은 해시, 서명된 정책 문을 base64로 인코딩합니다.
+ `tr` 은 URL 쿼리 문자열 파라미터에 사용할 수 없는 문자를 유효한 문자로 교체합니다.

서명을 만드는 방법을 보여주는 코드 예시는 [서명 URL에 대한 서명을 만드는 코드 예제](PrivateCFSignatureCodeAndExamples.md)을 참조하세요.

# 서명 URL에 대한 서명을 만드는 코드 예제
<a name="PrivateCFSignatureCodeAndExamples"></a>

이 단원에는 서명된 URL에 대한 서명을 만드는 방법을 담은 애플리케이션 예제가 수록되어 있으며 이를 다운로드할 수 있습니다. 예제는 Perl, PHP, C\$1, Java로 제공됩니다. 이러한 예제를 사용하여 서명된 URL을 만들 수 있습니다. Perl 스크립트는 Linux 및 masOS 플랫폼에서 실행됩니다. PHP 예제는 PHP를 실행하는 모든 서버에서 작동합니다. C\$1 예제는 NET Framework를 사용합니다.

JavaScript(Node.js)의 예제 코드는 AWS 개발자 블로그의 [Node.js에서 Amazon CloudFront 서명 URL 생성](https://aws.amazon.com/blogs/developer/creating-amazon-cloudfront-signed-urls-in-node-js/)을 참조하세요.

Python의 예제 코드는 *AWS SDK for Python(Boto3) API 참조*의 [Amazon CloudFront에 대한 서명된 URL 생성](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#examples)과 Boto3 GitHub 리포지토리의 [이 예제 코드](https://github.com/boto/boto3/blob/develop/boto3/examples/cloudfront.rst)를 참조하세요.

**Topics**
+ [Perl을 사용한 URL 서명 생성](CreateURLPerl.md)
+ [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md)
+ [C\$1 및 .NET Framework를 사용한 URL 서명 생성](CreateSignatureInCSharp.md)
+ [Java를 사용한 URL 서명 생성](CFPrivateDistJavaDevelopment.md)

# Perl을 사용한 URL 서명 생성
<a name="CreateURLPerl"></a>

이 단원에는 프라이빗 콘텐츠에 대한 서명을 생성하는 데 사용할 수 있는 Linux/Mac 플랫폼용 Perl 스크립트가 포함되어 있습니다. 서명을 생성하려면, CloudFront URL, 서명자의 프라이빗 키 경로, 키 ID와 URL에 대한 만료 날짜를 지정하는 명령줄 인수를 포함한 스크립트를 실행합니다. 또한 이 도구는 서명된 URL을 디코딩할 수 있습니다.

**참고**  
URL 서명 생성은 서명된 URL을 통해 프라이빗 콘텐츠를 제공하는 프로세스의 한 부분에 불과합니다. 종단 간 프로세스에 대한 자세한 내용은 [서명된 URL 사용](private-content-signed-urls.md) 단원을 참조합니다.

**Topics**
+ [서명된 URL을 생성하기 위한 Perl 스크립트의 소스](#CreateURLPerlScriptSource)

## 서명된 URL을 생성하기 위한 Perl 스크립트의 소스
<a name="CreateURLPerlScriptSource"></a>

서명된 CloudFront URL을 만들기 위해 다음과 같은 Perl 소스 코드를 사용할 수 있습니다. 이 코드의 명령에는 명령줄 전환 및 이 도구의 기능에 대한 자세한 내용이 포함되어 있습니다.

```
#!/usr/bin/perl -w

# Copyright 2008 Amazon Technologies, Inc.  Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy of the License at:
#
# https://aws.amazon.com/apache2.0
#
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.

=head1 cfsign.pl

cfsign.pl - A tool to generate and verify Amazon CloudFront signed URLs

=head1 SYNOPSIS

This script uses an existing RSA key pair to sign and verify Amazon CloudFront signed URLs

View the script source for details as to which CPAN packages are required beforehand. 

For help, try:

cfsign.pl --help

URL signing examples:

cfsign.pl --action encode --url https://images.my-website.com/gallery1.zip --policy sample_policy.json --private-key privkey.pem --key-pair-id mykey

cfsign.pl --action encode --url https://images.my-website.com/gallery1.zip --expires 1257439868 --private-key privkey.pem --key-pair-id mykey

URL decode example:

cfsign.pl --action decode --url "http//mydist.cloudfront.net/?Signature=AGO-PgxkYo99MkJFHvjfGXjG1QDEXeaDb4Qtzmy85wqyJjK7eKojQWa4BCRcow__&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovLypicmFkbS5qcGciLCJDb25kaXRpb24iOnsiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI6IjEwLjUyLjE3LjkvMCJ9LCJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTI1MjUyMDgzMH19fV19Cg__&Key-Pair-Id=mykey"


To generate an RSA key pair, you can use openssl and the following commands:

# Generate a 2048 bit key pair
openssl genrsa -out private-key.pem 2048
openssl rsa -in private-key.pem -pubout -out public-key.pem


=head1 OPTIONS

=over 8

=item B<--help>

Print a help message and exits.

=item B<--action> [action]

The action to execute.  action can be one of:

  encode - Generate a signed URL (using a canned policy or a user policy)
  decode - Decode a signed URL

=item B<--url>

The URL to en/decode

=item B<--stream>

The stream to en/decode

=item B<--private-key>

The path to your private key.

=item B<--key-pair-id>

The key pair identifier.

=item B<--policy>

The CloudFront policy document.

=item B<--expires>

The Unix epoch time when the URL is to expire. If both this option and
the --policy option are specified, --policy will be used. Otherwise, this 
option alone will use a canned policy.

=back

=cut

use strict;
use warnings;

# you might need to use CPAN to get these modules.
# run perl -MCPAN -e "install <module>" to get them.
# The openssl command line will also need to be in your $PATH.
use File::Temp qw/tempfile/;
use File::Slurp;
use Getopt::Long;
use IPC::Open2;
use MIME::Base64 qw(encode_base64 decode_base64);
use Pod::Usage;
use URI;

my $CANNED_POLICY 
    = '{"Statement":[{"Resource":"<RESOURCE>","Condition":{"DateLessThan":{"AWS:EpochTime":<EXPIRES>}}}]}';

my $POLICY_PARAM      = "Policy";
my $EXPIRES_PARAM     = "Expires";
my $SIGNATURE_PARAM   = "Signature";
my $KEY_PAIR_ID_PARAM = "Key-Pair-Id";

my $verbose = 0;
my $policy_filename = "";
my $expires_epoch = 0;
my $action = "";
my $help = 0;
my $key_pair_id = "";
my $url = "";
my $stream = "";
my $private_key_filename = "";

my $result = GetOptions("action=s"      => \$action,
                        "policy=s"      => \$policy_filename,
                        "expires=i"     => \$expires_epoch,
                        "private-key=s" => \$private_key_filename,
                        "key-pair-id=s" => \$key_pair_id,
                        "verbose"       => \$verbose,
                        "help"          => \$help,
                        "url=s"         => \$url,
                        "stream=s"      => \$stream,
                    );

if ($help or !$result) {
    pod2usage(1);
    exit;
}

if ($url eq "" and $stream eq "") {
    print STDERR "Must include a stream or a URL to encode or decode with the --stream or --url option\n";
    exit;
}

if ($url ne "" and $stream ne "") {
    print STDERR "Only one of --url and --stream may be specified\n";
    exit;
}

if ($url ne "" and !is_url_valid($url)) {
    exit;
}

if ($stream ne "") {
    exit unless is_stream_valid($stream);

    # The signing mechanism is identical, so from here on just pretend we're
    # dealing with a URL
    $url = $stream;
} 

if ($action eq "encode") {
    # The encode action will generate a private content URL given a base URL, 
    # a policy file (or an expires timestamp) and a key pair id parameter
    my $private_key;
    my $public_key;
    my $public_key_file;
    
    my $policy;
    if ($policy_filename eq "") {
        if ($expires_epoch == 0) {
            print STDERR "Must include policy filename with --policy argument or an expires" . 
                          "time using --expires\n";            
        }
        
        $policy = $CANNED_POLICY;
        $policy =~ s/<EXPIRES>/$expires_epoch/g;
        $policy =~ s/<RESOURCE>/$url/g;
    } else {
        if (! -e $policy_filename) {
            print STDERR "Policy file $policy_filename does not exist\n";
            exit;
        }
        $expires_epoch = 0; # ignore if set
        $policy = read_file($policy_filename);
    }

    if ($private_key_filename eq "") {
        print STDERR "You must specific the path to your private key file with --private-key\n";
        exit;
    }

    if (! -e $private_key_filename) {
        print STDERR "Private key file $private_key_filename does not exist\n";
        exit;
    }

    if ($key_pair_id eq "") {
        print STDERR "You must specify a key pair id with --key-pair-id\n";
        exit;
    }

    my $encoded_policy = url_safe_base64_encode($policy);
    my $signature = rsa_sha1_sign($policy, $private_key_filename);
    my $encoded_signature = url_safe_base64_encode($signature);

    my $generated_url = create_url($url, $encoded_policy, $encoded_signature, $key_pair_id, $expires_epoch);


    if ($stream ne "") {
        print "Encoded stream (for use within a swf):\n" . $generated_url . "\n";
        print "Encoded and escaped stream (for use on a webpage):\n" .  escape_url_for_webpage($generated_url) . "\n"; 
    } else {
        print "Encoded URL:\n" . $generated_url . "\n";
    }
} elsif ($action eq "decode") {
    my $decoded = decode_url($url);
    if (!$decoded) {
        print STDERR "Improperly formed URL\n";
        exit;
    }

    print_decoded_url($decoded);
} else {
    # No action specified, print help.  But only if this is run as a program (caller will be empty)
    pod2usage(1) unless caller();
}

# Decode a private content URL into its component parts
sub decode_url {
    my $url = shift;

    if ($url =~ /(.*)\?(.*)/) {
        my $base_url = $1;
        my $params = $2;

        my @unparsed_params = split(/&/, $params);
        my %params = ();
        foreach my $param (@unparsed_params) {
            my ($key, $val) = split(/=/, $param);
            $params{$key} = $val;
        }

        my $encoded_signature = "";
        if (exists $params{$SIGNATURE_PARAM}) {
            $encoded_signature = $params{"Signature"};
        } else {
            print STDERR "Missing Signature URL parameter\n";
            return 0;
        }

        my $encoded_policy = "";
        if (exists $params{$POLICY_PARAM}) {
            $encoded_policy = $params{$POLICY_PARAM};
        } else {
            if (!exists $params{$EXPIRES_PARAM}) {
                print STDERR "Either the Policy or Expires URL parameter needs to be specified\n";
                return 0;    
            }
            
            my $expires = $params{$EXPIRES_PARAM};
            
            my $policy = $CANNED_POLICY;
            $policy =~ s/<EXPIRES>/$expires/g;
            
            my $url_without_cf_params = $url;
            $url_without_cf_params =~ s/$SIGNATURE_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$POLICY_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$EXPIRES_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$KEY_PAIR_ID_PARAM=[^&]*&?//g;
            
            if ($url_without_cf_params =~ /(.*)\?$/) {
                $url_without_cf_params = $1;
            }
            
            $policy =~ s/<RESOURCE>/$url_without_cf_params/g;
            
            $encoded_policy = url_safe_base64_encode($policy);
        }

        my $key = "";
        if (exists $params{$KEY_PAIR_ID_PARAM}) {
            $key = $params{$KEY_PAIR_ID_PARAM};
        } else {
            print STDERR "Missing $KEY_PAIR_ID_PARAM parameter\n";
            return 0;
        }

        my $policy = url_safe_base64_decode($encoded_policy);

        my %ret = ();
        $ret{"base_url"} = $base_url;
        $ret{"policy"} = $policy;
        $ret{"key"} = $key;

        return \%ret;
    } else {
        return 0;
    }
}

# Print a decoded URL out
sub print_decoded_url {
    my $decoded = shift;

    print "Base URL: \n" . $decoded->{"base_url"} . "\n";
    print "Policy: \n" . $decoded->{"policy"} . "\n";
    print "Key: \n" . $decoded->{"key"} . "\n";
}

# Encode a string with base 64 encoding and replace some invalid URL characters
sub url_safe_base64_encode {
    my ($value) = @_;

    my $result = encode_base64($value);
    $result =~ tr|+=/|-_~|;

    return $result;
}

# Decode a string with base 64 encoding.  URL-decode the string first
# followed by reversing any special character ("+=/") translation.
sub url_safe_base64_decode {
    my ($value) = @_;

    $value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
    $value =~ tr|-_~|+=/|;

    my $result = decode_base64($value);

    return $result;
}

# Create a private content URL
sub create_url {
    my ($path, $policy, $signature, $key_pair_id, $expires) = @_;
    
    my $result;
    my $separator = $path =~ /\?/ ? '&' : '?';
    if ($expires) {
        $result = "$path$separator$EXPIRES_PARAM=$expires&$SIGNATURE_PARAM=$signature&$KEY_PAIR_ID_PARAM=$key_pair_id";
    } else {
        $result = "$path$separator$POLICY_PARAM=$policy&$SIGNATURE_PARAM=$signature&$KEY_PAIR_ID_PARAM=$key_pair_id";
    }
    $result =~ s/\n//g;

    return $result;
}

# Sign a document with given private key file.
# The first argument is the document to sign
# The second argument is the name of the private key file
sub rsa_sha1_sign {
    my ($to_sign, $pvkFile) = @_;
    print "openssl sha1 -sign $pvkFile $to_sign\n";

    return write_to_program($pvkFile, $to_sign);
}

# Helper function to write data to a program
sub write_to_program {
my ($keyfile, $data) = @_;
unlink "temp_policy.dat" if (-e "temp_policy.dat");
unlink "temp_sign.dat" if (-e "temp_sign.dat");

write_file("temp_policy.dat", $data);

system("openssl dgst -sha1 -sign \"$keyfile\" -out temp_sign.dat temp_policy.dat");

my $output = read_file("temp_sign.dat");

    return $output;
}

# Read a file into a string and return the string
sub read_file {
    my ($file) = @_;

    open(INFILE, "<$file") or die("Failed to open $file: $!");
    my $str = join('', <INFILE>);
    close INFILE;

    return $str;
}

sub is_url_valid {
    my ($url) = @_;

    # HTTP distributions start with http[s]:// and are the correct thing to sign
    if ($url =~ /^https?:\/\//) {
        return 1;
    } else {
        print STDERR "CloudFront requires absolute URLs for HTTP distributions\n";
        return 0;
    }
}

sub is_stream_valid {
    my ($stream) = @_;

    if ($stream =~ /^rtmp:\/\// or $stream =~ /^\/?cfx\/st/) {
        print STDERR "Streaming distributions require that only the stream name is signed.\n";
        print STDERR "The stream name is everything after, but not including, cfx/st/\n";
        return 0;
    } else {
        return 1;
    }
}

# flash requires that the query parameters in the stream name are url
# encoded when passed in through javascript, etc.  This sub handles the minimal
# required url encoding.
sub escape_url_for_webpage {
    my ($url) = @_;

    $url =~ s/\?/%3F/g;
    $url =~ s/=/%3D/g;
    $url =~ s/&/%26/g;

    return $url;
}

1;
```

# PHP를 사용한 URL 서명 생성
<a name="CreateURL_PHP"></a>

PHP를 실행하는 모든 웹 서버는 이 PHP 예제 코드를 사용하여 프라이빗 CloudFront 배포에 대한 정책 설명 및 서명을 만듭니다. 예제 전체에서는 CloudFront 스트리밍을 사용하여 비디오 스트림을 재생하는 서명된 URL 링크가 있는 정상 웹 페이지를 만듭니다. [demo-php.zip](samples/demo-php.zip) 파일에서 전체 예제를 다운로드할 수 있습니다.

**참고**  
URL 서명 생성은 서명된 URL을 통해 프라이빗 콘텐츠를 제공하는 프로세스의 한 부분에 불과합니다. 전체 프로세스에 대한 자세한 내용은 [서명된 URL 사용](private-content-signed-urls.md)을 참조합니다.
AWS SDK for PHP에서 `UrlSigner` 클래스를 사용하여 서명된 URL을 생성할 수도 있습니다. 자세한 내용은 *AWS SDK for PHP API 참조*의 [Class UrlSigner](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.CloudFront.UrlSigner.html)를 참조하세요.

**Topics**
+ [RSA SHA-1 서명 생성](#sample-rsa-sign)
+ [준비된 정책 생성](#sample-canned-policy)
+ [사용자 지정 정책 생성](#sample-custom-policy)
+ [전체 코드 예제](#full-example)

다음 섹션에서는 코드 예제를 각 부분으로 나눕니다. 아래 [전체 코드 예제](#full-example)에서 확인할 수 있습니다.

## RSA SHA-1 서명 생성
<a name="sample-rsa-sign"></a>

이 코드 예제에서는 다음을 수행합니다.
+ `rsa_sha1_sign` 함수는 정책 문을 해시하고 서명합니다. 필요한 인수는 배포의 신뢰할 수 있는 키 그룹에 있는 퍼블릭 키에 해당하는 프라이빗 키와 정책 설명입니다.
+ 다음으로 `url_safe_base64_encode` 함수는 서명의 안전한 URL 버전을 만듭니다.

```
function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";

    // load the private key
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);

    // compute signature
    openssl_sign($policy, $signature, $pkeyid);

    // free the key from memory
    openssl_free_key($pkeyid);

    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    // replace unsafe characters +, = and / with 
    // the safe characters -, _ and ~
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}
```

다음 코드 조각은 `get_canned_policy_stream_name()` 함수 및 `get_custom_policy_stream_name()`을 사용하여 준비된 사용자 지정 정책을 만듭니다. CloudFront는 정책을 사용하여 만료 시간 지정을 비롯해 동영상 스트리밍용 URL을 만듭니다.

그런 다음 준비된 정책 또는 사용자 지정 정책을 사용하여 콘텐츠에 대한 액세스를 관리하는 방법을 결정할 수 있습니다. 선택할 항목에 대한 자세한 내용은 [서명된 URL에 대해 미리 준비된 정책 또는 사용자 지정 정책 사용 결정](private-content-signed-urls.md#private-content-choosing-canned-custom-policy) 섹션을 참조하시기 바랍니다.

## 준비된 정책 생성
<a name="sample-canned-policy"></a>

다음 예제 코드는 서명에 대한 *미리 준비된* 정책 설명을 구성합니다.

**참고**  
`$expires` 변수는 문자열이 아닌 정수여야 하는 날짜/타임 스탬프입니다.

```
function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
    // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
    $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($canned_policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($canned_policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
    // URL-encode the query string characters
    return $stream_name;
}
```

미리 준비된 정책에 대한 자세한 내용은 [미리 준비된 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-canned-policy.md)을 참조하세요.

## 사용자 지정 정책 생성
<a name="sample-custom-policy"></a>

다음 예제 코드는 서명에 대한 *사용자 지정* 정책 설명을 구성합니다.

```
function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
    // URL-encode the query string characters
    return $stream_name;
}
```

사용자 지정 정책에 대한 내용은 [사용자 지정 정책을 사용하여 서명된 URL 생성](private-content-creating-signed-url-custom-policy.md)을 참조하세요.

## 전체 코드 예제
<a name="full-example"></a>

다음 예제 코드는 PHP로 CloudFront 서명 URL을 만드는 전체 예제를 제공합니다. [demo-php.zip](samples/demo-php.zip) 파일에서 전체 예제를 다운로드할 수 있습니다.

다음 예제에서는 IPv4 및 IPv6 주소 범위를 모두 허용하도록 `$policy` `Condition` 요소를 수정할 수 있습니다. 예제는 Amazon Simple Storage Service 사용 설명서의 [IAM 정책에서 IPv6 주소 사용](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ipv6-access.html#ipv6-access-iam)을 참조합니다.**

```
<?php

function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";

    // load the private key
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);

    // compute signature
    openssl_sign($policy, $signature, $pkeyid);

    // free the key from memory
    openssl_free_key($pkeyid);

    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    // replace unsafe characters +, = and / with the safe characters -, _ and ~
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}

function create_stream_name($stream, $policy, $signature, $key_pair_id, $expires) {
    $result = $stream;
    // if the stream already contains query parameters, attach the new query parameters to the end
    // otherwise, add the query parameters
    $separator = strpos($stream, '?') == FALSE ? '?' : '&';
    // the presence of an expires time means we're using a canned policy
    if($expires) {
        $result .= $separator . "Expires=" . $expires . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
    }
    // not using a canned policy, include the policy itself in the stream name
    else {
        $result .= $separator . "Policy=" . $policy . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
    }

    // new lines would break us, so remove them
    return str_replace('\n', '', $result);
}


function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
    // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
    $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($canned_policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($canned_policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
    // URL-encode the query string characters
    return $stream_name;
}

function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
    // URL-encode the query string characters
    return $stream_name;
}


// Path to your private key.  Be very careful that this file is not accessible
// from the web!

$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';

// Make sure you have "Restrict viewer access" enabled on this path behaviour and using the above Trusted key groups (recommended).
$video_path = 'https://example.com/secure/example.mp4';

$expires = time() + 300; // 5 min from now
$canned_policy_stream_name = get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires);

// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$policy =
'{'.
    '"Statement":['.
        '{'.
            '"Resource":"'. $video_path . '",'.
            '"Condition":{'.
                '"IpAddress":{"AWS:SourceIp":"' . $client_ip . '/32"},'.
                '"DateLessThan":{"AWS:EpochTime":' . $expires . '}'.
            '}'.
        '}'.
    ']' .
    '}';
$custom_policy_stream_name = get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy);

?>

<html>

<head>
    <title>CloudFront</title>
</head>

<body>
    <h1>Amazon CloudFront</h1>
    <h2>Canned Policy</h2>
    <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?></h3>
    <br />

    <div id='canned'>The canned policy video will be here: <br>
    
        <video width="640" height="360" autoplay muted controls>
        <source src="<?php echo $canned_policy_stream_name; ?>" type="video/mp4">
        Your browser does not support the video tag.
        </video>
    </div>

    <h2>Custom Policy</h2>
    <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h3>
    <div id='custom'>The custom policy video will be here: <br>

         <video width="640" height="360" autoplay muted controls>
         <source src="<?php echo $custom_policy_stream_name; ?>" type="video/mp4">
         Your browser does not support the video tag.
        </video>
    </div> 

</body>

</html>
```

추가 URL 서명 예제를 알아보려면 다음 주제를 참조하시기 바랍니다.
+ [Perl을 사용한 URL 서명 생성](CreateURLPerl.md)
+ [C\$1 및 .NET Framework를 사용한 URL 서명 생성](CreateSignatureInCSharp.md)
+ [Java를 사용한 URL 서명 생성](CFPrivateDistJavaDevelopment.md)

서명된 URL을 사용하여 서명을 만드는 대신 서명된 쿠키를 사용할 수 있습니다. 자세한 내용은 [PHP를 사용하여 서명된 쿠키 생성](signed-cookies-PHP.md) 섹션을 참조하세요.

# C\$1 및 .NET Framework를 사용한 URL 서명 생성
<a name="CreateSignatureInCSharp"></a>

이 섹션의 C\$1 예제는 사용자 지정 및 미리 준비된 정책 설명을 사용하여 CloudFront 프라이빗 배포에 대한 서명을 만드는 방법을 보여주는 예제 애플리케이션을 구현합니다. 이 예제는 .NET 애플리케이션에서 유용할 수 있는 [AWS SDK for .NET](https://aws.amazon.com/sdkfornet)를 기반으로 한 유틸리티 함수를 포함합니다.

SDK for .NET를 사용하여 서명된 URL과 서명된 쿠키를 생성할 수도 있습니다. *SDK for .NET API 참조*에서 다음 주제를 참조하세요.
+ **서명된 URL** – [AmazonCloudFrontUrlSigner](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFront/TCloudFrontUrlSigner.html) 
+ **서명된 쿠키** – [AmazonCloudFrontCookieSigner](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFront/TCloudFrontCookieSigner.html) 

코드를 다운로드하려면 [C\$1의 서명 코드](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip)를 참조하세요.

**참고**  
`AmazonCloudFrontUrlSigner` 및 `AmazonCloudFrontCookieSigner` 클래스가 별도의 패키지로 이전되었습니다. 해당 클래스 사용에 대한 자세한 내용은 *AWS SDK for .NET(V4) 개발자 안내서*의 [CookieSigner and UrlSigner](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html#net-dg-v4-CookieSigner-UrlSigner)를 참조하시기 바랍니다.
URL 서명 생성은 서명된 URL을 통해 프라이빗 콘텐츠를 제공하는 프로세스의 한 부분에 불과합니다. 자세한 내용은 [서명된 URL 사용](private-content-signed-urls.md) 섹션을 참조하세요. 서명된 쿠키 사용에 대한 자세한 내용은 [서명된 쿠키 사용](private-content-signed-cookies.md) 섹션을 참조하세요.

## .NET Framework에서 RSA 키 사용
<a name="rsa-key-sdk-net"></a>

.NET Framework에서 RSA 키를 사용하려면 AWS가 제공한 .pem 파일을 .NET Framework에서 사용하는 XML 형식으로 변환해야 합니다.

변환 후, RSA 프라이빗 키 파일의 형식은 다음과 같습니다.

**Example : XML .NET Framework 형식의 RSA 프라이빗 키**  <a name="RSAPrivateKeyXML.NETFrameworkFormat"></a>

```
<RSAKeyValue>
  <Modulus>
    wO5IvYCP5UcoCKDo1dcspoMehWBZcyfs9QEzGi6Oe5y+ewGr1oW+vB2GPB
    ANBiVPcUHTFWhwaIBd3oglmF0lGQljP/jOfmXHUK2kUUnLnJp+oOBL2NiuFtqcW6h/L5lIpD8Yq+NRHg
    Ty4zDsyr2880MvXv88yEFURCkqEXAMPLE=
  </Modulus>
  <Exponent>AQAB</Exponent>
  <P>
    5bmKDaTz
    npENGVqz4Cea8XPH+sxt+2VaAwYnsarVUoSBeVt8WLloVuZGG9IZYmH5KteXEu7fZveYd9UEXAMPLE==
  </P>
  <Q>
    1v9l/WN1a1N3rOK4VGoCokx7kR2SyTMSbZgF9IWJNOugR/WZw7HTnjipO3c9dy1Ms9pUKwUF4
    6d7049EXAMPLE==
  </Q>
  <DP>
    RgrSKuLWXMyBH+/l1Dx/I4tXuAJIrlPyo+VmiOc7b5NzHptkSHEPfR9s1
    OK0VqjknclqCJ3Ig86OMEtEXAMPLE==
  </DP>
  <DQ>
    pjPjvSFw+RoaTu0pgCA/jwW/FGyfN6iim1RFbkT4
    z49DZb2IM885f3vf35eLTaEYRYUHQgZtChNEV0TEXAMPLE==
  </DQ>
  <InverseQ>
    nkvOJTg5QtGNgWb9i
    cVtzrL/1pFEOHbJXwEJdU99N+7sMK+1066DL/HSBUCD63qD4USpnf0myc24in0EXAMPLE==</InverseQ>
  <D>
      Bc7mp7XYHynuPZxChjWNJZIq+A73gm0ASDv6At7F8Vi9r0xUlQe/v0AQS3ycN8QlyR4XMbzMLYk
      3yjxFDXo4ZKQtOGzLGteCU2srANiLv26/imXA8FVidZftTAtLviWQZBVPTeYIA69ATUYPEq0a5u5wjGy
      UOij9OWyuEXAMPLE=
   </D>
</RSAKeyValue>
```

## C\$1의 미리 준비된 정책 서명 메서드
<a name="canned-policy-signed-url-net"></a>

다음 C\$1 코드는 다음을 수행하여 미리 준비된 정책을 사용하는 서명된 URL을 만듭니다.
+ 정책 설명을 만듭니다.
+ SHA1을 사용하여 정책 설명을 해시하고, RSA와 해당 퍼블릭 키가 신뢰할 수 있는 키 그룹에 있는 프라이빗 키를 사용하여 결과에 서명합니다.
+ Base64 방식으로 해시 및 서명된 정책 설명을 인코딩하고 특수 문자를 교체하여 URL 요청 파라미터로 사용하기에 안전한 문자열을 만드세요.
+ 값을 연결합니다.

완전한 구현에 대한 내용은 [C\$1의 서명 코드](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip)에서 예제를 참조하세요.

**참고**  
CloudFront에 퍼블릭 키를 업로드하면 `keyId`가 반환됩니다. 자세한 내용은 ![\[6\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/callouts/6.png)[ &Key-Pair-Id](private-content-creating-signed-url-canned-policy.md)를 참조하세요.

**Example : C\$1의 미리 준비된 정책 서명 메서드**  <a name="ExampleCannedPolicySigningMethod-CSharp"></a>

```
public static string ToUrlSafeBase64String(byte[] bytes)
{
    return System.Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('=', '_')
        .Replace('/', '~');
}

public static string CreateCannedPrivateURL(string urlString, 
    string durationUnits, string durationNumber, string pathToPolicyStmnt, 
    string pathToPrivateKey, string keyId)
{
    // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days 
    // to expiration, 3-numberOfPreviousUnits, 4-pathToPolicyStmnt, 
    // 5-pathToPrivateKey, 6-keyId

    TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber);

    // Create the policy statement.
    string strPolicy = CreatePolicyStatement(pathToPolicyStmnt,
        urlString, 
        DateTime.Now, 
        DateTime.Now.Add(timeSpanInterval), 
        "0.0.0.0/0");
    if ("Error!" == strPolicy) return "Invalid time frame." + 
        "Start time cannot be greater than end time.";

    // Copy the expiration time defined by policy statement.
    string strExpiration = CopyExpirationTimeFromPolicy(strPolicy);

    // Read the policy into a byte buffer.
    byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy);

    // Initialize the SHA1CryptoServiceProvider object and hash the policy data.
    using (SHA1CryptoServiceProvider 
        cryptoSHA1 = new SHA1CryptoServiceProvider())
    {
        bufferPolicy = cryptoSHA1.ComputeHash(bufferPolicy);

        // Initialize the RSACryptoServiceProvider object.
        RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider();
        XmlDocument xmlPrivateKey = new XmlDocument();

        // Load your private key, which you created by converting your 
        // .pem file to the XML format that the .NET framework uses.  
        // Several tools are available. 
        xmlPrivateKey.Load(pathToPrivateKey);

        // Format the RSACryptoServiceProvider providerRSA and 
        // create the signature.
        providerRSA.FromXmlString(xmlPrivateKey.InnerXml);
        RSAPKCS1SignatureFormatter rsaFormatter = 
            new RSAPKCS1SignatureFormatter(providerRSA);
        rsaFormatter.SetHashAlgorithm("SHA1");
        byte[] signedPolicyHash = rsaFormatter.CreateSignature(bufferPolicy);

        // Convert the signed policy to URL-safe base64 encoding and 
        // replace unsafe characters + = / with the safe characters - _ ~
        string strSignedPolicy = ToUrlSafeBase64String(signedPolicyHash);

        // Concatenate the URL, the timestamp, the signature, 
        // and the key pair ID to form the signed URL.
        return urlString + 
            "?Expires=" + 
            strExpiration + 
            "&Signature=" + 
            strSignedPolicy + 
            "&Key-Pair-Id=" + 
            keyId;
    }
}
```

## C\$1의 사용자 지정 정책 서명 메서드
<a name="custom-policy-signed-url-net"></a>

다음 C\$1 코드는 다음을 수행하여 사용자 지정 정책을 사용하는 서명된 URL을 만듭니다.

1. 정책 설명을 만듭니다.

1. Base64 방식으로 정책 설명을 인코딩하고 특수 문자를 교체하여 URL 요청 파라미터로 사용하기에 안전한 문자열을 만드세요.

1. SHA1을 사용하여 정책 설명을 해시하고, RSA와 해당 퍼블릭 키가 신뢰할 수 있는 키 그룹에 있는 프라이빗 키를 사용하여 결과를 암호화합니다.

1. Base64 방식으로 해시된 정책 설명을 인코딩하고 특수 문자를 교체하여 URL 요청 파라미터로 사용하기에 안전한 문자열을 만드세요.

1. 값을 연결합니다.

완전한 구현에 대한 내용은 [C\$1의 서명 코드](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip)에서 예제를 참조하세요.

**참고**  
CloudFront에 퍼블릭 키를 업로드하면 `keyId`가 반환됩니다. 자세한 내용은 ![\[6\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/callouts/6.png)[ &Key-Pair-Id](private-content-creating-signed-url-canned-policy.md)를 참조하세요.

**Example : C\$1의 사용자 지정 정책 서명 메서드**  <a name="ExampleCustomPolicySigningMethod-CSharp"></a>

```
public static string ToUrlSafeBase64String(byte[] bytes)
{
    return System.Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('=', '_')
        .Replace('/', '~');
}

public static string CreateCustomPrivateURL(string urlString, 
    string durationUnits, string durationNumber, string startIntervalFromNow, 
    string ipaddress, string pathToPolicyStmnt, string pathToPrivateKey, 
    string keyId)
{
    // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days 
    // to expiration, 3-numberOfPreviousUnits, 4-starttimeFromNow, 
    // 5-ip_address, 6-pathToPolicyStmt, 7-pathToPrivateKey, 8-keyId

    TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber);
    TimeSpan timeSpanToStart = GetDurationByUnits(durationUnits, 
        startIntervalFromNow);
    if (null == timeSpanToStart) 
        return "Invalid duration units." + 
            "Valid options: seconds, minutes, hours, or days";
            
    string strPolicy = CreatePolicyStatement(
        pathToPolicyStmnt, urlString, DateTime.Now.Add(timeSpanToStart), 
        DateTime.Now.Add(timeSpanInterval), ipaddress);

    // Read the policy into a byte buffer.
    byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy);

    // Convert the policy statement to URL-safe base64 encoding and 
    // replace unsafe characters + = / with the safe characters - _ ~

    string urlSafePolicy = ToUrlSafeBase64String(bufferPolicy);

    // Initialize the SHA1CryptoServiceProvider object and hash the policy data.
    byte[] bufferPolicyHash;
    using (SHA1CryptoServiceProvider cryptoSHA1 = 
        new SHA1CryptoServiceProvider())
    {
        bufferPolicyHash = cryptoSHA1.ComputeHash(bufferPolicy);

        // Initialize the RSACryptoServiceProvider object.
        RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider();
        XmlDocument xmlPrivateKey = new XmlDocument();

        // Load your private key, which you created by converting your 
        // .pem file to the XML format that the .NET framework uses.  
        // Several tools are available. 
        xmlPrivateKey.Load(pathToPrivateKey);

        // Format the RSACryptoServiceProvider providerRSA 
        // and create the signature.
        providerRSA.FromXmlString(xmlPrivateKey.InnerXml);
        RSAPKCS1SignatureFormatter RSAFormatter = 
            new RSAPKCS1SignatureFormatter(providerRSA);
        RSAFormatter.SetHashAlgorithm("SHA1");
        byte[] signedHash = RSAFormatter.CreateSignature(bufferPolicyHash);

        // Convert the signed policy to URL-safe base64 encoding and 
        // replace unsafe characters + = / with the safe characters - _ ~
        string strSignedPolicy = ToUrlSafeBase64String(signedHash);

        return urlString + 
            "?Policy=" + 
            urlSafePolicy + 
            "&Signature=" + 
            strSignedPolicy + 
            "&Key-Pair-Id=" + 
            keyId;
    }
}
```

## 서명 생성을 위한 유틸리티 메서드
<a name="utility-methods-signed-url"></a>

다음 메서드는 파일에서 정책 설명을 가져오고 서명 생성을 위해 시간 간격을 구문 분석합니다.

**Example : 서명 생성을 위한 유틸리티 메서드**  <a name="UtilityMethodsForSignatureGeneration"></a>

```
public static string CreatePolicyStatement(string policyStmnt, 
   string resourceUrl, 
   DateTime startTime, 
   DateTime endTime, 
   string ipAddress)
   
{
   // Create the policy statement.
   FileStream streamPolicy = new FileStream(policyStmnt, FileMode.Open, FileAccess.Read);
   using (StreamReader reader = new StreamReader(streamPolicy))
   {
      string strPolicy = reader.ReadToEnd();

      TimeSpan startTimeSpanFromNow = (startTime - DateTime.Now);
      TimeSpan endTimeSpanFromNow = (endTime - DateTime.Now);
      TimeSpan intervalStart = 
         (DateTime.UtcNow.Add(startTimeSpanFromNow)) - 
         new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
      TimeSpan intervalEnd = 
         (DateTime.UtcNow.Add(endTimeSpanFromNow)) - 
         new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

      int startTimestamp = (int)intervalStart.TotalSeconds; // START_TIME
      int endTimestamp = (int)intervalEnd.TotalSeconds;  // END_TIME

      if (startTimestamp > endTimestamp)
         return "Error!";

      // Replace variables in the policy statement.
      strPolicy = strPolicy.Replace("RESOURCE", resourceUrl);
      strPolicy = strPolicy.Replace("START_TIME", startTimestamp.ToString());
      strPolicy = strPolicy.Replace("END_TIME", endTimestamp.ToString());
      strPolicy = strPolicy.Replace("IP_ADDRESS", ipAddress);
      strPolicy = strPolicy.Replace("EXPIRES", endTimestamp.ToString());
      return strPolicy;
   }   
}

public static TimeSpan GetDuration(string units, string numUnits)
{
   TimeSpan timeSpanInterval = new TimeSpan();
   switch (units)
   {
      case "seconds":
         timeSpanInterval = new TimeSpan(0, 0, 0, int.Parse(numUnits));
         break;
      case "minutes":
         timeSpanInterval = new TimeSpan(0, 0, int.Parse(numUnits), 0);
         break;
      case "hours":
         timeSpanInterval = new TimeSpan(0, int.Parse(numUnits), 0 ,0);
         break;
      case "days":
         timeSpanInterval = new TimeSpan(int.Parse(numUnits),0 ,0 ,0);
         break;
      default:
         Console.WriteLine("Invalid time units;" + 
            "use seconds, minutes, hours, or days");
         break;
   }
   return timeSpanInterval;
}

private static TimeSpan GetDurationByUnits(string durationUnits, 
   string startIntervalFromNow)
{
   switch (durationUnits)
   {
      case "seconds":
         return new TimeSpan(0, 0, int.Parse(startIntervalFromNow));
      case "minutes":
         return new TimeSpan(0, int.Parse(startIntervalFromNow), 0);
      case "hours":
         return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0);
      case "days":
         return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0, 0);
      default:
         return new TimeSpan(0, 0, 0, 0);
   }
}

public static string CopyExpirationTimeFromPolicy(string policyStatement)
{
   int startExpiration = policyStatement.IndexOf("EpochTime");
   string strExpirationRough = policyStatement.Substring(startExpiration + 
      "EpochTime".Length);
   char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
         
   List<char> listDigits = new List<char>(digits);
   StringBuilder buildExpiration = new StringBuilder(20);
         
   foreach (char c in strExpirationRough)
   {
      if (listDigits.Contains(c))
         buildExpiration.Append(c);
   }
   return buildExpiration.ToString();   
}
```

다음 사항도 참조하세요.
+ [Perl을 사용한 URL 서명 생성](CreateURLPerl.md)
+ [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md)
+ [Java를 사용한 URL 서명 생성](CFPrivateDistJavaDevelopment.md)

# Java를 사용한 URL 서명 생성
<a name="CFPrivateDistJavaDevelopment"></a>

다음 코드 예제 외에도 [AWS SDK for Java(버전 1)의 `CloudFrontUrlSigner` 유틸리티 클래스](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontUrlSigner.html)를 사용하여 [CloudFront 서명 URL](private-content-signed-urls.md)을 만들 수 있습니다.

자세한 예제는 AWS SDK Code Examples Code Library에서 [AWS SDK를 사용하여 서명된 URL 및 쿠키 만들기](https://docs.aws.amazon.com/code-library/latest/ug/cloudfront_example_cloudfront_CloudFrontUtilities_section.html)를 참조합니다.**

**참고**  
서명된 URL 생성은 [CloudFront를 통해 프라이빗 콘텐츠를 제공](PrivateContent.md)하는 프로세스의 한 부분에 불과합니다. 전체 프로세스에 대한 자세한 내용은 [서명된 URL 사용](private-content-signed-urls.md)을 참조하세요.

다음 예제는 CloudFront 서명된 URL을 만드는 방법을 보여줍니다.

**Example Java 정책 및 서명 암호화 메서드**  <a name="ExampleJavaPolicyAndSignatureEncryptionMethods"></a>

```
package org.example;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import software.amazon.awssdk.services.cloudfront.CloudFrontUtilities;
import software.amazon.awssdk.services.cloudfront.model.CannedSignerRequest;
import software.amazon.awssdk.services.cloudfront.url.SignedUrl;

public class Main {

    public static void main(String[] args) throws Exception {
        CloudFrontUtilities cloudFrontUtilities = CloudFrontUtilities.create();
        Instant expirationDate = Instant.now().plus(7, ChronoUnit.DAYS);
        String resourceUrl = "https://a1b2c3d4e5f6g7.cloudfront.net";
        String keyPairId = "K1UA3WV15I7JSD";
        CannedSignerRequest cannedRequest = CannedSignerRequest.builder()
                .resourceUrl(resourceUrl)
                .privateKey(new java.io.File("/path/to/private_key.pem").toPath())
                .keyPairId(keyPairId)
                .expirationDate(expirationDate)
                .build();
        SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCannedPolicy(cannedRequest);
        String url = signedUrl.url();
        System.out.println(url);

    }
}
```

추가 참고:
+ [Perl을 사용한 URL 서명 생성](CreateURLPerl.md)
+ [PHP를 사용한 URL 서명 생성](CreateURL_PHP.md)
+ [C\$1 및 .NET Framework를 사용한 URL 서명 생성](CreateSignatureInCSharp.md)

# AWS 오리진에 대한 액세스 제한
<a name="private-content-restricting-access-to-origin"></a>

다음과 같은 이점을 제공하는 방식으로 CloudFront 및 일부 AWS 오리진을 구성할 수 있습니다.
+ 공개적으로 액세스할 수 없도록 AWS 오리진에 대한 액세스를 제한합니다.
+ 뷰어(사용자)가 지정된 CloudFront 배포를 통해서만 AWS 오리진의 콘텐츠에 액세스할 수 있는지 확인합니다. 이렇게 하면 뷰어가 오리진에서 직접 또는 의도하지 않은 CloudFront 배포를 통해 콘텐츠에 액세스할 수 없습니다.

이렇게 하려면 인증된 요청을 AWS 오리진으로 보내도록 CloudFront를 구성하고 CloudFront의 인증된 요청에 대한 액세스만 허용하도록 AWS 오리진을 구성합니다. 자세한 정보는 호환되는 AWS 오리진 유형에 대한 다음 주제를 참조합니다.

**Topics**
+ [AWS Elemental MediaPackage v2 오리진에 대한 액세스 제한](private-content-restricting-access-to-mediapackage.md)
+ [AWS Elemental MediaStore 오리진에 대한 액세스 제한](private-content-restricting-access-to-mediastore.md)
+ [AWS Lambda 함수 URL 오리진에 대한 액세스 제한](private-content-restricting-access-to-lambda.md)
+ [Amazon S3 오리진에 대한 액세스 제한](private-content-restricting-access-to-s3.md)
+ [VPC 오리진으로 액세스 제한](private-content-vpc-origins.md)

# AWS Elemental MediaPackage v2 오리진에 대한 액세스 제한
<a name="private-content-restricting-access-to-mediapackage"></a>

CloudFront는 MediaPackage v2 오리진에 대한 액세스를 제한하기 위한 오리진 액세스 제어(OAC)를 제공합니다.**

**참고**  
CloudFront OAC는 MediaPackage v2만 지원합니다. MediaPackage v1은 지원되지 않습니다.

**Topics**
+ [새 OAC 생성](#create-oac-overview-mediapackage)
+ [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-mediapackage)

## 새 OAC 생성
<a name="create-oac-overview-mediapackage"></a>

다음 주제에 설명된 단계를 완료하여 CloudFront에서 새 OAC를 설정합니다.

**Topics**
+ [사전 조건](#oac-prerequisites-mediapackage)
+ [MediaPackage v2 오리진에 액세스할 수 있는 CloudFront 권한 부여](#oac-permission-to-access-mediapackage)
+ [OAC 생성](#create-oac-mediapackage)

### 사전 조건
<a name="oac-prerequisites-mediapackage"></a>

OAC를 생성하고 설정하기 전에 MediaPackage v2 오리진과 함께 CloudFront 배포가 있어야 합니다. 자세한 내용은 [MediaStore 컨테이너 또는 MediaPackage 채널 사용](DownloadDistS3AndCustomOrigins.md#concept_AWS_Media) 섹션을 참조하세요.

### MediaPackage v2 오리진에 액세스할 수 있는 CloudFront 권한 부여
<a name="oac-permission-to-access-mediapackage"></a>

OAC를 만들거나 CloudFront 배포에서 설정하기 전에 CloudFront에 MediaPackage v2 오리진에 액세스할 수 있는 권한이 있는지 확인합니다. 이 작업은 CloudFront 배포를 생성한 후, 배포 구성에서 MediaPackage v2 오리진에 OAC를 추가하기 전에 수행합니다.

IAM 정책을 사용하여 CloudFront 서비스 위탁자(`cloudfront.amazonaws.com`)가 오리진에 액세스하도록 허용합니다. 이 정책의 `Condition` 요소는 요청이 MediaPackage v2 오리진을 포함하는 CloudFront 배포를 대신하는 경우에만 CloudFront가 MediaPackage v2 오리진에 액세스할 수 있도록 허용합니다.** OAC를 추가하려는 MediaPackage v2 오리진이 있는 배포입니다.

**Example : CloudFront 배포에서 OAC에 대한 읽기 전용 액세스를 허용하는 IAM 정책**  
다음 정책은 MediaPackage v2 오리진에 대한 CloudFront 배포(`E1PDK09ESKHJWT`) 액세스를 허용합니다. 오리진은 `Resource` 요소에 지정된 ARN입니다.    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {"Service": "cloudfront.amazonaws.com"},
            "Action": "mediapackagev2:GetObject",
            "Resource": "arn:aws:mediapackagev2:us-east-1:123456789012:channelGroup/channel-group-name/channel/channel-name/originEndpoint/origin_endpoint_name",
            "Condition": {
                "StringEquals": {"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT"}
            }
        }
    ]
}
```

**참고**  
MQAR 기능 및 오리진 액세스 제어(OAC)를 사용 설정한 경우 IAM 정책에 `mediapackagev2:GetHeadObject` 작업을 추가합니다. MediaPackage v2 오리진으로 `HEAD` 요청을 보내려면 MQAR에 이 권한이 필요합니다. MQAR에 대한 자세한 내용은 [미디어 품질 인식 복원력](media-quality-score.md) 섹션을 참조하시기 바랍니다.
MediaPackage v2 오리진에 대한 권한이 없는 배포를 생성하는 경우 CloudFront 콘솔에서 **정책 복사**를 선택한 다음 **엔드포인트 권한 업데이트**를 선택할 수 있습니다. 그런 다음 복사한 권한을 엔드포인트에 연결할 수 있습니다. 자세한 내용은 AWS Elemental MediaPackage 사용자 설명서의 [엔드포인트 정책 필드](https://docs.aws.amazon.com/mediapackage/latest/userguide/endpoints-policy.html)를 참조합니다.**

### OAC 생성
<a name="create-oac-mediapackage"></a>

OAC를 생성하려면 AWS Management Console, CloudFormation, AWS CLI 또는 CloudFront API를 사용할 수 있습니다.

------
#### [ Console ]

**OAC를 만들려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **Origin access**(원본 액세스)를 선택합니다.

1. **Create control setting**(제어 설정 생성)을 선택합니다.

1. **새로운 OAC 생성** 양식에서 다음을 수행합니다.

   1. OAC의 **이름**을 입력하고 선택적으로 **설명**을 입력합니다.

   1. **서명 동작**의 경우 기본 설정인 **요청 서명(권장)**을 유지하는 것이 좋습니다. 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-mediapackage) 섹션을 참조하세요.

1. **오리진 유형**으로는 **MediaPackage V2**를 선택합니다.

1. **생성**을 선택합니다.
**작은 정보**  
OAC를 생성한 후 **이름**을 기록해 둡니다. 다음 절차에서 필요합니다.

**배포의 MediaPackage v2 오리진에 OAC를 추가하려는 경우**

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. OAC를 추가하려는 MediaPackage V2 오리진이 있는 배포를 선택한 다음 **오리진** 탭을 선택합니다.

1. OAC를 추가할 MediaPackage V2 오리진을 선택한 다음 **편집**을 선택합니다.

1. 오리진의 **프로토콜**에 **HTTPS만 해당**을 선택합니다.

1. **오리진 액세스 제어** 드롭다운 메뉴에서 사용할 OAC를 선택합니다.

1. **변경 사항 저장**를 선택합니다.

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 MediaPackage V2 오리진으로 보내는 모든 요청에 서명합니다.

------
#### [ CloudFormation ]

CloudFormation에 OAC를 생성하려면 `AWS::CloudFront::OriginAccessControl` 리소스 유형을 사용합니다. 다음 예는 OAC를 생성하기 위한 YAML 형식의 CloudFormation 템플릿 구문을 보여줍니다.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: mediapackagev2
      SigningBehavior: always
      SigningProtocol: sigv4
```

자세한 내용은 AWS CloudFormation 사용 설명서의 [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html)을 참조하세요.**

------
#### [ CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 오리진 액세스 제어를 생성하려면 **aws cloudfront create-origin-access-control** 명령을 사용합니다. 각 개별 파라미터를 명령줄 입력으로 지정하는 대신 입력 파일을 사용하여 명령의 입력 파라미터를 제공할 수 있습니다.

**오리진 액세스 제어를 생성하려면(입력 파일과 CLI)**

1. 다음 명령을 사용하여 이름이 `origin-access-control.yaml`인 파일을 생성합니다. 이 파일에는 **create-origin-access-control** 명령에 대한 모든 입력 파라미터가 들어 있습니다.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. 방금 생성한 `origin-access-control.yaml` 파일을 엽니다. 파일을 편집하여 OAC의 이름, 설명(선택 사항)을 추가하고 `SigningBehavior`를 `always`로 변경합니다. 그런 다음 파일을 저장합니다.

   다른 OAC 설정에 대한 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-mediapackage) 섹션을 참조하세요.

1. 다음 명령으로 `origin-access-control.yaml` 파일의 입력 파라미터를 사용하여 오리진 액세스 제어를 만듭니다.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   명령 출력에 있는 `Id` 값을 기록해 둡니다. CloudFront 배포의 MediaPackage v2 오리진에 OAC를 추가하려면 필요합니다.

**OAC를 기존 배포의 MediaPackage v2 오리진에 연결하는 방법(입력 파일과 CLI)**

1. 다음 명령을 사용하여 OAC를 추가할 CloudFront 배포에 대한 배포 구성을 저장합니다. 배포에 MediaPackage v2 오리진이 있어야 합니다.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. 방금 생성한 `dist-config.yaml`이라는 파일을 엽니다. 파일을 편집하여 다음과 같이 변경합니다.
   + `Origins` 객체에서 `OriginAccessControlId`라는 필드에 OAC의 ID를 추가합니다.
   + `OriginAccessIdentity`라는 필드에서 값을 제거합니다(있는 경우).
   + `ETag` 필드의 이름을 `IfMatch`로 바꾸지만 필드 값은 변경하지 마세요.

   완료되면 파일을 저장합니다.

1. 오리진 액세스 제어를 사용하도록 배포를 업데이트하려면 다음 명령을 사용합니다.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 MediaPackage v2 오리진으로 보내는 모든 요청에 서명합니다.

------
#### [ API ]

CloudFront API를 사용하여 OAC를 생성하려면 [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html)을 사용합니다. 이 API 호출에서 지정하는 필드에 대한 자세한 내용은 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조하세요.

OAC를 생성한 후 다음 API 호출 중 하나를 사용하여 배포의 MediaPackage v2 오리진에 연결할 수 있습니다.
+ 기존 배포에 연결하려면 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)을 사용합니다.
+ 새 배포에 연결하려면 [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html)을 사용합니다.

이 두 API 호출에 대해 오리진 내부의 `OriginAccessControlId` 필드에 OAC ID를 제공합니다. 이러한 API 호출에서 지정하는 다른 필드에 대한 자세한 내용은 [모든 배포 설정 참조](distribution-web-values-specify.md)와 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조하세요.

------

## 오리진 액세스 제어를 위한 고급 설정
<a name="oac-advanced-settings-mediapackage"></a>

CloudFront OAC 기능에는 특정 사용 사례만을 위한 고급 설정이 포함되어 있습니다. 고급 설정이 특별히 필요한 경우가 아니면 권장 설정을 사용하세요.

OAC에는 **서명 동작**(콘솔) 또는 `SigningBehavior`(API, CLI 및 CloudFormation)라는 설정이 포함되어 있습니다. 이 설정은 다음 옵션을 제공합니다.

**항상 오리진 요청에 서명(권장 설정)**  
이 설정의 이름은 콘솔에서 **서명 요청(권장)**이고 API, CLI, CloudFormation에서 `always`이며, 이 설정을 사용하는 것이 좋습니다. 이 설정을 사용하면 CloudFront가 항상 MediaPackage v2 오리진으로 보내는 모든 요청에 서명합니다.

**오리진 요청 서명 안 함**  
이 설정의 이름은 콘솔에서 **Do not sign requests**(요청 서명 안 함)이고 API, CLI, CloudFormation에서 `never`입니다. 이 OAC를 사용하는 모든 배포의 모든 오리진에 대한 OAC를 끄려면 이 설정을 사용합니다. 오리진 액세스 제어를 사용하는 모든 오리진 및 배포에서 OAC를 하나씩 제거하는 것과 비교하여 시간과 노력을 절약할 수 있습니다. 이 설정을 사용하면 CloudFront가 MediaPackage v2 오리진으로 보내는 모든 요청에 서명하지 않습니다.  
이 설정을 사용하려면 MediaPackage v2 오리진에 공개적으로 액세스할 수 있어야 합니다. 공개적으로 액세스할 수 없는 MediaPackage v2 오리진에 이 설정을 사용하는 경우 CloudFront가 오리진에 액세스할 수 없습니다. MediaPackage v2 오리진은 CloudFront에 오류를 반환하고 CloudFront 해당 오류를 뷰어에 전달합니다. 자세한 내용은 AWS Elemental MediaPackage 사용 설명서의 [MediaPackage의 정책 및 권한](https://docs.aws.amazon.com/mediapackage/latest/userguide/policies-permissions.html)에 대한 MediaPackage v2 정책 예제를 참조하세요.**

**뷰어(클라이언트) `Authorization` 헤더 재정의 안 함**  
이 설정의 이름은 콘솔에서 **Do not override authorization header**(승인 헤더 재정의 안 함)이고 API, CLI, CloudFormation에서 `no-override`입니다. 해당 뷰어 요청에 `Authorization` 헤더가 포함되지 않은 경우에만 CloudFront에서 오리진 요청에 서명하도록 하려면 이 설정을 사용합니다. 이 설정을 사용하면 CloudFront에서는 뷰어 요청에 `Authorization` 헤더가 있는 경우 이를 전달하지만 뷰어 요청에 `Authorization` 헤더가 포함되어 있지 않으면 오리진 요청에 서명합니다(자체 `Authorization` 헤더 추가).  
뷰어 요청에서 `Authorization` 헤더를 전달하려면 이 오리진 액세스 제어와 연결된 MediaPackage v2 오리진을 사용하는 모든 캐시 동작에 대한 `Authorization` 헤더를 [캐시 정책](controlling-the-cache-key.md)에 반드시** 추가해야 합니다.

# AWS Elemental MediaStore 오리진에 대한 액세스 제한
<a name="private-content-restricting-access-to-mediastore"></a>

CloudFront는 AWS Elemental MediaStore 오리진에 대한 액세스를 제한할 수 있도록 *오리진 액세스 제어*(OAC)를 제공합니다.

**Topics**
+ [새 오리진 액세스 제어 생성](#create-oac-overview-mediastore)
+ [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-mediastore)

## 새 오리진 액세스 제어 생성
<a name="create-oac-overview-mediastore"></a>

다음 주제에 설명된 단계를 완료하여 CloudFront에서 새 오리진 액세스 제어를 설정합니다.

**Topics**
+ [사전 조건](#oac-prerequisites-mediastore)
+ [CloudFront에 MediaStore 오리진에 액세스할 수 있는 권한 부여](#oac-permission-to-access-mediastore)
+ [오리진 액세스 제어 생성](#create-oac-mediastore)

### 사전 조건
<a name="oac-prerequisites-mediastore"></a>

오리진 액세스 제어(OAC)를 생성하고 설정하기 전에 MediaStore 오리진과 함께 CloudFront 배포가 있어야 합니다.

### CloudFront에 MediaStore 오리진에 액세스할 수 있는 권한 부여
<a name="oac-permission-to-access-mediastore"></a>

오리진 액세스 제어를 만들거나 CloudFront 배포에서 이를 설정하기 전에 CloudFront에 MediaStore 오리진에 액세스할 수 있는 권한이 있는지 확인합니다. 이 작업은 CloudFront 배포를 생성한 후 배포 구성에서 MediaStore 오리진에 OAC를 추가하기 전에 수행해야 합니다.

MediaStore 컨테이너 정책을 사용하여 CloudFront 서비스 위탁자(`cloudfront.amazonaws.com`)가 오리진에 액세스하도록 허용합니다. 정책의 `Condition` 요소를 사용하여 MediaStore 오리진이 포함된 CloudFront 배포를 대신하는 요청인 경우에만 CloudFront에서 MediaStore 컨테이너에 액세스하도록 허용합니다. OAC를 추가하려는 MediaStore 오리진이 있는 배포입니다.

다음은 CloudFront 배포에서 MediaStore 오리진에 액세스할 수 있도록 허용하는 MediaStore 컨테이너 정책의 예제입니다.

**Example : CloudFront 배포에서 OAC에 대한 읽기 전용 액세스를 허용하도록 사용 설정된 MediaStore 컨테이너 정책**    
****  

```
{
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Sid": "AllowCloudFrontServicePrincipalReadOnly",
                "Effect": "Allow",
                "Principal": {
                  "Service": "cloudfront.amazonaws.com"
                },
                "Action": [ 
                  "mediastore:GetObject"
                ],
                "Resource": "arn:aws:mediastore:us-east-1:111122223333:container/<container name>/*",
                "Condition": {
                    "StringEquals": {
                      "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront-distribution-ID"
                    },
                    "Bool": {
                      "aws:SecureTransport": "true"
                    }
                }
            }
        ]
}
```

**Example : CloudFront 배포에서 OAC에 대한 읽기 및 쓰기 액세스를 허용하도록 사용 설정된 MediaStore 컨테이너 정책**    
****  

```
{
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Sid": "AllowCloudFrontServicePrincipalReadWrite",
                "Effect": "Allow",
                "Principal": {
                  "Service": "cloudfront.amazonaws.com"
                },
                "Action": [ 
                  "mediastore:GetObject",
                  "mediastore:PutObject"
                ],
                "Resource": "arn:aws:mediastore:us-east-1:111122223333:container/container-name/*",
                "Condition": {
                    "StringEquals": {
                      "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront-distribution-ID"
                    },
                    "Bool": {
                      "aws:SecureTransport": "true"
                    }
                }
            }
        ]
}
```

**참고**  
쓰기 액세스를 허용하려면 CloudFront 배포의 동작 설정에 `PUT`을 포함하기 위해 **Allowed HTTP methods**(허용된 HTTP 메서드)를 구성해야 합니다.

### 오리진 액세스 제어 생성
<a name="create-oac-mediastore"></a>

OAC를 생성하려면 AWS Management Console, CloudFormation, AWS CLI 또는 CloudFront API를 사용할 수 있습니다.

------
#### [ Console ]

**오리진 액세스 제어를 생성하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **Origin access**(원본 액세스)를 선택합니다.

1. **Create control setting**(제어 설정 생성)을 선택합니다.

1. **Create control setting**(제어 설정 생성) 양식을 사용하여 다음을 수행합니다.

   1. **Details**(세부 정보) 창에서 오리진 액세스 제어의 **Name**(이름) 및 선택적 **Description**(설명)을 입력합니다.

   1. **Settings**(설정) 창에서 기본 설정인 **Sign requests(recommended)**(요청 서명(권장))를 유지하는 것이 좋습니다. 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-mediastore) 섹션을 참조하세요.

1. **Origin type**(오리진 유형) 드롭다운에서 MediaStore를 선택합니다.

1. **생성(Create)**을 선택합니다.

   OAC를 생성한 후 **Name**(이름)을 기록해 둡니다. 다음 절차에서 필요합니다.

**배포의 MediaStore 오리진에 오리진 액세스 제어를 추가하는 방법**

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. OAC를 추가하려는 MediaStore 오리진이 있는 배포를 선택한 다음 **Origins**(오리진) 탭을 선택합니다.

1. OAC를 추가할 MediaStore 오리진을 선택한 다음 **Edit**(편집)을 선택합니다.

1. 오리진의 **Protocol**(프로토콜)에 **HTTPS only**(HTTPS만 해당)를 선택합니다.

1. **Origin access control**(원본 액세스 제어) 드롭다운 메뉴에서 사용할 OAC를 선택합니다.

1. **변경 사항 저장**을 선택합니다.

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 MediaStore 버킷 오리진으로 보내는 모든 요청에 서명합니다.

------
#### [ CloudFormation ]

CloudFormation에 오리진 액세스 제어(OAC)를 생성하려면 `AWS::CloudFront::OriginAccessControl` 리소스 유형을 사용합니다. 다음 예는 오리진 액세스 제어를 생성하기 위한 YAML 형식의 CloudFormation 템플릿 구문을 보여줍니다.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: mediastore
      SigningBehavior: always
      SigningProtocol: sigv4
```

자세한 내용은 *AWS CloudFormation 사용 설명서*의 [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html)을 참조하세요.

------
#### [ CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 오리진 액세스 제어를 생성하려면 **aws cloudfront create-origin-access-control** 명령을 사용합니다. 각 개별 파라미터를 명령줄 입력으로 지정하는 대신 입력 파일을 사용하여 명령의 입력 파라미터를 제공할 수 있습니다.

**오리진 액세스 제어를 생성하려면(입력 파일과 CLI)**

1. 다음 명령을 사용하여 이름이 `origin-access-control.yaml`인 파일을 생성합니다. 이 파일에는 **create-origin-access-control** 명령에 대한 모든 입력 파라미터가 들어 있습니다.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. 방금 생성한 `origin-access-control.yaml` 파일을 엽니다. 파일을 편집하여 OAC의 이름, 설명(선택 사항)을 추가하고 `SigningBehavior`를 `always`로 변경합니다. 그런 다음 파일을 저장합니다.

   다른 OAC 설정에 대한 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-mediastore) 섹션을 참조하세요.

1. 다음 명령으로 `origin-access-control.yaml` 파일의 입력 파라미터를 사용하여 오리진 액세스 제어를 만듭니다.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   명령 출력에 있는 `Id` 값을 기록해 둡니다. CloudFront 배포의 MediaStore 오리진에 OAC를 추가하려면 필요합니다.

**OAC를 기존 배포의 MediaStore 오리진에 연결하는 방법(입력 파일과 CLI)**

1. 다음 명령을 사용하여 OAC를 추가할 CloudFront 배포에 대한 배포 구성을 저장합니다. 배포에 MediaStore 오리진이 있어야 합니다.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. 방금 생성한 `dist-config.yaml`이라는 파일을 엽니다. 파일을 편집하여 다음과 같이 변경합니다.
   + `Origins` 객체에서 `OriginAccessControlId`라는 필드에 OAC의 ID를 추가합니다.
   + `OriginAccessIdentity`라는 필드에서 값을 제거합니다(있는 경우).
   + `ETag` 필드의 이름을 `IfMatch`로 바꾸지만 필드 값은 변경하지 마세요.

   완료되면 파일을 저장합니다.

1. 오리진 액세스 제어를 사용하도록 배포를 업데이트하려면 다음 명령을 사용합니다.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 MediaStore 오리진으로 보내는 모든 요청에 서명합니다.

------
#### [ API ]

CloudFront API를 사용하여 오리진 액세스 제어를 생성하려면 [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html)을 사용합니다. 이 API 호출에서 지정하는 필드에 대한 자세한 내용은 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조하세요.

오리진 액세스 제어를 생성한 후 다음 API 호출 중 하나를 사용하여 배포의 MediaStore 오리진에 연결할 수 있습니다.
+ 기존 배포에 연결하려면 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)을 사용합니다.
+ 새 배포에 연결하려면 [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html)을 사용합니다.

이 두 API 호출에 대해 오리진 내부의 `OriginAccessControlId` 필드에 오리진 액세스 제어 ID를 제공합니다. 이러한 API 호출에서 지정하는 다른 필드에 대한 자세한 내용은 [모든 배포 설정 참조](distribution-web-values-specify.md)와 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조하세요.

------

## 오리진 액세스 제어를 위한 고급 설정
<a name="oac-advanced-settings-mediastore"></a>

CloudFront 오리진 액세스 제어 기능에는 특정 사용 사례만을 위한 고급 설정이 포함되어 있습니다. 고급 설정이 특별히 필요한 경우가 아니면 권장 설정을 사용하세요.

오리진 액세스 제어에는 **Signing behavior**(서명 동작)(콘솔) 또는 `SigningBehavior`(API, CLI 및 CloudFormation)라는 설정이 포함되어 있습니다. 이 설정은 다음 옵션을 제공합니다.

**항상 오리진 요청에 서명(권장 설정)**  
이 설정의 이름은 콘솔에서 **서명 요청(권장)**이고 API, CLI, CloudFormation에서 `always`이며, 이 설정을 사용하는 것이 좋습니다. 이 설정을 사용하면 CloudFront가 항상 MediaStore 오리진으로 보내는 모든 요청에 서명합니다.

**오리진 요청 서명 안 함**  
이 설정의 이름은 콘솔에서 **Do not sign requests**(요청 서명 안 함)이고 API, CLI, CloudFormation에서 `never`입니다. 이 오리진 액세스 제어를 사용하는 모든 배포의 모든 오리진에 대한 오리진 액세스 제어를 끄려면 이 설정을 사용합니다. 오리진 액세스 제어를 사용하는 모든 오리진 및 배포에서 오리진 액세스 제어를 하나씩 제거하는 것과 비교하여 시간과 노력을 절약할 수 있습니다. 이 설정을 사용하면 CloudFront가 MediaStore 오리진으로 보내는 모든 요청에 서명하지 않습니다.  
이 설정을 사용하려면 MediaStore 오리진에 공개적으로 액세스할 수 있어야 합니다. 공개적으로 액세스할 수 없는 MediaStore 오리진에 이 설정을 사용하는 경우 CloudFront가 오리진에 액세스할 수 없습니다. MediaStore 오리진은 CloudFront에 오류를 반환하고 CloudFront 해당 오류를 뷰어에 전달합니다. 자세한 내용은 [Public read access over HTTPS](https://docs.aws.amazon.com/mediastore/latest/ug/policies-examples-public-https.html)(HTTPS를 통한 공개 읽기 액세스)에 대한 MediaStore 컨테이너 정책 예시를 참조하세요.

**뷰어(클라이언트) `Authorization` 헤더 재정의 안 함**  
이 설정의 이름은 콘솔에서 **Do not override authorization header**(승인 헤더 재정의 안 함)이고 API, CLI, CloudFormation에서 `no-override`입니다. 해당 뷰어 요청에 `Authorization` 헤더가 포함되지 않은 경우에만 CloudFront에서 오리진 요청에 서명하도록 하려면 이 설정을 사용합니다. 이 설정을 사용하면 CloudFront에서는 뷰어 요청에 `Authorization` 헤더가 있는 경우 이를 전달하지만 뷰어 요청에 `Authorization` 헤더가 포함되어 있지 않으면 오리진 요청에 서명합니다(자체 `Authorization` 헤더 추가).  
뷰어 요청에서 `Authorization` 헤더를 전달하려면 이 오리진 액세스 제어와 연결된 MediaStore 오리진을 사용하는 모든 캐시 동작에 대한 `Authorization` 헤더를 [캐시 정책](controlling-the-cache-key.md)에 반드시** 추가해야 합니다.

# AWS Lambda 함수 URL 오리진에 대한 액세스 제한
<a name="private-content-restricting-access-to-lambda"></a>

CloudFront는 Lambda 함수 URL 오리진에 대한 액세스를 제한하기 위한 오리진 액세스 제어(OAC)를 제공합니다.**

**Topics**
+ [새 OAC 생성](#create-oac-overview-lambda)
+ [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-lambda)
+ [예제 템플릿 코드](#example-template-code-lambda-oac)

## 새 OAC 생성
<a name="create-oac-overview-lambda"></a>

다음 주제에 설명된 단계를 완료하여 CloudFront에서 새 OAC를 설정합니다.

**중요**  
Lambda 함수 URL과 함께 `PUT` 또는 `POST` 메서드를 사용하는 경우 사용자가 요청을 CloudFront에 전송할 때 본문의 SHA256을 컴퓨팅하고 `x-amz-content-sha256` 헤더에 있는 요청 본문의 페이로드 해시 값을 포함해야 합니다. Lambda는 서명되지 않은 페이로드를 지원하지 않습니다.

**Topics**
+ [사전 조건](#oac-prerequisites-lambda)
+ [Lambda 함수 URL에 액세스할 수 있는 CloudFront 권한 부여](#oac-permission-to-access-lambda)
+ [OAC 생성](#create-oac-lambda)

### 사전 조건
<a name="oac-prerequisites-lambda"></a>

OAC를 생성하고 설정하기 전에 Lambda 함수 URL을 오리진으로 사용하는 CloudFront 배포가 있어야 합니다. OAC를 사용하려면 `AWS_IAM`을 `AuthType` 파라미터의 값으로 지정해야 합니다. 자세한 내용은 [Lambda 함수 URL 사용](DownloadDistS3AndCustomOrigins.md#concept_lambda_function_url) 섹션을 참조하세요.

### Lambda 함수 URL에 액세스할 수 있는 CloudFront 권한 부여
<a name="oac-permission-to-access-lambda"></a>

OAC를 만들거나 CloudFront 배포에서 설정하기 전에 CloudFront에 Lambda 함수 URL에 액세스할 수 있는 권한이 있는지 확인합니다. 이 작업은 CloudFront 배포를 생성한 후 배포 구성의 Lambda 함수 URL에 OAC를 추가하기 전에 수행해야 합니다.

**참고**  
Lambda 함수 URL에 대한 IAM 정책을 업데이트하려면 AWS Command Line Interface(AWS CLI)을 사용해야 합니다. Lambda 콘솔에서의 IAM 정책 편집은 현재 지원되지 않습니다.

다음 AWS CLI 명령은 Lambda 함수 URL에 대한 CloudFront 서비스 보안 주체(`cloudfront.amazonaws.com`) 액세스 권한을 부여합니다. 이 정책의 `Condition` 요소는 요청이 Lambda 함수 URL을 포함하는 CloudFront 배포를 대신하는 경우에만 CloudFront가 Lambda에 액세스할 수 있도록 허용합니다.** OAC를 추가하려는 Lambda 함수 URL 오리진이 있는 배포입니다.

**Example : CloudFront 배포에서 OAC에 대한 읽기 전용 액세스를 허용하도록 정책을 업데이트하는 AWS CLI 명령입니다.**  
다음 AWS CLI 명령을 실행하면 CloudFront 배포(`E1PDK09ESKHJWT`)가 Lambda *`FUNCTION_URL_NAME`*에 액세스할 수 있습니다.

```
aws lambda add-permission \
--statement-id "AllowCloudFrontServicePrincipal" \
--action "lambda:InvokeFunctionUrl" \
--principal "cloudfront.amazonaws.com" \
--source-arn "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT" \
--function-name FUNCTION_URL_NAME
```

```
aws lambda add-permission \
--statement-id "AllowCloudFrontServicePrincipalInvokeFunction" \
--action "lambda:InvokeFunction" \
--principal "cloudfront.amazonaws.com" \
--source-arn "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT" \
--function-name FUNCTION_URL_NAME
```

**참고**  
배포를 생성했는데 Lambda 함수 URL에 대한 권한이 없는 경우 CloudFront 콘솔에서 **Copy CLI 명령**을 선택한 다음 명령줄 터미널에서 이 명령을 입력할 수 있습니다. 자세한 정보는 AWS Lambda 개발자 안내서의 [AWS 서비스에 대한 액세스 부여](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke)를 참조합니다.**

### OAC 생성
<a name="create-oac-lambda"></a>

OAC를 생성하려면 AWS Management Console, CloudFormation, AWS CLI 또는 CloudFront API를 사용할 수 있습니다.

------
#### [ Console ]

**OAC를 만들려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **Origin access**(원본 액세스)를 선택합니다.

1. **Create control setting**(제어 설정 생성)을 선택합니다.

1. **새로운 OAC 생성** 양식에서 다음을 수행합니다.

   1. OAC의 **이름**을 입력하고 선택적으로 **설명**을 입력합니다.

   1. **서명 동작**의 경우 기본 설정인 **요청 서명(권장)**을 유지하는 것이 좋습니다. 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-lambda) 섹션을 참조하세요.

1. **오리진 유형**에 대해 **Lambda**를 선택합니다.

1. **생성(Create)**을 선택합니다.
**작은 정보**  
OAC를 생성한 후 **이름**을 기록해 둡니다. 다음 절차에서 필요합니다.

**배포의 Lambda 함수 URL에 오리진 액세스 제어를 추가하려는 경우**

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다

1. OAC를 추가하려는 Lambda 함수 URL이 있는 배포를 선택한 다음 **오리진** 탭을 선택합니다.

1. OAC를 추가할 Lambda 함수 URL을 선택한 다음 **편집**을 선택합니다.

1. 오리진의 **프로토콜**에 **HTTPS만 해당**을 선택합니다.

1. **오리진 액세스 제어** 드롭다운 메뉴에서 사용할 OAC를 선택합니다.

1. **변경 사항 저장**를 선택합니다.

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 Lambda 함수 URL로 보내는 모든 요청에 서명합니다.

------
#### [ CloudFormation ]

CloudFormation에 OAC를 생성하려면 `AWS::CloudFront::OriginAccessControl` 리소스 유형을 사용합니다. 다음 예는 OAC를 생성하기 위한 YAML 형식의 CloudFormation 템플릿 구문을 보여줍니다.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: lambda
      SigningBehavior: always
      SigningProtocol: sigv4
```

자세한 내용은 AWS CloudFormation 사용 설명서의 [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html)을 참조하세요.**

------
#### [ CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 오리진 액세스 제어를 생성하려면 **aws cloudfront create-origin-access-control** 명령을 사용합니다. 각 개별 파라미터를 명령줄 입력으로 지정하는 대신 입력 파일을 사용하여 명령의 입력 파라미터를 제공할 수 있습니다.

**오리진 액세스 제어를 생성하려면(입력 파일과 CLI)**

1. 다음 명령을 사용하여 이름이 `origin-access-control.yaml`인 파일을 생성합니다. 이 파일에는 **create-origin-access-control** 명령에 대한 모든 입력 파라미터가 들어 있습니다.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. 방금 생성한 `origin-access-control.yaml` 파일을 엽니다. 파일을 편집하여 OAC의 이름, 설명(선택 사항)을 추가하고 `SigningBehavior`를 `always`로 변경합니다. 그런 다음 파일을 저장합니다.

   다른 OAC 설정에 대한 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-lambda) 섹션을 참조하세요.

1. 다음 명령으로 `origin-access-control.yaml` 파일의 입력 파라미터를 사용하여 오리진 액세스 제어를 만듭니다.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   명령 출력에 있는 `Id` 값을 기록해 둡니다. CloudFront 배포의 Lambda 함수 URL에 OAC를 추가하려면 필요합니다.

**OAC를 기존 배포의 Lambda 함수 URL에 연결하려는 경우(입력 파일과 CLI)**

1. 다음 명령을 사용하여 OAC를 추가할 CloudFront 배포에 대한 배포 구성을 저장합니다. 배포에 오리진과 함께 Lambda 함수 URL이 있어야 합니다.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. 방금 생성한 `dist-config.yaml`이라는 파일을 엽니다. 파일을 편집하여 다음과 같이 변경합니다.
   + `Origins` 객체에서 `OriginAccessControlId`라는 필드에 OAC의 ID를 추가합니다.
   + `OriginAccessIdentity`라는 필드에서 값을 제거합니다(있는 경우).
   + `ETag` 필드의 이름을 `IfMatch`로 바꾸지만 필드 값은 변경하지 마세요.

   완료되면 파일을 저장합니다.

1. 오리진 액세스 제어를 사용하도록 배포를 업데이트하려면 다음 명령을 사용합니다.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 Lambda 함수 URL로 보내는 모든 요청에 서명합니다.

------
#### [ API ]

CloudFront API를 사용하여 OAC를 생성하려면 [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html)을 사용합니다. 이 API 호출에서 지정하는 필드에 대한 자세한 내용은 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조하세요.

OAC를 생성한 후 다음 API 호출 중 하나를 사용하여 배포의 Lambda 함수 URL에 연결할 수 있습니다.
+ 기존 배포에 연결하려면 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)을 사용합니다.
+ 새 배포에 연결하려면 [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html)을 사용합니다.

이 두 API 호출에 대해 오리진 내부의 `OriginAccessControlId` 필드에 OAC ID를 제공합니다. 이러한 API 호출에서 지정하는 다른 필드에 대한 자세한 내용은 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조합니다.

------

## 오리진 액세스 제어를 위한 고급 설정
<a name="oac-advanced-settings-lambda"></a>

CloudFront OAC 기능에는 특정 사용 사례만을 위한 고급 설정이 포함되어 있습니다. 고급 설정이 특별히 필요한 경우가 아니면 권장 설정을 사용하세요.

OAC에는 **서명 동작**(콘솔) 또는 `SigningBehavior`(API, CLI 및 CloudFormation)라는 설정이 포함되어 있습니다. 이 설정은 다음 옵션을 제공합니다.

**항상 오리진 요청에 서명(권장 설정)**  
이 설정의 이름은 콘솔에서 **서명 요청(권장)**이고 API, CLI, CloudFormation에서 `always`이며, 이 설정을 사용하는 것이 좋습니다. 이 설정을 사용하면 CloudFront가 항상 Lambda 함수 URL으로 보내는 모든 요청에 서명합니다.

**오리진 요청 서명 안 함**  
이 설정의 이름은 콘솔에서 **Do not sign requests**(요청 서명 안 함)이고 API, CLI, CloudFormation에서 `never`입니다. 이 OAC를 사용하는 모든 배포의 모든 오리진에 대한 OAC를 끄려면 이 설정을 사용합니다. OAC를 사용하는 모든 오리진 및 배포에서 OAC를 하나씩 제거하는 것과 비교하여 시간과 노력을 절약할 수 있습니다. 이 설정을 사용하면 CloudFront가 Lambda 함수 URL로 보내는 모든 요청에 서명하지 않습니다.  
이 설정을 사용하려면 Lambda 함수 URL이 공개적으로 액세스할 수 있어야 합니다. 공개적으로 액세스할 수 없는 Lambda 함수 URL에 이 설정을 사용하는 경우 CloudFront가 오리진에 액세스할 수 없습니다. Lambda 함수 URL은 CloudFront에 오류를 반환하고 CloudFront 해당 오류를 뷰어에 전달합니다. 자세한 내용은 **AWS Lambda 사용 설명서의 [Lambda 함수 URL에 대한 보안 및 인증 모델](https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html)을 참조하세요.

**뷰어(클라이언트) `Authorization` 헤더 재정의 안 함**  
이 설정의 이름은 콘솔에서 **Do not override authorization header**(승인 헤더 재정의 안 함)이고 API, CLI, CloudFormation에서 `no-override`입니다. 해당 뷰어 요청에 `Authorization` 헤더가 포함되지 않은 경우에만 CloudFront에서 오리진 요청에 서명하도록 하려면 이 설정을 사용합니다. 이 설정을 사용하면 CloudFront에서는 뷰어 요청에 `Authorization` 헤더가 있는 경우 이를 전달하지만 뷰어 요청에 `Authorization` 헤더가 포함되어 있지 않으면 오리진 요청에 서명합니다(자체 `Authorization` 헤더 추가).  
+ 이 설정을 사용하는 경우, Lambda 함수 URL에 대해 CloudFront 배포의 이름 또는 CNAME 대신 Signature Version 4 서명을 지정해야 합니다. CloudFront가 뷰어 요청의 `Authorization` 헤더를 Lambda 함수 URL로 전달하면 Lambda는 Lambda URL 도메인의 호스트에 대해 서명을 검증합니다. 서명이 Lambda URL 도메인을 기반으로 하지 않는 경우 서명의 호스트는 Lambda URL 오리진에서 사용하는 호스트와 일치하지 않습니다. 따라서 요청이 실패하여 서명 검증 오류가 발생합니다.
+ 뷰어 요청에서 `Authorization` 헤더를 전달하려면 이 오리진 액세스 제어와 연결된 Lambda 함수 URL을 사용하는 모든 캐시 동작에 대한 `Authorization` 헤더를 [캐시 정책](controlling-the-cache-key.md)에 반드시** 추가해야 합니다.

## 예제 템플릿 코드
<a name="example-template-code-lambda-oac"></a>

CloudFront 오리진이 OAC와 연결된 Lambda 함수 URL인 경우 다음 Python 스크립트를 사용하여 `POST` 메서드로 Lambda 함수에 파일을 업로드할 수 있습니다.

이 코드는 기본 서명 동작이 **오리진 요청에 항상 서명**으로 설정된 OAC를 구성했고 **승인 헤더 재정의 안 함** 설정을 선택하지 않았다고 가정합니다.

이 구성을 통해 OAC는 Lambda 호스트 이름을 사용하여 Lambda로 SigV4 인증을 올바르게 관리할 수 있습니다. 페이로드는 `IAM_AUTH` 유형으로 지정된 Lambda 함수 URL에 대해 승인된 IAM 자격 증명의 SigV4를 사용하여 서명됩니다.

템플릿은 클라이언트 측의 `POST` 요청에 대해 x-amz-content-sha256 헤더에서 서명된 페이로드 해시 값을 처리하는 방법을 보여줍니다. 특히 이 템플릿은 양식 데이터 페이로드를 관리하도록 설계되었습니다. 템플릿은 CloudFront를 통해 Lambda 함수 URL에 대한 보안 파일 업로드를 활성화하고 AWS 인증 메커니즘을 사용하여 승인된 요청만 Lambda 함수에 액세스할 수 있도록 합니다.

**코드에 다음 기능이 포함됩니다.**  
x-amz-content-sha256 헤더에 페이로드 해시를 포함하기 위한 요구 사항을 충족합니다.
보안 AWS 서비스 액세스를 위해 SigV4 인증 사용
멀티파트 양식 데이터를 사용하여 파일 업로드 지원
요청 예외에 대한 오류 처리 포함

```
import boto3
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
import requests
import hashlib
import os


def calculate_body_hash(body):
    return hashlib.sha256(body).hexdigest()


def sign_request(request, credentials, region, service):
    sigv4 = SigV4Auth(credentials, service, region)
    sigv4.add_auth(request)


def upload_file_to_lambda(cloudfront_url, file_path, region):
    # AWS credentials
    session = boto3.Session()
    credentials = session.get_credentials()

    # Prepare the multipart form-data
    boundary = "------------------------boundary"

    # Read file content
    with open(file_path, 'rb') as file:
        file_content = file.read()

    # Get the filename from the path
    filename = os.path.basename(file_path)

    # Prepare the multipart body
    body = (
        f'--{boundary}\r\n'
        f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'
        f'Content-Type: application/octet-stream\r\n\r\n'
    ).encode('utf-8')
    body += file_content
    body += f'\r\n--{boundary}--\r\n'.encode('utf-8')

    # Calculate SHA256 hash of the entire body
    body_hash = calculate_body_hash(body)

    # Prepare headers
    headers = {
        'Content-Type': f'multipart/form-data; boundary={boundary}',
        'x-amz-content-sha256': body_hash
    }

    # Create the request
    request = AWSRequest(
        method='POST',
        url=cloudfront_url,
        data=body,
        headers=headers
    )

    # Sign the request
    sign_request(request, credentials, region, 'lambda')

    # Get the signed headers
    signed_headers = dict(request.headers)

    # Print request headers before sending
    print("Request Headers:")
    for header, value in signed_headers.items():
        print(f"{header}: {value}")

    try:
        # Send POST request with signed headers
        response = requests.post(
            cloudfront_url,
            data=body,
            headers=signed_headers
        )

        # Print response status and content
        print(f"\nStatus code: {response.status_code}")
        print("Response:", response.text)

        # Print response headers
        print("\nResponse Headers:")
        for header, value in response.headers.items():
            print(f"{header}: {value}")

    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}")


# Usage
cloudfront_url = "https://d111111abcdef8.cloudfront.net"
file_path = r"filepath"
region = "us-east-1"  # example: "us-west-2"

upload_file_to_lambda(cloudfront_url, file_path, region)
```

# Amazon S3 오리진에 대한 액세스 제한
<a name="private-content-restricting-access-to-s3"></a>

CloudFront는 Amazon S3 오리진에 인증된 요청을 전송하는 두 가지 방법으로 *오리진 액세스 제어*(OAC)와 *오리진 액세스 ID*(OAI)를 제공합니다. OAC는 Amazon S3와 같은 오리진을 보호하는 데 도움이 됩니다.

OAC는 다음 기능을 지원하므로 OAC를 대신 사용할 것을 *권장*합니다.
+ 2022년 12월 이후에 출시된 옵트인 리전을 포함하여 모든 AWS 리전 리전의 모든 Amazon S3 버킷
+ Amazon S3 [AWS KMS를 사용한 서버 측 암호화](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html)(SSE-KMS)
+ Amazon S3에 대한 동적 요청(`PUT` 및 `DELETE`)

OAI는 이러한 기능을 지원하지 않거나 이러한 시나리오에서 추가 해결 방법을 필요로 합니다. 이미 OAI를 사용하고 있고 마이그레이션하려는 경우 [오리진 액세스 ID(OAI)에서 오리진 액세스 제어(OAC)로 마이그레이션](#migrate-from-oai-to-oac) 섹션을 참조하세요.

**참고**  
Amazon S3 버킷 오리진과 함께 CloudFront OAC를 사용하는 경우 **Amazon S3 객체 소유권**을 새 Amazon S3 버킷의 기본값인 **버킷 소유자 적용**으로 설정해야 합니다. ACL이 필요한 경우 **버킷 소유자 선호** 설정을 사용하여 CloudFront를 통해 업로드된 객체에 대한 제어를 유지합니다.
오리진이 [웹 사이트 엔드포인트](https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteEndpoints.html)로 구성된 Amazon S3 버킷인 경우 사용자 지정 오리진으로 CloudFront와 함께 버킷을 설정해야 합니다. 즉, OAC(또는 OAI)를 사용할 수 없습니다. OAC는 Lambda@Edge를 사용한 오리진 리디렉션을 지원하지 않습니다.

다음 주제에서는 Amazon S3 오리진에서 OAC를 사용하는 방법을 설명합니다.

**주제**
+ [새 오리진 액세스 제어 생성](#create-oac-overview-s3)
+ [S3 버킷에 OAC가 연결된 배포 삭제](#delete-oac-distribution-s3)
+ [오리진 액세스 ID(OAI)에서 오리진 액세스 제어(OAC)로 마이그레이션](#migrate-from-oai-to-oac)
+ [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-s3)

## 새 오리진 액세스 제어 생성
<a name="create-oac-overview-s3"></a>

다음 주제에 설명된 단계를 완료하여 CloudFront에서 새 오리진 액세스 제어를 설정합니다.

**Topics**
+ [사전 조건](#oac-prerequisites-s3)
+ [CloudFront에 S3 버킷에 액세스할 수 있는 권한 부여](#oac-permission-to-access-s3)
+ [오리진 액세스 제어 생성](#create-oac-s3)

### 사전 조건
<a name="oac-prerequisites-s3"></a>

오리진 액세스 제어(OAC)를 생성하고 설정하기 전에 Amazon S3 버킷 오리진과 함께 CloudFront 배포가 있어야 합니다. 이 오리진은 [웹 사이트 엔드포인트](https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteEndpoints.html)로 구성된 버킷이 아니라 일반 S3 버킷이어야 합니다. S3 버킷 오리진과 함께 CloudFront 배포를 설정하는 방법에 대한 자세한 내용은 [CloudFront 표준 배포 시작](GettingStarted.SimpleDistribution.md) 섹션을 참조하세요.

**중요**  
OAC를 사용하여 Amazon S3 오리진을 보호하는 경우 CloudFront와 Amazon S3 간의 통신은 *항상* HTTPS를 통해 이루어지지만 *항상 요청에 서명*하도록 선택한 경우에만 그렇습니다. 콘솔에서 **서명 요청 (권장)**을 선택하거나 CloudFront API, AWS CLI 또는 CloudFormation에서 `always`를 지정해야 합니다.  
대신 **요청 서명 안 함** 또는 **승인 헤더 재정의 안 함** 옵션을 선택하면 CloudFront는 다음 정책에서 지정한 연결 프로토콜을 사용합니다.  
[뷰어 프로토콜 정책](using-https-viewers-to-cloudfront.md) 
[오리진 프로토콜 정책](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy)(사용자 지정 오리진 전용)
예를 들어 **승인 헤더 재정의 안 함**을 선택하고 CloudFront와 Amazon S3 오리진 간에 HTTPS를 사용하려면 [뷰어 사용자 프로토콜 정책](using-https-viewers-to-cloudfront.md)에서 **HTTP를 HTTPS로 리디렉션** 또는 **HTTPS 전용**을 사용합니다.

### CloudFront에 S3 버킷에 액세스할 수 있는 권한 부여
<a name="oac-permission-to-access-s3"></a>

오리진 액세스 제어(OAC)를 만들거나 CloudFront 배포에서 이를 설정하기 전에 CloudFront에 S3 버킷 오리진에 액세스할 수 있는 권한이 있는지 확인합니다. 이 작업은 CloudFront 배포를 생성한 후 배포 구성에서 S3 오리진에 OAC를 추가하기 전에 수행해야 합니다.

S3 [버킷 정책](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html)을 사용하여 CloudFront 서비스 위탁자(`cloudfront.amazonaws.com`)가 버킷에 액세스하도록 허용합니다. 정책의 `Condition` 요소를 사용하여 S3 오리진이 포함된 CloudFront 배포를 위한 요청인 경우에만 CloudFront에서 버킷에 액세스하도록 허용합니다. OAC를 추가하려는 S3 오리진이 있는 배포입니다.

버킷 정책 추가 또는 수정에 대한 자세한 내용은 Amazon S3 사용 설명서의 [Amazon S3 콘솔을 사용하여 버킷 정책 추가](https://docs.aws.amazon.com/AmazonS3/latest/userguide/add-bucket-policy.html)를 참조합니다.**

다음은 CloudFront 배포에서 OAC가 S3 오리진에 액세스할 수 있도록 허용하는 S3 버킷 정책의 예제입니다.

**Example CloudFront 배포에서 OAC에 대한 읽기 전용 액세스를 허용하도록 사용 설정된 S3 버킷 정책**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipalReadOnly",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
        }
      }
    }
  ]
}
```

**Example CloudFront 배포에서 OAC에 대한 읽기 및 쓰기 액세스를 허용하도록 사용 설정된 S3 버킷 정책**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipalReadWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront-distribution-ID>"
        }
      }
    }
  ]
}
```

#### SSE-KMS
<a name="oac-permissions-sse-kms"></a>

S3 버킷 오리진의 객체가 [AWS Key Management Service(SSE-KMS)로 서버 측 암호화](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html)를 사용하여 암호화된 경우 CloudFront 배포에 AWS KMS 키를 사용할 권한이 있는지 확인해야 합니다. CloudFront 배포에 KMS 키를 사용할 수 있는 권한을 부여하려면 [KMS 키 정책](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html)에 스테이트먼트를 추가합니다. 키 정책을 수정하는 방법에 대한 자세한 내용은 *AWS Key Management Service 개발자 안내서*의 [키 정책 변경](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-modifying.html)을 참조하세요.

**Example KMS 키 정책 설명**  
다음 예제는 OAC가 있는 CloudFront 배포에서 SSE-KMS용 KMS 키에 액세스할 수 있도록 허용하는 AWS KMS 정책 스테이트먼트를 보여줍니다.  

```
{
    "Sid": "AllowCloudFrontServicePrincipalSSE-KMS",
    "Effect": "Allow",
    "Principal": {
        "Service": [
            "cloudfront.amazonaws.com"
        ]
     },
    "Action": [
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:GenerateDataKey*"
    ],
    "Resource": "*",
    "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
            }
        }
}
```

### 오리진 액세스 제어 생성
<a name="create-oac-s3"></a>

오리진 액세스 제어(OAC)를 생성하려면 AWS Management Console, CloudFormation, AWS CLI 또는 CloudFront API를 사용할 수 있습니다.

------
#### [ Console ]

**오리진 액세스 제어를 생성하려면**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **Origin access**(원본 액세스)를 선택합니다.

1. **Create control setting**(제어 설정 생성)을 선택합니다.

1. **Create control setting**(제어 설정 생성) 양식을 사용하여 다음을 수행합니다.

   1. **Details**(세부 정보) 창에서 오리진 액세스 제어의 **Name**(이름) 및 선택적 **Description**(설명)을 입력합니다.

   1. **Settings**(설정) 창에서 기본 설정인 **Sign requests(recommended)**(요청 서명(권장))를 유지하는 것이 좋습니다. 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-s3) 섹션을 참조하세요.

1. **Origin type**(오리진 유형) 드롭다운에서 S3를 선택합니다.

1. **생성(Create)**을 선택합니다.

   OAC를 생성한 후 **Name**(이름)을 기록해 둡니다. 다음 절차에서 필요합니다.

**배포의 S3 오리진에 오리진 액세스 제어를 추가하려면**

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. OAC를 추가하려는 S3 오리진이 있는 배포를 선택한 다음 **Origins**(원본) 탭을 선택합니다.

1. OAC를 추가할 S3 오리진을 선택한 다음 **Edit**(편집)을 선택합니다.

1. **원본 액세스**의 경우 **원본 액세스 제어 설정(권장)**를 선택합니다.

1. **Origin access control**(원본 액세스 제어) 드롭다운 메뉴에서 사용할 OAC를 선택합니다.

1. **변경 사항 저장**을 선택합니다.

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 S3 버킷 오리진으로 보내는 모든 요청에 서명합니다.

------
#### [ CloudFormation ]

CloudFormation에 오리진 액세스 제어(OAC)를 생성하려면 `AWS::CloudFront::OriginAccessControl` 리소스 유형을 사용합니다. 다음 예는 오리진 액세스 제어를 생성하기 위한 YAML 형식의 CloudFormation 템플릿 구문을 보여줍니다.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: s3
      SigningBehavior: always
      SigningProtocol: sigv4
```

자세한 내용은 *AWS CloudFormation 사용 설명서*의 [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html)을 참조하세요.

------
#### [ CLI ]

AWS Command Line Interface(AWS CLI)를 사용하여 오리진 액세스 제어를 생성하려면 **aws cloudfront create-origin-access-control** 명령을 사용합니다. 각 개별 파라미터를 명령줄 입력으로 지정하는 대신 입력 파일을 사용하여 명령의 입력 파라미터를 제공할 수 있습니다.

**오리진 액세스 제어를 생성하려면(입력 파일과 CLI)**

1. 다음 명령을 사용하여 이름이 `origin-access-control.yaml`인 파일을 생성합니다. 이 파일에는 **create-origin-access-control** 명령에 대한 모든 입력 파라미터가 들어 있습니다.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. 방금 생성한 `origin-access-control.yaml` 파일을 엽니다. 파일을 편집하여 OAC의 이름, 설명(선택 사항)을 추가하고 `SigningBehavior`를 `always`로 변경합니다. 그런 다음 파일을 저장합니다.

   다른 OAC 설정에 대한 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](#oac-advanced-settings-s3) 섹션을 참조하세요.

1. 다음 명령으로 `origin-access-control.yaml` 파일의 입력 파라미터를 사용하여 오리진 액세스 제어를 만듭니다.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   명령 출력에 있는 `Id` 값을 기록해 둡니다. CloudFront 배포의 S3 버킷 오리진에 OAC를 추가하려면 필요합니다.

**OAC를 기존 배포의 S3 버킷 오리진에 연결하려면(입력 파일과 CLI)**

1. 다음 명령을 사용하여 OAC를 추가할 CloudFront 배포에 대한 배포 구성을 저장합니다. 배포에는 S3 버킷 오리진이 있어야 합니다.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. 방금 생성한 `dist-config.yaml`이라는 파일을 엽니다. 파일을 편집하여 다음과 같이 변경합니다.
   + `Origins` 객체에서 `OriginAccessControlId`라는 필드에 OAC의 ID를 추가합니다.
   + `OriginAccessIdentity`라는 필드에서 값을 제거합니다(있는 경우).
   + `ETag` 필드의 이름을 `IfMatch`로 바꾸지만 필드 값은 변경하지 마세요.

   완료되면 파일을 저장합니다.

1. 오리진 액세스 제어를 사용하도록 배포를 업데이트하려면 다음 명령을 사용합니다.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

모든 CloudFront 엣지 로케이션에 배포가 시작됩니다. 엣지 로케이션은 새 구성을 수신하면 S3 버킷 오리진으로 보내는 모든 요청에 서명합니다.

------
#### [ API ]

CloudFront API를 사용하여 오리진 액세스 제어를 생성하려면 [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html)을 사용합니다. 이 API 호출에서 지정하는 필드에 대한 자세한 내용은 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조하세요.

오리진 액세스 제어를 생성한 후 다음 API 호출 중 하나를 사용하여 배포의 S3 버킷 오리진에 연결할 수 있습니다.
+ 기존 배포에 연결하려면 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)을 사용합니다.
+ 새 배포에 연결하려면 [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html)을 사용합니다.

이 두 API 호출에 대해 오리진 내부의 `OriginAccessControlId` 필드에 오리진 액세스 제어 ID를 제공합니다. 이러한 API 호출에서 지정하는 다른 필드에 대한 자세한 내용은 [모든 배포 설정 참조](distribution-web-values-specify.md)와 AWS SDK 또는 기타 API 클라이언트에 대한 API 참조 설명서를 참조하세요.

------

## S3 버킷에 OAC가 연결된 배포 삭제
<a name="delete-oac-distribution-s3"></a>

S3 버킷에 OAC가 연결된 배포를 삭제해야 하는 경우 S3 버킷 오리진을 삭제하기 전에 배포를 삭제해야 합니다. 또는 오리진 도메인 이름에 지역을 포함시킬 수도 있습니다. 이렇게 할 수 없는 경우 삭제하기 전에 공개로 전환하여 배포에서 OAC를 제거할 수 있습니다. 자세한 내용은 [배포 삭제](HowToDeleteDistribution.md) 섹션을 참조하세요.

## 오리진 액세스 ID(OAI)에서 오리진 액세스 제어(OAC)로 마이그레이션
<a name="migrate-from-oai-to-oac"></a>

레거시 오리진 액세스 ID(OAI)에서 오리진 액세스 제어(OAC)로 마이그레이션하려면 먼저 S3 버킷 오리진을 업데이트하여 OAC가 있는 배포 및 OAI 모두에서 버킷의 콘텐츠에 액세스할 수 있도록 합니다. 이렇게 하면 전환 중에 CloudFront가 버킷에 대한 액세스 권한을 잃지 않습니다. OAC가 있는 배포 및 OAI 모두에서 S3 버킷에 액세스할 수 있도록 하려면 각 위탁자에 대해 하나씩 두 개의 스테이트먼트를 포함하도록 [버킷 정책](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html)을 업데이트합니다.

다음 예제 S3 버킷 정책은 OAC가 있는 배포 및 OAI 모두에서 S3 오리진에 액세스할 수 있도록 허용합니다.

**Example OAC가 있는 CloudFront 배포 및 OAI에서 읽기 전용 액세스를 허용하도록 사용 설정된 S3 버킷 정책**    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipalReadOnly",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
                }
            }
        },
        {
            "Sid": "AllowLegacyOAIReadOnly",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*"
        }
    ]
}
```

OAI와 OAC에 대한 액세스를 모두 허용하도록 S3 오리진의 버킷 정책을 업데이트한 후 OAI 대신 OAC를 사용하도록 배포 구성을 업데이트할 수 있습니다. 자세한 내용은 [새 오리진 액세스 제어 생성](#create-oac-overview-s3) 섹션을 참조하세요.

배포가 완전히 배포되면 버킷 정책에서 OAI에 대한 액세스를 허용하는 명령문을 제거할 수 있습니다. 자세한 내용은 [CloudFront에 S3 버킷에 액세스할 수 있는 권한 부여](#oac-permission-to-access-s3) 섹션을 참조하세요.

## 오리진 액세스 제어를 위한 고급 설정
<a name="oac-advanced-settings-s3"></a>

CloudFront 오리진 액세스 제어 기능에는 특정 사용 사례만을 위한 고급 설정이 포함되어 있습니다. 고급 설정이 특별히 필요한 경우가 아니면 권장 설정을 사용하세요.

오리진 액세스 제어에는 **Signing behavior**(서명 동작)(콘솔) 또는 `SigningBehavior`(API, CLI 및 CloudFormation)라는 설정이 포함되어 있습니다. 이 설정은 다음 옵션을 제공합니다.

**항상 오리진 요청에 서명(권장 설정)**  
이 설정의 이름은 콘솔에서 **Sign requests(recommended)**(서명 요청(권장))이고 API, CLI, CloudFormation에서 `always`이며, 이 설정을 사용하는 것이 좋습니다. 이 설정을 사용하면 CloudFront가 항상 S3 버킷 오리진으로 보내는 모든 요청에 서명합니다.

**오리진 요청 서명 안 함**  
이 설정의 이름은 콘솔에서 **Do not sign requests**(요청 서명 안 함)이고 API, CLI, CloudFormation에서 `never`입니다. 이 오리진 액세스 제어를 사용하는 모든 배포의 모든 오리진에 대한 오리진 액세스 제어를 끄려면 이 설정을 사용합니다. 오리진 액세스 제어를 사용하는 모든 오리진 및 배포에서 오리진 액세스 제어를 하나씩 제거하는 것과 비교하여 시간과 노력을 절약할 수 있습니다. 이 설정을 사용하면 CloudFront가 S3 버킷 오리진으로 보내는 모든 요청에 서명하지 않습니다.  
이 설정을 사용하려면 S3 버킷 오리진에 공개적으로 액세스할 수 있어야 합니다. 공개적으로 액세스할 수 없는 S3 버킷 오리진에 이 설정을 사용하는 경우 CloudFront가 오리진에 액세스할 수 없습니다. S3 버킷 오리진은 CloudFront에 오류를 반환하고 CloudFront 해당 오류를 뷰어에 전달합니다.

**뷰어(클라이언트) `Authorization` 헤더 재정의 안 함**  
이 설정의 이름은 콘솔에서 **Do not override authorization header**(승인 헤더 재정의 안 함)이고 API, CLI, CloudFormation에서 `no-override`입니다. 해당 뷰어 요청에 `Authorization` 헤더가 포함되지 않은 경우에만 CloudFront에서 오리진 요청에 서명하도록 하려면 이 설정을 사용합니다. 이 설정을 사용하면 CloudFront에서는 뷰어 요청에 `Authorization` 헤더가 있는 경우 이를 전달하지만 뷰어 요청에 `Authorization` 헤더가 포함되어 있지 않으면 오리진 요청에 서명합니다(자체 `Authorization` 헤더 추가).  
뷰어 요청에서 `Authorization` 헤더를 전달하려면 이 오리진 액세스 제어와 연결된 S3 버킷 오리진을 사용하는 모든 캐시 동작에 대한 `Authorization` 헤더를 [캐시 정책](controlling-the-cache-key.md)에 *반드시* 추가해야 합니다.

## 오리진 액세스 ID 사용(레거시, 권장하지 않음)
<a name="private-content-restricting-access-to-s3-oai"></a>

### 오리진 액세스 ID 개요
<a name="private-content-restricting-access-to-s3-overview"></a>

CloudFront *오리진 액세스 ID*(OAI)는 *오리진 액세스 제어*(OAC)와 유사한 기능을 제공하지만 모든 시나리오에서 기능이 작동하는 것은 아닙니다. 특히 OAI는 다음을 지원하지 않습니다.
+ 옵트인 리전을 포함한 모든 AWS 리전의 Amazon S3 버킷
+ Amazon S3 [AWS KMS를 사용한 서버 측 암호화](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html)(SSE-KMS)
+ Amazon S3에 대한 동적 요청(`PUT`, `POST` 또는 `DELETE`)
+ 2023년 1월 이후 새롭게 AWS 리전 출시

**작은 정보**  
대신 OAC를 사용할 것을 권장합니다. OAC를 설정하려면 [새 오리진 액세스 제어 생성](#create-oac-overview-s3) 섹션을 참조하세요. OAI에서 OAC로 마이그레이션하는 방법에 대한 자세한 내용은 [오리진 액세스 ID(OAI)에서 오리진 액세스 제어(OAC)로 마이그레이션](#migrate-from-oai-to-oac) 섹션을 참조하세요.

### 오리진 액세스 ID에 Amazon S3 버킷의 파일을 읽을 수 있는 권한 부여
<a name="private-content-granting-permissions-to-oai"></a>

OAI를 생성하거나 CloudFront 콘솔을 사용하여 배포에 추가할 때 Amazon S3 버킷 정책을 자동으로 업데이트하여 OAI에 버킷 액세스 권한을 부여할 수 있습니다. 또는 버킷 정책을 수동으로 생성하거나 업데이트하도록 선택할 수 있습니다. 어떤 방법을 사용하든 권한을 검토하여 다음 사항을 확인하세요.
+ CloudFront를 통해 파일을 요청하는 최종 사용자를 대신하여 CloudFront OAI가 버킷의 파일에 액세스할 수 있습니다.
+ 최종 사용자는 Amazon S3 URL을 사용하여 CloudFront 외부의 파일에 액세스할 수 없습니다.

**중요**  
CloudFront가 지원하는 모든 HTTP 메서드를 수락하고 전달하도록 CloudFront를 구성하는 경우 CloudFront OAI에 원하는 권한을 부여해야 합니다. 예를 들어 `DELETE` 메서드를 사용하는 요청을 수락하고 전달하도록 CloudFront를 구성하는 경우, 뷰어가 원하는 파일만 삭제할 수 있도록 `DELETE` 요청을 적절하게 처리하도록 버킷 정책을 구성합니다.

#### Amazon S3 버킷 정책 사용
<a name="private-content-updating-s3-bucket-policies"></a>

다음과 같은 방법으로 버킷 정책을 만들거나 업데이트하여 Amazon S3 버킷의 파일에 대한 액세스 권한을 CloudFront OAI에 부여할 수 있습니다.
+ [Amazon S3 콘솔](https://console.aws.amazon.com/s3/home)에서 Amazon S3 버킷의 **Permissions**(권한) 탭 사용
+ Amazon S3 API에서 [PutBucketPolicy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketPolicy.html) 사용
+ [CloudFront 콘솔](https://console.aws.amazon.com/cloudfront/v4/home) 사용 OAI를 CloudFront 콘솔의 원본 설정에 추가할 때 **예, 버킷 정책을 업데이트합니다(Yes, update the bucket policy)**를 선택하여 사용자를 대신해 버킷 정책을 업데이트하도록 CloudFront에 지시할 수 있습니다.

버킷 정책을 수동으로 업데이트하는 경우 다음 사항을 확인하세요.
+ 정책에서 올바른 OAI를 `Principal`로 지정합니다.
+ 최종 사용자를 대신해 객체에 액세스하는 데 필요한 권한을 OAI에 부여합니다.

자세한 내용은 다음 단원을 참조하세요.

##### 버킷 정책에서 OAI를 `Principal`로 지정
<a name="private-content-updating-s3-bucket-policies-principal"></a>

Amazon S3 버킷 정책에서 OAI를 `Principal`로 지정하려면 OAI ID가 포함된 OAI의 Amazon 리소스 이름(ARN)을 사용합니다. 예제:

```
"Principal": {
    "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
}
```

CloudFront 콘솔의 **보안**, **오리진 액세스**, **ID(레거시)**에서 OAI ID를 찾습니다. 또는 CloudFront API의 [ListCloudFrontOriginAccessIdentities](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListCloudFrontOriginAccessIdentities.html)를 사용할 수도 있습니다.

##### OAI에 권한 부여
<a name="private-content-updating-s3-bucket-policies-permissions"></a>

OAI에 Amazon S3 버킷의 객체에 액세스할 수 있는 권한을 부여하려면 정책에서 특정 Amazon S3 API 작업과 관련된 작업을 사용합니다. 예를 들어 `s3:GetObject` 작업을 통해 OAI가 버킷의 객체를 읽을 수 있습니다. 자세한 내용은 다음 섹션의 예제를 참조하거나 *Amazon Simple Storage Service 사용 설명서*의 [Amazon S3 작업](https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html)을 참조하세요.

##### Amazon S3 버킷 정책 예제
<a name="private-content-updating-s3-bucket-policies-examples"></a>

다음 예제에서는 CloudFront OAI가 S3 버킷에 액세스하도록 허용하는 Amazon S3 버킷 정책을 보여줍니다.

CloudFront 콘솔의 **보안**, **오리진 액세스**, **ID (레거시)**에서 OAI ID를 찾을 수 있습니다. 또는 CloudFront API의 [ListCloudFrontOriginAccessIdentities](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListCloudFrontOriginAccessIdentities.html)를 사용할 수도 있습니다.

**Example OAI에 읽기 액세스 권한을 부여하는 Amazon S3 버킷 정책**  
다음 예제에서는 OAI가 지정된 버킷(`s3:GetObject`)의 객체를 읽을 수 있도록 허용합니다.    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*"
        }
    ]
}
```

**Example OAI에 읽기 및 쓰기 액세스 권한을 부여하는 Amazon S3 버킷 정책**  
다음 예제에서는 OAI가 지정된 버킷(`s3:GetObject` 및 `s3:PutObject`)의 객체를 읽고 쓸 수 있도록 허용합니다. 이렇게 하면 최종 사용자가 CloudFront를 통해 Amazon S3 버킷에 파일을 업로드할 수 있습니다.    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::<S3 bucket name>/*"
        }
    ]
}
```

#### Amazon S3 객체 ACL 사용(권장되지는 않음)
<a name="private-content-updating-s3-acls"></a>

**중요**  
[Amazon S3 버킷 정책을 사용](#private-content-updating-s3-bucket-policies)하여 OAI에 S3 버킷에 대한 액세스 권한을 부여하는 것이 좋습니다. 이 섹션에 설명된 대로 액세스 제어 목록(ACL)을 사용할 수 있지만, 권장하지는 않습니다.  
Amazon S3는 [S3 객체 소유권](https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html)을 **버킷 소유자 적용**으로 설정할 것을 권장합니다. 즉, 버킷 및 그 안의 객체에 대해 ACL이 비활성화됩니다. 객체 소유권에 이 설정을 적용하는 경우 버킷 정책을 사용하여 OAI에 대한 액세스 권한을 부여해야 합니다(이전 섹션 참조).  
다음 섹션은 ACL이 필요한 레거시 사용 사례에만 해당됩니다.

다음과 같은 방법으로 파일의 ACL을 만들거나 업데이트하여 Amazon S3 버킷의 파일에 대한 액세스 권한을 CloudFront OAI에 부여할 수 있습니다.
+ [Amazon S3 콘솔](https://console.aws.amazon.com/s3/home)에서 Amazon S3 객체의 **Permissions**(권한) 탭 사용
+ Amazon S3 API에서 [PutObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html) 사용

ACL을 사용하여 OAI에 액세스 권한을 부여하는 경우 Amazon S3 정식 사용자 ID를 사용하여 OAI를 지정해야 합니다. CloudFront 콘솔의 **보안**, **오리진 액세스**, **ID (레거시)**에서 이 ID를 찾을 수 있습니다. CloudFront API를 사용하는 경우, OAI를 만들 때 반환된 `S3CanonicalUserId` 요소의 값을 사용하거나 CloudFront API에서 [ListCloudFrontOriginAccessIdentities](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListCloudFrontOriginAccessIdentities.html)를 호출합니다.

### 서명 버전 4 인증만 지원하는 Amazon S3 리전에서 오리진 액세스 ID 사용
<a name="private-content-origin-access-identity-signature-version-4"></a>

새 Amazon S3 리전에서는 인증된 요청에 대해 서명 버전 4를 사용해야 합니다. (각 Amazon S3 리전에서 지원되는 서명 버전은 *AWS 일반 참조*의 [Amazon Simple Storage Service 엔드포인트 및 할당량](https://docs.aws.amazon.com/general/latest/gr/s3.html)을 참조하세요.) 오리진 액세스 ID를 사용 중이고 버킷이 서명 버전 4가 필요한 리전 중 하나에 있는 경우 다음에 유의해야 합니다.
+ `DELETE`, `GET`, `HEAD`, `OPTIONS` 및 `PATCH` 요청은 자격과 관계없이 지원됩니다.
+ `POST` 요청은 지원되지 않습니다.

# VPC 오리진으로 액세스 제한
<a name="private-content-vpc-origins"></a>

CloudFront를 사용하여 가상 프라이빗 클라우드(VPC) 프라이빗 서브넷에 호스팅되는 애플리케이션에서 콘텐츠를 제공할 수 있습니다. 프라이빗 서브넷의 Application Load Balancer(ALB), Network Load Balancer(NLB), EC2 인스턴스를 VPC 오리진으로 사용할 수 있습니다.

다음은 VPC 오리진을 사용하려는 몇 가지 이유입니다.
+ **보안** - VPC 오리진은 프라이빗 서브넷에 로드 밸런서와 EC2 인스턴스를 배치하여 애플리케이션의 보안 태세를 강화하도록 설계되어 CloudFront를 단일 진입점으로 만듭니다. 사용자 요청은 프라이빗 보안 연결을 통해 CloudFront에서 VPC 오리진으로 이동하므로 애플리케이션의 보안을 강화합니다.
+ **관리** - VPC 오리진은 CloudFront와 오리진 간의 보안 연결에 필요한 운영 오버헤드를 줄입니다. 퍼블릭 액세스 권한이 없는 프라이빗 서브넷으로 오리진을 이동할 수 있으며, 오리진에 대한 액세스를 제한하기 위해 액세스 제어 목록(ACL) 또는 기타 메커니즘을 구현할 필요가 없습니다. 이렇게 하면 CloudFront로 웹 애플리케이션을 보호하기 위해 차별화되지 않은 개발 작업에 투자할 필요가 없습니다.
+ **확장성 및 성능** - VPC 오리진을 사용하면 웹 애플리케이션을 보호할 수 있으므로 CloudFront를 통해 보안을 개선하고 고성능 및 글로벌 확장성을 유지하면서 중요한 비즈니스 애플리케이션을 성장시키는 데 집중할 시간을 확보할 수 있습니다. VPC 오리진은 보안 관리를 간소화하고 운영 복잡성을 줄여주므로 CloudFront를 애플리케이션의 단일 진입점으로 사용할 수 있습니다.

**작은 정보**  
CloudFront는 조직에 있든 없든 간에 AWS 계정에서 VPC 오리진 공유를 지원합니다. CloudFront 콘솔에서 VPC 오리진을 공유하거나 AWS Resource Access Manager(AWS RAM)를 사용할 수 있습니다. 자세한 내용은 [CloudFront에서 공유 리소스 작업](sharing-resources.md) 섹션을 참조하세요.

## 사전 조건
<a name="vpc-origin-prerequisites"></a>

CloudFront 배포에 대한 VPC 오리진을 만들기 전에 다음을 완료해야 합니다.

### VPC 구성
<a name="vpc-configuration"></a>

VPC 오리진이 지원되는 AWS 리전 중 하나에서 **Amazon VPC를 기반으로 가상 프라이빗 클라우드(VPC)를 생성합니다**. VPC 생성에 대한 자세한 내용은 *Amazon VPC 사용 설명서*의 [VPC 및 기타 VPC 리소스 생성](https://docs.aws.amazon.com/vpc/latest/userguide/create-vpc.html#create-vpc-and-other-resources)을 참조하시기 바랍니다. 지원되는 리전 목록은 섹션을 참조하세요[VPC 오리진에서 지원되는 AWS 리전](#vpc-origins-supported-regions)

VPC에는 다음 사항이 포함되어야 합니다.
+ **인터넷 게이트웨이** - VPC 오리진 리소스가 있는 VPC에 인터넷 게이트웨이를 추가해야 합니다. 인터넷 게이트웨이는 VPC가 인터넷에서 트래픽을 수신할 수 있음을 나타내는 데 필요합니다. 인터넷 게이트웨이는 서브넷 내의 오리진으로 트래픽을 라우팅하는 데 사용되지 않으므로 라우팅 정책을 업데이트할 필요가 없습니다.
+ **사용 가능한 IPv4 주소가 최소 하나 이상인 프라이빗 서브넷** - CloudFront는 사용자가 CloudFront에서 VPC 오리진 리소스를 정의한 후 CloudFront가 생성하는 서비스 관리형 탄력적 네트워크 인터페이스(ENI)를 사용하여 서브넷으로 라우팅합니다. ENI 생성 프로세스에 성공하려면 프라이빗 서브넷에 사용 가능한 IPv4 주소가 하나 이상 있어야 합니다. IPv4 주소는 프라이빗 주소일 수 있으며 추가 비용은 없습니다. IPv6 전용 서브넷은 지원되지 않습니다.

### 오리진 리소스
<a name="origin-resources"></a>

프라이빗 서브넷에서 Application Load Balancer, Network Load Balancer, 오리진으로 사용할 EC2 인스턴스를 시작합니다. 시작하는 리소스는 완전히 배포되고 활성 상태여야 VPC 오리진에 사용할 수 있습니다.

**오리진 제한 사항:**
+ Gateway Load Balancer는 오리진으로 추가할 수 없습니다.
+ 듀얼 스택 Network Load Balancer는 오리진으로 추가할 수 없습니다.
+ TLS 리스너가 있는 Network Load Balancer는 오리진으로 추가할 수 없습니다.
+ VPC 오리진으로 사용하려면 Network Load Balancer에 보안 그룹이 연결되어 있어야 합니다.

### 보안 그룹 구성
<a name="security-group-configuration"></a>

VPC 오리진 리소스(Application Load Balancer, Network Load Balancer 또는 EC2 인스턴스)에 보안 그룹이 연결되어 있어야 합니다. VPC 오리진을 생성하면 CloudFront에서 이름 지정 패턴 `CloudFront-VPCOrigins-Service-SG`를 사용하여 서비스 관리형 보안 그룹을 자동으로 생성합니다. 이 보안 그룹은 AWS에서 완전히 관리되므로 편집해서는 안 됩니다.

CloudFront의 트래픽이 VPC 오리진에 도달하도록 허용하려면 다음 방법 중 하나를 사용하여 인바운드 트래픽을 허용하도록 오리진 리소스(ALB, NLB 또는 EC2 인스턴스)에 연결된 보안 그룹을 업데이트합니다.
+ **옵션 1:** CloudFront 관리형 접두사 목록의 트래픽을 허용합니다. 자세한 내용은 [CloudFront 관리형 접두사 목록 사용](LocationsOfEdgeServers.md#managed-prefix-list) 섹션을 참조하세요. VPC 오리진을 생성하기 전에도 이 작업을 수행할 수 있습니다.
+ **옵션 2:** CloudFront 서비스 관리형 보안 그룹(`CloudFront-VPCOrigins-Service-SG`)의 트래픽을 허용합니다. VPC 오리진이 생성되고 서비스 관리형 보안 그룹이 생성된 후에만 이 작업을 수행할 수 있습니다. 이 구성은 CloudFront 배포로만 트래픽을 제한하므로 더욱 제한적입니다.

**중요**  
이름이 `CloudFront-VPCOrigins-Service-SG`로 시작하는 자체 보안 그룹은 생성하지 마세요. 이는 서비스 관리형 보안 그룹의 AWS 예약 이름 지정 패턴입니다. 자세한 내용은 [보안 그룹 생성](https://docs.aws.amazon.com/vpc/latest/userguide/creating-security-groups.html)을 참조하세요.

### 프로토콜 및 기능 제한 사항
<a name="protocol-feature-restrictions"></a>

VPC 오리진은 다음을 지원하지 않습니다.
+ WebSockets
+ gRPC 트래픽
+ Lambda@Edge를 사용한 오리진 요청 및 오리진 응답 트리거

## VPC 오리진 생성(새 배포)
<a name="new-vpc-origin"></a>

다음 절차에서는 CloudFront 콘솔에서 새 CloudFront 배포에 대한 VPC 오리진을 만드는 방법을 보여줍니다. 또는 AWS CLI나 AWS SDK에서 [CreateVpcOrigin](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateVpcOrigin.html) 및 [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html) API 작업을 사용할 수 있습니다.

**새 CloudFront 배포에 대한 VPC 오리진을 만들려면 다음과 같이 합니다.**

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. **VPC 오리진**, **VPC 오리진 생성**을 선택합니다.

1. 필수 필드를 입력합니다. **오리진 ARN**에서 Application Load Balancer, Network Load Balancer 또는 EC2 인스턴스의 ARN을 선택합니다. ARN이 표시되지 않으면 특정 리소스 ARN을 복사하여 여기에 붙여넣을 수 있습니다.

1. **VPC 오리진 생성**을 선택합니다.

1. VPC 오리진 상태가 **배포됨**으로 변경될 때까지 기다립니다. 이 프로세스는 최대 15분이 걸릴 수 있습니다.

1. **배포**, **배포 생성**을 선택합니다.

1. **원본 도메인**의 드롭다운 목록에서 VPC 오리진 리소스를 선택합니다.

   VPC 오리진이 EC2 인스턴스인 경우 인스턴스의 **프라이빗 IP DNS 이름**을 복사하여 **원본 도메인** 필드에 붙여넣습니다.

1. 배포 생성을 완료합니다. 자세한 내용은 [콘솔에서 CloudFront 배포 생성](distribution-web-creating-console.md#create-console-distribution) 섹션을 참조하세요.

## VPC 오리진 생성(기존 배포)
<a name="existing-vpc-origin"></a>

다음 절차에서는 CloudFront 콘솔에서 기존 CloudFront 배포에 대한 VPC 오리진을 만드는 방법을 보여줍니다. 이를 통해 애플리케이션의 지속적인 가용성을 보장할 수 있습니다. 또는 AWS CLI나 AWS SDK와 함께 [CreateVpcOrigin](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateVpcOrigin.html) 및 [UpdateDistributionWithStagingConfig](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistributionWithStagingConfig.html) API 작업을 사용할 수 있습니다.

필요에 따라 스테이징 배포를 만들지 않고 기존 배포에 VPC 오리진을 추가하도록 선택할 수 있습니다.

**기존 CloudFront 배포에 대한 VPC 오리진을 만들려면 다음과 같이 합니다.**

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. **VPC 오리진**, **VPC 오리진 생성**을 선택합니다.

1. 필수 필드를 입력합니다. **오리진 ARN**에서 Application Load Balancer, Network Load Balancer 또는 EC2 인스턴스의 ARN을 선택합니다. ARN이 표시되지 않으면 특정 리소스 ARN을 복사하여 여기에 붙여넣을 수 있습니다.

1. **VPC 오리진 생성**을 선택합니다.

1. VPC 오리진 상태가 **배포됨**으로 변경될 때까지 기다립니다. 이 프로세스는 최대 15분이 걸릴 수 있습니다.

1. 탐색 창에서 **Distributions(배포)**를 선택합니다.

1. 배포 ID를 선택합니다.

1. **일반** 탭의 **지속적 배포**에서 **스테이징 배포 생성**을 선택합니다. 자세한 내용은 [CloudFront 지속적 배포를 사용하여 CDN 구성 변경을 안전하게 테스트](continuous-deployment.md) 섹션을 참조하세요.

1. **스테이징 배포 생성** 마법사의 단계에 따라 스테이징 배포를 만듭니다. 다음 단계를 포함합니다.
   + **오리진**에서 **원본 생성**을 선택합니다.
   + **원본 도메인**의 드롭다운 메뉴에서 VPC 오리진 리소스를 선택합니다.

     VPC 오리진이 EC2 인스턴스인 경우 인스턴스의 **프라이빗 IP DNS 이름**을 복사하여 **원본 도메인** 필드에 붙여넣습니다.
   + **오리진 생성(Create Origin)**을 선택합니다.

1. 스테이징 배포에서 VPC 오리진을 테스트합니다.

1. 스테이징 배포 구성을 기본 배포로 승격합니다. 자세한 내용은 [스테이징 배포 구성 승격](working-with-staging-distribution-continuous-deployment-policy.md#promote-staging-distribution-configuration) 섹션을 참조하세요.

1. 서브넷을 프라이빗으로 설정하여 VPC 오리진에 대한 퍼블릭 액세스를 제거합니다. 이렇게 하면 인터넷을 통해 VPC 오리진을 검색할 수 없지만 CloudFront는 여전히 프라이빗 액세스 권한을 갖습니다. 자세한 내용은 *Amazon VPC 사용 설명서*의 [서브넷을 라우팅 테이블과 연결 또는 연결 해제](https://docs.aws.amazon.com/vpc/latest/userguide/WorkWithRouteTables.html#AssociateSubnet)를 참조하시기 바랍니다.

## VPC 오리진 업데이트
<a name="update-vpc-origin"></a>

다음 절차에서는 CloudFront 콘솔에서 CloudFront 배포의 VPC 오리진을 업데이트하는 방법을 보여줍니다. 또는 AWS CLI나 AWS SDK와 함께 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html) 및 [UpdateVpcOrigin](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateVpcOrigin.html) API 작업을 사용할 수 있습니다.

**CloudFront 배포의 기존 VPC 오리진을 업데이트하려면 다음과 같이 합니다.**

1. [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **Distributions(배포)**를 선택합니다.

1. 배포 ID를 선택합니다.

1. **동작** 탭을 선택합니다.

1. VPC 오리진이 캐시 동작의 기본 오리진인지 여부를 확인합니다.

1. **오리진** 탭을 선택합니다.

1. 업데이트할 VPC 오리진을 선택하고 **삭제**를 선택합니다. 이렇게 하면 배포에서 VPC 오리진의 연결이 해제됩니다. 2\$17단계를 반복하여 VPC 오리진을 다른 배포에서 연결 해제합니다.

1. **VPC 오리진**을 선택합니다.

1. VPC 오리진을 선택하고 **편집**을 선택합니다.

1. 업데이트를 수행하고 **VPC 오리진 업데이트**를 선택합니다.

1. VPC 오리진 상태가 **배포됨**으로 변경될 때까지 기다립니다. 이 프로세스는 최대 15분이 걸릴 수 있습니다.

1. 탐색 창에서 **Distributions(배포)**를 선택합니다.

1. 배포 ID를 선택합니다.

1. **오리진** 탭을 선택합니다.

1. **오리진 생성(Create Origin)**을 선택합니다.

1. **원본 도메인**의 드롭다운 메뉴에서 VPC 오리진 리소스를 선택합니다.

   VPC 오리진이 EC2 인스턴스인 경우 인스턴스의 **프라이빗 IP DNS 이름**을 복사하여 **원본 도메인** 필드에 붙여넣습니다.

1. **오리진 생성(Create Origin)**을 선택합니다. 이렇게 하면 VPC 오리진이 배포와 다시 연결됩니다. 12\$117단계를 반복하여 업데이트된 VPC 오리진을 다른 배포와 연결합니다.

## VPC 오리진에서 지원되는 AWS 리전
<a name="vpc-origins-supported-regions"></a>

VPC 오리진은 현재 다음 상업용 AWS 리전에서 지원됩니다. 가용 영역(AZ) 예외가 기록됩니다.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/private-content-vpc-origins.html)

# Application Load Balancer에 대한 액세스 제한
<a name="restrict-access-to-load-balancer"></a>

Amazon CloudFront에서는 내부 및 인터넷 연결 Application Load Balancer를 모두 사용할 수 있습니다. VPC 오리진을 사용하여 CloudFront의 프라이빗 서브넷 내에서 내부 Application Load Balancer를 사용할 수 있습니다. CloudFront VPC 오리진을 사용하면 퍼블릭 인터넷에 노출시키지 않고 프라이빗 VPC 서브넷에 호스팅된 애플리케이션에서 콘텐츠를 제공할 수 있습니다. 자세한 내용은 [VPC 오리진으로 액세스 제한](private-content-vpc-origins.md) 섹션을 참조하세요.

CloudFront에서 인터넷 연결 Application Load Balancer를 사용하는 경우 다음 보안 완화 조치를 사용하여 사용자가 Application Load Balancer에 직접 액세스하지 못하도록 하고 CloudFront를 통한 액세스만 허용할 수 있습니다.

1. Application Load Balancer로 보내는 요청에 사용자 지정 HTTP 헤더를 추가하도록 CloudFront를 구성합니다.

1. 사용자 지정 HTTP 헤더가 포함된 요청만 전달하도록 Application Load Balancer를 구성합니다.

1. HTTPS를 사용하도록 하여 이 솔루션의 보안을 강화합니다.

CloudFront는 지연 시간을 줄이고 일부 분산 서비스 거부(DDoS) 공격을 완화하는 데 도움이 됩니다.

사용 사례에 따라 인터넷을 통해 직접 CloudFront와 Application Load Balancer 모두에서 웹 애플리케이션에 이중 액세스해야 하는 경우 다음과 같이 웹 애플리케이션 API를 분할하는 것이 좋습니다.
+ CloudFront를 통과해야 하는 API. 이 경우 별도의 프라이빗 Application Load Balancer를 오리진으로 사용하는 것이 좋습니다.
+ Application Load Balancer를 통해 액세스해야 하는 API. 이 경우 CloudFront를 우회합니다.

또한 CloudFront는 Elastic Load Balancing에서 인터넷 경계 Application Load Balancer를 통해 제공되는 웹 애플리케이션 또는 기타 콘텐츠의 객체를 캐싱하고 사용자(뷰어)에게 직접 제공하여 Application Load Balancer의 로드를 줄입니다. 인터넷 경계 로드 밸런서는 공개적으로 확인 가능한 DNS 이름이 있으며 인터넷을 통해 클라이언트의 요청을 대상으로 라우팅합니다.

자세한 내용은 다음 항목을 참조하세요. 이 단계를 완료하면 사용자가 CloudFront를 통해서만 Application Load Balancer에 액세스할 수 있습니다.

**Topics**
+ [사용자 지정 HTTP 헤더를 요청에 추가하도록 CloudFront 구성](#restrict-alb-add-custom-header)
+ [특정 헤더가 포함된 요청만 전달하도록 Application Load Balancer 구성](#restrict-alb-route-based-on-header)
+ [(선택 사항) 이 솔루션의 보안 강화](#restrict-alb-improve-security)
+ [(선택 사항) CloudFront의 AWS-managed 접두사 목록을 사용하여 오리진에 대한 액세스를 제한합니다.](#limit-access-to-origin-using-aws-managed-prefixes)

## 사용자 지정 HTTP 헤더를 요청에 추가하도록 CloudFront 구성
<a name="restrict-alb-add-custom-header"></a>

오리진(이 경우 Application Load Balancer)으로 보내는 요청에 사용자 지정 HTTP 헤더를 추가하도록 CloudFront를 구성할 수 있습니다.

**중요**  
이 사용 사례에서는 사용자 지정 헤더의 이름과 값을 기밀로 유지해야 합니다. 헤더 이름과 값을 기밀로 유지하지 않으면 다른 HTTP 클라이언트에서 Application Load Balancer로 직접 보내는 요청에 헤더 이름과 값을 포함할 수 있습니다. 그러면 Application Load Balancer가 CloudFront의 요청이 아닌 것을 CloudFront의 요청처럼 처리할 수 있습니다. 이를 방지하려면 사용자 정의 헤더의 이름과 값을 기밀로 유지해야 합니다.

CloudFront 콘솔, CloudFormation 또는 CloudFront API를 사용하여 오리진 요청에 사용자 지정 HTTP 헤더를 추가하도록 CloudFront를 구성할 수 있습니다.

**사용자 지정 HTTP 헤더를 추가하려면(CloudFront 콘솔)**  
CloudFront 콘솔에서 **오리진 설정**의 **오리진 사용자 지정 헤더** 설정을 사용합니다. **헤더 이름** 및 해당 **값**을 입력합니다.  
프로덕션 환경에서는 무작위로 생성된 헤더 이름과 값을 사용합니다. 헤더 이름과 값은 사용자 이름 및 암호와 같은 보안 자격 증명으로 취급합니다.
기존 CloudFront 배포에 대한 오리진을 생성 또는 편집할 때와 새 배포를 생성할 때 **오리진 사용자 지정 헤더** 설정을 편집할 수 있습니다. 자세한 내용은 [배포 업데이트](HowToUpdateDistribution.md) 및 [배포 생성](distribution-web-creating-console.md)(을)를 참조하세요.

**사용자 지정 HTTP 헤더 추가(CloudFormation)**  
CloudFormation 템플릿에서 다음 예제와 같이 `OriginCustomHeaders` 속성을 사용합니다.  
이 예제에서 헤더 이름과 값은 데모용입니다. 프로덕션 환경에서는 무작위로 생성된 값을 사용합니다. 헤더 이름과 값은 사용자 이름 및 암호와 같은 보안 자격 증명으로 취급해야 합니다.

```
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  TestDistribution:
    Type: 'AWS::CloudFront::Distribution'
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: app-load-balancer.example.com
            Id: Example-ALB
            CustomOriginConfig:
              OriginProtocolPolicy: https-only
              OriginSSLProtocols:
                - TLSv1.2
            OriginCustomHeaders:
               - HeaderName: X-Custom-Header
                 HeaderValue: random-value-1234567890
        Enabled: 'true'
        DefaultCacheBehavior:
          TargetOriginId: Example-ALB
          ViewerProtocolPolicy: allow-all
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
        PriceClass: PriceClass_All
        ViewerCertificate:
          CloudFrontDefaultCertificate: 'true'
```
자세한 내용은 AWS CloudFormation사용 설명서의 [오리진](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origin.html) 및 [OriginCustomHeader](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origincustomheader.html) 속성을 참조합니다.**

**사용자 지정 HTTP 헤더를 추가하려면(CloudFront API)**  
CloudFront API에서 `CustomHeaders` 안에 `Origin` 객체를 사용합니다. 자세한 내용은 Amazon CloudFront API 참조의 [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html) 및 [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)과 SDK 또는 기타 API 클라이언트 설명서를 참조합니다.**

오리진 사용자 지정 헤더로 지정할 수 없는 헤더 이름이 몇 개 있습니다. 자세한 내용은 [CloudFront에서 오리진 요청에 추가할 수 없는 사용자 지정 헤더](add-origin-custom-headers.md#add-origin-custom-headers-denylist) 섹션을 참조하세요.

## 특정 헤더가 포함된 요청만 전달하도록 Application Load Balancer 구성
<a name="restrict-alb-route-based-on-header"></a>

Application Load Balancer로 보내는 요청에 사용자 지정 HTTP 헤더를 추가하도록 CloudFront를 구성([이전 섹션 참조](#restrict-alb-add-custom-header))한 후 이 사용자 지정 헤더가 포함된 요청만 전달하도록 로드 밸런서를 구성할 수 있습니다. 새 규칙을 추가하고 로드 밸런서의 리스너에서 기본 규칙을 수정하면 됩니다.

**사전 조건**  
다음 절차를 사용하려면 리스너가 하나 이상인 Application Load Balancer가 필요합니다. 아직 생성하지 않았다면 Application Load Balancer 사용 설명서에서 [Application Load Balancer 만들기](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-application-load-balancer.html)를 참조합니다.**

다음 절차에서는 HTTPS 수신기를 수정합니다. 동일한 프로세스를 사용하여 HTTP 수신기를 수정할 수 있습니다.

**Application Load Balancer 수신기의 규칙을 업데이트하려면**

1. 새 규칙을 추가합니다. [규칙 추가](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-update-rules.html#add-rule)의 지침을 따르고 다음과 같이 수정하세요.
   + CloudFront 배포의 오리진인 로드 밸런서에 규칙을 추가합니다.
   + **조건 추가**에서 **Http 헤더**를 선택합니다. CloudFront에서 오리진 사용자 지정 헤더로 추가한 HTTP 헤더 이름과 값을 지정합니다.
   + **작업 추가**에서 **다음으로 전달:**을 선택합니다. 요청을 전달할 대상 그룹을 선택합니다.

1. 로드 밸런서의 리스너에서 기본 규칙을 편집합니다. [규칙 편집](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-update-rules.html#edit-rule)의 지침을 따르고 다음과 같이 수정하세요.
   + CloudFront 배포의 오리진인 로드 밸런서의 기본 규칙을 편집합니다.
   + 기본 작업을 삭제한 다음 **작업 추가**에서 **고정 응답 반환**을 선택합니다.
   + **응답 코드**에 **403**을 입력합니다.
   + **응답 본문**에 **Access denied**를 입력합니다.

이 단계를 완료하면 2개의 규칙이 로드 밸런서 리스너에 추가됩니다. 한 규칙은 HTTP 헤더가 포함된 요청(CloudFront에서 오는 요청)을 전달합니다. 또 다른 규칙은 다른 모든 요청(CloudFront에서 오지 않은 요청)에 고정 응답을 보냅니다.

CloudFront 배포와 Application Load Balancer로 요청을 보내 솔루션이 작동하는지 확인할 수 있습니다. CloudFront에 대한 요청은 웹 애플리케이션 또는 콘텐츠를 반환하고 Application Load Balancer로 직접 전송된 요청은 일반 텍스트 메시지 `403`와 함께 `Access denied` 응답을 반환합니다.

## (선택 사항) 이 솔루션의 보안 강화
<a name="restrict-alb-improve-security"></a>

이 솔루션의 보안을 강화하려면 Application Load Balancer로 요청을 보낼 때 항상 HTTPS를 사용하도록 CloudFront 배포를 구성할 수 있습니다. 이 솔루션이 작동하려면 사용자 지정 헤더 이름과 값을 기밀로 유지해야 합니다. HTTPS를 사용하면 도청자가 헤더 이름과 값을 검색할 수 없습니다. 또한 헤더 이름과 값을 주기적으로 교체하는 것이 좋습니다.

**오리진 요청에 HTTPS 사용**  
오리진 요청에 HTTPS를 사용하도록 CloudFront를 구성하려면 **오리진 프로토콜 정책** 설정을 **HTTPS 전용**으로 설정합니다. 이 설정은 CloudFront 콘솔, CloudFormation 및 CloudFront API에서 사용할 수 있습니다. 자세한 내용은 [프로토콜(사용자 지정 오리진만 해당)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy) 섹션을 참조하세요.

오리진 요청에 HTTPS를 사용하도록 CloudFront를 구성하는 경우에도 다음이 적용됩니다.
+ 오리진 요청 정책에 따라 `Host` 헤더를 오리진에 전달하도록 CloudFront를 구성해야 합니다. [AllViewer 관리형 오리진](using-managed-origin-request-policies.md#managed-origin-request-policy-all-viewer) 요청 정책을 사용할 수 있습니다.
+ Application Load Balancer에 HTTPS 리스너가 있는지 확인합니다 ([이전 섹션](#restrict-alb-route-based-on-header) 참조). 자세한 내용은 Application Load Balancer 사용 설명서에서 [HTTPS 리스너 생성](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html)을 참조합니다.** HTTPS 리스너를 사용하려면 Application Load Balancer로 라우팅된 도메인 이름과 일치하는 SSL/TLS 인증서가 있어야 합니다.
+ CloudFront용 SSL/TLS 인증서는 AWS Certificate Manager(ACM)의 `us-east-1` AWS 리전 에서만 요청(또는 가져오기)할 수 있습니다. CloudFront는 글로벌 서비스이므로 해당 지역의 인증서를 CloudFront 배포와 관련된 모든 `us-east-1` 리전에 자동으로 배포합니다.
  + 예를 들어 `ap-southeast-2` 리전에 Application Load Balancer(ALB)가 있는 경우 `ap-southeast-2` 리전(CloudFront와 ALB 오리진 간 HTTPS 사용)과 `us-east-1` 리전(최종 사용자와 CloudFront 간 HTTPS 사용) 모두에서 SSL/TLS 인증서를 구성해야 합니다. 두 인증서는 Application Load Balancer로 라우팅되는 도메인 이름과 일치해야 합니다. 자세한 내용은 [AWS 리전 for AWS Certificate Manager](cnames-and-https-requirements.md#https-requirements-aws-region) 섹션을 참조하세요.
+ 웹 애플리케이션의 최종 사용자(*최종 사용자* 또는 *클라이언트*라고도 함)가 HTTPS를 사용할 수 있는 경우 최종 사용자의 HTTPS 연결을 기본적으로 사용하거나 요구하도록 CloudFront를 구성할 수도 있습니다. 이렇게 하려면 **뷰어 프로토콜 정책** 설정을 사용 합니다. 최종 사용자를 HTTP에서 HTTPS로 리디렉션하거나 HTTP를 사용하는 요청을 거부하도록 설정할 수 있습니다. 이 설정은 CloudFront 콘솔, CloudFormation 및 CloudFront API에서 사용할 수 있습니다. 자세한 내용은 [뷰어 프로토콜 정책](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy) 섹션을 참조하세요.

**헤더 이름과 값 교체**  
HTTPS를 사용하는 것에 더해 헤더 이름과 값을 주기적으로 교체하는 것이 좋습니다. 이 작업을 수행하는 간략한 단계는 다음과 같습니다.

1. Application Load Balancer로 보내는 요청에 추가 사용자 지정 HTTP 헤더를 추가하도록 CloudFront를 구성합니다.

1. 추가 사용자 지정 HTTP 헤더가 포함된 요청만 전달하도록 Application Load Balancer 리스너 규칙을 업데이트합니다.

1. Application Load Balancer로 보내는 요청에 원래 사용자 지정 HTTP 헤더를 추가하지 않도록 CloudFront를 구성합니다.

1. 원래 사용자 지정 HTTP 헤더가 포함된 요청을 전달하지 않도록 Application Load Balancer 리스너 규칙을 업데이트합니다.

이러한 단계를 수행하는 방법에 대한 자세한 내용은 이전 섹션을 참조하세요.

## (선택 사항) CloudFront의 AWS-managed 접두사 목록을 사용하여 오리진에 대한 액세스를 제한합니다.
<a name="limit-access-to-origin-using-aws-managed-prefixes"></a>

Application Load Balancer에 대한 액세스를 더욱 제한하려면 서비스가 AWS-managed 접두사 목록을 사용할 때만 CloudFront의 트래픽을 수락하도록 Application Load Balancer와 연결된 보안 그룹을 구성할 수 있습니다. 이렇게 하면 CloudFront에서 시작되지 않은 트래픽이 네트워크 계층(계층 3) 또는 전송 계층(계층 4)의 Application Load Balancer에 도달하는 것을 방지할 수 있습니다.

자세한 내용은 [Amazon CloudFront의 AWS-managed 접두사 목록을 사용하여 오리진에 대한 액세스 제한](https://aws.amazon.com//blogs/networking-and-content-delivery/limit-access-to-your-origins-using-the-aws-managed-prefix-list-for-amazon-cloudfront/) 블로그 게시물을 참조합니다.

# 콘텐츠의 지리적 배포 제한
<a name="georestrictions"></a>

**지리적 차단이라고도 하는 **지리적 제한을 사용하여 특정 지리적 위치에 있는 사용자가 Amazon CloudFront 배포를 통해 배포한 콘텐츠에 액세스하는 것을 차단할 수 있습니다. 지리적 제한을 사용하는 데에는 다음 두 가지 옵션이 있습니다.
+ CloudFront 지리적 제한 기능을 사용합니다. 이 옵션을 사용하면 배포와 연결된 파일 전체에 대한 액세스를 제한하고 국가 수준에서 액세스를 제한합니다.
+ 타사 지리적 위치 서비스를 사용합니다. 이 옵션을 사용하면 배포와 연결된 파일의 하위 집합에 대한 액세스를 제한하거나 국가 수준이 아닌 더욱 세분화된 범위에서 액세스를 제한합니다.

**Topics**
+ [CloudFront 지리적 제한 사용](#georestrictions-cloudfront)
+ [서드 파티 지리적 위치 서비스 사용](#georestrictions-geolocation-service)

## CloudFront 지리적 제한 사용
<a name="georestrictions-cloudfront"></a>

사용자가 콘텐츠를 요청할 경우 일반적으로 CloudFront는 사용자가 위치한 장소와 상관없이 요청한 콘텐츠를 제공합니다. 특정 지리적 위치에 있는 사용자가 콘텐츠에 액세스하는 것을 차단해야 하는 경우, CloudFront 지리적 제한 기능을 사용하여 다음 중 하나를 실행할 수 있습니다.
+ 허용 목록에 있는 승인된 국가에 있는 사용자만 콘텐츠에 액세스할 수 있도록 권한을 부여합니다.
+ 사용자가 거부 목록의 금지된 국가 중 하나에 있는 경우 액세스를 금지합니다.

예를 들어, 콘텐츠를 배포하도록 허용되지 않는 특정 국가로부터 요청이 온 경우 CloudFront 지리적 제한을 사용하여 이 요청을 차단할 수 있습니다.

**참고**  
CloudFront에서는 서드 파티 데이터베이스를 사용하여 사용자의 위치를 확인합니다. IP 주소 및 국가 간 매핑 정확도는 리전에 따라 다릅니다. 최근 테스트에 따르면 전반적인 정확도는 99.8%입니다. CloudFront에서 사용자 위치를 확인할 수 없는 경우 CloudFront는 사용자가 요청한 콘텐츠를 제공합니다.

지리적 제한이 작동하는 방식은 다음과 같습니다.

1. 리히텐슈타인에서만 콘텐츠를 배포할 권리를 보유하고 있다고 가정합니다. CloudFront 배포를 업데이트하고 리히텐슈타인만 포함된 허용 목록을 추가합니다. (또는 리히텐슈타인을 제외한 모든 국가가 포함된 거부 목록을 추가할 수도 있습니다.)

1. 모나코에 있는 사용자가 콘텐츠를 요청하고 DNS는 요청을 이탈리아 밀라노에 있는 CloudFront 엣지 로케이션으로 라우팅합니다.

1. 밀라노의 엣지 로케이션에서는 이 배포를 찾아 모나코에 있는 사용자의 콘텐츠 다운로드가 허용되지 않았음을 확인합니다.

1. CloudFront에서는 HTTP 상태 코드 `403 (Forbidden)`을 사용자에게 반환합니다.

선택적으로 CloudFront에서 사용자 지정 오류 메시지를 사용자에게 반환하도록 구성할 수 있으며, CloudFront에서 요청된 파일에 대한 오류 응답을 캐싱하려는 시간을 지정할 수 있습니다. 기본값은 10초입니다. 자세한 내용은 [특정 HTTP 상태 코드에 대한 사용자 지정 오류 페이지 생성](creating-custom-error-pages.md) 섹션을 참조하세요.

지리적 제한은 전체 배포에 적용됩니다. 하나의 제한을 콘텐츠의 특정 부분에 적용하고 또 다른 제한을 다른 부분에 적용해야 할 경우(또는 이 부분에 대한 제한이 없는 경우), 별도의 CloudFront 배포를 만들거나 [서드 파티 지리적 위치 서비스](#georestrictions-geolocation-service)를 사용해야 합니다.

CloudFront 액세스 [표준 로그](AccessLogs.md)(액세스 로그)를 사용하는 경우, `sc-status`(HTTP 상태 코드)의 값이 `403`인 로그 항목을 검색하여 CloudFront에서 거부된 요청을 식별할 수 있습니다. 그러나 표준 로그만 사용해서는 사용자의 위치에 따라 CloudFront에서 거부된 요청과 사용자가 다른 이유로 파일에 대한 액세스 권한이 없어 CloudFront에서 거부된 요청을 구별할 수 없습니다. Digital Element 또는 MaxMind와 같은 타사 지리적 위치 서비스가 있는 경우, 액세스 로그에 있는 `c-ip`(클라이언트 IP) 열의 IP 주소에 따라 요청의 위치를 식별할 수 있습니다. CloudFront 표준 로그에 대한 자세한 내용은 [액세스 로그(표준 로그)](AccessLogs.md) 단원을 참조하세요.

다음 절차는 CloudFront 콘솔을 사용하여 기존 배포에 지리적 제한을 추가하는 방법을 설명합니다. 콘솔을 사용하여 배포를 생성하는 방법에 대한 자세한 내용은 [배포 생성](distribution-web-creating-console.md) 섹션을 참조하세요.<a name="restrictions-geo-procedure"></a>

**CloudFront 웹 배포에 지리적 제한을 추가하려면(콘솔)**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **배포**를 선택한 후 업데이트하려는 배포를 선택합니다.

1. **보안** 탭을 선택한 다음 **지리적 제한**을 선택합니다.

1. **편집**을 선택합니다.

1. **허용 목록(Allow list)**을 선택하여 허용된 국가의 목록을 생성하거나 **차단 목록(Block list)**을 선택하여 차단된 국가의 목록을 생성합니다.

1. 원하는 국가를 목록에 추가한 다음 **변경 사항 저장(Save changes)**을 선택합니다.

## 서드 파티 지리적 위치 서비스 사용
<a name="georestrictions-geolocation-service"></a>

CloudFront 지리적 제한 기능을 사용하여 지정된 웹 배포를 통해 배포하는 전체 파일에 대해 국가 수준에서 콘텐츠의 배포를 제어할 수 있습니다. 국가의 경계를 따르지 않는 지리적 제한이 있는 경우 또는 해당 배포를 통해 제공하는 파일 중 일부에 대해서만 액세스를 제한하려는 경우, CloudFront와 서드 파티 지리적 위치 서비스를 조합할 수 있습니다. 이를 통해 국가에 따라서나 도시, 우편번호에 따라서는 물론이고 경도/위도에 따라서도 콘텐츠를 제어할 수 있습니다.

타사 지리적 위치 서비스를 사용하는 경우 CloudFront 서명된 URL을 사용하는 것이 좋습니다. 이렇게 하면 URL이 더 이상 유효하지 않게 된 이후의 만료 날짜 및 시간을 지정할 수 있습니다. 또한 오리진으로는 Amazon S3 버킷을 사용하는 것이 좋습니다. 이렇게 하면 CloudFront [오리진 액세스 제어](private-content-restricting-access-to-s3.md)를 사용하여 사용자가 오리진에서 콘텐츠에 직접 액세스하는 것을 차단할 수 있기 때문입니다. 서명된 URL 및 오리진 액세스 제어에 대한 자세한 내용은 [서명된 URL과 서명된 쿠키를 사용하여 프라이빗 콘텐츠 제공](PrivateContent.md) 섹션을 참조하세요.

다음 단계에서는 서드 파티 지리적 위치 서비스를 사용하여 파일에 대한 액세스를 제어하는 방법을 설명합니다.

**서드 파티 지리적 위치 서비스를 사용하여 CloudFront 배포의 파일에 대한 액세스를 제한하려면**

1. 지리적 위치 서비스를 통해 계정을 얻습니다.

1. Amazon S3 버킷에 콘텐츠를 업로드합니다.

1. 프라이빗 콘텐츠를 제공하도록 Amazon CloudFront 및 Amazon S3를 구성합니다. 자세한 내용은 [서명된 URL과 서명된 쿠키를 사용하여 프라이빗 콘텐츠 제공](PrivateContent.md) 단원을 참조하세요.

1. 다음을 수행하도록 웹 애플리케이션을 작성합니다.
   + 각 사용자 요청에 대한 IP 주소를 지리적 위치 서비스에 전송합니다.
   + 지리적 위치 서비스로부터의 반환 값을 평가하여 CloudFront에서 콘텐츠를 배포하려는 위치에 사용자가 있는지 여부를 확인합니다.
   + 사용자의 위치에 콘텐츠를 배포하려면 CloudFront 콘텐츠에 대해 서명된 URL을 생성합니다. 해당 위치에 콘텐츠를 배포하지 않으려면 HTTP 상태 코드 `403 (Forbidden)`를 사용자에게 반환합니다. 또는 사용자 지정 오류 메시지를 반환하도록 CloudFront를 구성할 수 있습니다. 자세한 내용은 [특정 HTTP 상태 코드에 대한 사용자 지정 오류 페이지 생성](creating-custom-error-pages.md) 섹션을 참조하세요.

   자세한 내용은 사용 중인 지리적 위치 서비스의 설명서를 참조하세요.

웹 서버 변수를 사용하여 웹 사이트를 방문한 사용자의 IP 주소를 가져올 수 있습니다. 다음 경고를 기록해 두세요.
+ 웹 서버가 로드 밸런서를 통해 인터넷에 연결되지 않은 경우, 웹 서버 변수를 사용하여 원격 IP 주소를 가져올 수 있습니다. 그러나 이 IP 주소는 사용자의 IP 주소와 항상 일치하지는 않으며, 사용자가 인터넷에 연결된 방법에 따라 프록시 서버의 IP 주소가 될 수도 있습니다.
+ 웹 서버가 로드 밸런서를 통해 인터넷에 연결된 경우, 웹 서버 변수에는 사용자의 IP 주소가 아닌 로드 밸런서의 IP 주소가 포함될 수 있습니다. 이러한 구성에서는 `X-Forwarded-For` HTTP 헤더의 마지막 IP 주소를 사용하는 것이 좋습니다. 이 헤더는 대개 두 개 이상의 IP 주소를 포함하고 있으며, 이들 중 대부분은 프록시나 로드 밸런서용 IP 주소입니다. 목록의 마지막 IP 주소는 사용자의 지리적 위치와 가장 관련성이 높은 주소입니다.

웹 서버가 로드 밸런서에 연결되지 않은 경우, IP 주소 스푸핑을 방지하기 위해 `X-Forwarded-For` 헤더 대신 웹 서버 변수를 사용하는 것이 좋습니다.

# 필드 수준 암호화를 사용하여 민감한 데이터 보호
<a name="field-level-encryption"></a>

Amazon CloudFront를 사용하면 HTTPS를 통해 오리진 서버에 대한 종단 간 보안 연결을 적용할 수 있습니다. 필드 레벨 암호화는 추가 보안 레이어를 추가하여 시스템 처리 전체에서 특정 데이터를 보호하고 특정 애플리케이션만 이를 볼 수 있도록 합니다.

필드 레벨 암호화를 통해 사용자가 민감한 정보를 웹 서버에 안전하게 업로드할 수 있습니다. 사용자가 제공한 민감한 정보는 사용자에게 가까운 엣지에서 암호화되고 전체 애플리케이션 스택에서 암호화를 유지하므로 데이터가 필요하고 이를 해독할 자격 증명을 보유한 애플리케이션만 이 작업을 수행할 수 있습니다.

필드 레벨 암호화를 사용하려면 CloudFront 배포를 구성하여 암호화되기를 원하는 POST 요청의 필드 세트와 암호화에 사용할 퍼블릭 키를 지정할 수 있습니다. 한 요청에서 최대 10개의 데이터 필드를 암호화할 수 있습니다. (필드 레벨 암호화된 요청의 모든 데이터를 암호화할 수는 없습니다. 암호화할 개별 필드를 지정해야 합니다.)

필드 레벨 암호화가 포함된 HTTPS 요청이 오리진에 전달될 때 요청은 오리진 애플리케이션 또는 하위 시스템 전체에 라우팅되고, 민감한 데이터는 계속 암호화되어 민감한 데이터의 침해 또는 우발적 데이터 손실의 위험을 줄입니다. 크레딧 번호에 대한 액세스를 필요로 하는 결제 처리 시스템과 같이 업무상 사유에 따라 민감한 데이터에 대한 액세스를 필요로 하는 구성 요소는 적절한 프라이빗 키를 사용하여 해독하고 데이터에 액세스할 수 있습니다.

**참고**  
필드 레벨 암호화를 사용하려면 오리진이 chunked 인코딩을 지원해야 합니다.

![\[CloudFront의 필드 레벨 암호화\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/fleoverview.png)


CloudFront 필드 레벨 암호화는 퍼블릭 키 암호화라고도 하는 비대칭 암호화를 사용합니다. CloudFront에 퍼블릭 키를 입력하면 지정한 모든 민감한 데이터가 자동적으로 암호화됩니다. CloudFront에 입력한 키는 암호화된 값의 해독에 사용할 수 없습니다. 이는 프라이빗 키만이 가능합니다.

![\[민감한 데이터만 암호화\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/encryptedfields.png)


**Topics**
+ [필드 레벨 암호화 개요](#field-level-encryption-overview)
+ [필드 레벨 암호화 설정](#field-level-encryption-setting-up)
+ [오리진의 데이터 필드 해독](#field-level-encryption-decrypt)

## 필드 레벨 암호화 개요
<a name="field-level-encryption-overview"></a>

다음 단계는 필드 레벨 암호화 설정의 개요를 제공합니다. 자세한 단계는 [필드 레벨 암호화 설정](#field-level-encryption-setting-up) 단원을 참조하세요.

1. **퍼블릭 키-프라이빗 키 페어를 가져옵니다.** CloudFront에서 필드 레벨 암호화를 설정하기 전에 퍼블릭 키를 얻고 이를 추가해야 합니다.

1. **필드 레벨 암호화 프로필을 생성합니다.** CloudFront에서 생성한 필드 레벨 암호화 프로필은 암호화하고자 하는 필드를 정의합니다.

1. **필드 레벨 암호화 구성을 생성합니다.** 구성은 요청의 콘텐츠 유형 또는 쿼리 인수를 기반으로 특정 데이터 필드 암호화에 사용할 프로필을 지정합니다. 여러 시나리오에 대해 원하는 요청 전달 동작 옵션을 선택할 수도 있습니다. 예를 들어 요청 URL의 쿼리 인수로 지정된 프로파일 이름이 CloudFront에 없는 경우에 대한 동작을 설정할 수 있습니다.

1. **캐시 동작에 연결합니다.** 배포에 대한 캐시 동작의 구성을 연결하여 CloudFront가 데이터를 암호화할 시기를 지정합니다.

## 필드 레벨 암호화 설정
<a name="field-level-encryption-setting-up"></a>

다음 단계를 따라 필드 레벨 암호화 사용을 시작합니다. 필드 레벨 암호화에 대한 할당량(이전에는 제한이라고 함)에 대한 자세한 내용은 [할당량](cloudfront-limits.md) 단원을 참조하세요.
+ [1단계: RSA 키 페어 생성](#field-level-encryption-setting-up-step1)
+ [2단계: CloudFront에 퍼블릭 키 추가](#field-level-encryption-setting-up-step2)
+ [3단계: 필드 레벨 암호화 프로필 생성](#field-level-encryption-setting-up-step3)
+ [4단계: 구성 생성](#field-level-encryption-setting-up-step4)
+ [5단계: 캐시 동작에 구성 추가](#field-level-encryption-setting-up-step5)

### 1단계: RSA 키 페어 생성
<a name="field-level-encryption-setting-up-step1"></a>

먼저, 퍼블릭 키와 프라이빗 키를 포함하는 RSA 키 페어를 생성해야 합니다. 퍼블릭 키를 사용하면 CloudFront가 데이터를 암호화할 수 있으며, 프라이빗 키를 사용하면 오리진의 구성 요소가 암호화된 필드를 해독할 수 있습니다. OpenSSL 또는 기타 도구를 사용해서 키 페어를 만들 수 있습니다. 키 크기는 2048비트여야 합니다.

예를 들어 OpenSSL을 사용하는 경우, 다음 명령으로 길이가 2048비트인 키 페어를 만들고 `private_key.pem` 파일에 저장할 수 있습니다.

```
openssl genrsa -out private_key.pem 2048
```

이렇게 만들어진 파일은 퍼블릭 키와 프라이빗 키를 모두 포함합니다. 그 파일에서 퍼블릭 키를 추출하려면 다음 명령을 실행합니다.

```
openssl rsa -pubout -in private_key.pem -out public_key.pem
```

퍼블릭 키 파일(`public_key.pem`)에는 다음 단계에서 붙여 넣는 암호화된 키 값이 포함됩니다.

### 2단계: CloudFront에 퍼블릭 키 추가
<a name="field-level-encryption-setting-up-step2"></a>

RSA 키 페어를 얻은 후 퍼블릭 키를 CloudFront에 추가합니다.<a name="field-level-encryption-setting-up-step2-procedure"></a>

**CloudFront에 퍼블릭 키를 추가하려면(콘솔)**

1. AWS Management Console에 로그인한 다음 [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home)에서 CloudFront 콘솔을 엽니다.

1. 탐색 창에서 **퍼블릭 키**를 선택합니다.

1. **Add public key(퍼블릭 키 추가)**를 선택합니다.

1. **키 이름**에 키의 고유 이름을 입력합니다. 이름은 공백을 포함할 수 없으며, 영숫자 문자, 밑줄(\$1) 및 하이픈(-)만 포함할 수 있습니다. 문자는 최대 128자입니다.

1. **Key value(키 값)**에 `-----BEGIN PUBLIC KEY-----` 및 `-----END PUBLIC KEY-----` 행을 포함한 퍼블릭 키의 암호화된 키 값을 붙여 넣습니다.

1. **설명**에 코멘트를 추가합니다(선택 사항). 예를 들어, 퍼블릭 키의 만료 날짜를 포함할 수 있습니다.

1. **추가**를 선택합니다.

이 절차의 단계를 반복하여 CloudFront에서 사용할 키를 더 추가할 수 있습니다.

### 3단계: 필드 레벨 암호화 프로필 생성
<a name="field-level-encryption-setting-up-step3"></a>

CloudFront에 하나 이상의 퍼블릭 키를 추가한 이후 CloudFront에 어떤 필드를 암호화할지 알리는 프로필을 생성합니다.<a name="field-level-encryption-setting-up-step3-procedure"></a>

**필드 레벨 암호화 프로필을 생성하려면(콘솔)**

1. 왼쪽 탐색 창에서 **Field-level encryption**(필드 레벨 암호화)을 선택합니다.

1. **Create profile(프로파일 생성)**을 선택합니다.

1. 다음 필드를 입력합니다.  
**프로필 이름**  
프로필의 고유한 이름을 입력합니다. 이름은 공백을 포함할 수 없으며, 영숫자 문자, 밑줄(\$1) 및 하이픈(-)만 포함할 수 있습니다. 문자는 최대 128자입니다.  
**퍼블릭 키 이름**  
드롭다운 목록에서, 2단계에서 CloudFront에 추가한 퍼블릭 키의 이름을 선택합니다. CloudFront는 키를 사용하여 이 프로필에서 지정한 필드를 암호화합니다.  
**공급자 이름**  
키 페어를 얻은 공급자와 같이 키를 식별하는 데 도움이 될 구문을 입력합니다. 프라이빗 키와 함께 이 정보는 애플리케이션이 데이터 필드를 해독할 때 필요합니다. 공급자 이름은 공백을 포함할 수 없으며, 영숫자 문자, 콜론(:), 밑줄(\$1) 및 하이픈(-)만 포함할 수 있습니다. 문자는 최대 128자입니다.  
**일치시킬 필드 이름 패턴**  
CloudFront에서 암호화하고자 하는 데이터 필드의 이름 또는 요청에서 데이터 필드 이름을 식별하는 패턴을 입력합니다. \$1 옵션을 사용하여 이 키를 사용하여 암호화하고자 하는 모든 필드를 추가합니다.  
필드 이름 패턴의 경우 데이터 필드의 전체 이름(예: DateOfBirth)을 입력하거나 와일드카드 문자(\$1)를 포함하여 이름의 첫 부분(예: CreditCard\$1)만을 입력할 수 있습니다. 필드 이름 패턴은 영숫자 문자, 대괄호([ 및 ]), 마침표(.), 밑줄(\$1) 및 하이픈(-)만을 포함할 수 있으며, 추가로 와일드카드 문자(\$1)를 선택적으로 포함할 수 있습니다.  
다른 필드 이름 패턴과 중첩되는 문자를 사용하지 마세요. 예를 들어, ABC\$1라는 필드 이름 패턴을 보유한 경우 또 다른 AB\$1 필드 이름 패턴을 추가할 수는 없습니다. 또한 필드 이름은 대소문자를 구분하며, 사용할 수 있는 최대 문자는 128자입니다.  
**Comment**  
(선택 사항) 이 프로필에 대한 설명을 입력합니다. 사용할 수 있는 최대 문자 수는 128자입니다.

1. 필드에 내용을 입력한 후 **Create profile(프로파일 생성)**을 선택합니다.

1. 프로필을 더 추가하고자 하는 경우 **프로필 추가**를 선택합니다.

### 4단계: 구성 생성
<a name="field-level-encryption-setting-up-step4"></a>

하나 이상의 필드 레벨 암호화 프로필을 생성한 이후, 암호화할 데이터를 포함하는 요청의 콘텐츠 유형, 암호화에 사용할 프로필, CloudFront의 암호화 처리 방법을 지정하는 기타 옵션을 지정하는 구성을 생성합니다.

예를 들어, CloudFront가 데이터를 암호화할 수 없을 때 다음 시나리오에서 CloudFront가 요청을 차단하거나 오리진으로 전달할지 여부를 지정할 수 있습니다.
+ **요청의 콘텐츠 유형이 구성에 없을 때** – 구성에 콘텐츠 유형을 추가하지 않은 경우 CloudFront가 해당 콘텐츠 유형을 포함한 요청을 데이터 필드 암호화 없이 오리진에 전달할지 아니면 요청을 차단하고 오류를 반환할지 지정할 수 있습니다.
**참고**  
구성에 콘텐츠 유형을 추가했지만 해당 유형을 사용할 프로필을 지정하지 않은 경우 CloudFront에서 해당 콘텐츠 유형을 포함한 요청을 항상 오리진으로 전달합니다.
+ **쿼리 인수에 입력된 프로필 이름이 알 수 없는 이름임** – 배포에 존재하지 않는 프로필 이름을 포함하는 `fle-profile` 쿼리 인수를 지정할 때 CloudFront가 요청을 데이터 필드 암호화 없이 오리진으로 보낼지 아니면 요청을 차단하고 오류를 반환할지 지정할 수 있습니다.

구성에서 URL에 쿼리 인수로 프로필을 입력함으로써 해당 쿼리에 대한 콘텐츠 유형으로 매핑한 프로필을 무시할지 여부를 지정할 수도 있습니다. 기본적으로 CloudFront는 콘텐츠 유형에 매핑한 프로필을 사용합니다(이를 지정한 경우). 이를 통해 기본적으로 사용할 프로필을 가질 수 있지만 다른 프로필을 적용하고자 하는 특정 요청을 정할 수도 있습니다.

예를 들어, 사용할 쿼리 인수로 (구성에 있는) **SampleProfile**을 지정할 수 있습니다. 그런 다음, `https://d1234.cloudfront.net?fle-profile=SampleProfile` 대신 URL `https://d1234.cloudfront.net`을 사용하여 CloudFront가 요청의 콘텐츠 유형에 대해 설정한 프로필 대신 이 요청에서 **SampleProfile**을 사용하도록 할 수 있습니다.

단일 계정에 대해 최대 10개의 구성을 생성할 수 있으며 계정에 대한 모든 배포의 캐시 동작에 구성 중 하나를 연결할 수 있습니다.<a name="field-level-encryption-setting-up-step4-procedure"></a>

**필드 레벨 암호화 구성을 생성하려면(콘솔)**

1. **Field-level encryption(필드 레벨 암호화)** 페이지에서 **구성 만들기**를 선택합니다.

   참고: 최소 하나의 프로필을 생성하지 않은 경우 구성 생성 옵션이 표시되지 않습니다.

1. 다음 필드를 입력하여 사용할 프로필을 지정합니다. (일부 필드는 변경할 수 없습니다.)  
**콘텐츠 유형(변경할 수 없음)**  
콘텐츠 유형은 `application/x-www-form-urlencoded`로 설정되며 변경할 수 없습니다.  
**기본 프로필 ID(선택 사항)**  
드롭다운 목록 가운데 **콘텐츠 유형** 필드에서 콘텐츠 유형을 매핑하고자 하는 프로필을 선택합니다.  
**콘텐츠 형식(변경할 수 없음)**  
콘텐츠 형식은 `URLencoded`로 설정되며 변경할 수 없습니다.

1. 다음 옵션에 대한 CloudFront 기본 동작을 변경하고자 하는 경우 해당 확인란을 선택합니다.  
**요청의 콘텐츠 유형이 구성되지 않을 때 오리진으로 요청 전달**  
*요청의 콘텐츠 유형에 대해 사용할 프로필을 지정하지 않았다면* 요청이 오리진으로 이동하도록 허용할 경우 확인란을 선택합니다.  
**입력된 쿼리 인수를 포함한 콘텐츠 유형에 대한 프로필 무시**  
쿼리 인수에 입력된 프로필이 *콘텐츠 유형에 대해 지정한 프로필을 무시하도록* 허용할 경우 확인란을 선택합니다.

1. 확인란을 선택하여 쿼리 인수가 기본 프로필을 무시하도록 허용할 경우 구성에 대한 다음 추가 필드를 입력해야 합니다. 쿼리에 사용할 쿼리 인수 매핑 가운데 최대 5개를 생성할 수 있습니다.  
**쿼리 인수**  
`fle-profile` 쿼리 인수에 대해 URL에서 포함하고자 하는 값을 입력합니다. 이 값은 CloudFront에게 이 쿼리의 필드 레벨 암호화에 대한 쿼리 인수와 연결된 프로필 ID(다음 필드에서 지정)를 사용하도록 합니다.  
사용할 수 있는 최대 문자 수는 128자입니다. 값에는 공백이 포함될 수 없으며, 영숫자 문자와 다음 문자만을 사용할 수 있습니다. 대시(-), 마침표(.), 밑줄(\$1), 별표(\$1) 더하기 기호(\$1), 퍼센트(%).  
**프로필 ID**  
드롭다운 목록 가운데 **쿼리 인수**에 입력한 값과 연결하고자 하는 프로필을 선택합니다.  
**쿼리 인수에 지정된 프로필이 존재하지 않을 때 요청을 오리진에 전달**  
*쿼리 인수에서 지정된 프로필이 CloudFront에서 정의되지 않은 경우* 요청이 오리진으로 이동하도록 허용할 경우 확인란을 선택합니다.

### 5단계: 캐시 동작에 구성 추가
<a name="field-level-encryption-setting-up-step5"></a>

필드 레벨 암호화를 사용하려면 배포에 대한 값으로 구성 ID를 추가함으로써 배포에 대한 캐시 동작과 구성을 연결합니다.

**중요**  
필드 레벨 암호화 구성을 캐시 동작에 연결하려면 항상 HTTPS를 사용하고 최종 사용자의 HTTP `POST` 및 `PUT` 요청을 수락하도록 배포를 구성해야 합니다. 즉, 다음 조건이 충족되어야 합니다.  
캐시 동작의 **Viewer Protocol Policy(최종 사용자 프로토콜 정책)**을 **Redirect HTTP to HTTPS(HTTP에서 HTTPS로 리디렉션)** 또는 **HTTPS Only(HTTPS만)**로 설정해야 합니다. (CloudFormation 또는 CloudFront API에서는 `ViewerProtocolPolicy`를 `redirect-to-https` 또는 `https-only`로 설정해야 합니다.)
캐시 동작의 **Allowed HTTP Methods(허용되는 HTTP 메서드)**를 **GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE**로 설정해야 합니다. (CloudFormation 또는 CloudFront API에서 `AllowedMethods`를 `GET`, `HEAD`, `OPTIONS`, `PUT`, `POST`, `PATCH`, `DELETE`로 설정해야 합니다. 이러한 값은 임의의 순서로 지정할 수 있습니다.)
오리진 설정의 **Origin Protocol Policy(오리진 프로토콜 정책)**를 **Match Viewer(최종 사용자와 일치)** 또는 **HTTPS Only(HTTPS만)**로 설정해야 합니다. (CloudFormation 또는 CloudFront API에서는 `OriginProtocolPolicy`를 `match-viewer` 또는 `https-only`로 설정해야 합니다.)

자세한 내용은 [모든 배포 설정 참조](distribution-web-values-specify.md) 섹션을 참조하세요.

## 오리진의 데이터 필드 해독
<a name="field-level-encryption-decrypt"></a>

CloudFront는 [AWS Encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html)를 사용하여 데이터 필드를 암호화합니다. 데이터는 애플리케이션 스택에 걸쳐 암호화를 유지하며, 이를 해독할 자격 증명을 보유한 애플리케이션만이 액세스할 수 있습니다.

암호화 이후 암호 텍스트는 base64 암호화됩니다. 애플리케이션이 오리진의 텍스트를 해독할 때 우선 암호 텍스트를 디코딩한 다음 AWS 암호화 SDK를 사용하여 데이터를 복호화해야 합니다.

다음 코드 예제는 애플리케이션이 오리진의 데이터를 해독하는 방법을 보여줍니다. 다음을 참조하세요.
+ 예제를 간소화하기 위해 이 샘플은 작업 디렉터리에 있는 파일에서 퍼블릭 및 프라이빗 키(DER 형식)를 로드합니다. 실제로는 프라이빗 키를 오프라인 하드웨어 보안 모듈과 같은 안전한 오프라인 위치에 저장하고, 퍼블릭 키를 개발 팀에 배포합니다.
+ CloudFront는 데이터를 암호화하는 동안 특정 정보를 사용하며 동일한 파라미터 세트를 오리진에서 사용하여 이를 해독해야 합니다. MasterKey를 초기화하는 동안 CloudFront가 사용하는 파라미터는 다음을 포함합니다.
  + PROVIDER\$1NAME: 필드 레벨 암호화 프로필을 생성할 때 이 값을 지정했습니다. 여기에서 동일한 값을 사용합니다.
  + KEY\$1NAME: 퍼블릭 키를 CloudFront로 업로드할 때 퍼블릭 키의 이름을 생성했으며, 프로필에서 키 이름을 지정했습니다. 여기에서 동일한 값을 사용합니다.
  + ALGORITHM: CloudFront는 `RSA/ECB/OAEPWithSHA-256AndMGF1Padding`을 암호화 알고리즘으로 사용합니다. 따라서 동일한 알고리즘을 사용하여 데이터를 해독해야 합니다.
+ 입력으로 암호 텍스트를 포함한 다음 샘플 프로그램을 실행하는 경우 암호화된 데이터가 콘솔에 출력됩니다. 자세한 내용은 AWS 암호화 SDK의 [Java 예제 코드](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/java-example-code.html)를 참조하세요.

### 샘플 코드
<a name="field-level-encryption-decrypt-sample"></a>

```
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import org.apache.commons.codec.binary.Base64;

import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.jce.JceMasterKey;

/**
 * Sample example of decrypting data that has been encrypted by CloudFront field-level encryption.
 */
public class DecryptExample {

    private static final String PRIVATE_KEY_FILENAME = "private_key.der";
    private static final String PUBLIC_KEY_FILENAME = "public_key.der";
    private static PublicKey publicKey;
    private static PrivateKey privateKey;

    // CloudFront uses the following values to encrypt data, and your origin must use same values to decrypt it.
    // In your own code, for PROVIDER_NAME, use the provider name that you specified when you created your field-level
    // encryption profile. This sample uses 'DEMO' for the value.
    private static final String PROVIDER_NAME = "DEMO";
    // In your own code, use the key name that you specified when you added your public key to CloudFront. This sample
    // uses 'DEMOKEY' for the key name.
    private static final String KEY_NAME = "DEMOKEY";
    // CloudFront uses this algorithm when encrypting data.
    private static final String ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";

    public static void main(final String[] args) throws Exception {

        final String dataToDecrypt = args[0];

        // This sample uses files to get public and private keys.
        // In practice, you should distribute the public key and save the private key in secure storage.
        populateKeyPair();

        System.out.println(decrypt(debase64(dataToDecrypt)));
    }

    private static String decrypt(final byte[] bytesToDecrypt) throws Exception {
        // You can decrypt the stream only by using the private key.

        // 1. Instantiate the SDK
        final AwsCrypto crypto = new AwsCrypto();

        // 2. Instantiate a JCE master key
        final JceMasterKey masterKey = JceMasterKey.getInstance(
                publicKey,
                privateKey,
                PROVIDER_NAME,
                KEY_NAME,
                ALGORITHM);

        // 3. Decrypt the data
        final CryptoResult <byte[], ? > result = crypto.decryptData(masterKey, bytesToDecrypt);
        return new String(result.getResult());
    }

    // Function to decode base64 cipher text.
    private static byte[] debase64(final String value) {
        return Base64.decodeBase64(value.getBytes());
    }

    private static void populateKeyPair() throws Exception {
        final byte[] PublicKeyBytes = Files.readAllBytes(Paths.get(PUBLIC_KEY_FILENAME));
        final byte[] privateKeyBytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILENAME));
        publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(PublicKeyBytes));
        privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
    }
}
```