

# 함수를 사용하여 엣지에서 사용자 지정
<a name="edge-functions"></a>

Amazon CloudFront를 사용하면 자체 코드를 작성하여 CloudFront 배포에서 HTTP 요청 및 응답을 처리하는 방법을 사용자 지정할 수 있습니다. 코드는 최종 사용자(사용자) 가까이에서 실행되어 지연 시간을 최소화하고 서버나 기타 인프라를 관리할 필요가 없습니다. 코드를 작성하여 CloudFront를 통해 흐르는 요청 및 응답을 조작하고, 기본 인증 및 권한 부여를 수행하고, 엣지에서 HTTP 응답을 생성하는 등의 작업을 수행할 수 있습니다.

CloudFront 배포에 작성하고 연결하는 코드를 *엣지 함수*라고 합니다. CloudFront는 엣지 함수를 작성하고 관리하는 두 가지 방법을 제공합니다.

**CloudFront 함수**  
지연 시간에 민감한 대규모 CDN 사용자 지정을 위해 JavaScript로 경량 함수를 작성할 수 있습니다. CloudFront 함수 런타임 환경은 밀리초 미만의 시작 시간을 제공하고 초당 수백만 건의 요청을 처리할 수 있도록 즉시 확장되며 매우 안전합니다. CloudFront 함수는 CloudFront의 기본 기능입니다. 즉, CloudFront 내에서 완전히 코드를 빌드, 테스트 및 배포할 수 있습니다.

**Lambda@Edge**  
Lambda@Edge는 더 가까운 전체 애플리케이션 로직 및 복잡한 함수에 대한 강력하면서도 유연한 서버리스 컴퓨팅을 뷰어에게 제공하는 [AWS Lambda](https://aws.amazon.com/lambda/)의 확장으로, 매우 안전합니다. Lambda@Edge 함수는 Node.js 또는 Python 런타임 환경에서 실행됩니다. 단일 AWS 리전에 함수를 게시하고, 함수를 CloudFront 배포에 연결하면 Lambda@Edge에서 자동으로 전 세계에 코드를 복제합니다.

CloudFront에서 AWS WAF를 실행하는 경우, CloudFront 함수 및 Lambda@Edge 모두에 AWS WAF 삽입 헤더를 사용할 수 있습니다. 이는 최종 사용자 및 오리진 요청과 응답에 사용할 수 있습니다.

**Topics**
+ [CloudFront Functions와 Lambda@Edge 간 차이점](edge-functions-choosing.md)
+ [CloudFront Functions를 사용하여 엣지에서 사용자 지정](cloudfront-functions.md)
+ [CloudFront 연결 함수를 사용하여 사용자 지정](customize-connections-validation-with-connection-functions.md)
+ [Lambda@Edge를 사용하여 엣지에서 사용자 지정](lambda-at-the-edge.md)
+ [엣지 함수에 대한 제한 사항](edge-functions-restrictions.md)

# CloudFront Functions와 Lambda@Edge 간 차이점
<a name="edge-functions-choosing"></a>

CloudFront 함수와 Lambda@Edge 모두 CloudFront 이벤트에 대한 응답으로 코드를 실행할 수 있는 방법을 제공합니다.

CloudFront Functions는 다음과 같은 사용 사례의 단기 실행 경량 함수에 적합합니다.
+ **캐시 키 정규화** – HTTP 요청 속성(헤더, 쿼리 문자열, 쿠키 및 URL 경로)을 변환하여 캐시 적중률을 개선할 수 있도록 최적의 [캐시 키](understanding-the-cache-key.md)를 생성합니다.
+ **헤더 조작** – 요청 또는 응답에서 HTTP 헤더를 삽입, 수정 또는 삭제합니다. 예를 들어 모든 요청에 `True-Client-IP` 헤더를 추가할 수 있습니다.
+ **URL 리디렉션 또는 다시 쓰기** – 요청 정보에 따라 뷰어를 다른 페이지로 리디렉션하거나 한 경로에서 다른 경로로 모든 요청을 다시 씁니다.
+ **요청 권한 부여** – 권한 부여 헤더 또는 다른 요청 메타데이터를 검사하여 JSON 웹 토큰(JWT)과 같은 해시된 권한 부여 토큰을 검증합니다.

CloudFront 함수를 시작하려면 [CloudFront Functions를 사용하여 엣지에서 사용자 지정](cloudfront-functions.md) 단원을 참조하세요.

Lambda@Edge는 다음과 같은 사용 사례에 적합합니다.
+ 완료하는 데 몇 밀리초 이상이 걸리는 함수
+ 조정 가능한 CPU 또는 메모리가 필요한 함수
+ 서드 파티 라이브러리(다른 AWS 서비스와의 통합을 위한 AWS SDK 포함)에 의존하는 함수
+ 처리에 외부 서비스를 사용하기 위해 네트워크 액세스가 필요한 함수
+ 파일 시스템 액세스 또는 HTTP 요청 본문에 대한 액세스가 필요한 함수

Lambda@Edge를 시작하려면 [Lambda@Edge를 사용하여 엣지에서 사용자 지정](lambda-at-the-edge.md) 단원을 참조세요.

사용 사례에 맞는 옵션을 적절히 선택할 수 있도록 다음 표를 통해 CloudFront Functions와 Lambda@Edge 간의 차이점을 파악하세요. 오리진 수정 헬퍼 메서드에 적용되는 차이점에 대한 자세한 내용은 [CloudFront Functions과 Lambda@Edge 중에서 선택](helper-functions-origin-modification.md#origin-modification-considerations) 섹션을 참조하세요.


|  | CloudFront 함수 | Lambda@Edge | 
| --- | --- | --- | 
| 프로그래밍 언어 | JavaScript(ECMAScript 5.1 호환) | Node.js 및 Python | 
| 이벤트 소스 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/edge-functions-choosing.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/edge-functions-choosing.html)  | 
|  [Amazon CloudFront KeyValueStore](kvs-with-functions.md) 지원  |  예 CloudFront KeyValueStore는 [JavaScript 런타임 2.0](functions-javascript-runtime-20.md)만 지원합니다.  |  아니요  | 
| 규모 조정 | 초당 최대 수백만 개의 요청 | 리전별 초당 최대 10,000건의 요청 | 
| 함수 지속 시간 | 서브밀리초 |  최대 30초(최종 사용자 요청 및 최종 사용자 응답) 최대 30초(오리진 요청 및 오리진 응답)  | 
|  최대 함수 메모리 크기  | 2MB |  128MB(최종 사용자 요청 및 최종 사용자 응답) 10,240MB(10GB)(오리진 요청 및 오리진 응답) 자세한 내용은 [Lambda@Edge에 대한 할당량](cloudfront-limits.md#limits-lambda-at-edge) 섹션을 참조하세요.  | 
| 함수 코드 및 포함된 라이브러리의 최대 크기 | 10KB |  50MB(뷰어 요청 및 뷰어 응답) 50MB(오리진 요청 및 오리진 응답)  | 
| 네트워크 액세스 | 아니요 | 예 | 
| 파일 시스템 액세스 | 아니요 | 예 | 
| 요청 본문에 대한 액세스 | 아니요 | 예 | 
| 위치 정보 및 장치 데이터에 대한 액세스 | 예 |  No(최종 사용자 요청 및 최종 사용자 응답) Yes(오리진 요청 및 오리진 응답)  | 
| CloudFront 내에서 완전히 빌드 및 테스트 가능 | 예 | 아니요 | 
| 함수 로깅 및 지표 | 예 | 예 | 

# CloudFront Functions를 사용하여 엣지에서 사용자 지정
<a name="cloudfront-functions"></a>

CloudFront 함수를 사용하면 지연 시간에 민감한 대규모 CDN 사용자 지정을 위해 JavaScript로 경량 함수를 작성할 수 있습니다. 함수는 CloudFront를 통해 흐르는 요청 및 응답을 조작하고, 기본 인증 및 권한 부여를 수행하고, 엣지에서 HTTP 응답을 생성하는 등의 작업을 수행할 수 있습니다. CloudFront 함수 런타임 환경은 밀리초 미만의 시작 시간을 제공하고 초당 수백만 건의 요청을 처리할 수 있도록 즉시 확장되며 매우 안전합니다. CloudFront 함수는 CloudFront의 기본 기능입니다. 즉, CloudFront 내에서 완전히 코드를 빌드, 테스트 및 배포할 수 있습니다.

CloudFront 배포를 CloudFront 함수와 연결하면 CloudFront가 CloudFront 엣지 로케이션에서 요청 및 응답을 가로채고 함수에 전달합니다. 다음 이벤트가 발생할 때 CloudFront 함수를 간접 호출할 수 있습니다.
+ CloudFront가 최종 사용자의 요청을 수신할 때(최종 사용자 요청)
+ CloudFront가 최종 사용자에게 응답을 반환하기 전(최종 사용자 응답)
+ TLS 연결 설정(연결 요청) 중 - 현재 상호 TLS(mTLS) 연결에 사용 가능

CloudFront Functions에 대한 자세한 내용은 다음 주제를 참조하세요.

**Topics**
+ [튜토리얼: CloudFront Functions를 사용하여 간단한 함수 생성](functions-tutorial.md)
+ [튜토리얼: 키 값을 포함하는 CloudFront 함수 생성](functions-tutorial-kvs.md)
+ [함수 코드 작성](writing-function-code.md)
+ [함수 생성](create-function.md)
+ [함수 테스트](test-function.md)
+ [함수 업데이트](update-function.md)
+ [함수 게시](publish-function.md)
+ [배포에 함수 연결](associate-function.md)
+ [Amazon CloudFront KeyValueStore](kvs-with-functions.md)

# 튜토리얼: CloudFront Functions를 사용하여 간단한 함수 생성
<a name="functions-tutorial"></a>

이 자습서에서는 CloudFront 함수를 시작하는 방법을 설명합니다. 뷰어를 다른 URL로 리디렉션하고 사용자 지정 응답 헤더를 반환하는 간단한 함수를 만들 수 있습니다.

**Contents**
+ [사전 조건](#functions-tutorial-prerequisites)
+ [함수 생성](#functions-tutorial-create)
+ [함수 확인](#functions-tutorial-verify)

## 사전 조건
<a name="functions-tutorial-prerequisites"></a>

CloudFront 함수를 사용하려면 CloudFront 배포가 필요합니다. 계정이 없는 경우 [CloudFront 표준 배포 시작](GettingStarted.SimpleDistribution.md) 단원을 참조하십시오.

## 함수 생성
<a name="functions-tutorial-create"></a>

CloudFront 콘솔을 사용하여 뷰어를 다른 URL로 리디렉션하고 사용자 지정 응답 헤더를 반환하는 간단한 함수를 만들 수 있습니다.

**CloudFront 함수를 생성하려면**

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

1. 탐색 창에서 **함수**를 선택한 후, **함수 생성**을 선택합니다.

1. **함수 생성** 페이지에서 **이름**에 *MyFunctionName*과 같은 함수 이름을 입력합니다.

1. (선택 사항) 설명에 **Simple test function**과 같은 기능에 대한 **설명**을 입력합니다.

1. **런타임**의 경우 선택한 기본 JavaScript 버전을 유지합니다.

1. **함수 생성**을 선택합니다.

1. 다음 함수 코드를 복사합니다. 이 함수 코드는 최종 사용자를 다른 URL로 리디렉션하고 사용자 지정 응답 헤더도 반환합니다.

   ```
   function handler(event) {
       // NOTE: This example function is for a viewer request event trigger. 
       // Choose viewer request for event trigger when you associate this function with a distribution. 
       var response = {
           statusCode: 302,
           statusDescription: 'Found',
           headers: {
               'cloudfront-functions': { value: 'generated-by-CloudFront-Functions' },
               'location': { value: 'https://aws.amazon.com/cloudfront/' }
           }
       };
       return response;
   }
   ```

1. **함수 코드**의 경우 코드를 코드 편집기에 붙여넣어 기본 코드를 대체합니다.

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

1. (선택 사항) 함수를 게시하기 전에 테스트할 수 있습니다. 이 자습서에서는 함수를 테스트하는 방법에 대해 설명하지 않습니다. 자세한 내용은 [함수 테스트](test-function.md) 섹션을 참조하세요.

1. **게시** 탭을 선택한 다음 **게시 함수**를 선택합니다. 함수를 CloudFront 배포와 연결하려면 먼저 함수를 게시해야 합니다**.

1. 다음으로 함수를 배포 또는 캐시 동작과 연결할 수 있습니다. *MyFunctionName*페이지에서 **게시** 탭을 선택합니다.
**주의**  
다음 단계에서는 테스트에 사용할 배포 또는 캐시 동작을 선택합니다. 이 테스트 함수를 프로덕션 환경에서 사용되는 배포 또는 캐시 동작과 연결하지 마세요.

1. **Add association**을 선택합니다.

1. **연결** 대화 상자에서 배포 및/또는 캐시 동작을 선택합니다. **이벤트 유형**의 경우 기본값을 유지합니다.

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

   **연결된 배포** 테이블에 연결된 배포가 표시됩니다.

1. 연결된 배포가 배포될 때까지 몇 분 정도 기다립니다. 그런 다음 배포 상태를 확인하려면 **연결된 배포** 테이블에서 해당 배포를 선택하고 **배포 보기**를 선택합니다.

   배포의 상태가 **배포됨**(Deployed)이면 함수가 작동하는지 확인할 준비가 된 것입니다.

## 함수 확인
<a name="functions-tutorial-verify"></a>

함수를 배포한 후 해당 함수가 배포에서 작동하는지 확인할 수 있습니다.

**함수를 확인하려면**

1. 웹 브라우저에서 배포의 도메인 이름(예: `https://d111111abcdef8.cloudfront.net`)으로 이동합니다.

   이 함수는 브라우저로 리디렉션을 반환하므로 브라우저가 자동으로 `https://aws.amazon.com/cloudfront/`(으)로 이동합니다.

1. 명령줄 창에서 같은 **curl** 도구를 사용하여 배포의 도메인 이름으로 요청을 보낼 수 있습니다.

   ```
   curl -v https://d111111abcdef8.cloudfront.net/
   ```

   응답에는 리디렉션 응답(`302 Found`)과 함수가 추가한 사용자 지정 응답 헤더가 표시됩니다. 응답은 다음 예와 같이 보일 수 있습니다.  
**Example**  

   ```
   curl -v https://d111111abcdef8.cloudfront.net/
   > GET / HTTP/1.1
   > Host: d111111abcdef8.cloudfront.net
   > User-Agent: curl/7.64.1
   > Accept: */*
   >
   < HTTP/1.1 302 Found
   < Server: CloudFront
   < Date: Tue, 16 Mar 2021 18:50:48 GMT
   < Content-Length: 0
   < Connection: keep-alive
   < Location: https://aws.amazon.com/cloudfront/
   < Cloudfront-Functions: generated-by-CloudFront-Functions
   < X-Cache: FunctionGeneratedResponse from cloudfront
   < Via: 1.1 3035b31bddaf14eded329f8d22cf188c.cloudfront.net (CloudFront)
   < X-Amz-Cf-Pop: PHX50-C2
   < X-Amz-Cf-Id: ULZdIz6j43uGBlXyob_JctF9x7CCbwpNniiMlmNbmwzH1YWP9FsEHg==
   ```

# 튜토리얼: 키 값을 포함하는 CloudFront 함수 생성
<a name="functions-tutorial-kvs"></a>

이 자습서에서는 CloudFront 함수를 사용하여 키 값을 포함하는 방법을 보여줍니다. 키 값은 키 값 페어의 일부입니다. 사용자는 키 값 페어의 이름을 함수 코드에 포함할 수 있습니다. 함수 실행 시 CloudFront가 이름을 값으로 대체합니다.

키 값 페어는 키 값 저장소에 저장되는 변수입니다. 함수에 하드 코딩된 값 대신 키를 사용하면 함수가 더 유연해집니다. 코드 변경 내용을 배포하지 않고도 키 값을 변경할 수 있습니다. 키 값 페어를 사용하면 함수 크기를 줄일 수도 있습니다. 자세한 내용은 [Amazon CloudFront KeyValueStore](kvs-with-functions.md) 섹션을 참조하세요.

**Contents**
+ [사전 조건](#functions-kvs-tutorial-prerequisites)
+ [키 값 저장소 생성](#functions-kvs-tutorial-kvs-step)
+ [키 값 저장소에 키 값 페어 추가](#add-key-value-pairs-to-store)
+ [키 값 저장소를 함수와 연결](#functions-kvs-tutorial-functions-step)
+ [함수 코드 테스트 및 게시](#test-and-publish-function-code)

## 사전 조건
<a name="functions-kvs-tutorial-prerequisites"></a>

CloudFront Functions 함수 및 키 값 저장소를 처음 사용하는 경우 [튜토리얼: CloudFront Functions를 사용하여 간단한 함수 생성](functions-tutorial.md)의 튜토리얼을 따르는 것이 좋습니다.

해당 튜토리얼을 완료한 후에는 이 튜토리얼을 따라 이전에 생성한 함수를 확장할 수 있습니다. 이 튜토리얼에서는 키 값 저장소를 먼저 생성하려는 것이 좋습니다.

## 키 값 저장소 생성
<a name="functions-kvs-tutorial-kvs-step"></a>

먼저 함수에 사용할 키 값 저장소를 생성합니다.

**키 값 저장소를 생성하려면**

1. 함수에 포함하려는 키 값 페어를 계획합니다. 키 이름을 적어두세요. 함수에 사용하려는 키 값 페어는 하나의 키 값 저장소에 있어야 합니다.

1. 작업 순서를 결정합니다. 다음 두 가지 방법으로 진행할 수 있습니다.
   + 키 값 저장소를 생성하고 저장소에 키 값 페어를 추가합니다. 그런 다음 함수를 생성(또는 수정)하고 키 이름을 통합합니다.
   + 또는 함수를 생성(또는 수정)하고 사용하려는 키 이름으로 통합합니다. 그런 다음 키 값 저장소를 생성하고 저장소에 키 값 페어를 추가합니다.

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

1. 탐색 창에서 **함수**를 선택한 다음 **KeyValueStores** 탭을 선택합니다.

1. **KeyValueStore 생성**을 선택하고 다음과 같이 필드를 작성합니다.
   + 저장소 이름을 입력하고 필요한 경우 설명을 입력합니다.
   + **S3 URI**를 비워 둡니다. 이 튜토리얼에서는 키 값 페어를 수동으로 입력합니다.

1. **생성(Create)**을 선택합니다. 새로운 키 값 저장소의 세부 정보 페이지가 나타납니다. 이 페이지에는 현재 비어 있는 **키 값 페어** 섹션이 포함되어 있습니다.

## 키 값 저장소에 키 값 페어 추가
<a name="add-key-value-pairs-to-store"></a>

그런 다음 이전에 생성한 키 값 저장소에 키 값 페어의 목록을 수동으로 추가합니다.

**키 값 저장소에 키 값 페어를 추가하려면**

1. **키 값 페어** 섹션에서 **키 값 페어 추가**를 선택합니다.

1. **태그 추가**를 선택한 다음 키와 값을 입력합니다. 확인 표시를 선택하여 변경 사항을 확인하고 이 단계를 반복하여 더 추가합니다.

1. 작업을 마쳤으면 **변경 사항 저장**을 선택하여 키 값 페어를 키 값 저장소에 저장합니다. 확인 대화 상자에서 **완료**를 선택합니다.

이제 키 값 페어 그룹이 포함된 키 값 저장소가 생겼습니다.



## 키 값 저장소를 함수와 연결
<a name="functions-kvs-tutorial-functions-step"></a>

이제 키 값 저장소가 생성되었습니다. 그리고 키 값 저장소의 키 이름을 포함하는 함수를 만들거나 수정했습니다. 이제 키 값 저장소와 함수를 연결할 수 있습니다. 이 연결은 함수 내에서 생성할 수 있습니다.

**키 값 저장소를 함수와 연결하려면**

1. 탐색 창에서 **함수**를 선택합니다. 기본적으로 **함수** 탭이 맨 위에 표시됩니다.

1. 함수 이름을 선택하고 **연결된 KeyValueStore** 섹션에서 **기존 KeyValueStore 연결**을 선택합니다.

1. 키 값 저장소를 선택하고 **KeyValueStore 연결**을 선택합니다.

**참고**  
각 함수에는 하나의 키 값 저장소만 연결할 수 있습니다.

## 함수 코드 테스트 및 게시
<a name="test-and-publish-function-code"></a>

키 값 저장소를 함수와 연결한 후 함수 코드를 테스트하고 게시할 수 있습니다. 다음을 수행할 때를 포함하여 함수 코드를 수정할 때마다 항상 함수 코드를 테스트해야 합니다.
+ 키 값 저장소를 함수와 연결할 때
+ 새로운 키 값 페어를 포함하도록 함수와 해당 키 값 저장소를 수정할 때
+ 키 값 페어의 값을 변경할 때

**함수 코드를 테스트하고 게시하려면**

1. 함수를 테스트하는 방법은 [함수 테스트](test-function.md) 섹션을 참조하세요. `DEVELOPMENT` 스테이지에서 함수를 테스트하도록 선택해야 합니다.

1. `LIVE` 환경에서 새 키 값 페어 또는 수정된 키 값 페어와 함께 함수를 사용할 준비가 되면 함수를 게시합니다.

   함수를 게시하면 CloudFront는 `DEVELOPMENT` 스테이지에서 라이브 스테이지로 함수 버전을 복사합니다. 함수에는 새 코드가 포함되며 키 값 저장소와 연결됩니다. 라이브 스테이지에서는 연결을 다시 수행하지 않아도 됩니다.

   함수를 게시하는 방법은 [함수 게시](publish-function.md) 섹션을 참조하세요.

# 함수 코드 작성
<a name="writing-function-code"></a>

CloudFront Functions를 사용하여 지연 시간에 민감한 대규모 CDN 사용자 지정을 위해 JavaScript로 경량 함수를 작성할 수 있습니다. 함수 코드는 CloudFront를 통해 흐르는 요청 및 응답을 조작하고, 기본 인증 및 권한 부여를 수행하고, 엣지에서 HTTP 응답을 생성하는 등의 작업을 수행할 수 있습니다.

CloudFront Functions의 함수 코드를 작성하는 데 도움을 받으려면 다음 주제를 참조하세요. 코드 예제는 [CloudFront의 CloudFront Functions 예제](service_code_examples_cloudfront_functions_examples.md) 및 GitHub의 [amazon-cloudfront-functions 리포지토리](https://github.com/aws-samples/amazon-cloudfront-functions)를 참조하시기 바랍니다.

**Topics**
+ [함수 용도 결정](function-code-choose-purpose.md)
+ [이벤트 구조](functions-event-structure.md)
+ [JavaScript 런타임 기능](functions-javascript-runtime-features.md)
+ [키 값 저장소를 위한 도우미 메서드](functions-custom-methods.md)
+ [오리진 수정용 헬퍼 메서드](helper-functions-origin-modification.md)
+ [CloudFront SaaS Manager 속성에 대한 헬퍼 메서드](saas-specific-logic-function-code.md)
+ [async 및 await 사용](async-await-syntax.md)
+ [CloudFront Functions에 대한 CWT 지원](cwt-support-cloudfront-functions.md)
+ [일반 헬퍼 메서드](general-helper-methods.md)

# 함수 용도 결정
<a name="function-code-choose-purpose"></a>

함수 코드를 작성하기 전에 함수의 용도를 결정합니다. CloudFront 함수의 대부분의 함수는 다음 용도 중 하나를 가지고 있습니다.

**Topics**
+ [뷰어 요청 이벤트 유형의 HTTP 요청 수정](#function-code-modify-request)
+ [뷰어 요청 이벤트 유형에 HTTP 응답 생성](#function-code-generate-response)
+ [뷰어 응답 이벤트 유형의 HTTP 응답 수정](#function-code-modify-response)
+ [연결 요청 이벤트 유형에서 mTLS 연결 검증](#function-code-connection-request)
+ [관련 정보](#related-information-cloudfront-functions-purpose)

함수의 용도에 관계없이 `handler`은(는) 모든 함수의 진입점입니다. CloudFront에 의해 함수에 전달되는 `event`(이)라고 하는 단일 인수가 필요합니다. `event`은(는) HTTP 요청(그리고 함수가 HTTP 응답을 수정하는 경우 응답)의 표현을 포함하는 JSON 객체입니다.

## 뷰어 요청 이벤트 유형의 HTTP 요청 수정
<a name="function-code-modify-request"></a>

함수는 CloudFront가 최종 사용자(클라이언트)로부터 수신하는 HTTP 요청을 수정하고 수정된 요청을 CloudFront로 반환하여 처리를 계속할 수 있습니다. 예를 들어 함수 코드가 [캐시 키](understanding-the-cache-key.md)를 정규화하거나 요청 헤더를 수정할 수 있습니다.

HTTP 요청을 수정하는 함수를 만들고 게시한 후 *뷰어 요청* 이벤트 유형 연결을 추가해야 합니다. 자세한 내용은 [함수 생성](functions-tutorial.md#functions-tutorial-create) 섹션을 참조하세요. 즉, 요청된 객체가 CloudFront 캐시에 있는지 여부를 확인하기 위해 점검하기 전에 CloudFront가 뷰어의 요청을 수신할 때마다 함수가 실행됩니다.

**Example 예제**  
다음 유사 코드는 HTTP 요청을 수정하는 함수의 구조를 보여줍니다.  

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

    // Modify the request object here.

    return request;
}
```
이 함수는 수정된 `request` 객체를 CloudFront로 반환합니다. CloudFront는 CloudFront 캐시에서 캐시 적중률을 확인하고 필요한 경우 오리진에 요청을 전송하여 반환된 요청을 계속 처리합니다.

## 뷰어 요청 이벤트 유형에 HTTP 응답 생성
<a name="function-code-generate-response"></a>

함수는 CloudFront에서 캐시된 응답이나 추가 처리를 확인하지 않고 엣지에서 HTTP 응답을 생성하여 최종 사용자(클라이언트)에게 직접 반환할 수 있습니다. 예를 들어 함수 코드는 요청을 새 URL로 리디렉션하거나 권한 부여를 확인하고 권한 없는 요청에 `401` 또는 `403` 응답을 반환할 수 있습니다.

HTTP 응답을 생성하는 함수를 생성할 때는 *최종 사용자 요청* 이벤트 유형을 선택해야 합니다. 즉, CloudFront가 추가 요청을 처리하기 전에 CloudFront가 최종 사용자의 요청을 수신할 때마다 함수가 실행됩니다.

**Example 예제**  
다음 유사 코드는 HTTP 응답을 생성하는 함수의 구조를 보여줍니다.  

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

    var response = ...; // Create the response object here,
                        // using the request properties if needed.

    return response;
}
```
이 함수는 CloudFront에 `response` 객체를 반환하며, CloudFront는 CloudFront 캐시를 확인하거나 오리진에 요청을 보내지 않고 즉시 최종 사용자에게 반환합니다.

## 뷰어 응답 이벤트 유형의 HTTP 응답 수정
<a name="function-code-modify-response"></a>

CloudFront가 HTTP 응답을 최종 사용자(클라이언트)에게 전송하기 전에 함수는 HTTP 응답을 수정할 수 있습니다. 응답이 CloudFront 캐시에서 왔는지 오리진에서 왔는지는 관계없습니다. 예를 들어 함수 코드에서 응답 헤더, 상태 코드 및 본문 콘텐츠를 추가하거나 수정할 수 있습니다.

HTTP 응답을 수정하는 함수를 생성할 때는 *최종 사용자 응답* 이벤트 유형을 선택해야 합니다. 즉, 응답이 CloudFront 캐시에서 왔는지 오리진에서 왔는지 관계없이 CloudFront가 최종 사용자에게 응답을 반환하기 전에 함수가 실행됩니다.

**Example 예제**  
다음 유사 코드는 HTTP 응답을 수정하는 함수의 구조를 보여줍니다.  

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

    // Modify the response object here,
    // using the request properties if needed.

    return response;
}
```
이 함수는 수정된 `response` 객체를 CloudFront로 반환하며 CloudFront는 즉시 최종 사용자에게 반환합니다.

## 연결 요청 이벤트 유형에서 mTLS 연결 검증
<a name="function-code-connection-request"></a>

연결 함수는 사용자 지정 검증 및 인증 로직을 제공하기 위해 TLS 연결 중에 실행되는 CloudFront Functions의 한 유형입니다. 연결 함수는 현재 상호 TLS(mTLS) 연결에 사용할 수 있으며, 여기서 클라이언트 인증서를 검증하고 표준 인증서 검증을 넘어 사용자 지정 인증 로직을 구현할 수 있습니다. 연결 함수는 TLS 핸드셰이크 프로세스 중에 실행되며 인증서 속성, 클라이언트 IP 주소 또는 기타 기준에 따라 연결을 허용하거나 거부할 수 있습니다.

연결 함수를 생성하고 게시한 후에는 mTLS 지원 배포에 *연결 요청* 이벤트 유형에 대한 연결을 추가해야 합니다. 이렇게 하면 클라이언트가 CloudFront와 mTLS 연결을 설정하려고 할 때마다 함수가 실행됩니다.

**Example**  
다음 의사 코드는 연결 함수의 구조를 보여줍니다.  

```
function connectionHandler(connection) {
    // Validate certificate and connection properties here.
    
    if (/* validation passes */) {
        connection.allow();
    } else {
        connection.deny();
    }
}
```
함수는 헬퍼 메서드를 사용하여 연결을 허용할지 거부할지를 결정합니다. 뷰어 요청 및 뷰어 응답 함수와 달리 연결 함수는 HTTP 요청 또는 응답을 수정할 수 없습니다.

## 관련 정보
<a name="related-information-cloudfront-functions-purpose"></a>

CloudFront Functions 작업에 대한 자세한 내용은 다음 주제를 참조하세요.
+ [이벤트 구조](functions-event-structure.md)
+ [JavaScript 런타임 기능](functions-javascript-runtime-features.md)
+ [CloudFront Functions 예제 ](service_code_examples_cloudfront_functions_examples.md)
+ [엣지 함수에 대한 제한 사항](edge-functions-restrictions.md)

# CloudFront 함수 이벤트 구조
<a name="functions-event-structure"></a>

CloudFront 함수는 함수를 실행할 때 `event` 객체를 함수 코드에 입력으로 전달합니다. [함수를 테스트](test-function.md)할 때 `event` 객체를 생성하여 함수에 전달합니다. 함수를 테스트하기 위해 `event` 객체를 생성할 때 `distributionDomainName` 객체의 `distributionId`, `requestId` 및 `context` 필드를 생략할 수 있습니다. 헤더의 이름이 소문자인지 확인합니다. CloudFront Functions가 프로덕션 환경에서 함수에 전달하는 `event` 객체의 경우 항상 소문자입니다.

다음은 이 이벤트 객체의 구조에 대한 개요를 보여 줍니다.

```
{
    "version": "1.0",
    "context": {
        <context object>
    },
    "viewer": {
        <viewer object>
    },
    "request": {
        <request object>
    },
    "response": {
        <response object>
    }
}
```

자세한 내용은 다음 항목을 참조하세요.

**Topics**
+ [버전 필드](#functions-event-structure-version)
+ [컨텍스트 객체](#functions-event-structure-context)
+ [연결 이벤트 구조](#functions-event-structure-connection)
+ [최종 사용자 객체](#functions-event-structure-viewer)
+ [요청 객체](#functions-event-structure-request)
+ [응답 객체](#functions-event-structure-response)
+ [상태 코드 및 본문](#functions-event-structure-status-body)
+ [쿼리 문자열, 헤더 및 쿠키 구조](#functions-event-structure-query-header-cookie)
+ [예시 응답 객체](#functions-response-structure-example)
+ [예시 이벤트 객체](#functions-event-structure-example)

## 버전 필드
<a name="functions-event-structure-version"></a>

`version` 필드에는 CloudFront 함수 이벤트 객체의 버전을 지정하는 문자열이 포함되어 있습니다. 현재 버전은 `1.0`입니다.

## 컨텍스트 객체
<a name="functions-event-structure-context"></a>

`context` 객체는 이벤트에 대한 컨텍스트 정보를 포함합니다. 여기에는 다음 필드가 포함됩니다.

**`distributionDomainName`**  
이벤트와 연결된 표준 배포의 CloudFront 도메인 이름(예: d111111abcdef8.cloudfront.net)입니다.  
`distributionDomainName` 필드는 함수가 표준 배포에서 호출될 때만 나타납니다.

**`endpoint`**  
이벤트와 연결된 연결 그룹의 CloudFront 도메인 이름(예: d111111abcdef8.cloudfront.net)입니다.  
`endpoint` 필드는 함수가 다중 테넌트 배포에서 호출될 때만 나타납니다.

**`distributionId`**  
이벤트와 연결된 배포의 ID(예: EDFDVBD6EXAMPLE)입니다.

**`eventType`**  
이벤트 유형(`viewer-request` 또는 `viewer-response`)입니다.

**`requestId`**  
CloudFront 요청(및 연결된 응답)을 고유하게 식별하는 문자열입니다.

## 연결 이벤트 구조
<a name="functions-event-structure-connection"></a>

연결 함수는 뷰어 함수와 다른 이벤트 구조를 수신합니다. 연결 이벤트 구조 및 응답 형식에 대한 자세한 내용은 [CloudFront 연결 함수 연결](connection-functions.md) 섹션을 참조하세요.

## 최종 사용자 객체
<a name="functions-event-structure-viewer"></a>

`viewer` 객체는 요청을 보낸 최종 사용자(클라이언트)의 IP 주소 값이 있는 `ip` 필드를 포함합니다. 최종 사용자가 HTTP 프록시 또는 로드 밸런서를 사용하여 요청을 전송한 경우 이 값은 프록시 또는 로드 밸런서의 IP 주소입니다.

## 요청 객체
<a name="functions-event-structure-request"></a>

`request` 객체는 viewer-to-CloudFront HTTP 요청의 표현을 포함합니다. 함수에 전달된 `event` 객체에서 `request` 객체는 CloudFront가 뷰어에게 받은 실제 요청을 나타냅니다.

함수 코드가 CloudFront에 `request` 객체를 반환하는 경우 동일한 구조를 사용해야 합니다.

`request` 객체는 다음 필드를 포함합니다.

**`method`**  
요청의 HTTP 메서드. 함수 코드가 `request`를 반환하면 이 필드를 수정할 수 없습니다. 이 필드는 `request` 객체에서 유일한 읽기 전용 필드입니다.

**`uri`**  
요청된 객체의 상대 경로입니다.  
함수가 `uri` 값을 수정하는 경우 다음 사항이 적용됩니다.  
+ 새 `uri` 값은 슬래시(`/`)로 시작해야 합니다.
+ 함수가 `uri` 값을 변경하는 경우 이로 인해 최종 사용자가 요청 중인 객체가 변경됩니다.
+ 함수가 `uri` 값을 변경하는 경우 이로 인해 요청 또는 요청이 전송되는 오리진에 대한 캐시 동작이 변경되지 **않습니다.

**`querystring`**  
요청의 쿼리 문자열을 나타내는 객체입니다. 요청에 쿼리 문자열이 포함되지 않더라도 `request` 객체에는 여전히 빈 `querystring` 객체가 포함됩니다.  
`querystring` 객체는 요청의 각 쿼리 문자열 파라미터에 대해 하나의 필드를 포함합니다.

**`headers`**  
요청의 HTTP 헤더를 나타내는 객체입니다. 요청에 `Cookie` 헤더가 포함되어 있으면 해당 헤더는 `headers` 객체의 일부가 아닙니다. 쿠키는 `cookies` 객체에서 별도로 표시됩니다.  
`headers` 객체는 요청의 각 헤더에 대해 하나의 필드를 포함합니다. 헤더 이름은 이벤트 객체에서 ASCII 소문자로 변환되므로 함수 코드에서 추가될 경우 헤더 이름은 ASCII 소문자여야 합니다. CloudFront Functions이 이벤트 객체를 HTTP 요청으로 다시 변환할 경우 헤더 이름이 ASCII 문자이면 헤더 이름에 있는 각 단어의 첫 글자가 대문자로 표시됩니다. CloudFront Functions은 헤더 이름의 ASCII가 아닌 기호에 변경 사항을 적용하지 않습니다. 예를 들어 `TÈst-header`는 함수 내 `tÈst-header`에 있게 됩니다. ASCII가 아닌 기호(`È`)는 변경되지 않습니다.  
단어는 하이픈(`-`)으로 구분됩니다. 예를 들어 함수 코드가 `example-header-name`이라는 이름의 헤더를 추가하는 경우, CloudFront는 이것을 HTTP 요청에서 `Example-Header-Name`으로 변환합니다.

**`cookies`**  
요청(`Cookie` 헤더)의 쿠키를 나타내는 객체입니다.  
`cookies` 객체는 요청의 각 쿠키에 대해 하나의 필드를 포함합니다.

쿼리 문자열, 헤더 및 쿠키의 구조에 대한 자세한 내용은 [쿼리 문자열, 헤더 및 쿠키 구조](#functions-event-structure-query-header-cookie) 단원을 참조하세요.

예제 `event` 객체에 대해서는 [예시 이벤트 객체](#functions-event-structure-example) 단원을 참조하세요.

## 응답 객체
<a name="functions-event-structure-response"></a>

`response` 객체는 CloudFront-to-Viewer HTTP 응답의 표현을 포함합니다. 함수에 전달된 `event` 객체에서 `response` 객체는 뷰어 요청에 대한 CloudFront의 실제 응답을 나타냅니다.

함수 코드가 `response` 객체를 반환하는 경우 이 동일한 구조를 사용해야 합니다.

`response` 객체는 다음 필드를 포함합니다.

**`statusCode`**  
응답의 HTTP 상태 코드입니다. 이 값은 문자열이 아닌 정수입니다.  
함수는 `statusCode`를 생성하거나 수정할 수 있습니다.

**`statusDescription`**  
응답의 HTTP 상태 설명입니다. 함수 코드에서 응답을 생성하는 경우 이 필드는 선택 사항입니다.

**`headers`**  
응답에서 HTTP 헤더를 나타내는 객체입니다. 응답에 `Set-Cookie` 헤더가 포함되어 있으면 해당 헤더는 `headers` 객체의 일부가 아닙니다. 쿠키는 `cookies` 객체에서 별도로 표시됩니다.  
`headers` 객체는 응답의 각 헤더에 대해 하나의 필드를 포함합니다. 헤더 이름은 이벤트 객체에서 소문자로 변환되므로, 헤더 이름은 함수 코드에 의해 추가될 때 소문자여야 합니다. CloudFront 함수가 이벤트 객체를 HTTP 응답으로 다시 변환하는 경우 헤더 이름에 있는 각 단어의 첫 글자가 대문자로 표시됩니다. 단어는 하이픈(`-`)으로 구분됩니다. 예를 들어 함수 코드가 `example-header-name`이라는 이름의 헤더를 추가하는 경우, CloudFront는 이것을 HTTP 응답에서 `Example-Header-Name`으로 변환합니다.

**`cookies`**  
응답(`Set-Cookie` 헤더)에서 쿠키를 나타내는 객체입니다.  
`cookies` 객체는 응답의 각 쿠키에 대해 하나의 필드를 포함합니다.

**`body`**  
`body` 필드 추가는 선택 사항이며 함수에서 지정하지 않는 한 `response` 객체에 표시되지 않습니다. 함수는 CloudFront 캐시 또는 오리진에서 반환된 원래 본문에 액세스할 수 없습니다. 뷰어 응답 함수에서 `body` 필드를 지정하지 않으면 CloudFront 캐시 또는 오리진에서 반환되는 원래 본문이 뷰어에게 반환됩니다.  
CloudFront에서 뷰어에게 사용자 지정 본문을 반환하도록 하려면 `data` 필드에 본문 콘텐츠를 지정하고 `encoding` 필드에 본문 인코딩을 지정하세요. 인코딩을 일반 텍스트(`"encoding": "text"`) 또는 Base64로 인코딩된 콘텐츠(`"encoding": "base64"`)로 지정할 수 있습니다.  
단축키로 `body` 필드(`"body": "<specify the body content here>"`)에서 직접 본문 콘텐츠를 지정할 수도 있습니다. 이 작업을 수행할 때는 `data` 및 `encoding` 필드를 생략하세요. 이 경우 CloudFront는 본문을 일반 텍스트로 취급합니다.    
`encoding`  
`body` 콘텐츠(`data`필드)의 인코딩입니다. 유일하게 유효한 인코딩은 `text`과 `base64`입니다.  
`encoding`을 `base64`로 지정하지만 본문이 유효한 base64가 아닌 경우 CloudFront는 오류를 반환합니다.  
`data`  
`body` 콘텐츠입니다.

수정된 상태 코드 및 본문 콘텐츠에 대한 자세한 내용은 [상태 코드 및 본문](#functions-event-structure-status-body)를 참조하세요.

헤더 및 쿠키의 구조에 대한 자세한 내용은 [쿼리 문자열, 헤더 및 쿠키 구조](#functions-event-structure-query-header-cookie) 단원을 참조하세요.

예제 `response` 객체에 대해서는 [예시 응답 객체](#functions-response-structure-example) 단원을 참조하세요.

## 상태 코드 및 본문
<a name="functions-event-structure-status-body"></a>

CloudFront Functions를 사용하여 뷰어 응답 상태 코드를 업데이트하고 응답 본문 전체를 새것으로 바꾸거나 제거할 수 있습니다. CloudFront 캐시 또는 오리진에서 응답의 여러 측면을 평가한 후 뷰어 응답을 업데이트하는 일반적인 시나리오는 다음과 같습니다.
+ 상태를 변경하여 HTTP 200 상태 코드를 설정하고 정적 본문 콘텐츠를 생성하여 뷰어에게 반환합니다.
+ 상태를 변경하여 HTTP 301 또는 302 상태 코드를 설정하고 사용자를 다른 웹 페이지로 리디렉션합니다.
+ 뷰어 응답의 본문을 제공할지 아니면 삭제할지 결정합니다.

**참고**  
오리진에서 400 이상의 HTTP 오류를 반환하는 경우 CloudFront Function이 실행되지 않습니다. 자세한 내용은 [모든 엣지 함수에 대한 제한 사항](edge-function-restrictions-all.md)을 참조하세요.

HTTP 응답 본문을 사용하여 작업 중일 때 CloudFront Functions가 응답 본문에 액세스하지 못합니다. 원하는 값으로 설정하여 본문 콘텐츠를 바꾸거나 값을 비어 있음으로 설정하여 본문을 제거할 수 있습니다. 함수의 본문 필드를 업데이트하지 않은 경우 CloudFront 캐시 또는 오리진에서 반환된 원래 본문이 뷰어에게 반환됩니다.

**작은 정보**  
CloudFront Functions를 사용하여 본문을 교체하는 경우`content-encoding`, `content-type` 또는 `content-length` 등의 해당 헤더를 새 본문 콘텐츠에 맞게 정렬해야 합니다.  
예를 들어 CloudFront 오리진 또는 캐시가 `content-encoding: gzip`을 반환하지만 뷰어 응답 함수가 일반 텍스트인 본문을 설정하는 경우 함수는 `content-encoding` 및 `content-type` 헤더도 그에 따라 변경해야 합니다.

CloudFront Function이 400 이상의 HTTP 오류를 반환하도록 구성된 경우 동일한 상태 코드에 대해 지정한 [사용자 지정 오류 페이지](creating-custom-error-pages.md)가 뷰어에게 표시되지 않습니다.

## 쿼리 문자열, 헤더 및 쿠키 구조
<a name="functions-event-structure-query-header-cookie"></a>

쿼리 문자열, 헤더 및 쿠키는 동일한 구조를 공유합니다. 쿼리 문자열은 요청에 표시될 수 있습니다. 헤더는 요청 및 응답에 표시됩니다. 쿠키는 요청 및 응답에 표시됩니다.

각 쿼리 문자열, 헤더 또는 쿠키는 상위 `querystring`, `headers` 또는 `cookies` 객체 내에서 고유한 필드입니다. 필드 이름은 쿼리 문자열, 헤더 또는 쿠키의 이름입니다. 각 필드에는 쿼리 문자열, 헤더 또는 쿠키의 값이 있는 `value` 속성이 포함됩니다.

**Contents**
+ [쿼리 문자열 값 또는 쿼리 문자열 객체](#functions-event-structure-query)
+ [헤더에 대한 특별 고려 사항](#functions-event-structure-headers)
+ [중복 쿼리 문자열, 헤더 및 쿠키(`multiValue` 배열)](#functions-event-structure-multivalue)
+ [쿠키 속성](#functions-event-structure-cookie-attributes)

### 쿼리 문자열 값 또는 쿼리 문자열 객체
<a name="functions-event-structure-query"></a>

함수는 쿼리 문자열 객체 외에도 쿼리 문자열 값을 반환할 수 있습니다. 쿼리 문자열 값을 사용하여 쿼리 문자열 파라미터를 사용자 지정 순서로 정렬할 수 있습니다.

**Example 예제**  
함수 코드에서 쿼리 문자열을 수정하려면 다음과 같은 코드를 사용합니다.  

```
var request = event.request; 
request.querystring = 'ID=42&Exp=1619740800&TTL=1440&NoValue=&querymv=val1&querymv=val2,val3';
```

### 헤더에 대한 특별 고려 사항
<a name="functions-event-structure-headers"></a>

헤더의 경우, 헤더 이름은 이벤트 객체에서 소문자로 변환되므로, 헤더 이름은 함수 코드에 의해 추가될 때 소문자여야 합니다. CloudFront 함수가 이벤트 객체를 HTTP 요청 또는 응답으로 다시 변환하는 경우 헤더 이름에 있는 각 단어의 첫 글자가 대문자로 표시됩니다. 단어는 하이픈(`-`)으로 구분됩니다. 예를 들어 함수 코드가 `example-header-name`이라는 이름의 헤더를 추가하는 경우, CloudFront는 이것을 HTTP 요청 또는 응답에서 `Example-Header-Name`으로 변환합니다.

**Example 예제**  
HTTP 요청에서 다음 `Host` 헤더를 고려합니다.  

```
Host: video.example.com
```
이 헤더는 `request` 객체에서 다음과 같이 표시됩니다.  

```
"headers": {
    "host": {
        "value": "video.example.com"
    }
}
```
함수 코드의 `Host` 헤더에 액세스하려면 다음과 같은 코드를 사용합니다.  

```
var request = event.request;
var host = request.headers.host.value;
```
함수 코드에서 헤더를 추가하거나 수정하려면 다음과 같은 코드를 사용합니다(이 코드는 `X-Custom-Header` 값이 있는 `example value`(이)라는 이름의 헤더를 추가함).  

```
var request = event.request;
request.headers['x-custom-header'] = {value: 'example value'};
```

### 중복 쿼리 문자열, 헤더 및 쿠키(`multiValue` 배열)
<a name="functions-event-structure-multivalue"></a>

HTTP 요청 또는 응답은 동일한 이름의 하나 이상의 쿼리 문자열, 헤더 또는 쿠키를 포함할 수 있습니다. 이 경우 중복 쿼리 문자열, 헤더 또는 쿠키가 `request` 또는 `response` 객체의 한 필드로 축소되지만 이 필드에는 `multiValue`(이)라는 추가 속성이 포함되어 있습니다. `multiValue` 속성에는 중복 쿼리 문자열, 헤더 또는 쿠키의 각 값이 포함된 배열이 포함됩니다.

**Example 예제**  
예를 들어 다음 `Accept` 헤더가 있는 HTTP 요청을 고려합니다.  

```
Accept: application/json
Accept: application/xml
Accept: text/html
```
이러한 헤더는 `request` 객체에 다음과 같이 표시됩니다.  

```
"headers": {
    "accept": {
        "value": "application/json",
        "multiValue": [
            {
                "value": "application/json"
            },
            {
                "value": "application/xml"
            },
            {
                "value": "text/html"
            }
        ]
    }
}
```

**참고**  
첫 번째 헤더 값(이 경우 `application/json`)은 `value` 및 `multiValue` 속성 모두에서 반복됩니다. 이렇게 하면 `multiValue` 배열을 반복하여 *모든* 값에 액세스할 수 있습니다.

함수 코드가 `multiValue` 배열이 있는 쿼리 문자열, 헤더 또는 쿠키를 수정하는 경우 CloudFront 함수는 다음 규칙을 사용하여 변경 사항을 적용합니다.

1. `multiValue` 배열이 존재하고 수정이 있으면 해당 수정이 적용됩니다. `value` 속성의 첫 번째 요소는 무시됩니다.

1. 그렇지 않으면 `value` 속성에 대한 수정 사항이 적용되고 후속 값(있는 경우)은 변경되지 않습니다.

`multiValue` 속성은 앞의 예제와 같이 HTTP 요청 또는 응답에 동일한 이름의 중복 쿼리 문자열, 헤더 또는 쿠키가 포함된 경우에만 사용됩니다. 그러나 단일 쿼리 문자열, 헤더 또는 쿠키에 값이 여러 개 있으면 `multiValue` 속성이 사용되지 않습니다.

**Example 예제**  
예를 들어 세 개의 값을 포함하는 하나의 `Accept` 헤더가 있는 요청을 고려합니다.  

```
Accept: application/json, application/xml, text/html
```
이 헤더는 `request` 객체에서 다음과 같이 표시됩니다.  

```
"headers": {
    "accept": {
        "value": "application/json, application/xml, text/html"
    }
}
```

### 쿠키 속성
<a name="functions-event-structure-cookie-attributes"></a>

HTTP 응답의 `Set-Cookie` 헤더에서 헤더에는 쿠키의 이름-값 쌍과 세미콜론으로 구분된 속성 집합이 포함됩니다.

**Example 예제**  

```
Set-Cookie: cookie1=val1; Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT
```
`response` 객체에서 이러한 속성은 쿠키 필드의 `attributes` 속성에 표시됩니다. 예를 들어, 앞의 `Set-Cookie` 헤더는 다음과 같이 표시됩니다.  

```
"cookie1": {
    "value": "val1",
    "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT"
}
```

## 예시 응답 객체
<a name="functions-response-structure-example"></a>

다음 예시는 본문이 뷰어 응답 함수로 대체된 `response` 객체(뷰어 응답 함수의 출력)를 보여줍니다.

```
{
  "response": {
    "statusCode": 200,
    "statusDescription": "OK",
    "headers": {
      "date": {
        "value": "Mon, 04 Apr 2021 18:57:56 GMT"
      },
      "server": {
        "value": "gunicorn/19.9.0"
      },
      "access-control-allow-origin": {
        "value": "*"
      },
      "access-control-allow-credentials": {
        "value": "true"
      },
      "content-type": {
        "value": "text/html"
      },
      "content-length": {
        "value": "86"
      }
    },
    "cookies": {
      "ID": {
        "value": "id1234",
        "attributes": "Expires=Wed, 05 Apr 2021 07:28:00 GMT"
      },
      "Cookie1": {
        "value": "val1",
        "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT",
        "multiValue": [
          {
            "value": "val1",
            "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT"
          },
          {
            "value": "val2",
            "attributes": "Path=/cat; Domain=example.com; Expires=Wed, 10 Jan 2021 07:28:00 GMT"
          }
        ]
      }
    },
    
    // Adding the body field is optional and it will not be present in the response object
    // unless you specify it in your function.
    // Your function does not have access to the original body returned by the CloudFront
    // cache or origin.
    // If you don't specify the body field in your viewer response function, the original
    // body returned by the CloudFront cache or origin is returned to viewer.

     "body": {
      "encoding": "text",
      "data": "<!DOCTYPE html><html><body><p>Here is your custom content.</p></body></html>"
    }
  }
}
```

## 예시 이벤트 객체
<a name="functions-event-structure-example"></a>

다음 예는 완전한 `event` 객체를 보여줍니다. 이 예제는 다중 테넌트 배포가 아닌 표준 배포에서의 호출입니다. 다중 테넌트 배포의 경우 `distributionDomainName` 대신 `endpoint` 필드가 사용됩니다. `endpoint`의 값은 이벤트와 연결된 연결 그룹의 CloudFront 도메인 이름(예: d111111abcdef8.cloudfront.net)입니다.

**참고**  
`event` 객체는 함수에 대한 입력입니다. 함수는 `request` 또는 `response` 객체만 반환하고 전체 `event` 객체는 반환하지 않습니다.

```
{
    "version": "1.0",
    "context": {
        "distributionDomainName": "d111111abcdef8.cloudfront.net",
        "distributionId": "EDFDVBD6EXAMPLE",
        "eventType": "viewer-response",
        "requestId": "EXAMPLEntjQpEXAMPLE_SG5Z-EXAMPLEPmPfEXAMPLEu3EqEXAMPLE=="
    },
    "viewer": {"ip": "198.51.100.11"},
    "request": {
        "method": "GET",
        "uri": "/media/index.mpd",
        "querystring": {
            "ID": {"value": "42"},
            "Exp": {"value": "1619740800"},
            "TTL": {"value": "1440"},
            "NoValue": {"value": ""},
            "querymv": {
                "value": "val1",
                "multiValue": [
                    {"value": "val1"},
                    {"value": "val2,val3"}
                ]
            }
        },
        "headers": {
            "host": {"value": "video.example.com"},
            "user-agent": {"value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0"},
            "accept": {
                "value": "application/json",
                "multiValue": [
                    {"value": "application/json"},
                    {"value": "application/xml"},
                    {"value": "text/html"}
                ]
            },
            "accept-language": {"value": "en-GB,en;q=0.5"},
            "accept-encoding": {"value": "gzip, deflate, br"},
            "origin": {"value": "https://website.example.com"},
            "referer": {"value": "https://website.example.com/videos/12345678?action=play"},
            "cloudfront-viewer-country": {"value": "GB"}
        },
        "cookies": {
            "Cookie1": {"value": "value1"},
            "Cookie2": {"value": "value2"},
            "cookie_consent": {"value": "true"},
            "cookiemv": {
                "value": "value3",
                "multiValue": [
                    {"value": "value3"},
                    {"value": "value4"}
                ]
            }
        }
    },
    "response": {
        "statusCode": 200,
        "statusDescription": "OK",
        "headers": {
            "date": {"value": "Mon, 04 Apr 2021 18:57:56 GMT"},
            "server": {"value": "gunicorn/19.9.0"},
            "access-control-allow-origin": {"value": "*"},
            "access-control-allow-credentials": {"value": "true"},
            "content-type": {"value": "application/json"},
            "content-length": {"value": "701"}
        },
        "cookies": {
            "ID": {
                "value": "id1234",
                "attributes": "Expires=Wed, 05 Apr 2021 07:28:00 GMT"
            },
            "Cookie1": {
                "value": "val1",
                "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT",
                "multiValue": [
                    {
                        "value": "val1",
                        "attributes": "Secure; Path=/; Domain=example.com; Expires=Wed, 05 Apr 2021 07:28:00 GMT"
                    },
                    {
                        "value": "val2",
                        "attributes": "Path=/cat; Domain=example.com; Expires=Wed, 10 Jan 2021 07:28:00 GMT"
                    }
                ]
            }
        }
    }
}
```

# CloudFront 함수에 대한 JavaScript 런타임 기능
<a name="functions-javascript-runtime-features"></a>

CloudFront Functions JavaScript 런타임 환경은 [ECMAScript(ES) 버전 5.1](https://www.ecma-international.org/ecma-262/5.1/)을 준수하며, ES 버전 6에서 12까지의 일부 기능을 지원합니다.

최신 기능을 이용하려면 JavaScript 런타임 2.0을 사용하는 것이 좋습니다.

JavaScript 1.0과 비교한 JavaScript 2.0의 변경 사항은 다음과 같습니다.
+ 버퍼 모듈 메서드 사용 가능
+ 다음과 같은 비표준 문자열 프로토타입 메서드는 사용할 수 없습니다.
  + `String.prototype.bytesFrom()`
  + `String.prototype.fromBytes()`
  + `String.prototype.fromUTF8()`
  + `String.prototype.toBytes()`
  + `String.prototype.toUTF8()`
+ 암호화 모듈의 변경 사항은 다음과 같습니다.
  + `hash.digest()` - 인코딩이 제공되지 않은 경우 반환 유형이 `Buffer`로 변경됩니다.
  + `hmac.digest()` - 인코딩이 제공되지 않은 경우 반환 유형이 `Buffer`로 변경됩니다.
+ 이 밖의 새로운 기능에 대한 자세한 내용은 [CloudFront Functions를 위한 JavaScript 런타임 2.0 기능](functions-javascript-runtime-20.md) 섹션을 참조하세요.

**Topics**
+ [JavaScript 런타임 1.0 기능](functions-javascript-runtime-10.md)
+ [JavaScript 런타임 2.0 기능](functions-javascript-runtime-20.md)

# CloudFront Functions를 위한 JavaScript 런타임 1.0 기능
<a name="functions-javascript-runtime-10"></a>

CloudFront 함수 JavaScript 런타임 환경은 [ECMAScript(ES) 버전 5.1](https://262.ecma-international.org/5.1/)을 준수하며, ES 버전 6에서 9까지의 일부 기능을 지원합니다. 또한 ES 사양의 일부가 아닌 일부 비표준 방법을 제공합니다.

다음 항목에는 지원되는 모든 언어 기능이 나열되어 있습니다.

**Topics**
+ [핵심 기능](#writing-functions-javascript-features-core)
+ [기본 객체](#writing-functions-javascript-features-primitive-objects)
+ [기본 제공 객체](#writing-functions-javascript-features-builtin-objects)
+ [오류 유형](#writing-functions-javascript-features-error-types)
+ [Globals](#writing-functions-javascript-features-globals)
+ [기본 제공 모듈](#writing-functions-javascript-features-builtin-modules)
+ [제한된 기능](#writing-functions-javascript-features-restricted-features)

## 핵심 기능
<a name="writing-functions-javascript-features-core"></a>

ES의 다음과 같은 핵심 기능이 지원됩니다.

**유형**  
모든 ES 5.1 유형이 지원됩니다. 여기에는 부울 값, 숫자, 문자열, 객체, 배열, 함수, 함수 생성자 및 정규 표현식이 포함됩니다.

**연산자**  
모든 ES 5.1 연산자가 지원됩니다.  
ES 7 거듭제곱 연산자(`**`)가 지원됩니다.

**Statement**  
`const` 및 `let` 문은 지원되지 않습니다.
다음 ES 5.1 문이 지원됩니다.  
+ `break`
+ `catch`
+ `continue`
+ `do-while`
+ `else`
+ `finally`
+ `for`
+ `for-in`
+ `if`
+ `return`
+ `switch`
+ `throw`
+ `try`
+ `var`
+ `while`
+ 레이블이 지정된 명령문

**리터럴**  
ES 6 템플릿 리터럴은 여러 줄 문자열, 표현식 보간 및 중첩 템플릿에 대해 지원됩니다..

**함수**  
모든 ES 5.1 함수 기능이 지원됩니다.  
ES 6 화살표 함수가 지원되며 ES 6 나머지 파라미터 구문이 지원됩니다.

**유니코드**  
소스 텍스트 및 문자열 리터럴에는 유니코드로 인코딩된 문자가 포함될 수 있습니다. 6자의 유니코드 코드 포인트 이스케이프 시퀀스(예: `\uXXXX`)도 지원됩니다.

**엄격 모드**  
함수는 기본적으로 엄격 모드에서 작동하므로 함수 코드에 `use strict` 명령문을 추가할 필요가 없습니다. 이것은 변경할 수 없습니다.

## 기본 객체
<a name="writing-functions-javascript-features-primitive-objects"></a>

ES의 다음과 같은 기본 객체가 지원됩니다.

**객체**  
객체에 대해 다음과 같은 ES 5.1 메서드가 지원됩니다.  
+ `create`(속성 목록 제외)
+ `defineProperties`
+ `defineProperty`
+ `freeze`
+ `getOwnPropertyDescriptor`
+ `getOwnPropertyNames`
+ `getPrototypeOf`
+ `hasOwnProperty`
+ `isExtensible`
+ `isFrozen`
+ `prototype.isPrototypeOf`
+ `isSealed`
+ `keys`
+ `preventExtensions`
+ `prototype.propertyIsEnumerable`
+ `seal`
+ `prototype.toString`
+ `prototype.valueOf`
객체에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `assign`
+ `is`
+ `prototype.setPrototypeOf`
객체에 대해 다음과 같은 ES 8 메서드가 지원됩니다.  
+ `entries`
+ `values`

**문자열**  
문자열에 대해 다음 ES 5.1 메서드가 지원됩니다.  
+ `fromCharCode`
+ `prototype.charAt`
+ `prototype.concat`
+ `prototype.indexOf`
+ `prototype.lastIndexOf`
+ `prototype.match`
+ `prototype.replace`
+ `prototype.search`
+ `prototype.slice`
+ `prototype.split`
+ `prototype.substr`
+ `prototype.substring`
+ `prototype.toLowerCase`
+ `prototype.trim`
+ `prototype.toUpperCase`
문자열에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `fromCodePoint`
+ `prototype.codePointAt`
+ `prototype.endsWith`
+ `prototype.includes`
+ `prototype.repeat`
+ `prototype.startsWith`
문자열에 대해 다음 ES 8 메서드가 지원됩니다.  
+ `prototype.padStart`
+ `prototype.padEnd`
문자열에 대해 다음 ES 9 메서드가 지원됩니다.  
+ `prototype.trimStart`
+ `prototype.trimEnd`
문자열에 대해 다음과 같은 비표준 메서드가 지원됩니다.  
+ `prototype.bytesFrom(array | string, encoding)`

  옥텟 배열 또는 인코딩된 문자열에서 바이트 문자열을 만듭니다. 문자열 인코딩 옵션은 `hex`, `base64` 및 `base64url`입니다.
+ `prototype.fromBytes(start[, end])`

  각 바이트가 해당 유니코드 코드 포인트로 대체되는 바이트 문자열에서 유니코드 문자열을 만듭니다.
+ `prototype.fromUTF8(start[, end])`

  UTF-8 인코딩된 바이트 문자열에서 유니코드 문자열을 만듭니다. 인코딩이 올바르지 않으면 `null`이(가) 반환됩니다.
+ `prototype.toBytes(start[, end])`

  유니코드 문자열에서 바이트 문자열을 만듭니다. 모든 문자는 [0,255] 범위에 있어야 합니다. 그렇지 않은 경우 `null`이 반환됩니다.
+ `prototype.toUTF8(start[, end])`

  유니코드 문자열에서 UTF-8 인코딩된 바이트 문자열을 만듭니다.

**번호**  
숫자에 대한 모든 ES 5.1 메서드가 지원됩니다.  
숫자에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `isFinite`
+ `isInteger`
+ `isNaN`
+ `isSafeInteger`
+ `parseFloat`
+ `parseInt`
+ `prototype.toExponential`
+ `prototype.toFixed`
+ `prototype.toPrecision`
+ `EPSILON`
+ `MAX_SAFE_INTEGER`
+ `MAX_VALUE`
+ `MIN_SAFE_INTEGER`
+ `MIN_VALUE`
+ `NEGATIVE_INFINITY`
+ `NaN`
+ `POSITIVE_INFINITY`

## 기본 제공 객체
<a name="writing-functions-javascript-features-builtin-objects"></a>

ES의 다음 내장 객체가 지원됩니다.

**수학 연산**  
모든 ES 5.1 수학 메서드가 지원됩니다.  
CloudFront 함수 런타임 환경에서 `Math.random()` 구현은 함수가 실행될 때의 타임스탬프와 함께 시드된 OpenBSD `arc4random`을(를) 사용합니다.
다음 ES 6 수학 메서드가 지원됩니다.  
+ `acosh`
+ `asinh`
+ `atanh`
+ `cbrt`
+ `clz32`
+ `cosh`
+ `expm1`
+ `fround`
+ `hypot`
+ `imul`
+ `log10`
+ `log1p`
+ `log2`
+ `sign`
+ `sinh`
+ `tanh`
+ `trunc`
+ `E`
+ `LN10`
+ `LN2`
+ `LOG10E`
+ `LOG2E`
+ `PI`
+ `SQRT1_2`
+ `SQRT2`

**날짜**  
모든 ES 5.1 `Date` 기능이 지원됩니다.  
보안상의 이유로 단일 함수 실행의 수명 동안 `Date`은(는) 항상 동일한 값(함수의 시작 시간)을 반환합니다. 자세한 내용은 [제한된 기능](#writing-functions-javascript-features-restricted-features) 단원을 참조하세요.

**함수**  
`apply`, `bind` 및 `call` 메서드가 지원됩니다.  
함수 생성자는 지원되지 않습니다.

**정규식**  
모든 ES 5.1 정규 표현식 기능이 지원됩니다. 정규 표현식 언어는 Perl과 호환됩니다. ES 9 명명된 캡처 그룹이 지원됩니다.

**JSON**  
`parse` 및 `stringify`을(를) 포함하여 모든 ES 5.1 JSON 기능이 지원됩니다.

**배열**  
배열에 대해 다음 ES 5.1 메서드가 지원됩니다.  
+ `isArray`
+ `prototype.concat`
+ `prototype.every`
+ `prototype.filter`
+ `prototype.forEach`
+ `prototype.indexOf`
+ `prototype.join`
+ `prototype.lastIndexOf`
+ `prototype.map`
+ `prototype.pop`
+ `prototype.push`
+ `prototype.reduce`
+ `prototype.reduceRight`
+ `prototype.reverse`
+ `prototype.shift`
+ `prototype.slice`
+ `prototype.some`
+ `prototype.sort`
+ `prototype.splice`
+ `prototype.unshift`
배열에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `of`
+ `prototype.copyWithin`
+ `prototype.fill`
+ `prototype.find`
+ `prototype.findIndex`
배열에 대해 다음 ES 7 메서드가 지원됩니다.  
+ `prototype.includes`

**형식화된 배열**  
다음 ES 6 형식화된 배열이 지원됩니다.  
+ `Int8Array`
+ `Uint8Array`
+ `Uint8ClampedArray`
+ `Int16Array`
+ `Uint16Array`
+ `Int32Array`
+ `Uint32Array`
+ `Float32Array`
+ `Float64Array`
+ `prototype.copyWithin`
+ `prototype.fill`
+ `prototype.join`
+ `prototype.set`
+ `prototype.slice`
+ `prototype.subarray`
+ `prototype.toString`

**배열 버퍼**  
`ArrayBuffer`에 대해 메서드가 지원됩니다.  
+ `prototype.isView`
+ `prototype.slice`

**Promise**  
Promise에 대해 다음 메서드가 지원됩니다.  
+ `reject`
+ `resolve`
+ `prototype.catch`
+ `prototype.finally`
+ `prototype.then`

**crypto**  
암호화 모듈은 표준 해싱 및 HMAC(해시 기반 메시지 인증 코드) 헬퍼를 제공합니다. `require('crypto')`을(를) 사용하여 모듈을 로드할 수 있습니다. 모듈은 해당 Node.js 대응으로 정확하게 동작하는 다음과 같은 메서드를 노출합니다.  
+ `createHash(algorithm)`
+ `hash.update(data)`
+ `hash.digest([encoding])`
+ `createHmac(algorithm, secret key)`
+ `hmac.update(data)`
+ `hmac.digest([encoding])`
자세한 내용은 기본 제공 모듈 단원의 [암호화(해시 및 HMAC)](#writing-functions-javascript-features-builtin-modules-crypto)를 참조하세요.

**콘솔**  
디버깅을 위한 헬퍼 객체입니다. 로그 메시지를 기록하는 `log()` 메서드만 지원합니다.  
CloudFront 함수는 `console.log('a', 'b')`와 같은 쉼표 구문을 지원하지 않습니다. 대신 `console.log('a' + ' ' + 'b')` 형식을 사용합니다.

## 오류 유형
<a name="writing-functions-javascript-features-error-types"></a>

다음과 같은 오류 객체가 지원됩니다.
+ `Error`
+ `EvalError`
+ `InternalError`
+ `MemoryError`
+ `RangeError`
+ `ReferenceError`
+ `SyntaxError`
+ `TypeError`
+ `URIError`

## Globals
<a name="writing-functions-javascript-features-globals"></a>

`globalThis` 객체가 지원됩니다.

다음 ES 5.1 전역 함수가 지원됩니다.
+ `decodeURI`
+ `decodeURIComponent`
+ `encodeURI`
+ `encodeURIComponent`
+ `isFinite`
+ `isNaN`
+ `parseFloat`
+ `parseInt`

다음과 같은 글로벌 제약이 지원됩니다.
+ `NaN`
+ `Infinity`
+ `undefined`

## 기본 제공 모듈
<a name="writing-functions-javascript-features-builtin-modules"></a>

다음 기본 제공 모듈이 지원됩니다.

**Topics**
+ [암호화(해시 및 HMAC)](#writing-functions-javascript-features-builtin-modules-crypto)
+ [쿼리 문자열](#writing-functions-javascript-features-builtin-modules-query-string)

### 암호화(해시 및 HMAC)
<a name="writing-functions-javascript-features-builtin-modules-crypto"></a>

암호화 모듈(`crypto`)은 표준 해싱 및 HMAC(해시 기반 메시지 인증 코드) 헬퍼를 제공합니다. `require('crypto')`을(를) 사용하여 모듈을 로드할 수 있습니다. 이 모듈은 Node.js 대응물과 정확히 동일하게 동작하는 다음과 같은 메서드를 제공합니다.

**해싱 메서드**

`crypto.createHash(algorithm)`  
지정된 알고리즘(`md5`, `sha1` 또는 `sha256`)을 사용하여 해시 다이제스트를 생성하는 데 사용할 수 있는 해시 객체를 생성하고 반환합니다.

`hash.update(data)`  
지정된 `data`(으)로 해시 콘텐츠를 업데이트합니다.

`hash.digest([encoding])`  
`hash.update()`을(를) 사용하여 전달된 모든 데이터의 다이제스트를 계산합니다. 인코딩은 `hex`, `base64` 또는 `base64url`일 수 있습니다.

**HMAC 메서드**

`crypto.createHmac(algorithm, secret key)`  
지정된 `algorithm` 및 `secret key`을(를) 사용하는 HMAC 객체를 생성 및 반환합니다. 알고리즘은 `md5`, `sha1` 또는 `sha256`일 수 있습니다.

`hmac.update(data)`  
지정된 `data`(으)로 HMAC 콘텐츠를 업데이트합니다.

`hmac.digest([encoding])`  
`hmac.update()`을(를) 사용하여 전달된 모든 데이터의 다이제스트를 계산합니다. 인코딩은 `hex`, `base64` 또는 `base64url`일 수 있습니다.

### 쿼리 문자열
<a name="writing-functions-javascript-features-builtin-modules-query-string"></a>

**참고**  
[CloudFront 함수 이벤트 객체](functions-event-structure.md)는 URL 쿼리 문자열을 자동으로 구문 분석합니다. 즉, 대부분의 경우 이 모듈을 사용할 필요가 없습니다.

쿼리 문자열 모듈(`querystring`)은 URL 쿼리 문자열을 구문 분석하고 서식을 지정하는 메서드를 제공합니다. `require('querystring')`을 사용하여 모듈을 로드할 수 있습니다. 이 모듈은 다음과 같은 방법을 제공합니다.

`querystring.escape(string)`  
지정된 `string`을 URL-인코딩하여 이스케이프된 쿼리 문자열을 반환합니다. 이 방법은 `querystring.stringify()`에서 사용되며 직접 사용해서는 안 됩니다.

`querystring.parse(string[, separator[, equal[, options]]])`  
쿼리 문자열(`string`)을 구문 분석하고 객체를 반환합니다.  
`separator` 파라미터는 쿼리 문자열에서 키와 값 페어를 구분하기 위한 하위 문자열입니다. 기본 설정은 `&`입니다.  
`equal` 파라미터는 쿼리 문자열에서 키와 값을 구분하기 위한 하위 문자열입니다. 기본 설정은 `=`입니다.  
`options` 파라미터는 다음 키를 가진 객체입니다.    
`decodeURIComponent function`  
쿼리 문자열에서 백분율로 인코딩된 문자를 디코딩하는 함수입니다. 기본 설정은 `querystring.unescape()`입니다.  
`maxKeys number`  
구문 분석할 최대 키 수입니다. 기본 설정은 `1000`입니다. `0` 값을 사용하여 키 카운트 제한을 제거합니다.
기본적으로 쿼리 문자열 내의 백분율로 인코딩된 문자는 UTF-8 인코딩을 사용하는 것으로 간주됩니다. 잘못된 UTF-8 시퀀스는 `U+FFFD` 대체 문자로 대체됩니다.  
예를 들어 다음 쿼리 문자열의 경우:  

```
'name=value&abc=xyz&abc=123'
```
`querystring.parse()`의 반환 값:  

```
{
name: 'value',
abc: ['xyz', '123']
}
```
`querystring.decode()`는 `querystring.parse()`의 별칭입니다.

`querystring.stringify(object[, separator[, equal[, options]]])`  
`object`를 직렬화하고 쿼리 문자열을 반환합니다.  
`separator` 파라미터는 쿼리 문자열에서 키와 값 쌍을 구분하기 위한 하위 문자열입니다. 기본 설정은 `&`입니다.  
`equal` 파라미터는 쿼리 문자열에서 키와 값을 구분하기 위한 하위 문자열입니다. 기본 설정은 `=`입니다.  
`options` 파라미터는 다음 키를 가진 객체입니다.    
`encodeURIComponent function`  
URL에 안전하지 않은 문자를 쿼리 문자열에서 백분율 인코딩으로 변환하는 데 사용할 함수입니다. 기본 설정은 `querystring.escape()`입니다.
기본적으로 쿼리 문자열 내에서 백분율 인코딩이 필요한 문자는 UTF-8로 인코딩됩니다. 다른 인코딩을 사용하려면 `encodeURIComponent` 옵션을 지정합니다.  
예를 들어, 다음 코드의 경우:  

```
querystring.stringify({ name: 'value', abc: ['xyz', '123'], anotherName: '' });
```
반환 값:  

```
'name=value&abc=xyz&abc=123&anotherName='
```
`querystring.encode()`는 `querystring.stringify()`의 별칭입니다.

`querystring.unescape(string)`  
지정된 `string`의 URL 백분율로 인코딩된 문자를 디코딩하여 이스케이프되지 않은 쿼리 문자열을 반환합니다. 이 방법은 `querystring.parse()`에서 사용되며 직접 사용해서는 안 됩니다.

## 제한된 기능
<a name="writing-functions-javascript-features-restricted-features"></a>

다음 JavaScript 언어 기능은 보안 문제로 인해 지원되지 않거나 제한됩니다.

**동적 코드 평가**  
동적 코드 평가는 지원되지 않습니다. 시도하면 `eval()` 및 `Function` 생성자 모두 오류가 발생합니다. 예를 들어 `const sum = new Function('a', 'b', 'return a + b')`에서 오류가 발생합니다.

**타이머**  
`setTimeout()`, `setImmediate()` 및 `clearTimeout()` 함수는 지원되지 않습니다. 함수 실행 내에서 연기하거나 출력할 프로비전이 없습니다. 함수가 완료되려면 동기적으로 실행되어야 합니다.

**날짜 및 타임스탬프**  
보안상의 이유로 고해상도 타이머에 액세스할 수 없습니다. 현재 시간을 쿼리하는 모든 `Date` 메서드는 단일 함수 실행의 수명 동안 항상 동일한 값을 반환합니다. 반환된 타임 스탬프는 함수가 실행을 시작한 시간입니다. 따라서 함수에서 경과 시간을 측정할 수 없습니다.

**파일 시스템 액세스**  
파일 시스템 액세스가 없습니다. 예를 들어 Node.js에서처럼 파일 시스템 액세스를 위한 `fs` 모듈이 없습니다.

**프로세스 액세스**  
프로세스 액세스가 없습니다. 예를 들어 Node.js와는 달리 정보 액세스를 처리하기 위한 `process` 글로벌 객체가 없습니다.

**환경 변수**  
환경 변수에 액세스할 수 없습니다.  
대신 CloudFront KeyValueStore를 사용하여 CloudFront Functions에 대한 키 값 페어의 중앙 집중식 데이터 스토어를 생성할 수 있습니다. CloudFront KeyValueStore를 사용하면 코드 변경 사항을 배포할 필요 없이 구성 데이터를 동적으로 업데이트할 수 있습니다. CloudFront KeyValueStore를 사용하려면 [JavaScript 런타임 2.0](functions-javascript-runtime-20.md)을 사용해야 합니다. 자세한 내용은 [Amazon CloudFront KeyValueStore](kvs-with-functions.md) 섹션을 참조하세요.

**네트워크 액세스**  
네트워크 통화에 대한 지원이 없습니다. 예를 들어 XHR, HTTP(S) 및 소켓은 지원되지 않습니다.

# CloudFront Functions를 위한 JavaScript 런타임 2.0 기능
<a name="functions-javascript-runtime-20"></a>

CloudFront Functions JavaScript 런타임 환경은 [ECMAScript(ES) 버전 5.1](https://262.ecma-international.org/5.1/)을 준수하며, ES 버전 6에서 12까지의 일부 기능을 지원합니다. 또한 ES 사양의 일부가 아닌 일부 비표준 방법을 제공합니다. 다음 주제에는 이 런타임에서 지원되는 모든 기능이 나열되어 있습니다.

**Topics**
+ [핵심 기능](#writing-functions-javascript-features-core-20)
+ [기본 객체](#writing-functions-javascript-features-primitive-objects-20)
+ [기본 제공 객체](#writing-functions-javascript-features-builtin-objects-20)
+ [오류 유형](#writing-functions-javascript-features-error-types-20)
+ [Globals](#writing-functions-javascript-features-globals-20)
+ [기본 제공 모듈](#writing-functions-javascript-features-builtin-modules-20)
+ [제한된 기능](#writing-functions-javascript-features-restricted-features-20)

## 핵심 기능
<a name="writing-functions-javascript-features-core-20"></a>

ES의 다음과 같은 핵심 기능이 지원됩니다.

**유형**  
모든 ES 5.1 유형이 지원됩니다. 여기에는 부울 값, 숫자, 문자열, 객체, 배열, 함수, 정규 표현식이 포함됩니다.

**연산자**  
모든 ES 5.1 연산자가 지원됩니다.  
ES 7 거듭제곱 연산자(`**`)가 지원됩니다.

**Statement**  
다음 ES 5.1 문이 지원됩니다.  
+ `break`
+ `catch`
+ `continue`
+ `do-while`
+ `else`
+ `finally`
+ `for`
+ `for-in`
+ `if`
+ `label`
+ `return`
+ `switch`
+ `throw`
+ `try`
+ `var`
+ `while`
다음 ES 6 문이 지원됩니다.  
+ `const`
+ `let`
다음 ES 8 문이 지원됩니다.  
+ `async`
+ `await`
`async`, `await`, `const` 및 `let`가 JavaScript 런타임 2.0에서 지원됩니다.  
`await`는 `async` 함수 내에서만 사용할 수 있습니다. `async` 인수 및 종료는 지원되지 않습니다.

**리터럴**  
ES 6 템플릿 리터럴은 여러 줄 문자열, 표현식 보간 및 중첩 템플릿에 대해 지원됩니다..

**함수**  
모든 ES 5.1 함수 기능이 지원됩니다.  
ES 6 화살표 함수가 지원되며 ES 6 나머지 파라미터 구문이 지원됩니다.

**유니코드**  
소스 텍스트 및 문자열 리터럴에는 유니코드로 인코딩된 문자가 포함될 수 있습니다. 6자의 유니코드 코드 포인트 이스케이프 시퀀스(예: `\uXXXX`)도 지원됩니다.

**엄격 모드**  
함수는 기본적으로 엄격 모드에서 작동하므로 함수 코드에 `use strict` 명령문을 추가할 필요가 없습니다. 이것은 변경할 수 없습니다.

## 기본 객체
<a name="writing-functions-javascript-features-primitive-objects-20"></a>

ES의 다음과 같은 기본 객체가 지원됩니다.

**객체**  
객체에 대해 다음과 같은 ES 5.1 메서드가 지원됩니다.  
+ `Object.create()`(속성 목록 제외)
+ `Object.defineProperties()`
+ `Object.defineProperty()`
+ `Object.freeze()`
+ `Object.getOwnPropertyDescriptor()`
+ `Object.getOwnPropertyDescriptors()`
+ `Object.getOwnPropertyNames()`
+ `Object.getPrototypeOf()`
+ `Object.isExtensible()`
+ `Object.isFrozen()`
+ `Object.isSealed()`
+ `Object.keys()`
+ `Object.preventExtensions()`
+ `Object.seal()`
객체에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `Object.assign()`
객체에 대해 다음과 같은 ES 8 메서드가 지원됩니다.  
+ `Object.entries()`
+ `Object.values()`
객체에 대해 다음과 같은 ES 5.1 프로토타입 메서드가 지원됩니다.  
+ `Object.prototype.hasOwnProperty()`
+ `Object.prototype.isPrototypeOf()`
+ `Object.prototype.propertyIsEnumerable()`
+ `Object.prototype.toString()`
+ `Object.prototype.valueOf()`
객체에 대해 다음과 같은 ES 6 프로토타입 메서드가 지원됩니다.  
+ `Object.prototype.is()`
+ `Object.prototype.setPrototypeOf()`

**문자열**  
문자열에 대해 다음 ES 5.1 메서드가 지원됩니다.  
+ `String.fromCharCode()`
문자열에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `String.fromCodePoint()`
문자열에 대해 다음 ES 5.1 프로토타입 메서드가 지원됩니다.  
+ `String.prototype.charAt()`
+ `String.prototype.concat()`
+ `String.prototype.indexOf()`
+ `String.prototype.lastIndexOf()`
+ `String.prototype.match()`
+ `String.prototype.replace()`
+ `String.prototype.search()`
+ `String.prototype.slice()`
+ `String.prototype.split()`
+ `String.prototype.substr()`
+ `String.prototype.substring()`
+ `String.prototype.toLowerCase()`
+ `String.prototype.trim()`
+ `String.prototype.toUpperCase()`
문자열에 대해 다음 ES 6 프로토타입 메서드가 지원됩니다.  
+ `String.prototype.codePointAt()`
+ `String.prototype.endsWith()`
+ `String.prototype.includes()`
+ `String.prototype.repeat()`
+ `String.prototype.startsWith()`
문자열에 대해 다음 ES 8 프로토타입 메서드가 지원됩니다.  
+ `String.prototype.padStart()`
+ `String.prototype.padEnd()`
문자열에 대해 다음 ES 9 프로토타입 메서드가 지원됩니다.  
+ `String.prototype.trimStart()`
+ `String.prototype.trimEnd()`
문자열에 대해 다음 ES 12 프로토타입 메서드가 지원됩니다.  
+ `String.prototype.replaceAll()`
**참고**  
`String.prototype.replaceAll()`이 JavaScript 런타임 2.0에 새로 추가되었습니다.

**숫자**  
모든 ES 5.1 숫자가 지원됩니다.  
숫자에 대해 다음 ES 6 속성이 지원됩니다.  
+ `Number.EPSILON`
+ `Number.MAX_SAFE_INTEGER`
+ `Number.MIN_SAFE_INTEGER`
+ `Number.MAX_VALUE`
+ `Number.MIN_VALUE`
+ `Number.NaN`
+ `Number.NEGATIVE_INFINITY`
+ `Number.POSITIVE_INFINITY`
숫자에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `Number.isFinite()`
+ `Number.isInteger()`
+ `Number.isNaN()`
+ `Number.isSafeInteger()`
+ `Number.parseInt()`
+ `Number.parseFloat()`
숫자에 대해 다음 ES 5.1 프로토타입 메서드가 지원됩니다.  
+ `Number.prototype.toExponential()`
+ `Number.prototype.toFixed()`
+ `Number.prototype.toPrecision()`
ES 12 숫자 구분자가 지원됩니다.  
ES 12 숫자 구분자가 JavaScript 런타임 2.0에 새로 추가되었습니다.

## 기본 제공 객체
<a name="writing-functions-javascript-features-builtin-objects-20"></a>

ES의 다음 내장 객체가 지원됩니다.

**수학 연산**  
모든 ES 5.1 수학 메서드가 지원됩니다.  
CloudFront 함수 런타임 환경에서 `Math.random()` 구현은 함수가 실행될 때의 타임스탬프와 함께 시드된 OpenBSD `arc4random`을(를) 사용합니다.
다음 ES 6 수학 속성이 지원됩니다.  
+ `Math.E`
+ `Math.LN10`
+ `Math.LN2`
+ `Math.LOG10E`
+ `Math.LOG2E`
+ `Math.PI`
+ `Math.SQRT1_2`
+ `Math.SQRT2`
다음 ES 6 수학 메서드가 지원됩니다.  
+ `Math.abs()`
+ `Math.acos()`
+ `Math.acosh()`
+ `Math.asin()`
+ `Math.asinh()`
+ `Math.atan()`
+ `Math.atan2()`
+ `Math.atanh()`
+ `Math.cbrt()`
+ `Math.ceil()`
+ `Math.clz32()`
+ `Math.cos()`
+ `Math.cosh()`
+ `Math.exp()`
+ `Math.expm1()`
+ `Math.floor()`
+ `Math.fround()`
+ `Math.hypot()`
+ `Math.imul()`
+ `Math.log()`
+ `Math.log1p()`
+ `Math.log2()`
+ `Math.log10()`
+ `Math.max()`
+ `Math.min()`
+ `Math.pow()`
+ `Math.random()`
+ `Math.round()`
+ `Math.sign()`
+ `Math.sinh()`
+ `Math.sin()`
+ `Math.sqrt()`
+ `Math.tan()`
+ `Math.tanh()`
+ `Math.trunc()`

**날짜**  
모든 ES 5.1 `Date` 기능이 지원됩니다.  
보안상의 이유로 단일 함수 실행의 수명 동안 `Date`은(는) 항상 동일한 값(함수의 시작 시간)을 반환합니다. 자세한 내용은 [제한된 기능](functions-javascript-runtime-10.md#writing-functions-javascript-features-restricted-features) 단원을 참조하세요.

**함수**  
다음 ES 5.1 프로토타입 메서드가 지원됩니다.  
+ `Function.prototype.apply()`
+ `Function.prototype.bind()`
+ `Function.prototype.call()`
함수 생성자는 지원되지 않습니다.

**정규식**  
모든 ES 5.1 정규 표현식 기능이 지원됩니다. 정규 표현식 언어는 Perl과 호환됩니다.  
다음 ES 5.1 프로토타입 접근자 속성이 지원됩니다.  
+ `RegExp.prototype.global`
+ `RegExp.prototype.ignoreCase`
+ `RegExp.protoype.multiline`
+ `RegExp.protoype.source`
+ `RegExp.prototype.sticky`
+ `RegExp.prototype.flags`
**참고**  
`RegExp.prototype.sticky`, `RegExp.prototype.flags`가 JavaScript 런타임 2.0에 새로 추가되었습니다.
다음 ES 5.1 프로토타입 메서드가 지원됩니다.  
+ `RegExp.prototype.exec()`
+ `RegExp.prototype.test()`
+ `RegExp.prototype.toString()`
+ `RegExp.prototype[@@replace]()`
+ `RegExp.prototype[@@split]()`
**참고**  
`RegExp.prototype[@@split]()`이 JavaScript 런타임 2.0에 새로 추가되었습니다.
다음 ES 5.1 인스턴스 속성이 지원됩니다.  
+ `lastIndex`
ES 9 명명된 캡처 그룹이 지원됩니다.

**JSON**  
다음 ES 5.1 메서드가 지원됩니다.  
+ `JSON.parse()`
+ `JSON.stringify()`

**배열**  
배열에 대해 다음 ES 5.1 메서드가 지원됩니다.  
+ `Array.isArray()`
배열에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `Array.of()`
다음 ES 5.1 프로토타입 메서드가 지원됩니다.  
+ `Array.prototype.concat()`
+ `Array.prototype.every()`
+ `Array.prototype.filter()`
+ `Array.prototype.forEach()`
+ `Array.prototype.indexOf()`
+ `Array.prototype.join()`
+ `Array.prototype.lastIndexOf()`
+ `Array.prototype.map()`
+ `Array.prototype.pop()`
+ `Array.prototype.push()`
+ `Array.prototype.reduce()`
+ `Array.prototype.reduceRight()`
+ `Array.prototype.reverse()`
+ `Array.prototype.shift()`
+ `Array.prototype.slice()`
+ `Array.prototype.some()`
+ `Array.prototype.sort()`
+ `Array.prototype.splice()`
+ `Array.prototype.unshift()`
다음 ES 6 프로토타입 메서드가 지원됩니다.  
+ `Array.prototype.copyWithin()`
+ `Array.prototype.fill()`
+ `Array.prototype.find()`
+ `Array.prototype.findIndex()`
다음 ES 7 프로토타입 메서드가 지원됩니다.  
+ `Array.prototype.includes()`

**형식화된 배열**  
다음 ES 6 형식화된 배열 생성자가 지원됩니다.  
+ `Float32Array`
+ `Float64Array`
+ `Int8Array`
+ `Int16Array`
+ `Int32Array`
+ `Uint8Array`
+ `Uint8ClampedArray`
+ `Uint16Array`
+ `Uint32Array`
다음 ES 6 메서드가 지원됩니다.  
+ `TypedArray.from()`
+ `TypedArray.of()`
**참고**  
`TypedArray.from()`, `TypedArray.of()`가 JavaScript 런타임 2.0에 새로 추가되었습니다.
다음 ES 6 프로토타입 메서드가 지원됩니다.  
+ `TypedArray.prototype.copyWithin()`
+ `TypedArray.prototype.every()`
+ `TypedArray.prototype.fill()`
+ `TypedArray.prototype.filter()`
+ `TypedArray.prototype.find()`
+ `TypedArray.prototype.findIndex()`
+ `TypedArray.prototype.forEach()`
+ `TypedArray.prototype.includes()`
+ `TypedArray.prototype.indexOf()`
+ `TypedArray.prototype.join()`
+ `TypedArray.prototype.lastIndexOf()`
+ `TypedArray.prototype.map()`
+ `TypedArray.prototype.reduce()`
+ `TypedArray.prototype.reduceRight()`
+ `TypedArray.prototype.reverse()`
+ `TypedArray.prototype.some()`
+ `TypedArray.prototype.set()`
+ `TypedArray.prototype.slice()`
+ `TypedArray.prototype.sort()`
+ `TypedArray.prototype.subarray()`
+ `TypedArray.prototype.toString()`
**참고**  
`TypedArray.prototype.every()`, `TypedArray.prototype.fill()`, `TypedArray.prototype.filter()`, `TypedArray.prototype.find()`, `TypedArray.prototype.findIndex()`, `TypedArray.prototype.forEach()`, `TypedArray.prototype.includes()`, `TypedArray.prototype.indexOf()`, `TypedArray.prototype.join()`, `TypedArray.prototype.lastIndexOf()`, `TypedArray.prototype.map()`, `TypedArray.prototype.reduce()`, `TypedArray.prototype.reduceRight()`, `TypedArray.prototype.reverse()`, `TypedArray.prototype.some()`이 JavaScript 런타임 2.0에 새로 추가되었습니다.

**배열 버퍼**  
ArrayBuffer에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `isView()`
ArrayBuffer에 대해 다음 ES 6 프로토타입 메서드가 지원됩니다.  
+ `ArrayBuffer.prototype.slice()`

**Promise**  
프로미스에 대해 다음 ES 6 메서드가 지원됩니다.  
+ `Promise.all()`
+ `Promise.allSettled()`
+ `Promise.any()`
+ `Promise.reject()`
+ `Promise.resolve()`
+ `Promise.race()`
**참고**  
`Promise.all()`, `Promise.allSettled()`, `Promise.any()`, `Promise.race()`가 JavaScript 런타임 2.0에 새로 추가되었습니다.
프로미스에 대해 다음 ES 6 프로토타입 메서드가 지원됩니다.  
+ `Promise.prototype.catch()`
+ `Promise.prototype.finally()`
+ `Promise.prototype.then()`

**DataView**  
다음 ES 6 프로토타입 메서드가 지원됩니다.  
+ `DataView.prototype.getFloat32()`
+ `DataView.prototype.getFloat64()`
+ `DataView.prototype.getInt16()`
+ `DataView.prototype.getInt32()`
+ `DataView.prototype.getInt8()`
+ `DataView.prototype.getUint16()`
+ `DataView.prototype.getUint32()`
+ `DataView.prototype.getUint8()`
+ `DataView.prototype.setFloat32()`
+ `DataView.prototype.setFloat64()`
+ `DataView.prototype.setInt16()`
+ `DataView.prototype.setInt32()`
+ `DataView.prototype.setInt8()`
+ `DataView.prototype.setUint16()`
+ `DataView.prototype.setUint32()`
+ `DataView.prototype.setUint8()`
**참고**  
모든 Dataview ES 6 프로토타입 메서드가 JavaScript 런타임 2.0에 새로 추가되었습니다.

**Symbol**  
다음 ES 6 메서드가 지원됩니다.  
+ `Symbol.for()`
+ `Symbol.keyfor()`
**참고**  
모든 Symbol ES 6 메서드가 JavaScript 런타임 2.0에 새로 추가되었습니다.

**텍스트 디코더**  
다음 프로토타입 메서드가 지원됩니다.  
+ `TextDecoder.prototype.decode()`
다음 프로토타입 접근자 속성이 지원됩니다.  
+ `TextDecoder.prototype.encoding`
+ `TextDecoder.prototype.fatal`
+ `TextDecoder.prototype.ignoreBOM`

**텍스트 인코더**  
다음 프로토타입 메서드가 지원됩니다.  
+ `TextEncoder.prototype.encode()`
+ `TextEncoder.prototype.encodeInto()`

## 오류 유형
<a name="writing-functions-javascript-features-error-types-20"></a>

다음과 같은 오류 객체가 지원됩니다.
+ `Error`
+ `EvalError`
+ `InternalError`
+ `RangeError`
+ `ReferenceError`
+ `SyntaxError`
+ `TypeError`
+ `URIError`

## Globals
<a name="writing-functions-javascript-features-globals-20"></a>

`globalThis` 객체가 지원됩니다.

다음 ES 5.1 전역 함수가 지원됩니다.
+ `decodeURI()`
+ `decodeURIComponent()`
+ `encodeURI()`
+ `encodeURIComponent()`
+ `isFinite()`
+ `isNaN()`
+ `parseFloat()`
+ `parseInt()`

다음 ES 6 전역 함수가 지원됩니다.
+ `atob()`
+ `btoa()`
**참고**  
`atob()`, `btoa()`가 JavaScript 런타임 2.0에 새로 추가되었습니다.

다음과 같은 글로벌 제약이 지원됩니다.
+ `NaN`
+ `Infinity`
+ `undefined`
+ `arguments`

## 기본 제공 모듈
<a name="writing-functions-javascript-features-builtin-modules-20"></a>

다음 기본 제공 모듈이 지원됩니다.

**Topics**
+ [Buffer](#writing-functions-javascript-features-builtin-modules-buffer-20)
+ [쿼리 문자열](#writing-functions-javascript-features-builtin-modules-query-string-20)
+ [crypto](#writing-functions-javascript-features-builtin-modules-crypto-20)

### Buffer
<a name="writing-functions-javascript-features-builtin-modules-buffer-20"></a>

이 모듈은 다음과 같은 메서드를 제공합니다.
+ `Buffer.alloc(size[, fill[, encoding]])`

  `Buffer`를 할당합니다.
  + `size`: 버퍼 크기입니다. 정수를 입력합니다.
  + `fill`: 선택 사항입니다. 문자열, `Buffer`, Uint8Array 또는 정수를 입력합니다. 기본값은 `0`입니다.
  + `encoding`: 선택 사항입니다. `fill`이 문자열인 경우 `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.allocUnsafe(size)`

  초기화되지 않은 `Buffer` 값을 할당합니다.
  + `size`: 정수를 입력합니다.
+ `Buffer.byteLength(value[, encoding])`

  값의 길이를 바이트 단위로 반환합니다.
  + `value`: 문자열, `Buffer`, TypedArray, Dataview 또는 Arraybuffer입니다.
  + `encoding`: 선택 사항입니다. `value`가 문자열인 경우 `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.compare(buffer1, buffer2)`

  두 `Buffer`를 비교하면 배열을 정렬하는 데 도움이 됩니다. 두 값이 같으면 `0`, `buffer1`이 먼저 오면 `-1`, `buffer2`가 먼저 오면 `1`을 반환합니다.
  + `buffer1`: `Buffer`를 입력합니다.
  + `buffer2`: 다른 `Buffer`를 입력합니다.
+ `Buffer.concat(list[, totalLength])`

  여러 개의 `Buffer`를 연결합니다. 없으면 `0`을 반환합니다. `totalLength`까지 반환합니다.
  + `list`: `Buffer` 목록을 입력합니다. 이 항목은 `totalLength` 기준으로 잘려서 표시된다는 점에 유의하세요.
  + `totalLength`: 선택 사항입니다. 부호 없는 정수를 입력합니다. 비어 있는 경우 목록에 있는 `Buffer` 인스턴스의 합계를 사용하세요.
+ `Buffer.from(array)`

  배열에서 `Buffer`를 생성합니다.
  + `array`: `0`에서 `255`까지 바이트 배열을 입력합니다.
+ `Buffer.from(arrayBuffer, byteOffset[, length]))`

  `byteOffset` 오프셋에서 시작하여 `length` 길이를 기준으로 `arrayBuffer`에서 뷰를 생성합니다.
  + `arrayBuffer`: `Buffer` 배열을 입력합니다.
  + `byteOffset`: 정수를 입력합니다.
  + `length`: 선택 사항입니다. 정수를 입력합니다.
+ `Buffer.from(buffer)`

  `Buffer`의 사본을 생성합니다.
  + `buffer`: `Buffer`를 입력합니다.
+ `Buffer.from(object[, offsetOrEncoding[, length]])`

  객체에서 `Buffer`를 생성합니다. `valueOf()` 값이 객체와 동일하지 않으면 `Buffer.from(object.valueOf(), offsetOrEncoding, length)` 값을 반환합니다.
  + `object`: 객체를 입력합니다.
  + `offsetOrEncoding`: 선택 사항입니다. 정수 또는 인코딩 문자열을 입력합니다.
  + `length`: 선택 사항입니다. 정수를 입력합니다.
+ `Buffer.from(string[, encoding])`

  문자열에서 `Buffer`를 생성합니다.
  + `string`: 문자열을 입력합니다.
  + `encoding`: 선택 사항입니다. `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.isBuffer(object)`

  `object`가 버퍼인지 확인합니다. `true` 또는 `false`를 반환합니다.
  + `object`: 객체를 입력합니다.
+ `Buffer.isEncoding(encoding)`

  `encoding`이 지원되는지 확인합니다. `true` 또는 `false`를 반환합니다.
  + `encoding`: 선택 사항입니다. `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.

이 모듈은 다음과 같은 버퍼 프로토타입 메서드를 제공합니다.
+ `Buffer.prototype.compare(target[, targetStart[, targetEnd[, sourceStart[, sourceEnd]]]])`

  `Buffer`를 대상과 비교합니다. 두 값이 같으면 `0`, `buffer`이 먼저 오면 `1`, `target`가 먼저 오면 `-1`을 반환합니다.
  + `target`: `Buffer`를 입력합니다.
  + `targetStart`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
  + `targetEnd`: 선택 사항입니다. 정수를 입력합니다. 기본값은 `target` 길이입니다.
  + `sourceStart`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
  + `sourceEnd`: 선택 사항입니다. 정수를 입력합니다. 기본값은 `Buffer` 길이입니다.
+ `Buffer.prototype.copy(target[, targetStart[, sourceStart[, sourceEnd]]])`

  버퍼를 `target`으로 복사합니다.
  + `target`: `Buffer` 또는 `Uint8Array`를 입력합니다.
  + `targetStart`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
  + `sourceStart`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
  + `sourceEnd`: 선택 사항입니다. 정수를 입력합니다. 기본값은 `Buffer` 길이입니다.
+ `Buffer.prototype.equals(otherBuffer)`

  `Buffer`와 `otherBuffer`를 비교합니다. `true` 또는 `false`를 반환합니다.
  + `otherBuffer`: 문자열을 입력합니다.
+ `Buffer.prototype.fill(value[, offset[, end][, encoding])`

  `Buffer`를 `value`로 채웁니다.
  + `value`: 문자열, `Buffer` 또는 정수를 입력합니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다.
  + `end`: 선택 사항입니다. 정수를 입력합니다.
  + `encoding`: 선택 사항입니다. `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.prototype.includes(value[, byteOffset][, encoding])`

  `Buffer`에서 `value`를 찾습니다. `true` 또는 `false`를 반환합니다.
  + `value`: 문자열, `Buffer`, `Uint8Array` 또는 정수를 입력합니다.
  + `byteOffset`: 선택 사항입니다. 정수를 입력합니다.
  + `encoding`: 선택 사항입니다. `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.prototype.indexOf(value[, byteOffset][, encoding])`

  `Buffer`에서 첫 번째 `value`를 찾습니다. 값이 발견되면 `index`, 발견되지 않으면 `-1`을 반환합니다.
  + `value`: 문자열, `Buffer`, Unit8Array 또는 0에서 255 사이의 정수를 입력합니다.
  + `byteOffset`: 선택 사항입니다. 정수를 입력합니다.
  + `encoding`: 선택 사항입니다. `value`가 문자열인 경우 `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.prototype.lastIndexOf(value[, byteOffset][, encoding])`

  `Buffer`에서 마지막 `value`를 찾습니다. 값이 발견되면 `index`, 발견되지 않으면 `-1`을 반환합니다.
  + `value`: 문자열, `Buffer`, Unit8Array 또는 0에서 255 사이의 정수를 입력합니다.
  + `byteOffset`: 선택 사항입니다. 정수를 입력합니다.
  + `encoding`: 선택 사항입니다. `value`가 문자열인 경우 `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.prototype.readInt8(offset)`

  `Buffer`의 `offset`에서 `Int8`을 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readIntBE(offset, byteLength)`

  `Buffer`의 `offset`에서 `Int`를 빅 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: 선택 사항입니다. `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.readInt16BE(offset)`

  `Buffer`의 `offset`에서 `Int16`을 빅 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readInt32BE(offset)`

  `Buffer`의 `offset`에서 `Int32`를 빅 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readIntLE(offset, byteLength)`

  `Buffer`의 `offset`에서 `Int`를 리틀 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.readInt16LE(offset)`

  `Buffer`의 `offset`에서 `Int16`을 리틀 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readInt32LE(offset)`

  `Buffer`의 `offset`에서 `Int32`을 리틀 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readUInt8(offset)`

  `Buffer`의 `offset`에서 `UInt8`을 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readUIntBE(offset, byteLength)`

  `Buffer`의 `offset`에서 `UInt`를 빅 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.readUInt16BE(offset)`

  `Buffer`의 `offset`에서 `UInt16`을 빅 엔디안으로 읽습니다.
+ 
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readUInt32BE(offset)`

  `Buffer`의 `offset`에서 `UInt32`를 빅 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readUIntLE(offset, byteLength)`

  `Buffer`의 `offset`에서 `UInt`을 리틀 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.readUInt16LE(offset)`

  `Buffer`의 `offset`에서 `UInt16`을 리틀 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readUInt32LE(offset)`

  `Buffer`의 `offset`에서 `UInt32`을 리틀 엔디안으로 읽습니다.
  + `offset`: 정수를 입력합니다.
+ `Buffer.prototype.readDoubleBE([offset])`

  `Buffer`의 `offset`에서 64비트 배정도를 빅 엔디안으로 읽습니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다.
+ `Buffer.prototype.readDoubleLE([offset])`

  `Buffer`의 `offset`에서 64비트 배정도를 리틀 엔디안으로 읽습니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다.
+ `Buffer.prototype.readFloatBE([offset])`

  `Buffer`의 `offset`에서 32비트 부동소수점을 빅 엔디안으로 읽습니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다.
+ `Buffer.prototype.readFloatLE([offset])`

  `Buffer`의 `offset`에서 32비트 부동소수점을 리틀 엔디안으로 읽습니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다.
+ `Buffer.prototype.subarray([start[, end]])`

  오프셋되고 새 `start` 및 `end`로 크롭된 `Buffer`의 복사본을 반환합니다.
  + `start`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
  + `end`: 선택 사항입니다. 정수를 입력합니다. 기본값은 버퍼 길이입니다.
+ `Buffer.prototype.swap16()`

  `Buffer` 배열을 16비트 숫자로 구성된 배열로 취급하여 바이트 순서를 바꿉니다. `Buffer` 길이는 2로 나눌 수 있어야 합니다. 그렇지 않으면 오류가 발생합니다.
+ `Buffer.prototype.swap32()`

  `Buffer` 배열을 32비트 숫자로 구성된 배열로 취급하여 바이트 순서를 바꿉니다. `Buffer` 길이는 4로 나눌 수 있어야 합니다. 그렇지 않으면 오류가 발생합니다.
+ `Buffer.prototype.swap64()`

  `Buffer` 배열을 64비트 숫자로 구성된 배열로 취급하여 바이트 순서를 바꿉니다. `Buffer` 길이는 8로 나눌 수 있어야 합니다. 그렇지 않으면 오류가 발생합니다.
+ `Buffer.prototype.toJSON()`

  `Buffer`를 JSON으로 반환합니다.
+ `Buffer.prototype.toString([encoding[, start[, end]]])`

  `start`에서 `end`로, 인코딩된 문자열로 `Buffer`를 변환합니다.
  + `encoding`: 선택 사항입니다. `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
  + `start`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
  + `end`: 선택 사항입니다. 정수를 입력합니다. 기본값은 버퍼 길이입니다.
+ `Buffer.prototype.write(string[, offset[, length]][, encoding])`

  공간이 있는 경우 인코딩된 `string`을 `Buffer`에 쓰고, 공간이 충분하지 않으면 잘라낸 `string`을 씁니다.
  + `string`: 문자열을 입력합니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
  + `length`: 선택 사항입니다. 정수를 입력합니다. 기본값은 문자열 길이입니다.
  + `encoding`: 선택 사항입니다. 필요에 따라 `utf8`, `hex`, `base64`, `base64url` 중 하나를 입력합니다. 기본값은 `utf8`입니다.
+ `Buffer.prototype.writeInt8(value, offset, byteLength)`

  `offset`에서 `byteLength`의 `Int8` `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeIntBE(value, offset, byteLength)`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeInt16BE(value, offset, byteLength)`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeInt32BE(value, offset, byteLength)`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeIntLE(offset, byteLength)`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeInt16LE(offset, byteLength)`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeInt32LE(offset, byteLength)`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeUInt8(value, offset, byteLength)`

  `offset`에서 `byteLength`의 `UInt8` `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeUIntBE(value, offset, byteLength)`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeUInt16BE(value, offset, byteLength)`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeUInt32BE(value, offset, byteLength)`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeUIntLE(value, offset, byteLength)`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeUInt16LE(value, offset, byteLength)`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeUInt32LE(value, offset, byteLength)`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 정수를 입력합니다.
  + `byteLength`: `1`에서 `6`까지의 정수를 입력합니다.
+ `Buffer.prototype.writeDoubleBE(value, [offset])`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
+ `Buffer.prototype.writeDoubleLE(value, [offset])`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
+ `Buffer.prototype.writeFloatBE(value, [offset])`

  빅 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.
+ `Buffer.prototype.writeFloatLE(value, [offset])`

  리틀 엔디안을 사용하여 `offset`에서 `value`를 `Buffer`에 씁니다.
  + `value`: 정수를 입력합니다.
  + `offset`: 선택 사항입니다. 정수를 입력합니다. 기본값은 0.

다음 인스턴스 메서드가 지원됩니다.
+ `buffer[index]`

  `Buffer`에 `index`의 8진수(바이트)를 가져와 설정합니다.
  + `0`에서 `255`의 숫자를 가져옵니다. 또는 `0`부터 `255`까지의 숫자를 설정할 수도 있습니다.

다음 인스턴스 속성이 지원됩니다.
+ `buffer`

  버퍼의 `ArrayBuffer` 객체를 가져옵니다.
+ `byteOffset`

  버퍼의 `Arraybuffer` 객체에 대한 `byteOffset`을 가져옵니다.
+ `length`

  버퍼 바이트 수를 가져옵니다.

**참고**  
모든 버퍼 모듈 메서드가 JavaScript 런타임 2.0에 새로 추가되었습니다.

### 쿼리 문자열
<a name="writing-functions-javascript-features-builtin-modules-query-string-20"></a>

**참고**  
[CloudFront 함수 이벤트 객체](functions-event-structure.md)는 URL 쿼리 문자열을 자동으로 구문 분석합니다. 즉, 대부분의 경우 이 모듈을 사용할 필요가 없습니다.

쿼리 문자열 모듈(`querystring`)은 URL 쿼리 문자열을 구문 분석하고 서식을 지정하는 메서드를 제공합니다. `require('querystring')`을 사용하여 모듈을 로드할 수 있습니다. 이 모듈은 다음과 같은 방법을 제공합니다.

`querystring.escape(string)`  
지정된 `string`을 URL-인코딩하여 이스케이프된 쿼리 문자열을 반환합니다. 이 방법은 `querystring.stringify()`에서 사용되며 직접 사용해서는 안 됩니다.

`querystring.parse(string[, separator[, equal[, options]]])`  
쿼리 문자열(`string`)을 구문 분석하고 객체를 반환합니다.  
`separator` 파라미터는 쿼리 문자열에서 키와 값 페어를 구분하기 위한 하위 문자열입니다. 기본 설정은 `&`입니다.  
`equal` 파라미터는 쿼리 문자열에서 키와 값을 구분하기 위한 하위 문자열입니다. 기본 설정은 `=`입니다.  
`options` 파라미터는 다음 키를 가진 객체입니다.    
`decodeURIComponent function`  
쿼리 문자열에서 백분율로 인코딩된 문자를 디코딩하는 함수입니다. 기본 설정은 `querystring.unescape()`입니다.  
`maxKeys number`  
구문 분석할 최대 키 수입니다. 기본 설정은 `1000`입니다. `0` 값을 사용하여 키 카운트 제한을 제거합니다.
기본적으로 쿼리 문자열 내의 백분율로 인코딩된 문자는 UTF-8 인코딩을 사용하는 것으로 간주됩니다. 잘못된 UTF-8 시퀀스는 `U+FFFD` 대체 문자로 대체됩니다.  
예를 들어 다음 쿼리 문자열의 경우:  

```
'name=value&abc=xyz&abc=123'
```
`querystring.parse()`의 반환 값:  

```
{
name: 'value',
abc: ['xyz', '123']
}
```
`querystring.decode()`는 `querystring.parse()`의 별칭입니다.

`querystring.stringify(object[, separator[, equal[, options]]])`  
`object`를 직렬화하고 쿼리 문자열을 반환합니다.  
`separator` 파라미터는 쿼리 문자열에서 키와 값 쌍을 구분하기 위한 하위 문자열입니다. 기본 설정은 `&`입니다.  
`equal` 파라미터는 쿼리 문자열에서 키와 값을 구분하기 위한 하위 문자열입니다. 기본 설정은 `=`입니다.  
`options` 파라미터는 다음 키를 가진 객체입니다.    
`encodeURIComponent function`  
URL에 안전하지 않은 문자를 쿼리 문자열에서 백분율 인코딩으로 변환하는 데 사용할 함수입니다. 기본 설정은 `querystring.escape()`입니다.
기본적으로 쿼리 문자열 내에서 백분율 인코딩이 필요한 문자는 UTF-8로 인코딩됩니다. 다른 인코딩을 사용하려면 `encodeURIComponent` 옵션을 지정합니다.  
예를 들어, 다음 코드의 경우:  

```
querystring.stringify({ name: 'value', abc: ['xyz', '123'], anotherName: '' });
```
반환 값:  

```
'name=value&abc=xyz&abc=123&anotherName='
```
`querystring.encode()`는 `querystring.stringify()`의 별칭입니다.

`querystring.unescape(string)`  
지정된 `string`의 URL 백분율로 인코딩된 문자를 디코딩하여 이스케이프되지 않은 쿼리 문자열을 반환합니다. 이 방법은 `querystring.parse()`에서 사용되며 직접 사용해서는 안 됩니다.

### crypto
<a name="writing-functions-javascript-features-builtin-modules-crypto-20"></a>

암호화 모듈(`crypto`)은 표준 해싱 및 HMAC(해시 기반 메시지 인증 코드) 헬퍼를 제공합니다. `require('crypto')`을(를) 사용하여 모듈을 로드할 수 있습니다.

**해싱 메서드**

`crypto.createHash(algorithm)`  
지정된 알고리즘(`md5`, `sha1` 또는 `sha256`)을 사용하여 해시 다이제스트를 생성하는 데 사용할 수 있는 해시 객체를 생성하고 반환합니다.

`hash.update(data)`  
지정된 `data`(으)로 해시 콘텐츠를 업데이트합니다.

`hash.digest([encoding])`  
`hash.update()`을(를) 사용하여 전달된 모든 데이터의 다이제스트를 계산합니다. 인코딩은 `hex`, `base64` 또는 `base64url`일 수 있습니다.

**HMAC 메서드**

`crypto.createHmac(algorithm, secret key)`  
지정된 `algorithm` 및 `secret key`을(를) 사용하는 HMAC 객체를 생성 및 반환합니다. 알고리즘은 `md5`, `sha1` 또는 `sha256`일 수 있습니다.

`hmac.update(data)`  
지정된 `data`(으)로 HMAC 콘텐츠를 업데이트합니다.

`hmac.digest([encoding])`  
`hmac.update()`을(를) 사용하여 전달된 모든 데이터의 다이제스트를 계산합니다. 인코딩은 `hex`, `base64` 또는 `base64url`일 수 있습니다.

## 제한된 기능
<a name="writing-functions-javascript-features-restricted-features-20"></a>

다음 JavaScript 언어 기능은 보안 문제로 인해 지원되지 않거나 제한됩니다.

**동적 코드 평가**  
동적 코드 평가는 지원되지 않습니다. 시도하면 `eval()` 및 `Function` 생성자 모두 오류가 발생합니다. 예를 들어 `const sum = new Function('a', 'b', 'return a + b')`에서 오류가 발생합니다.

**타이머**  
`setTimeout()`, `setImmediate()` 및 `clearTimeout()` 함수는 지원되지 않습니다. 함수 실행 내에서 연기하거나 출력할 프로비전이 없습니다. 함수가 완료되려면 동기적으로 실행되어야 합니다.

**날짜 및 타임스탬프**  
보안상의 이유로 고해상도 타이머에 액세스할 수 없습니다. 현재 시간을 쿼리하는 모든 `Date` 메서드는 단일 함수 실행의 수명 동안 항상 동일한 값을 반환합니다. 반환된 타임 스탬프는 함수가 실행을 시작한 시간입니다. 따라서 함수에서 경과 시간을 측정할 수 없습니다.

**파일 시스템 액세스**  
파일 시스템 액세스가 없습니다. 예를 들어 Node.js에서처럼 파일 시스템 액세스를 위한 `fs` 모듈이 없습니다.

**프로세스 액세스**  
프로세스 액세스가 없습니다. 예를 들어 Node.js와는 달리 정보 액세스를 처리하기 위한 `process` 글로벌 객체가 없습니다.

**환경 변수**  
환경 변수에 액세스할 수 없습니다. 대신 CloudFront KeyValueStore를 사용하여 CloudFront Functions에 대한 키 값 페어의 중앙 집중식 데이터 스토어를 생성할 수 있습니다. CloudFront KeyValueStore를 사용하면 코드 변경 사항을 배포할 필요 없이 구성 데이터를 동적으로 업데이트할 수 있습니다. 자세한 내용은 [Amazon CloudFront KeyValueStore](kvs-with-functions.md) 섹션을 참조하세요.

**네트워크 액세스**  
네트워크 통화에 대한 지원이 없습니다. 예를 들어 XHR, HTTP(S) 및 소켓은 지원되지 않습니다.

# 키 값 저장소를 위한 도우미 메서드
<a name="functions-custom-methods"></a>

**참고**  
CloudFront Functions의 키 값 저장소 헬퍼 메서드 호출은 AWS CloudTrail 데이터 이벤트를 트리거하지 않습니다. 이러한 이벤트는 CloudTrail 이벤트 기록에 로그되지 않습니다. 자세한 내용은 [AWS CloudTrail을 사용하여 Amazon CloudFront API 직접 호출 로깅](logging_using_cloudtrail.md) 섹션을 참조하세요.

이 섹션은 생성한 함수에 [CloudFront 키 값 저장소](kvs-with-functions.md)를 사용하여 키 값을 포함하는 경우에 적용됩니다. CloudFront Functions에는 키 값 저장소에서 값을 읽을 수 있는 세 가지 도우미 메서드를 제공하는 모듈이 있습니다.

함수 코드에서 이 모듈을 사용하려면 [키 값 저장소를 함수와 연결](kvs-with-functions-associate.md)했는지 확인합니다.

그런 다음 함수 코드의 첫 줄에 다음 명령문을 포함시킵니다.

```
import cf from 'cloudfront';
const kvsHandle = cf.kvs();
```



## `get()` 메서드
<a name="functions-custom-methods-get"></a>

이 메서드를 사용하여 지정한 키 이름의 키 값을 반환합니다.

**요청**

```
get("key", options);
```
+ `key`: 값을 가져와야 하는 키의 이름입니다.
+ `options`: 한 가지 옵션으로 `format`이 있습니다. 이 옵션을 사용하면 함수가 데이터를 올바르게 파싱합니다. 가능한 값은 다음과 같습니다.
  + `string`: (기본값) UTF8 인코딩
  + `json` 
  + `bytes`: 원시 바이너리 데이터 버퍼

**요청 예제**

```
const value = await kvsHandle.get("myFunctionKey", { format: "string"});
```

**응답**

응답은 `options`를 사용하여 요청한 형식의 값으로 해석되는 `promise`입니다. 기본적으로 값은 문자열로 반환됩니다.

### 오류 처리
<a name="error-handling-exists-method"></a>

요청된 키가 관련 키 값 저장소에 존재하지 않는 경우 `get()` 메서드는 오류를 반환합니다. 이 사용 사례를 관리하기 위해 코드에 `try` 및 `catch` 블록을 추가할 수 있습니다.

**주의**  
promise 결합자(예: `Promise.all`, `Promise.any`) 및 promise 체인 메서드(예: `then` 및 `catch`)를 사용하려면 많은 함수 메모리 사용량이 필요할 수 있습니다. 함수가 [최대 함수 메모리](cloudfront-limits.md#limits-functions) 할당량을 초과하면 실행에 실패합니다. 이 오류를 방지하려면 `await` 구문을 순차적으로 사용하거나 루프에서 여러 값을 요청하는 것이 좋습니다.  
**예제**  

```
var value1 = await kvs.get('key1');
var value2 = await kvs.get('key2');
```
현재 다음 예제와 같이 promise 결합자를 사용하여 여러 값을 가져오더라도 성능이 향상되지 않습니다.  

```
var values = await Promise.all([kvs.get('key1'), kvs.get('key2'),]);
```

## `exists()` 메서드
<a name="functions-custom-methods-exists"></a>

키가 키 값 저장소에 존재하는지 여부를 지정하려면 이 메서드를 사용합니다.

**요청**

```
exists("key");
```

**요청 예제**

```
const exist = await kvsHandle.exists("myFunctionkey");
```

**응답**

응답은 부울(`true` 또는 `false`)을 반환하는 `promise`입니다. 이 값은 키가 키 값 저장소에 존재하는지 여부를 지정합니다.

## `meta()` 메서드
<a name="functions-custom-methods-meta"></a>

이 메서드를 사용하여 키 값 저장소에 대한 메타데이터를 반환합니다.

**요청**

```
meta();
```

**요청 예제**

```
const meta = await kvsHandle.meta();
```

**응답**

응답은 다음과 같은 속성을 가진 객체로 확인되는 `promise`입니다.
+ `creationDateTime`: 키 값 저장소가 생성된 ISO 8601 형식의 날짜 및 시간입니다.
+ `lastUpdatedDateTime`: 키 값 저장소가 소스에서 마지막으로 동기화된 ISO 8601 형식의 날짜 및 시간입니다. 엣지로의 전파 시간은 값에 포함되지 않습니다.
+ `keyCount`: 소스와의 마지막 동기화 이후 KVS에 있는 키의 총 개수입니다.

**응답 예제**

```
{keyCount:3,creationDateTime:2023-11-30T23:07:55.765Z,lastUpdatedDateTime:2023-12-15T03:57:52.411Z}
```

# 오리진 수정용 헬퍼 메서드
<a name="helper-functions-origin-modification"></a>

이 섹션은 CloudFront Functions 코드 내에서 요청에 사용되는 오리진을 동적으로 업데이트하거나 변경하는 경우에 적용됩니다. *뷰어 요청* CloudFront Functions에서만 오리진을 업데이트할 수 있습니다. CloudFront Functions에는 오리진을 동적으로 업데이트하거나 변경하는 헬퍼 메서드를 제공하는 모듈이 있습니다.

이 모듈을 사용하려면 JavaScript 런타임 2.0을 사용하여 CloudFront Functions을 만들고 함수 코드의 첫 번째 줄에 다음 스테이트먼트를 포함합니다.

```
import cf from 'cloudfront';
```

자세한 내용은 [CloudFront Functions를 위한 JavaScript 런타임 2.0 기능](functions-javascript-runtime-20.md) 섹션을 참조하세요.

**참고**  
테스트 API 및 테스트 콘솔 페이지에서는 오리진 수정이 발생했는지 여부를 테스트하지 않습니다. 그러나 테스트는 함수 코드가 오류 없이 실행되도록 합니다.

## CloudFront Functions과 Lambda@Edge 중에서 선택
<a name="origin-modification-considerations"></a>

CloudFront Functions 또는 Lambda@Edge를 사용하여 오리진을 업데이트할 수 있습니다.

CloudFront Functions을 사용하여 오리진을 업데이트할 때 *뷰어 요청* 이벤트 트리거를 사용합니다. 즉, 이 함수가 사용될 때 해당 로직이 모든 요청에서 실행됩니다. Lambda@Edge를 사용하는 경우 오리진 업데이트 기능은 *오리진 요청* 이벤트 트리거에 존재합니다. 즉, 이 로직은 캐시 누락에서만 실행됩니다.

주로 워크로드와 배포에서 CloudFront Functions 및 Lambda@Edge의 기존 사용량에 따라 선택이 달라집니다. 다음 고려 사항을 통해 CloudFront Functions 또는 Lambda@Edge를 사용하여 오리진을 업데이트할지 여부를 결정할 수 있습니다.

CloudFront Functions은 다음과 같은 상황에서 가장 유용합니다.
+ 요청이 동적(즉, 캐싱할 수 없음)이고 항상 오리진으로 이동하는 경우입니다. CloudFront Functions은 더 나은 성능과 더 낮은 전체 비용을 제공합니다.
+ 각 요청에서 실행되는 기존 뷰어 요청 CloudFront Functions이 이미 있는 경우 기존 함수에 오리진 업데이트 로직을 추가할 수 있습니다.

CloudFront Functions을 사용하여 오리진을 업데이트하려면 다음 주제의 헬퍼 메서드를 참조하시기 바랍니다.

Lambda@Edge는 다음과 같은 상황에서 가장 유용합니다.
+ 캐싱 가능성이 높은 콘텐츠가 있으면 Lambda@Edge는 캐시 누락 시에만 실행되고 CloudFront Functions은 모든 요청 시 실행되므로 더 비용 효율적일 수 있습니다.
+ 기존 오리진 요청 Lambda@Edge 함수가 이미 있는 경우 오리진 업데이트 로직을 기존 함수에 추가할 수 있습니다.
+ 오리진 업데이트 로직에서 Amazon DynamoDB 또는 Amazon S3와 같은 서드 파티 데이터 소스에서 데이터를 가져와야 하는 경우입니다.

Lambda@Edge에 대한 자세한 내용은 [Lambda@Edge를 사용하여 엣지에서 사용자 지정](lambda-at-the-edge.md) 섹션을 참조하시기 바랍니다.

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

`updateRequestOrigin()` 메서드를 사용하여 요청의 오리진 설정을 업데이트합니다. 이 메서드를 사용하여 배포에 이미 정의된 오리진의 기존 오리진 속성을 업데이트하거나 요청에 대한 새 오리진을 정의할 수 있습니다. 이렇게 하려면 변경하려는 속성을 지정합니다.

**중요**  
`updateRequestOrigin()`에서 지정하지 않은 설정은 기존 오리진의 구성에서 *동일한 설정*을 상속합니다.

`updateRequestOrigin()` 메서드에 따라 설정된 오리진은 HTTP 엔드포인트일 수 있으며 CloudFront 배포 내의 기존 오리진일 필요는 없습니다.

**참고**  
오리진 그룹의 일부인 오리진을 업데이트하는 경우 오리진 그룹의 *프라이머리 오리진*만 업데이트됩니다. 보조 오리진은 변경되지 않습니다. 장애 조치 기준과 일치하는 수정된 오리진의 모든 응답 코드는 보조 오리진으로 장애 조치를 트리거합니다.
오리진 유형을 변경하고 OAC를 사용 설정한 경우 `originAccessControlConfig`의 오리진 유형이 새 오리진 유형과 일치하는지 확인합니다.
`updateRequestOrigin()` 메서드를 사용하여 [VPC 오리진](private-content-vpc-origins.md)을 업데이트할 수 없습니다. 요청이 완료되지 않습니다.

**요청**

```
updateRequestOrigin({origin properties})
```

`origin properties`에는 다음 사항이 포함될 수 있습니다.

**domainName(선택 사항)**  
오리진의 도메인 이름입니다. 이를 제공하지 않으면 대신 할당된 오리진의 도메인 이름이 사용됩니다.    
**사용자 지정 오리진의 경우**  
DNS 도메인 이름(예: `www.example.com`)을 지정합니다. 도메인 이름에는 콜론(`:`)이 포함될 수 없으며 IP 주소가 될 수 없습니다. 도메인 이름은 최대 253자일 수 있습니다.  
**S3 오리진의 경우**  
Amazon S3 버킷의 DNS 도메인 이름(예: `amzn-s3-demo-bucket.s3.eu-west-1.amazonaws.com`)을 지정합니다. 이름은 최대 128자여야 하며, 모두 소문자여야 합니다.

**hostHeader(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
오리진에 요청할 때 사용할 호스트 헤더입니다. 제공하지 않으면 domainName 파라미터의 값이 사용됩니다. 호스트 헤더 또는 도메인 이름 파라미터가 제공되지 않은 경우 할당된 오리진의 도메인 이름이 사용되고, 오리진으로 전달(FTO) 정책에 호스트가 포함된 경우 수신 요청의 호스트 헤더가 사용됩니다. 호스트 헤더에는 콜론(`:`)이 포함될 수 없으며 IP 주소가 될 수 없습니다. 호스트 헤더는 최대 253자까지 작성할 수 있습니다.

**originPath(선택 사항)**  
요청이 콘텐츠를 찾아야 하는 오리진의 디렉터리 경로입니다. 경로는 슬래시(/)로 시작해야 하지만 슬래시 하나로 끝나지 않아야 합니다. 예를 들어 `example-path/`로 끝나지 않아야 합니다. 이를 제공하지 않으면 할당된 오리진의 오리진 경로가 사용됩니다.    
**사용자 지정 오리진의 경우**  
경로는 URL 인코딩되어야 하고 최대 255자여야 합니다.

**customHeaders(선택 사항)**  
각 사용자 지정 헤더에 대한 헤더 이름 및 값 페어를 지정하여 요청을 포함한 사용자 지정 헤더를 포함할 수 있습니다. 형식은 이벤트 구조에서 요청 및 응답 헤더의 형식과 다릅니다. 다음의 키/값 쌍 구문을 사용합니다.  

```
{"key1": "value1", "key2": "value2", ...}
```
허용되지 않는 헤더는 추가할 수 없으며 동일한 이름의 헤더가 수신되는 요청 `headers`에 존재할 수 없습니다. 헤더 이름은 함수 코드에서 소문자여야 합니다. CloudFront Functions이 이벤트 객체를 HTTP 요청으로 다시 변환하는 경우 헤더 이름에 있는 각 단어의 첫 글자가 대문자로 표시됩니다. 단어는 하이픈으로 구분됩니다.  
예를 들어 함수 코드가 `example-header-name`이라는 이름의 헤더를 추가하는 경우, CloudFront는 이 헤더를 HTTP 요청에서 `Example-Header-Name`으로 변환합니다. 자세한 내용은 [CloudFront에서 오리진 요청에 추가할 수 없는 사용자 지정 헤더](add-origin-custom-headers.md#add-origin-custom-headers-denylist) 및 [엣지 함수에 대한 제한 사항](edge-functions-restrictions.md)(을)를 참조하세요.  
이를 제공하지 않으면 할당된 오리진의 사용자 지정 헤더가 사용됩니다.

**connectionAttempts(선택 사항)**  
CloudFront가 오리진에 연결을 시도하는 횟수입니다. 최솟값은 1이고, 최댓값은 3입니다. 이를 제공하지 않으면 할당된 오리진을 통해 연결 시도가 사용됩니다.

**originShield(선택 사항)**  
이렇게 하면 CloudFront Origin Shield가 사용 설정되거나 업데이트됩니다. Origin Shield를 사용하면 오리진의 부하를 줄일 수 있습니다. 자세한 내용은 [Amazon CloudFront Origin Shield 사용](origin-shield.md) 섹션을 참조하세요. 이를 제공하지 않으면 할당된 오리진을 통해 Origin Shield 설정이 사용됩니다.    
**enabled(필수)**  
Origin Shield를 사용 또는 사용 해제하는 부울 표현식입니다. `true` 또는 `false` 값을 허용합니다.  
**region(사용 설정된 경우 필수)**  
Origin Shield의 AWS 리전입니다. 오리진에 대한 지연 시간이 가장 낮은 AWS 리전을 지정합니다. 리전 이름이 아닌 리전 코드를 사용합니다. 예를 들어 `us-east-2`를 사용하여 미국 동부(오하이오) 리전을 지정합니다.  
CloudFront Origin Shield를 사용하는 경우 이에 대한 AWS 리전을 지정해야 합니다. 사용 가능한 AWS 리전 목록과 오리진에 가장 적합한 리전을 선택하는 데 도움이 되는 목록은 [Origin Shield의 AWS 리전 선택](origin-shield.md#choose-origin-shield-region) 섹션을 참조하시기 바랍니다.

**originAccessControlConfig(선택 사항)**  
해당 오리진에 대한 원본 액세스 제어(OAC)의 고유한 식별자입니다. 이는 오리진이 Amazon S3, Lambda 함수 URL, MediaStore, MediaPackage V2 등 CloudFront OAC를 지원하는 경우에만 사용됩니다. 이를 제공하지 않으면 할당된 오리진의 OAC 설정이 사용됩니다.  
이는 레거시 오리진 액세스 ID(OAI)를 지원하지 않습니다. 자세한 내용은 [AWS 오리진에 대한 액세스 제한](private-content-restricting-access-to-origin.md) 섹션을 참조하세요.    
**enabled(필수)**  
OAC를 사용 또는 사용 해제하는 부울 표현식입니다. `true` 또는 `false` 값을 허용합니다.  
**signingBehavior(사용 설정된 경우 필수)**  
CloudFront가 서명(인증 정보 추가)하는 요청을 지정합니다. 대부분의 사용 사례에서 `always`를 지정합니다.. 자세한 내용은 [오리진 액세스 제어를 위한 고급 설정](private-content-restricting-access-to-s3.md#oac-advanced-settings-s3) 섹션을 참조하세요.  
이 필드는 다음 값 중 하나를 가질 수 있습니다.  
+ `always` - CloudFront가 모든 오리진 요청을 서명하고, 최종 사용자 요청으로부터 `Authorization` 헤더를 덮어씁니다(있는 경우).
+ `never` - CloudFront가 오리진 요청을 서명하지 않습니다. 이 값은 오리진에 대한 오리진 액세스 제어를 끕니다.
+ `no-override` - 뷰어 요청에 `Authorization` 헤더가 포함되지 않은 경우 CloudFront가 오리진 요청을 서명합니다. 뷰어 요청에 `Authorization` 헤더가 포함된 경우 CloudFront가 오리진 요청에 서명하지 않고 최종 사용자 요청의 `Authorization` 헤더와 함께 전달합니다.
**주의**  
뷰어 요청에서 `Authorization` 헤더를 전달하려면 이 오리진 액세스 제어와 연결된 오리진을 사용하는 모든 캐시 동작에 대한 해당 헤더를 오리진 요청 정책에 추가해야 합니다. 자세한 내용은 [정책을 통한 오리진 요청 제어](controlling-origin-requests.md) 섹션을 참조하세요.  
**signingProtocol(사용 설정된 경우 필수)**  
CloudFront가 요청을 서명(인증)하는 방법을 결정하는 OAC의 서명 프로토콜입니다. 유일한 유효 값은 `sigv4`입니다.  
**originType(사용 설정된 경우 필수)**  
이 OAC의 오리진 유형입니다. 유효한 값에는 `s3`, `mediapackagev2`, `mediastore` 및 `lambda` 등이 있습니다.

**timeouts(선택 사항)**  
CloudFront가 오리진이 응답하거나 데이터를 전송할 때까지 대기해야 하는 기간에 대해 지정할 수 있는 제한 시간입니다. 이를 제공하지 않으면 할당된 오리진의 제한 시간 설정이 사용됩니다.  
달리 명시되지 않은 한, 이러한 제한 시간은 사용자 지정 오리진과 Amazon S3 오리진을 모두 지원합니다.  
**readTimeout(선택 사항)**  
`readTimeout`은 다음 두 값 모두에 적용됩니다.  
+ CloudFront가 오리진에 요청을 전달한 후 응답을 기다리는 시간(초).
+ CloudFront가 오리진으로부터 응답 패킷을 수신한 후 다음 패킷을 수신할 때까지 대기하는 시간(초).
최소 제한 시간은 1초이고, 최대 제한 시간은 120초입니다. 자세한 내용은 [응답 제한 시간](DownloadDistValuesOrigin.md#DownloadDistValuesOriginResponseTimeout) 섹션을 참조하세요.  
**responseCompletionTimeout(선택 사항)**  
CloudFront에서 오리진으로의 요청이 열려 있고 응답을 기다릴 수 있는 시간(초). 이 시간까지 오리진에서 완전한 응답을 받지 못하면 CloudFront는 연결을 종료합니다.  
`responseCompletionTimeout` 값은 `readTimeout` 값과 같거나 이보다 커야 합니다. 자세한 내용은 [응답 완료 제한 시간](DownloadDistValuesOrigin.md#response-completion-timeout) 섹션을 참조하세요.  
**keepAliveTimeout(선택 사항)**  
이 제한 시간은 Amazon S3 오리진이 아닌 사용자 지정 오리진에만 적용됩니다. (S3 오리진 구성은 이러한 설정을 무시합니다.)   
`keepAliveTimeout`은 응답의 마지막 패킷을 수신한 후 CloudFront가 오리진에 대한 연결을 유지하려고 시도하는 시간을 지정합니다. 최소 제한 시간은 1초이고, 최대 제한 시간은 120초입니다. 자세한 내용은 [연결 유지 제한 시간(사용자 지정 및 VPC 오리진만 해당)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginKeepaliveTimeout) 섹션을 참조하세요.  
**connectionTimeout(선택 사항)**  
오리진에 대한 연결을 설정하려고 할 때 CloudFront가 대기하는 시간(초)입니다. 최소 제한 시간은 1초이고, 최대 제한 시간은 10초입니다. 자세한 내용은 [연결 제한 시간](DownloadDistValuesOrigin.md#origin-connection-timeout) 섹션을 참조하세요.

**customOriginConfig(선택 사항)**  
`customOriginConfig`를 사용하여 Amazon S3 버킷이 *아닌* 오리진에 대한 연결 설정을 지정합니다. 한 가지 예외는 다음과 같습니다. S3 버킷이 고정 웹 사이트 호스팅으로 구성된 경우 이러한 설정을 지정할 수 있습니다. (다른 유형의 S3 버킷 구성은 이러한 설정을 무시합니다.) `customOriginConfig`가 제공되지 않으면 할당된 오리진의 설정이 사용됩니다.    
**port(필수)**  
CloudFront가 오리진에 연결하는 데 사용하는 HTTP 포트입니다. 오리진에서 수신 대기하는 HTTP 포트를 지정하십시오.  
**protocol(필수)**  
CloudFront가 오리진에 연결하는 데 사용하는 프로토콜(HTTP 또는 HTTPS)을 지정합니다. 유효한 값은 다음과 같습니다.  
+ `http` - CloudFront는 항상 HTTP를 사용하여 오리진에 연결합니다.
+ `https` - CloudFront는 항상 HTTPS를 사용하여 오리진에 연결합니다.  
**sslProtocols(필수)**  
HTTPS를 통해 오리진에 연결할 때 CloudFront에서 사용하는 최소 SSL/TLS 프로토콜을 지정하는 목록입니다. 유효한 값에는 `SSLv3`, `TLSv1`, `TLSv1.1` 및 `TLSv1.2` 등이 있습니다. 자세한 내용은 [최소 오리진 SSL 프로토콜](DownloadDistValuesOrigin.md#DownloadDistValuesOriginSSLProtocols) 섹션을 참조하세요.  
**ipAddressType(선택 사항)**  
CloudFront가 오리진에 연결하는 데 사용하는 IP 주소 유형을 지정합니다. 유효값에는 `ipv4`, `ipv6` 및 `dualstack`이 있습니다. `ipAddressType` 변경은 `domainName` 속성도 변경 중인 경우에만 지원됩니다.

**sni(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
서버 이름 표시(SNI)는 Transport Layer Security(TLS) 프로토콜의 확장으로, 클라이언트가 TLS 핸드셰이크 프로세스를 시작할 때 연결을 시도하는 호스트 이름을 나타냅니다. 이 값은 오리진 서버의 TLS 인증서에 있는 일반 이름과 일치해야 합니다. 그렇지 않으면 오리진 서버에서 오류가 발생할 수 있습니다.  
제공하지 않으면 `hostHeader` 파라미터의 값이 사용됩니다. 호스트 헤더가 제공되지 않으면 `domainName` 파라미터의 값이 사용됩니다.  
호스트 헤더 또는 도메인 이름 파라미터가 제공되지 않은 경우 할당된 오리진의 도메인 이름이 사용되고, 오리진으로 전달(FTO) 정책에 호스트가 포함된 경우 수신 요청의 호스트 헤더가 사용됩니다. SNI에는 콜론(`:`)이 포함될 수 없으며 IP 주소가 될 수 없습니다. SNI는 최대 253자까지 작성할 수 있습니다.

**allowedCertificateNames(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
CloudFront에서 오리진 서버와의 TLS 핸드셰이크 중에 오리진 서버 TLS 인증서와 일치하는 도메인의 유효성을 검사하는 데 사용할 유효한 인증서 이름 목록을 포함할 수 있습니다. 이 필드에는 유효한 도메인 이름 배열이 필요하며 `*.example.com`과 같은 와일드카드 도메인이 포함될 수 있습니다.  
허용되는 인증서 이름은 최대 20개까지 지정할 수 있습니다. 각 인증서의 이름은 최대 64자까지 가능합니다.

**Example - Amazon S3 요청 오리진 업데이트**  
다음 예제에서는 뷰어 요청의 오리진을 S3 버킷으로 변경하고 OAC를 사용 설정하며 오리진으로 전송된 사용자 지정 헤더를 재설정합니다.  

```
cf.updateRequestOrigin({
    "domainName" : "amzn-s3-demo-bucket-in-us-east-1.s3.us-east-1.amazonaws.com",
    "originAccessControlConfig": {
        "enabled": true,
        "signingBehavior": "always",
        "signingProtocol": "sigv4",
        "originType": "s3"
    },
    // Empty object resets any header configured on the assigned origin
    "customHeaders": {}
});
```

**Example - Application Load Balancer 요청 오리진 업데이트**  
다음 예제에서는 뷰어 요청의 오리진을 Application Load Balancer 오리진으로 변경하고 사용자 지정 헤더와 제한 시간을 설정합니다.  

```
cf.updateRequestOrigin({
    "domainName" : "example-1234567890.us-east-1.elb.amazonaws.com",
    "timeouts": {
        "readTimeout": 30,
        "connectionTimeout": 5
    },
    "customHeaders": {
        "x-stage": "production",
        "x-region": "us-east-1"
    }
});
```

**Example - Origin Shield가 사용 설정된 오리진으로 업데이트**  
다음 예제에서는 배포의 오리진에 Origin Shield가 사용 설정되어 있습니다. 함수 코드는 오리진에 사용되는 도메인 이름만 업데이트하고 다른 모든 선택 사항 파라미터를 생략합니다. 이 경우 Origin Shield 파라미터가 업데이트되지 않았으므로 Origin Shield는 수정된 오리진 도메인 이름과 함께 계속 사용됩니다.  

```
cf.updateRequestOrigin({
    "domainName" : "www.example.com"
});
```

**Example - 호스트 헤더, SNI 및 허용된 인증서 이름 업데이트**  
대부분의 사용 사례에서는 오리진으로 이동하는 요청에 이러한 유형의 수정을 사용할 필요가 없습니다. 이러한 값 변경의 영향을 이해하지 못한다면 이러한 파라미터를 사용해서는 안 됩니다.
다음 예시에서는 요청에 대한 도메인 이름, 호스트 헤더, SNI 및 허용된 인증서를 오리진으로 변경합니다.  

```
cf.updateRequestOrigin({ 
    "domainName": "www.example.com", 
    "hostHeader": "test.example.com", 
    "sni": "test.example.net", 
    "allowedCertificateNames": ["*.example.com", "*.example.net"],
});
```

## selectRequestOriginById() 메서드
<a name="select-request-origin-id-helper-function"></a>

`selectRequestOriginById()`를 사용해 배포에 이미 구성된 다른 오리진을 선택하여 기존 오리진을 업데이트합니다. 이 메서드는 업데이트된 오리진에서 정의한 것과 동일한 설정을 모두 사용합니다.

이 메서드는 함수를 실행할 때 사용된 것과 동일한 배포에 이미 정의된 오리진만 허용합니다. 오리진은 오리진을 설정할 때 정의한 오리진 이름인 오리진 ID로 참조됩니다.

배포에 VPC 오리진이 구성된 경우 이 메서드를 사용하여 오리진을 VPC 오리진으로 업데이트할 수 있습니다. 자세한 내용은 [VPC 오리진으로 액세스 제한](private-content-vpc-origins.md) 섹션을 참조하세요.

**참고**  
`selectRequestOriginById()` 함수는 상호 TLS(오리진)가 활성화된 오리진을 선택할 수 없습니다. 이 함수를 사용하여 상호 TLS(오리진)가 활성화된 오리진을 선택하려고 하면 검증 오류가 발생합니다.
사용 사례에 따라 상호 TLS(오리진)를 사용한 동적 오리진 선택이 필요한 경우, 모든 대상 오리진이 동일한 클라이언트 인증서를 사용하도록 `updateRequestOrigin()`을 대신 사용하세요.

**요청**

```
cf.selectRequestOriginById(origin_id, {origin_overrides})
```

이전 예시에서 `origin_id`는 함수를 실행하는 배포에서 오리진의 오리진 이름을 가리키는 문자열입니다. `origin_overrides `파라미터에는 다음이 포함될 수 있습니다.

**hostHeader(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
오리진에 요청할 때 사용할 호스트 헤더입니다. 제공하지 않으면 `domainName` 파라미터의 값이 사용됩니다.  
호스트 헤더 또는 도메인 이름 파라미터가 제공되지 않은 경우 할당된 오리진의 도메인 이름이 사용되고, 오리진으로 전달(FTO) 정책에 호스트가 포함된 경우 수신 요청의 호스트 헤더가 사용됩니다. 호스트 헤더에는 콜론(`:`)이 포함될 수 없으며 IP 주소가 될 수 없습니다. 호스트 헤더는 최대 253자까지 작성할 수 있습니다.

**sni(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
서버 이름 표시(SNI)는 Transport Layer Security(TLS) 프로토콜의 확장으로, 클라이언트가 TLS 핸드셰이크 프로세스를 시작할 때 연결을 시도하는 호스트 이름을 나타냅니다. 이 값은 오리진 서버의 TLS 인증서에 있는 일반 이름과 일치해야 합니다. 그렇지 않으면 오리진 서버에서 오류가 발생할 수 있습니다.  
제공하지 않으면 `hostHeader` 파라미터의 값이 사용됩니다. 호스트 헤더가 제공되지 않으면 `domainName` 파라미터의 값이 사용됩니다.  
호스트 헤더 또는 도메인 이름 파라미터가 제공되지 않은 경우 할당된 오리진의 도메인 이름이 사용되고, 오리진으로 전달(FTO) 정책에 호스트가 포함된 경우 수신 요청의 호스트 헤더가 사용됩니다. SNI에는 콜론(`:`)이 포함될 수 없으며 IP 주소가 될 수 없습니다. SNI는 최대 253자까지 작성할 수 있습니다.

**allowedCertificateNames(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
CloudFront에서 오리진 서버와의 TLS 핸드셰이크 중에 오리진 서버 TLS 인증서와 일치하는 도메인의 유효성을 검사하는 데 사용할 유효한 인증서 이름 목록을 포함할 수 있습니다. 이 필드에는 유효한 도메인 이름 배열이 필요하며 `*.example.com`과 같은 와일드카드 도메인이 포함될 수 있습니다.  
허용되는 인증서 이름은 최대 20개까지 지정할 수 있습니다. 각 인증서의 이름은 최대 64자까지 가능합니다.

**요청**

```
selectRequestOriginById(origin_id)
```

앞의 예시에서 `origin_id`는 함수를 실행하는 배포에서 오리진의 오리진 이름을 가리키는 문자열입니다.

**Example - Amazon S3 요청 오리진 선택**  
다음 예시에서는 배포와 연결된 오리진 목록에서 `amzn-s3-demo-bucket-in-us-east-1`라는 오리진을 선택하고 `amzn-s3-demo-bucket-in-us-east-1` 오리진의 구성 설정을 요청에 적용합니다.  

```
cf.selectRequestOriginById("amzn-s3-demo-bucket-in-us-east-1");
```

**Example - Application Load Balancer 요청 오리진 선택**  
다음 예시에서는 배포와 연결된 오리진 목록에서 `myALB-prod`라는 Application Load Balancer 오리진을 선택하고 `myALB-prod`의 구성 설정을 요청에 적용합니다.  

```
cf.selectRequestOriginById("myALB-prod");
```

**Example - Application Load Balancer 요청 오리진을 선택하고 호스트 헤더를 재정의합니다.**  
이전 예시와 같이 다음 예시에서는 배포와 연결된 오리진 목록에서 `myALB-prod`라는 Application Load Balancer 오리진을 선택하고 `myALB-prod`의 구성 설정을 요청에 적용합니다. 그러나 이 예제에서는 `origin_overrides`를 사용하여 호스트 헤더 값을 재정의합니다.  

```
cf.overrideRequestOrigin("myALB-prod",{ 
        "hostHeader" : "test.example.com"
});
```

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

`createRequestOriginGroup()`를 사용하여 고가용성이 필요한 시나리오에서 장애 조치용 [오리진 그룹](high_availability_origin_failover.md#concept_origin_groups.creating)으로 사용할 두 개의 오리진을 정의합니다.

오리진 그룹에는 두 개의 오리진(프라이머리 및 보조)과 사용자가 지정하는 장애 조치 기준이 포함됩니다. CloudFront에서 오리진 장애 조치를 지원할 오리진 그룹을 생성합니다. 이 메서드를 사용하여 오리진 그룹을 생성하거나 업데이트할 때 단일 오리진 대신 오리진 그룹을 지정할 수 있습니다. CloudFront는 장애 조치 기준을 사용하여 프라이머리 오리진에서 보조 오리진으로 장애 조치를 수행합니다.

배포에 VPC 오리진이 구성된 경우 이 메서드를 통해 VPC 오리진을 사용하여 오리진 그룹을 생성할 수 있습니다. 자세한 내용은 [VPC 오리진으로 액세스 제한](private-content-vpc-origins.md) 섹션을 참조하세요.

**참고**  
`createRequestOriginGroup()` 함수는 상호 TLS(오리진)가 활성화된 오리진을 포함하는 오리진 그룹 생성을 지원하지 않습니다. 상호 TLS(오리진) 오리진이 있는 오리진 그룹은 CloudFront Functions를 통해 동적으로 생성할 수 없습니다.
상호 TLS(오리진)를 사용한 오리진 장애 조치 기능이 필요한 경우 함수에서 동적으로 생성하는 대신 CloudFront 배포 설정에서 오리진 그룹을 직접 구성하세요.

### 요청
<a name="create-origin-group-request"></a>

```
createRequestOriginGroup({origin_group_properties})
```

앞의 예시에서 `origin_group_properties`에는 다음이 포함될 수 있습니다.

**originIds(필수)**  
`origin_ids` 배열이며, 여기서 `origin_id`는 함수를 실행하는 배포에서 오리진의 오리진 이름을 가리키는 문자열입니다. 배열의 일부로 두 개의 오리진을 제공해야 합니다. 목록의 첫 번째 오리진은 프라이머리 오리진이고 두 번째 오리진은 장애 조치를 위한 보조 오리진 역할을 합니다.

**originOverrides(선택 사항)**  
 `{origin_overrides}` 파라미터를 사용하여 몇 가지 고급 설정을 덮어쓸 수 있습니다. `origin overrides`에는 다음 사항이 포함될 수 있습니다.    
**hostHeader(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
오리진에 요청할 때 사용할 호스트 헤더입니다. 제공하지 않으면 `domainName` 파라미터의 값이 사용됩니다.  
호스트 헤더 또는 도메인 이름 파라미터가 제공되지 않은 경우 할당된 오리진의 도메인 이름이 사용되고, 오리진으로 전달(FTO) 정책에 호스트가 포함된 경우 수신 요청의 호스트 헤더가 사용됩니다. 호스트 헤더에는 콜론(`:`)이 포함될 수 없으며 IP 주소가 될 수 없습니다. 호스트 헤더는 최대 253자까지 작성할 수 있습니다.  
**sni(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
서버 이름 표시(SNI)는 클라이언트가 TLS 핸드셰이크 프로세스를 시작할 때 연결을 시도하는 호스트 이름을 나타내는 Transport Layer Security(TLS) 프로토콜의 확장입니다. 이 값은 오리진 서버의 TLS 인증서에 있는 일반 이름과 일치해야 합니다. 그렇지 않으면 오리진 서버에서 오류가 발생할 수 있습니다.  
제공하지 않으면 `hostHeader` 파라미터의 값이 사용됩니다. 호스트 헤더가 제공되지 않으면 `domainName` 파라미터의 값이 사용됩니다.  
호스트 헤더 또는 도메인 이름 파라미터가 제공되지 않은 경우 할당된 오리진의 도메인 이름이 사용되고, 오리진으로 전달(FTO) 정책에 호스트가 포함된 경우 수신 요청의 호스트 헤더가 사용됩니다. SNI에는 콜론(`:`)이 포함될 수 없으며 IP 주소가 될 수 없습니다. SNI는 최대 253자까지 작성할 수 있습니다.  
**allowedCertificateNames(선택 사항, S3가 아닌 사용자 지정 오리진의 경우)**  
CloudFront에서 오리진 서버와의 TLS 핸드셰이크 중에 오리진 서버 TLS 인증서와 일치하는 도메인의 유효성을 검사하는 데 사용할 유효한 인증서 이름 목록을 포함할 수 있습니다. 이 필드에는 유효한 도메인 이름 배열이 필요하며 `*.example.com`과 같은 와일드카드 도메인이 포함될 수 있습니다.  
허용되는 인증서 이름은 최대 20개까지 지정할 수 있습니다. 각 인증서의 이름은 최대 64자까지 가능합니다.

**selectionCriteria(선택 사항)**  
`default` 오리진 장애 조치 기준을 사용할지 아니면 `media-quality-score` 기반 장애 조치 로직을 사용할지 선택합니다. 유효한 값은 다음과 같습니다.  
+ `default`는 `failoverCriteria`에 지정된 상태 코드를 기반으로 장애 조치 기준을 사용합니다. 함수에서 `selectionCriteria`를 설정하지 않으면 `default`가 사용됩니다.
+ `media-quality-score`는 미디어 인식 라우팅 기능을 사용할 때 사용됩니다.

**failoverCriteria(필수)**  
프라이머리 오리진에서 반환될 때 CloudFront가 보조 오리진으로 장애 조치하도록 트리거하는 상태 코드 배열입니다. 기존 오리진 그룹을 덮어쓰면 이 배열은 오리진 그룹의 원래 구성에 설정된 모든 장애 조치 상태 코드를 덮어씁니다.  
`media-quality-score` `selectionCriteria`를 사용하는 경우 CloudFront는 미디어 품질 점수를 기반으로 요청을 라우팅하려고 시도합니다. 선택한 오리진이 이 배열에 설정된 오류 코드를 반환하면 CloudFront는 다른 오리진으로 장애 조치를 수행합니다.

**Example - 요청 오리진 그룹 생성**  
다음 예시에서는 오리진 ID를 사용하여 요청에 대한 오리진 그룹을 생성합니다. 이러한 오리진 ID는 이 함수를 실행하는 데 사용되는 배포의 오리진 그룹 구성에서 가져옵니다.  
선택적으로 `originOverrides`를 사용하여 `sni`, `hostHeader` 및 `allowedCertificateNames`에 대한 오리진 그룹 구성을 재정의할 수 있습니다.  

```
import cf from 'cloudfront';

function handler(event) {
    cf.createRequestOriginGroup({
        "originIds": [
            {
                "originId": "origin-1",
                "originOverrides": {
                    "hostHeader": "hostHeader.example.com",
                    "sni": "sni.example.com",
                    "allowedCertificateNames": ["cert1.example.com", "cert2.example.com", "cert3.example.com"]
                }
            },
            {
                "originId": "origin-2",
                "originOverrides": {
                    "hostHeader": "hostHeader2.example.com",
                    "sni": "sni2.example.com",
                    "allowedCertificateNames": ["cert4.example.com", "cert5.example.com"]
                }
            }
        ],
        "failoverCriteria": {
            "statusCodes": [500]
        }
    });
    
    event.request.headers['x-hookx'] = { value: 'origin-overrides' };
    return event.request;
}
```

# CloudFront SaaS Manager 속성에 대한 헬퍼 메서드
<a name="saas-specific-logic-function-code"></a>

CloudFront SaaS Manager에서 다음 헬퍼 함수를 사용하여 직접 만든 함수에서 다중 테넌트 배포의 값을 검색합니다. 이 페이지의 예제를 사용하려면 먼저 JavaScript 런타임 2.0을 사용하여 CloudFront 함수를 만들어야 합니다. 자세한 설명은 [CloudFront Functions를 위한 JavaScript 런타임 2.0 기능](functions-javascript-runtime-20.md) 섹션을 참조하세요.

**Topics**
+ [연결 그룹](#connection-groups-helper-function)
+ [배포 테넌트](#distribution-tenants-helper-functions)

## 연결 그룹
<a name="connection-groups-helper-function"></a>

배포 테넌트와 연결된 연결 그룹에는 도메인 이름이 있습니다.

이 값을 가져오려면 이벤트 객체의 `context` 하위 객체에서 `endpoint` 필드를 사용합니다.

**요청**

```
const value = event.context.endpoint;
```

**응답**

응답은 연결 그룹의 도메인 이름이 포함된 `string`(예: d111111abcdef8.cloudfront.net)입니다. `endpoint` 필드는 연결된 연결 그룹이 있는 다중 테넌트 배포에 대해 함수가 호출되는 경우에만 나타납니다. 자세한 내용은 [컨텍스트 객체](functions-event-structure.md#functions-event-structure-context) 섹션을 참조하세요.

## 배포 테넌트
<a name="distribution-tenants-helper-functions"></a>

CloudFront Functions에는 특정 배포 테넌트 값에 대한 액세스를 제공하는 모듈이 있습니다.

이 모듈을 사용하려면 다음 함수 코드의 첫 줄에 다음 스테이트먼트를 포함합니다.

```
import cf from 'cloudfront';
```

다음 예제는 `handler` 함수에서만 직접 또는 중첩 호출 함수를 통해 사용할 수 있습니다.

### `distributionTenant.id` 필드
<a name="distribution-tenants-field"></a>

이 필드를 사용하여 배포 테넌트 ID의 값을 가져옵니다.

**요청**

```
const value = cf.distributionTenant.id;
```

**응답**

응답은 배포 테넌트 ID를 포함하는 `string`(예: `dt_1a2b3c4d5e6f7`)입니다.

**오류 처리**.

함수가 표준 배포에서 호출되는 경우 `distributionTenant.id` 필드를 지정하면 `distributionTenant module is not available` 유형 오류가 반환됩니다. 이 사용 사례를 처리하기 위해 코드에 `try` 및 `catch` 블록을 추가할 수 있습니다.

### `distributionTenant.parameters.get()` 메서드
<a name="distribution-tenant-parameters-get-method"></a>

이 메서드를 사용하여 지정한 배포 테넌트 파라미터 이름의 값을 반환합니다.

```
distributionTenant.parameters.get("key");
```

`key`: 값을 가져오려는 배포 테넌트 파라미터 이름입니다.

**요청**

```
const value = distributionTenant.parameters.get("key");
```

**응답**

응답은 배포 테넌트 파라미터의 값을 포함하는 `string`입니다. 예를 들어 키 이름이 `TenantPath`인 경우 이 파라미터의 값은 `tenant1`일 수 있습니다.

**오류 처리**.

다음 오류가 표시될 수 있습니다.
+ 함수가 표준 배포에서 호출되는 경우 `distributionTenant.parameters.get()` 메서드는 `distributionTenant module is not available` 유형 오류를 반환합니다.
+ 지정한 배포 테넌트 파라미터가 존재하지 않으면 `DistributionTenantParameterKeyNotFound` 오류가 반환됩니다.

이 사용 사례를 관리하기 위해 코드에 `try` 및 `catch` 블록을 추가할 수 있습니다.

# async 및 await 사용
<a name="async-await-syntax"></a>

CloudFront Functions JavaScript 런타임 함수 2.0은 `Promise` 객체를 처리하기 위한 `async` 및 `await` 구문을 제공합니다. 프로미스는 `async`로 표시된 함수의 `await` 키워드를 통해 액세스할 수 있는 지연된 결과를 나타냅니다. 다양한 새 WebCrypto 함수가 프로미스를 사용합니다.

`Promise` 객체에 대한 자세한 내용은 [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)를 참조하세요.

**참고**  
다음 코드 샘플에는 JavaScript 런타임 2.0을 사용해야 합니다.  
`await`는 `async` 함수 내에서만 사용할 수 있습니다. `async` 인수 및 종료는 지원되지 않습니다.

```
async function answer() {
    return 42;
}

// Note: async, await can be used only inside an async function. async arguments and closures are not supported.

async function handler(event) {
    // var answer_value = answer(); // returns Promise, not a 42 value
    let answer_value = await answer(); // resolves Promise, 42
    console.log("Answer"+answer_value);
    event.request.headers['answer'] = { value : ""+answer_value };
    return event.request;
}
```

다음 예제 JavaScript 코드는 `then` 체인 메서드로 프로미스를 보는 방법을 보여줍니다. `catch`를 사용하여 오류를 확인할 수 있습니다.

**주의**  
promise 결합자(예: `Promise.all`, `Promise.any`) 및 promise 체인 메서드(예: `then` 및 `catch`)를 사용하려면 많은 함수 메모리 사용량이 필요할 수 있습니다. 함수가 [최대 함수 메모리](cloudfront-limits.md#limits-functions) 할당량을 초과하면 실행에 실패합니다. 이 오류를 방지하도록 `promise` 메서드 대신 `await` 구문을 사용하는 것이 좋습니다.

```
async function answer() {
    return 42;
}

async function squared_answer() {
   return answer().then(value => value * value)
} 
// Note: async, await can be used only inside an async function. async arguments and closures are not supported.
async function handler(event) {
    // var answer_value = answer(); // returns Promise, not a 42 value
    let answer_value = await squared_answer(); // resolves Promise, 42
    console.log("Answer"+answer_value);
    event.request.headers['answer'] = { value : ""+answer_value };
    return event.request;
}
```

# CloudFront Functions에 대한 CWT 지원
<a name="cwt-support-cloudfront-functions"></a>

이 섹션에서는 CloudFront 엣지 로케이션에서 보안 토큰 기반 인증 및 권한 부여를 활성화하는 CloudFront Functions의 CBOR 웹 토큰(CWT) 지원에 대한 세부 정보를 제공합니다. 이 지원은 CloudFront Functions에서 액세스할 수 있는 모듈로 제공됩니다.

이 모듈을 사용하려면 JavaScript 런타임 2.0을 사용하여 CloudFront Functions을 만들고 함수 코드의 첫 번째 줄에 다음 스테이트먼트를 포함합니다.

```
import cf from 'cloudfront';
```

이 모듈과 연결된 메서드는 다음을 통해 액세스할 수 있습니다(여기서 \$1는 모듈에 있는 다양한 함수를 나타내는 와일드카드).

```
cf.cwt.*
```

자세한 내용은 [CloudFront Functions를 위한 JavaScript 런타임 2.0 기능](functions-javascript-runtime-20.md) 섹션을 참조하세요.

현재 모듈은 최대 토큰 크기에 대해 한도가 1KB인 HS256(HMAC-SHA256) 알고리즘을 사용하는 MAC0 구조만 지원합니다.

## 토큰 구조
<a name="token-structure"></a>

이 섹션에서는 CWT 모듈에서 예상되는 토큰 구조를 다룹니다. 모듈은 토큰에 태그를 올바르게 지정하고 식별할 수 있어야 합니다(예: COSE MAC0). 또한 토큰의 구조와 마찬가지로 모듈은 [CBOR 객체 서명 및 암호화(COSE)[RFC 8152]](https://datatracker.ietf.org/doc/html/rfc8152)에서 설정한 표준을 따릅니다.

```
( // CWT Tag (Tag value: 61) --- optional    
    ( // COSE MAC0 Structure Tag (Tag value: 17) --- required        
        [            
            protectedHeaders,            
            unprotectedHeaders,            
            payload,            
            tag,        
        ]    
    )
)
```

**Example : COSE MAC0 구조를 사용한 CWT**  

```
61( // CWT tag     
    17( // COSE_MAC0 tag       
        [         
            { // Protected Headers           
                1: 4  // algorithm : HMAC-256-64         
            },         
            { // Unprotected Headers           
                4: h'53796d6d6574726963323536' // kid : Symmetric key id          
            },         
            { // Payload           
                1: "https://iss.example.com", // iss           
                2: "exampleUser", // sub           
                3: "https://aud.example.com", // aud           
                4: 1444064944, // exp           
                5: 1443944944, // nbf           
                6: 1443944944, // iat         
            },         
            h'093101ef6d789200' // tag       
        ]     
    )   
)
```
CWT 태그는 토큰을 생성할 때 선택 사항입니다. 그러나 COSE 구조 태그는 필수입니다.

## validateToken() 메서드
<a name="validatetoken-method"></a>

함수는 지정된 키를 사용하여 CWT 토큰을 디코딩하고 검증합니다. 검증에 성공하면 디코딩된 CWT 토큰을 반환합니다. 그렇지 않으면 오류가 발생합니다. 이 함수는 클레임 세트에 대한 검증을 수행하지 않습니다.

### 요청
<a name="validatetoken-request"></a>

```
cf.cwt.validateToken(token, handlerContext{key})
```Parameters

**토큰(필수)**  
검증을 위한 인코딩된 토큰입니다. JavaScript 버퍼여야 합니다.

**handlerContext(필수)**  
validateToken 직접 호출에 대한 컨텍스트를 저장하는 JavaScript 객체입니다. 현재 키 속성만 지원됩니다.

**키(필수)**  
메시지 다이제스트 계산을 위한 비밀 키입니다. 문자열 또는 JavaScript 버퍼로 제공할 수 있습니다.

### 응답
<a name="validatetoken-response"></a>

`validateToken()` 메서드가 성공적으로 검증된 토큰을 반환하면 함수의 응답은 다음 형식의 `CWTObject`입니다. 디코딩되면 모든 클레임 키가 문자열로 표시됩니다.

```
CWTObject {    
    protectedHeaders,    
    unprotectedHeaders,    
    payload
}
```

### 예제 - 토큰의 일부로 전송된 KID로 토큰 검증
<a name="validatetoken-example"></a>

이 예제는 키드가 헤더에서 추출되는 CWT 토큰 검증을 보여줍니다. 그런 다음 키드가 CloudFront Functions KeyValueStore로 전달되어 토큰을 검증하는 데 사용되는 보안 키를 가져옵니다.

```
import cf from 'cloudfront'

const CwtClaims = {
   iss: 1,
   aud: 3,
   exp: 4
}

async function handler(event) {
    try {
        let request = event.request;
        let encodedToken = request.headers['x-cwt-token'].value;
        let kid = request.headers['x-cwt-kid'].value;
                
        // Retrieve the secret key from the kvs
        let secretKey = await cf.kvs().get(kid);
                 
        // Now you can use the secretKey to decode & validate the token.
        let tokenBuffer = Buffer.from(encodedToken, 'base64url');
                
        let handlerContext = {
           key: secretKey,
        }
                
        try {
            let cwtObj = cf.cwt.validateToken(tokenBuffer, handlerContext);
                        
            // Check if token is expired
            const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
            if (cwtObj[CwtClaims.exp] && cwtObj[CwtClaims.exp] < currentTime) {
                return {
                    statusCode: 401,
                    statusDescription: 'Token expired'
                };
            }
        } catch (error) {
            return {
               statusCode: 401,
               statusDescription: 'Invalid token'
            };
         }
    } catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
     }
    return request;
}
```

## generateToken() 메서드
<a name="generatetoken-method"></a>

이 함수는 제공된 페이로드 및 컨텍스트 설정을 사용하여 새 CWT 토큰을 생성합니다.

### 요청
<a name="generatetoken-request"></a>

```
cf.cwt.generateToken(generatorContext, payload)
```Parameters

**generatorContext(필수)**  
이 JavaScript 객체는 토큰을 생성하기 위한 컨텍스트로 사용되며 다음 키 값 페어를 포함합니다.    
**cwtTag(선택 사항)**  
이 값은 부울로, `true`인 경우 `cwtTag`를 추가해야 함을 지정합니다.  
**coseTag(필수)**  
COSE 태그 유형을 지정합니다. 현재 `MAC0`만 지원됩니다.  
**키(필수)**  
메시지 다이제스트를 계산하는 비밀 키입니다. 이 값은 문자열 또는 JavaScript `Buffer`일 수 있습니다.

**페이로드(필수)**  
인코딩을 위한 토큰 페이로드입니다. 페이로드는 `CWTObject` 형식이어야 합니다.

### 응답
<a name="generatetoken-response"></a>

인코딩된 토큰이 포함된 JavaScript 버퍼를 반환합니다.

**Example : CWT 토큰 생성**  

```
import cf from 'cloudfront';

const CwtClaims = {
    iss: 1,
    sub: 2,
    exp: 4
};

const CatClaims = {
    catu: 401,
    catnip: 402,
    catm: 403,
    catr: 404
};

const Catu = {
    host: 1,
    path: 2,
    ext: 3
};

const CatuMatchTypes = {
    prefix_match: 1,
    suffix_match: 2,
    exact_match: 3
};

const Catr = {
    renewal_method: 1,
    next_renewal_time: 2,
    max_uses: 3
};

async function handler(event) {
    try {
        const response = {
            statusCode: 200,
            statusDescription: 'OK',
            headers: {}
        };
        
        const commonAccessToken = {
            protected: {
                1: "5",
            },
            unprotected: {},
            payload: {
                [CwtClaims.iss]: "cloudfront-documentation",
                [CwtClaims.sub]: "cwt-support-on-cloudfront-functions",
                [CwtClaims.exp]: 1740000000,
                [CatClaims.catu]: {
                    [Catu.host]: {
                        [CatuMatchTypes.suffix_match]: ".cloudfront.net"
                    },
                    [Catu.path]: {
                        [CatuMatchTypes.prefix_match]: "/media/live-stream/cf-4k/"
                    },
                    [Catu.ext]: {
                        [CatuMatchTypes.exact_match]: [
                            ".m3u8",
                            ".ts",
                            ".mpd"
                        ]
                    }
                },
                [CatClaims.catnip]: [
                    "[IP_ADDRESS]",
                    "[IP_ADDRESS]"
                ],
                [CatClaims.catm]: [
                    "GET",
                    "HEAD"
                ],
                [CatClaims.catr]: {
                    [Catr.renewal_method]: "header_renewal",
                    [Catr.next_renewal_time]: 1750000000,
                    [Catr.max_uses]: 5
                }
            }
        };
        
        if (!request.headers['x-cwt-kid']) {
            throw new Error('Missing x-cwt-kid header');
        }
        
        const kid = request.headers['x-cwt-kid'].value;
        const secretKey = await cf.kvs().get(kid);
        
        if (!secretKey) {
            throw new Error('Secret key not found for provided kid');
        }
        
        try {
            const genContext = {
                cwtTag: true,
                coseTag: "MAC0",
                key: secretKey
            };
            
            const tokenBuffer = cf.cwt.generateToken(commonAccessToken, genContext);
            response.headers['x-generated-cwt-token'] = { value: tokenBuffer.toString('base64url') };
                        
            return response;
        } catch (tokenError) {
            return {
                statusCode: 401,
                statusDescription: 'Could not generate the token'
            };
        }
    } catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
    }
}
```

**Example : 일부 로직을 기반으로 토큰 새로 고침**  

```
import cf from 'cloudfront'

const CwtClaims = {
   iss: 1,
   aud: 3,
   exp: 4
}

async function handler(event) {
    try {
        let request = event.request;
        let encodedToken = request.headers['x-cwt-token'].value;
        let kid = request.headers['x-cwt-kid'].value;
        let secretKey = await cf.kvs().get(kid); // Retrieve the secret key from the kvs
                
        // Now you can use the secretKey to decode & validate the token.
        let tokenBuffer = Buffer.from(encodedToken, 'base64url');
                
        let handlerContext = {
           key: secretKey,
        }
                
        try {
            let cwtJSON = cf.cwt.validateToken(tokenBuffer, handlerContext);
                        
            // Check if token is expired
            const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
            if (cwtJSON[CwtClaims.exp] && cwtJSON[CwtClaims.exp] < currentTime) {
                // We can regnerate the token and add 8 hours to the expiry time
                cwtJSON[CwtClaims.exp] = Math.floor(Date.now() / 1000) + (8 * 60 * 60);
                                
                let genContext = {
                  coseTag: "MAC0",
                  key: secretKey
                }
                                
                let newTokenBuffer = cf.cwt.generateToken(cwtJSON, genContext);
                 request.headers['x-cwt-regenerated-token'] = newTokenBuffer.toString('base64url');
            }
        } catch (error) {
            return {
               statusCode: 401,
               statusDescription: 'Invalid token'
            };
         }
    }
    catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
     }
    return request;
}
```

# 일반 헬퍼 메서드
<a name="general-helper-methods"></a>

이 페이지에서는 CloudFront Functions 내의 추가 헬퍼 메서드를 제공합니다. 이러한 메서드를 사용하려면 JavaScript 런타임 2.0을 사용하여 CloudFront Functions를 생성합니다.

```
import cf from 'cloudfront';
```

자세한 내용은 [CloudFront Functions를 위한 JavaScript 런타임 2.0 기능](functions-javascript-runtime-20.md) 섹션을 참조하세요.

## `edgeLocation` 메타데이터
<a name="edge-location-metadata"></a>

이 메서드를 사용하려면 `cloudfront` 모듈을 사용해야 합니다.

**참고**  
뷰어 요청 함수에만 이 방법을 사용할 수 있습니다. 뷰어 응답 함수의 경우 이 메서드는 비어 있습니다.

이 JavaScript 객체를 사용하여 요청을 처리하는 데 사용되는 엣지 로케이션 공항 코드, 예상 [리전 엣지 캐시](HowCloudFrontWorks.md#CloudFrontRegionaledgecaches) 리전 또는 CloudFront 서버 IP 주소를 가져옵니다. 이 메타데이터는 뷰어 요청 이벤트 트리거만 사용할 수 있습니다.

```
cf.edgeLocation = {
    name: SEA
    serverIp: 1.2.3.4
    region: us-west-2
}
```

`cf.edgeLocation` 객체에는 다음 사항이 포함될 수 있습니다.

**이름**  
요청을 처리한 엣지 로케이션의 세 글자 [IATA 코드](https://en.wikipedia.org/wiki/IATA_airport_code)입니다.

**serverIp**  
요청을 처리한 서버의 IPv4 또는 IPv6 주소입니다.

**region**  
캐시 누락이 있는 경우 요청이 사용할 것으로 *예상되는* CloudFront 리전 엣지 캐시(REC)입니다. 이 값은 예상 REC를 사용할 수 없고 백업 REC가 요청에 사용되는 경우 업데이트되지 않습니다. 여기에는 사용 중인 Origin Shield 위치가 포함되지 않습니다. 단, 기본 REC와 Origin Shield가 동일한 위치인 경우는 예외입니다.

**참고**  
CloudFront가 오리진 장애 조치를 사용하도록 구성된 경우 CloudFront Functions는 두 번째로 간접 호출되지 않습니다. 자세한 내용은 [CloudFront 오리진 장애 조치를 통한 고가용성 최적화](high_availability_origin_failover.md) 섹션을 참조하세요.

## `rawQueryString()` 메서드
<a name="raw-query-string-method"></a>

이 메서드에는 `cloudFront` 모듈이 필요하지 않습니다.

`rawQueryString()` 메서드를 사용하여 구문 분석되지 않은 쿼리 문자열과 변경되지 않은 쿼리 문자열을 문자열로 검색합니다.

**요청**

```
function handler(event) {
    var request = event.request;
    const qs = request.rawQueryString();
}
```

**응답**

수신 요청의 전체 쿼리 문자열을 선행 `?` 없이 문자열 값으로 반환합니다.
+ 쿼리 문자열이 없지만 `?`가 있는 경우 함수는 빈 문자열을 반환합니다.
+ 쿼리 문자열이 없고 `?`가 없는 경우 함수는 `undefined`를 반환합니다.

**사례 1: 반환된 전체 쿼리 문자열(선행 `?` 없음)**  
수신 요청 URL: `https://example.com/page?name=John&age=25&city=Boston`  
`rawQueryString()`에서 를 반환합니다.`"name=John&age=25&city=Boston"`

**사례 2: 빈 문자열 반환됨(`?`가 있지만 파라미터가 없는 경우)**  
수신 요청 URL: `https://example.com/page?`  
`rawQueryString()`에서 를 반환합니다.`""`

**사례 3: `undefined` 반환됨(쿼리 문자열 및 `?` 없음)**  
수신 요청 URL: `https://example.com/page`  
`rawQueryString()`에서 를 반환합니다.`undefined`

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

함수는 두 단계로 생성합니다.

1. 함수 코드를 JavaScript로 생성합니다. CloudFront 콘솔의 기본 예제를 사용하거나, 직접 작성할 수 있습니다. 자세한 정보는 다음의 주제를 참조하세요.
   + [함수 코드 작성](writing-function-code.md)
   + [CloudFront 함수 이벤트 구조](functions-event-structure.md)
   + [CloudFront의 CloudFront Functions 예제](service_code_examples_cloudfront_functions_examples.md)

1. CloudFront를 사용하여 함수를 생성하고 코드를 포함합니다. 코드는 함수 내에 존재합니다(참조용이 아님).

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

**함수를 만들려면**

1. CloudFront 콘솔([https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions))에 로그인하고 **함수** 페이지를 엽니다.

1. **함수 생성(Create function)**을 선택합니다.

1. AWS 계정 내에서 고유한 함수 이름을 입력한 다음 JavaScript 버전을 선택하고 **계속**을 선택합니다. 새 함수의 세부 정보 페이지가 나타납니다.
**참고**  
함수에서 [키 값 페어](kvs-with-functions.md)를 사용하려면 JavaScript 런타임 2.0을 선택해야 합니다.

1. **함수 코드** 섹션에서 **빌드** 탭을 선택하고 함수 코드를 입력합니다. **빌드** 탭에 포함된 샘플 코드는 함수 코드의 기본 구문을 보여줍니다.

1. **Save changes**(변경 사항 저장)를 선택합니다.

1. 함수 코드에서 키 값 페어를 사용하는 경우 키 값 저장소를 연결해야 합니다.

   함수를 처음 생성할 때 키 값 저장소를 연결할 수 있습니다. 또는 나중에 [함수를 업데이트](update-function.md)하여 연결할 수도 있습니다.

   지금 키 값 저장소를 연결하려면 다음 단계를 따르세요.
   + **KeyValueStore 연결** 섹션에서 **기존 KeyValueStore 연결**을 선택합니다.
   + 함수의 키 값 페어가 들어 있는 키 값 저장소를 선택한 다음 **KeyValueStore 연결**을 선택합니다.

   CloudFront는 저장소를 함수와 즉시 연결하므로 함수를 저장하지 않아도 됩니다.

------
#### [ CLI ]

CLI를 사용하는 경우 일반적으로 먼저 파일에 함수 코드를 생성한 다음 AWS CLI로 함수를 생성합니다.

**함수를 만들려면**

1. 함수 코드를 파일로 만든 다음 컴퓨터가 연결할 수 있는 디렉터리에 저장합니다.

1. 다음 예제와 같이 명령을 실행합니다. 이 예제에서는 `fileb://` 표기법을 사용하여 파일을 전달합니다. 명령을 더 쉽게 읽을 수 있도록 줄 바꿈도 포함되어 있습니다.

   ```
   aws cloudfront create-function \
       --name MaxAge \
       --function-config '{"Comment":"Max Age 2 years","Runtime":"cloudfront-js-2.0","KeyValueStoreAssociations":{"Quantity":1,"Items":[{"KeyValueStoreARN":"arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"}]}}' \
       --function-code fileb://function-max-age-v1.js
   ```
**Notes**  
`Runtime` - JavaScript의 버전입니다. 함수에 [키 값 페어](kvs-with-functions.md)를 사용하려면 버전 2.0을 지정해야 합니다.
`KeyValueStoreAssociations` - 함수에서 키 값 페어를 사용하는 경우 함수를 처음 생성할 때 키 값 저장소를 연결할 수 있습니다. 또는 `update-function`을 사용하여 나중에 연결할 수도 있습니다. 각 함수에 키 값 저장소가 하나만 연결될 수 있기 때문에 `Quantity`는 항상 `1`입니다.

   명령이 제대로 실행되면 다음과 비슷한 출력이 표시됩니다.

   ```
   ETag: ETVABCEXAMPLE
   FunctionSummary:
     FunctionConfig:
       Comment: Max Age 2 years
       Runtime: cloudfront-js-2.0
       KeyValueStoreAssociations= \
         {Quantity=1, \
         Items=[{KeyValueStoreARN='arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111'}]} \
     FunctionMetadata:
       CreatedTime: '2021-04-18T20:38:56.915000+00:00'
       FunctionARN: arn:aws:cloudfront::111122223333:function/MaxAge
       LastModifiedTime: '2023-11-19T20:38:56.915000+00:00'
       Stage: DEVELOPMENT
     Name: MaxAge
     Status: UNPUBLISHED
   Location: https://cloudfront.amazonaws.com/2020-05-31/function/arn:aws:cloudfront:::function/MaxAge
   ```

   대부분의 정보는 요청에서 반복된 내용입니다. 기타 정보는 CloudFront에 의해 추가됩니다.
**Notes**  
`ETag` - 이 값은 키 값 저장소를 수정할 때마다 변경됩니다. 나중에 이 값과 함수 이름을 사용하여 함수를 참조할 수 있습니다. 항상 현재 `ETag`를 사용하도록 하세요.
`FunctionARN` - CloudFront 함수의 ARN입니다.
111122223333 – AWS 계정입니다.
`Stage` - 함수의 스테이지(`LIVE` 또는 `DEVELOPMENT`)입니다.
`Status` - 함수의 상태(`PUBLISHED` 또는 `UNPUBLISHED`)입니다.

------

생성한 함수는 `DEVELOPMENT` 스테이지에 추가됩니다. [함수를 게시](publish-function.md)하기 전에 [함수를 테스트](test-function.md)하는 것이 좋습니다. 함수를 게시하고 나면 함수가 `LIVE` 스테이지로 변경됩니다.

# 함수 테스트
<a name="test-function"></a>

라이브 스테이지(프로덕션)에 함수를 배포하기 전에 함수를 테스트하여 의도한 대로 작동하는지 확인할 수 있습니다. 함수를 테스트하려면 CloudFront 배포가 프로덕션 환경에서 수신할 수 있는 HTTP 요청 또는 응답을 나타내는 *이벤트 객체*를 지정합니다.

CloudFront 함수는 다음을 수행합니다.

1. 제공된 이벤트 객체를 입력으로 사용하여 함수를 실행합니다.

1. 함수 로그 또는 오류 메시지 및 함수의 *컴퓨팅 사용률*과 함께 함수의 결과(수정된 이벤트 객체)를 반환합니다. 컴퓨팅 사용률에 대한 자세한 내용은 [컴퓨팅 활용 이해](#compute-utilization) 섹션을 참조하세요.

**참고**  
함수를 테스트할 때 CloudFront는 함수 실행 오류에 대해서만 검증합니다. CloudFront는 요청이 게시된 후 성공적으로 전달되는지 여부를 검증하지 않습니다. 예를 들어 함수가 필수 헤더를 삭제하면 코드에 문제가 없기 때문에 테스트가 성공합니다. 그러나 함수를 게시하고 배포와 연결하면 CloudFront를 통해 요청이 이루어질 때 함수가 실패합니다.

**Contents**
+ [이벤트 객체 설정](#test-function-create-event)
+ [함수 테스트](#test-function-step-test)
+ [컴퓨팅 활용 이해](#compute-utilization)

## 이벤트 객체 설정
<a name="test-function-create-event"></a>

함수를 테스트하기 전에 함수를 테스트할 이벤트 객체를 설정해야 합니다. 이때 여러 가지 선택지가 있습니다.

**선택 1: 이벤트 객체를 저장하지 않고 설정**  
CloudFront 콘솔의 시각적 편집기에서 이벤트 객체를 설정한 후 저장하지 않아도 됩니다.  
저장되지 않았더라도 이 이벤트 객체를 사용하여 CloudFront 콘솔에서 함수를 테스트할 수 있습니다.

**선택 2: 시각적 편집기에서 이벤트 객체 생성**  
CloudFront 콘솔의 시각적 편집기에서 이벤트 객체를 설정한 후 저장하지 않아도 됩니다. 예를 들어, 가능한 여러 입력을 테스트할 수 있도록 각 함수에 대해 10개의 이벤트 객체를 생성할 수 있습니다.  
이러한 방식으로 이벤트 객체를 생성하면 이벤트 객체를 사용하여 CloudFront 콘솔에서 함수를 테스트할 수 있습니다. AWS API 또는 SDK를 사용하여 함수를 테스트하는 데는 이벤트 객체를 사용할 수 없습니다.

**선택 3: 텍스트 편집기를 사용하여 이벤트 객체 생성**  
텍스트 편집기를 사용하여 JSON 형식으로 이벤트 객체를 만들 수 있습니다. 이벤트 객체의 구조에 대한 자세한 내용은 [이벤트 구조](functions-event-structure.md) 섹션을 참조하세요.  
이 이벤트 객체로 CLI를 사용하여 함수를 테스트할 수 있습니다. 하지만 CloudFront 콘솔에서 함수를 테스트하는 데는 사용할 수 없습니다.

**이벤트 객체를 생성하려면(옵션 1 또는 2)**

1. CloudFront 콘솔([https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions))에 로그인하고 **함수** 페이지를 엽니다.

   테스트할 함수를 선택합니다.

1. 함수 세부 정보 페이지에서 **테스트** 탭을 선택합니다.

1. **이벤트 유형**에서 다음 옵션 중 하나를 선택합니다.
   + 함수가 HTTP 요청을 수정하거나 요청에 따라 응답을 생성하는 경우 **뷰어 요청**을 선택합니다. **요청** 섹션이 나타납니다.
   + **뷰어 응답**을 선택합니다. **요청** 및 **응답** 섹션이 나타납니다.

1. 이벤트에 포함할 필드를 작성합니다. **JSON 편집**을 선택하여 원시 JSON을 확인할 수 있습니다.

1. (선택 사항) 이벤트를 저장하려면 **저장**을 선택하고 **테스트 이벤트 저장**에서 이름을 입력한 다음 **저장**을 선택합니다.

   **JSON 편집**을 선택하고 원시 JSON을 복사한 다음 CloudFront 외부의 자체 파일에 저장할 수도 있습니다.

**이벤트 객체를 생성하려면(옵션 3)**

텍스트 편집기를 사용하여 이벤트 객체를 생성합니다. 컴퓨터가 연결할 수 있는 디렉터리에 파일을 저장합니다.

다음 가이드라인을 따르도록 합니다.
+ `distributionDomainName`, `distributionId`, `requestId` 필드는 생략하세요.
+ 헤더, 쿠키, 쿼리 문자열의 이름은 소문자여야 합니다.

이러한 방식으로 이벤트 객체를 생성하는 한 가지 방법은 시각적 편집기를 사용하여 샘플을 만드는 것입니다. 샘플 형식이 올바른지 확인할 수 있습니다. 그런 다음 원시 JSON을 복사해 텍스트 편집기에 붙여넣고 파일을 저장할 수 있습니다.

이벤트의 구조에 대한 자세한 내용은 [이벤트 구조](functions-event-structure.md) 섹션을 참조하세요.

## 함수 테스트
<a name="test-function-step-test"></a>

CloudFront 콘솔 또는 AWS Command Line Interface(AWS CLI)를 사용하여 함수를 테스트할 수 있습니다.

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

**함수를 테스트하려면**

1. CloudFront 콘솔([https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions))에 로그인하고 **함수** 페이지를 엽니다.

1. 테스트할 함수를 선택합니다.

1. **테스트** 탭을 선택합니다.

1. 올바른 이벤트가 표시되는지 확인합니다. 현재 표시된 이벤트에서 다른 이벤트로 전환하려면 **테스트 이벤트 선택** 필드에서 다른 이벤트를 선택하세요.

1. **함수 테스트**를 선택합니다. 콘솔에는 함수 로그와 컴퓨팅 활용을 비롯한 함수 출력이 표시됩니다.

------
#### [ CLI ]

**aws cloudfront test-function** 명령을 사용하여 함수를 테스트할 수 있습니다.

**함수를 테스트하려면**

1. 명령줄 창을 엽니다.

1. 지정된 파일이 들어 있는 디렉터리에서 다음 명령을 실행합니다.

   이 예제에서는 `fileb://` 표기법을 사용하여 이벤트 객체 파일을 전달합니다. 명령을 더 쉽게 읽을 수 있도록 줄 바꿈도 포함되어 있습니다.

   ```
   aws cloudfront test-function \
       --name MaxAge \
       --if-match ETVABCEXAMPLE \
       --event-object fileb://event-maxage-test01.json \
       --stage DEVELOPMENT
   ```
**참고**  
함수의 이름과 ETag(`if-match` 파라미터 내)로 함수를 참조합니다. 파일 시스템에서의 위치를 기준으로 이벤트 객체를 참조합니다.
스테이지는 `DEVELOPMENT` 또는 `LIVE`일 수 있습니다.

   명령이 제대로 실행되면 다음과 비슷한 출력이 표시됩니다.

   ```
   TestResult:
     ComputeUtilization: '21'
     FunctionErrorMessage: ''
     FunctionExecutionLogs: []
     FunctionOutput: '{"response":{"headers":{"cloudfront-functions":{"value":"generated-by-CloudFront-Functions"},"location":{"value":"https://aws.amazon.com/cloudfront/"}},"statusDescription":"Found","cookies":{},"statusCode":302}}'
     FunctionSummary:
       FunctionConfig:
         Comment: MaxAge function
         Runtime: cloudfront-js-2.0
         KeyValueStoreAssociations= \
         {Quantity=1, \
         Items=[{KeyValueStoreARN='arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111'}]} \
       FunctionMetadata:
         CreatedTime: '2021-04-18T20:38:56.915000+00:00'
         FunctionARN: arn:aws:cloudfront::111122223333:function/MaxAge
         LastModifiedTime: '2023-17-20T10:38:57.057000+00:00'
         Stage: DEVELOPMENT
       Name: MaxAge
       Status: UNPUBLISHED
   ```

------

**참고**  
`FunctionExecutionLogs`에는 해당 함수가 `console.log()` 명령문(있는 경우)에 작성한 로그 행 목록이 포함되어 있습니다.
`ComputeUtilization`에는 함수 실행에 대한 정보가 들어 있습니다. [컴퓨팅 활용 이해](#compute-utilization)을(를) 참조하세요.
`FunctionOutput`에는 함수가 반환한 이벤트 객체가 포함됩니다.

## 컴퓨팅 활용 이해
<a name="compute-utilization"></a>

**컴퓨팅 활용(Compute utilization)**은 함수가 실행되는 데 걸린 시간의 최대 허용 시간의 백분율입니다. 예를 들어, 값이 35이면 함수가 최대 허용 시간의 35%에서 완료되었음을 의미합니다.

함수가 계속해서 최대 허용 시간을 초과할 경우 CloudFront는 해당 함수를 제한합니다. 다음 목록에서는 컴퓨팅 사용률 값에 따라 함수가 제한될 가능성을 설명합니다.

**컴퓨팅 사용률 값:**
+ **1 \$1 50** - 함수가 최대 허용 시간에 도달하기까지 많이 남았으므로 제한 없이 실행됩니다.
+ **51 \$1 70** - 함수가 최대 허용 시간에 근접하고 있습니다. 함수 코드를 최적화하는 것이 좋습니다.
+ **71 \$1 100** - 함수가 최대 허용 시간에 매우 근접하거나 최대 허용 시간을 초과합니다. 배포와 연결할 경우 CloudFront에서 이 함수를 제한할 가능성이 있습니다.

# 함수 업데이트
<a name="update-function"></a>

함수는 언제든지 업데이트할 수 있습니다. `DEVELOPMENT` 스테이지에 있는 함수 버전만 변경됩니다. 업데이트를 `DEVELOPMENT` 스테이지에서 `LIVE`로 복사하려면 [함수를 게시](publish-function.md)해야 합니다.

CloudFront 콘솔 또는 AWS Command Line Interface(AWS CLI)를 사용하여 함수의 코드를 업데이트할 수 있습니다.

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

**함수 코드를 업데이트하려면**

1. CloudFront 콘솔([https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions))에 로그인하고 **함수** 페이지를 엽니다.

   업데이트할 함수를 선택합니다.

1. **편집**을 선택하고 다음과 같이 변경합니다.
   + **세부 정보** 섹션의 모든 필드를 업데이트합니다.
   + 연결된 키 값 저장소를 변경하거나 제거합니다. 키 값 저장소에 대한 자세한 내용은 [Amazon CloudFront KeyValueStore](kvs-with-functions.md) 섹션을 참조하세요.
   + 함수 코드를 변경합니다. **빌드** 탭을 선택하고 필요한 부분을 변경한 다음 **변경 사항 저장**을 선택하여 코드의 변경 사항을 저장합니다.

------
#### [ CLI ]

**함수 코드를 업데이트하려면**

1. 명령줄 창을 엽니다.

1. 다음 명령을 실행합니다.

   이 예제에서는 `fileb://` 표기법을 사용하여 파일을 전달합니다. 명령을 더 쉽게 읽을 수 있도록 줄 바꿈도 포함되어 있습니다.

   ```
   aws cloudfront update-function \
       --name MaxAge \
       --function-config '{"Comment":"Max Age 2 years","Runtime":"cloudfront-js-2.0","KeyValueStoreAssociations":{"Quantity":1,"Items":[{"KeyValueStoreARN":"arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"}]}}' \
       --function-code fileb://function-max-age-v1.js \
       --if-match ETVABCEXAMPLE
   ```
**참고**  
함수의 이름과 ETag(`if-match` 파라미터 내)로 함수를 식별할 수 있습니다. 현재 ETag를 사용하도록 하세요. [DescribeFunction](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DescribeFunction.html) API 작업에서 이 값을 얻을 수 있습니다.
변경하지 않을 때에도 `function-code`가 포함되어야 합니다.
`function-config`에 유의하세요. 구성에 유지하려는 모든 내용을 전달해야 합니다. 특히 키 값 저장소는 다음과 같이 처리하세요.  
기존 키 값 저장소 연결(있는 경우)을 유지하려면 **기존 저장소의 이름을 지정합니다.
연결을 변경하려면 **새 키 값 저장소의 이름을 지정합니다.
연결을 제거하려면 `KeyValueStoreAssociations` 파라미터를 생략하세요.

   명령이 제대로 실행되면 다음과 비슷한 출력이 표시됩니다.

   ```
   ETag: ETVXYZEXAMPLE
   FunctionSummary:
     FunctionConfig:
       Comment: Max Age 2 years \
       Runtime: cloudfront-js-2.0 \
       KeyValueStoreAssociations= \
         {Quantity=1, \
         Items=[{KeyValueStoreARN='arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111'}]} \
     FunctionMetadata: \
       CreatedTime: '2021-04-18T20:38:56.915000+00:00' \
       FunctionARN: arn:aws:cloudfront::111122223333:function/MaxAge \
       LastModifiedTime: '2023-12-19T23:41:15.389000+00:00' \
       Stage: DEVELOPMENT \
     Name: MaxAge \
     Status: UNPUBLISHED
   ```

------

대부분의 정보는 요청에서 반복된 내용입니다. 기타 정보는 CloudFront에 의해 추가됩니다.

**참고**  
`ETag` - 이 값은 키 값 저장소를 수정할 때마다 변경됩니다.
`FunctionARN` - CloudFront 함수의 ARN입니다.
`Stage` - 함수의 스테이지(`LIVE` 또는 `DEVELOPMENT`)입니다.
`Status` - 함수의 상태(`PUBLISHED` 또는 `UNPUBLISHED`)입니다.

# 함수 게시
<a name="publish-function"></a>

함수를 게시하면 `DEVELOPMENT` 스테이지에서 `LIVE` 스테이지로 함수가 복사됩니다.

함수와 연결된 캐시 동작이 없는 경우 이를 게시하면 캐시 동작과 연결할 수 있습니다. 캐시 동작은 `LIVE` 스테이지에 있는 함수에만 연결할 수 있습니다.

**중요**  
함수를 게시하기 전에 [함수를 테스트](test-function.md)하는 것이 좋습니다.
함수를 게시하면 배포가 완료되는 즉시 해당 함수와 연결된 모든 캐시 동작이 새로 게시된 복사본을 사용하여 자동으로 시작됩니다.

CloudFront 콘솔 또는 AWS CLI를 사용하여 함수를 게시할 수 있습니다.

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

**함수를 게시하려면**

1. CloudFront 콘솔([https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions))에 로그인하고 **함수** 페이지를 엽니다.

1. 업데이트할 함수를 선택합니다.

1. **게시** 탭을 선택한 다음 **게시**를 선택합니다. 함수가 하나 이상의 캐시 동작에 이미 연결되어 있는 경우 **게시 및 업데이트**를 선택합니다.

1. (선택 사항) 해당 함수와 연결된 배포를 보려면 **연결된 CloudFront 배포**(Associated CloudFront distributions)를 선택하여 해당 섹션을 확장합니다.

성공하면 페이지 상단에 ***함수 이름*이 성공적으로 게시**되었다는 배너가 표시됩니다. **빌드**(Build) 탭을 선택한 다음 **라이브**(Live)를 선택하여 함수 코드의 라이브 버전을 볼 수도 있습니다.

------
#### [ CLI ]

**함수를 게시하려면**

1. 명령줄 창을 엽니다.

1. 다음 **aws cloudfront publish-function** 명령을 실행합니다. 이 예에서는 예제를 보다 읽기 쉽도록 줄 바꿈이 제공됩니다.

   ```
   aws cloudfront publish-function \
       --name MaxAge \
       --if-match ETVXYZEXAMPLE
   ```

   명령이 제대로 실행되면 다음과 비슷한 출력이 표시됩니다.

   ```
   FunctionSummary:
     FunctionConfig:
       Comment: Max Age 2 years
       Runtime: cloudfront-js-2.0
     FunctionMetadata:
       CreatedTime: '2021-04-18T21:24:21.314000+00:00'
       FunctionARN: arn:aws:cloudfront::111122223333:function/ExampleFunction
       LastModifiedTime: '2023-12-19T23:41:15.389000+00:00'
       Stage: LIVE
     Name: MaxAge
     Status: UNASSOCIATED
   ```

------

# 배포에 함수 연결
<a name="associate-function"></a>

배포에 함수를 사용하려면 함수를 배포의 하나 이상의 캐시 동작과 연결합니다. 여러 배포에서 여러 캐시 동작과 함수를 연결할 수 있습니다.

함수는 다음 중 무엇과도 연결할 수 있습니다.
+ 기존 캐시 동작
+ 기존 배포의 새로운 캐시 동작
+ 새 배포의 새로운 캐시 동작

함수를 캐시 동작과 연결할 때는 *이벤트 유형*(event type)을 선택해야 합니다. 이벤트 유형에 따라 CloudFront가 함수를 실행하는 시기가 결정됩니다.

다음과 같은 이벤트 유형을 선택할 수 있습니다.
+ **최종 사용자 요청** – 이 함수는 CloudFront가 최종 사용자의 요청을 수신할 때 실행됩니다.
+ **최종 사용자 응답** – 이 함수는 CloudFront가 최종 사용자에게 응답을 반환하기 전에 실행됩니다.

CloudFront Functions와 함께 오리진 관련 이벤트 유형(*오리진 요청* 및 *오리진 응답*)을 사용할 수 없습니다. 대신 Lambda@Edge를 사용할 수 있습니다. 자세한 내용은 [Lambda@Edge 함수를 트리거할 수 있는 CloudFront 이벤트](lambda-cloudfront-trigger-events.md) 단원을 참조하십시오.

**참고**  
함수를 연결하기 전에 [`LIVE` 스테이지에 게시](publish-function.md)해야 합니다.

CloudFront 콘솔 또는 AWS Command Line Interface(AWS CLI)를 사용하여 배포에 함수를 연결할 수 있습니다. 다음 절차에서는 함수를 기존 캐시 동작에 연결하는 방법을 보여 줍니다.

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

**기존 캐시 동작에 함수를 연결하려면**

1. CloudFront 콘솔([https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions))에 로그인하고 **함수** 페이지를 엽니다.

1. 연결할 함수를 선택합니다.

1. **함수** 페이지에서 **게시** 탭을 선택합니다.

1. **Publish 함수**를 선택합니다.

1. **연결 추가**를 선택합니다. 표시되는 대화 상자에서 배포, 이벤트 유형 및/또는 캐시 동작을 선택합니다.

   이벤트 유형에서 함수를 실행할 시기를 선택합니다.
   + **뷰어 요청** - CloudFront가 요청을 수신할 때마다 이 함수를 실행합니다.
   + **뷰어 응답** - CloudFront가 응답을 반환할 때마다 이 함수를 실행합니다.

1. 구성을 저장하려면 **연결 추가**를 선택합니다.

CloudFront가 배포를 함수와 연결합니다. 연결된 배포가 배포될 때까지 몇 분 정도 기다립니다. 함수 세부 정보 페이지에서 **배포 보기**를 선택하여 진행 상황을 확인할 수 있습니다.

------
#### [ CLI ]

**기존 캐시 동작에 함수를 연결하려면**

1. 명령줄 창을 엽니다.

1. 함수에 연결할 캐시 동작을 가진 배포에 대한 배포 구성을 저장하려면 다음 명령을 입력합니다. 이 명령은 배포 구성을 `dist-config.yaml`이라는 이름의 파일에 저장합니다. 이 명령을 사용하려면 다음을 수행합니다.
   + *`DistributionID`*를 해당 배포의 ID로 바꿉니다.
   + 한 줄로 명령을 실행합니다. 이 예에서는 예제를 보다 읽기 쉽도록 줄 바꿈이 제공됩니다.

   ```
   aws cloudfront get-distribution-config \
       --id DistributionID \
       --output yaml > dist-config.yaml
   ```

   명령이 성공하면 AWS CLI는 출력을 반환하지 않습니다.

1. 생성한 `dist-config.yaml`이라는 파일을 엽니다. 파일을 편집하여 다음과 같이 변경합니다.

   1. `ETag` 필드의 이름을 `IfMatch`로 바꾸지만 필드 값은 변경하지 마세요.

   1. 캐시 동작에서 `FunctionAssociations`(이)라는 이름의 객체를 찾습니다. 함수 연결을 추가하려면 이 객체를 업데이트합니다. 함수 연결에 대한 YAML 구문은 다음 예제와 같습니다.
      + 다음 예제에서는 최종 사용자 요청 이벤트 객체를 보여줍니다. 최종 사용자 응답 이벤트 유형을 사용하려면 `viewer-request`을(를)`viewer-response`(으)로 바꿉니다.
      + *`arn:aws:cloudfront::111122223333:function/ExampleFunction`*을 이 캐시 동작에 연결하려는 함수의 Amazon 리소스 이름(ARN)으로 바꿉니다. 함수 ARN을 얻으려면 **aws cloudfront list-functions** 명령을 사용할 수 있습니다.

      ```
      FunctionAssociations:
        Items:
          - EventType: viewer-request
            FunctionARN: arn:aws:cloudfront::111122223333:function/ExampleFunction
        Quantity: 1
      ```

   1. 이러한 변경을 수행한 후 파일을 저장합니다.

1. 다음 명령을 사용하여 배포를 업데이트하고 함수 연결을 추가합니다. 이 명령을 사용하려면 다음을 수행합니다.
   + *`DistributionID`*를 해당 배포의 ID로 바꿉니다.
   + 한 줄로 명령을 실행합니다. 이 예에서는 예제를 보다 읽기 쉽도록 줄 바꿈이 제공됩니다.

   ```
   aws cloudfront update-distribution \
       --id DistributionID \
       --cli-input-yaml file://dist-config.yaml
   ```

   명령이 성공하면 함수 연결로 방금 업데이트된 배포를 설명하는 다음과 같은 출력이 표시됩니다. 다음 예제 출력은 가독성을 위해 잘립니다.

   ```
   Distribution:
     ARN: arn:aws:cloudfront::111122223333:distribution/EBEDLT3BGRBBW
     ... truncated ...
     DistributionConfig:
       ... truncated ...
       DefaultCacheBehavior:
         ... truncated ...
         FunctionAssociations:
           Items:
           - EventType: viewer-request
             FunctionARN: arn:aws:cloudfront::111122223333:function/ExampleFunction
           Quantity: 1
         ... truncated ...
     DomainName: d111111abcdef8.cloudfront.net
     Id: EDFDVBD6EXAMPLE
     LastModifiedTime: '2021-04-19T22:39:09.158000+00:00'
     Status: InProgress
   ETag: E2VJGGQEG1JT8S
   ```

------

배포가 재배포되는 동안 배포의 `Status`가 `InProgress`로 변경됩니다. 새 배포 구성이 CloudFront 엣지 로케이션에 도달하면 해당 엣지 로케이션에 연결된 함수를 사용하기 시작합니다. 배포가 완전히 완료되면 `Status`가 다시 `Deployed`로 바뀝니다. 이는 연결된 CloudFront 함수가 전 세계의 모든 CloudFront 엣지 로케이션에서 작동함을 나타냅니다. 이 작업은 일반적으로 몇 분 정도 걸립니다.

# Amazon CloudFront KeyValueStore
<a name="kvs-with-functions"></a>

CloudFront KeyValueStore는 [CloudFront 함수](cloudfront-functions.md) 내에서 읽기 액세스를 허용하는 안전한 글로벌 키 값 데이터 스토어로, CloudFront 엣지 로케이션에서 고급 사용자 지정 로직을 사용할 수 있습니다.

CloudFront KeyValueStore를 사용하면 함수 코드를 업데이트하고 함수와 관련된 데이터를 서로 독립적으로 업데이트할 수 있습니다. 이렇게 분리하면 함수 코드가 간소화되고 코드 변경 사항을 배포할 필요 없이 데이터를 쉽게 업데이트할 수 있습니다.

**참고**  
[CloudFront KeyValueStore를 사용하려면 CloudFront 함수가 JavaScript 런타임 2.0](functions-javascript-runtime-20.md)을 사용해야 합니다.

키 값 페어를 사용하는 일반적인 절차는 다음과 같습니다.
+ 키 값 저장소를 만들고 키 값 페어 모음으로 채웁니다. Amazon S3 버킷에 키 값 스토어를 추가하거나 수동으로 입력할 수 있습니다.
+ 키 값 스토어를 CloudFront 함수와 연결합니다.
+ 함수 코드 내에서 키 이름을 사용하여 키와 관련된 값을 검색하거나 키가 존재하는지 알아볼 수 있습니다. 함수 코드에서 키 값 페어를 사용하는 방법과 도우미 메서드에 대한 자세한 내용은 [키 값 저장소를 위한 도우미 메서드](functions-custom-methods.md) 섹션을 참조하세요.

## 사용 사례
<a name="key-value-store-use-cases"></a>

다음 예제에 키 값 페어를 사용할 수 있습니다.
+ **URL 재작성 또는 리디렉션** - 키 값 페어에는 재작성된 URL 또는 리디렉션 URL이 포함될 수 있습니다.
+ **A/B 테스트 및 기능 플래그** - 웹사이트의 특정 버전에 트래픽 비율을 할당하여 실험을 실행하는 함수를 만들 수 있습니다.
+ **액세스 권한 부여** - 사용자가 정의한 기준과 KeyValueStore에 저장된 데이터에 따라 요청을 허용하거나 거부하는 액세스 제어를 구현할 수 있습니다.

## 지원되는 값 형식
<a name="key-value-store-supported-formats"></a>

키 값 페어의 값은 다음 형식 중 하나로 저장할 수 있습니다.
+ 문자열
+ 바이트로 인코딩된 문자열
+ JSON 

## 보안
<a name="key-value-store-security"></a>

CloudFront Functions 및 모든 키 값 저장소 데이터는 다음과 같이 안전하게 처리됩니다.
+ CloudFront는 저장 중이거나 전송 중(키 값 스토어를 읽거나 쓸 때)인 각 키 값 스토어를 [CloudFront KeyValueStore](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_Operations_Amazon_CloudFront_KeyValueStore.html) API 작업을 직접 호출할 때 암호화합니다.
+ 함수를 실행할 때 CloudFront는 CloudFront 엣지 로케이션의 메모리에 있는 각 키 값 페어를 복호화합니다.

CloudFront KeyValueStore를 시작하려면 다음 주제를 참조하세요.

**Topics**
+ [사용 사례](#key-value-store-use-cases)
+ [지원되는 값 형식](#key-value-store-supported-formats)
+ [보안](#key-value-store-security)
+ [키 값 저장소 사용](kvs-with-functions-kvs.md)
+ [키 값 데이터로 작업](kvs-with-functions-kvp.md)
+ CloudFront 키 값 저장소 시작 방법에 대한 자세한 내용은 [Introducing Amazon CloudFront KeyValueStore](https://aws.amazon.com/blogs/aws/introducing-amazon-cloudfront-keyvaluestore-a-low-latency-datastore-for-cloudfront-functions/) AWS 블로그 게시물을 참조하세요.

# 키 값 저장소 사용
<a name="kvs-with-functions-kvs"></a>

CloudFront Functions에서 사용하려는 키 값 페어를 보관할 키 값 저장소를 생성해야 합니다.

키 값 저장소를 생성하고 키-값 페어를 추가한 후 CloudFront 함수 코드에서 키 값을 사용할 수 있습니다.

시작하려면 다음 주제를 참조하세요.

**Topics**
+ [키 값 저장소 생성](kvs-with-functions-create.md)
+ [키 값 저장소를 함수와 연결](kvs-with-functions-associate.md)
+ [키 값 저장소 업데이트](kvs-with-functions-edit.md)
+ [키 값 저장소에 대한 참조 가져오기](kvs-with-functions-get-reference.md)
+ [키 값 저장소 삭제](kvs-with-functions-delete.md)
+ [키 값 페어의 파일 형식](kvs-with-functions-create-s3-kvp.md)

**참고**  
JavaScript 런타임 2.0에는 함수 코드의 키 값으로 작업하기 위한 몇 가지 도우미 메서드가 포함되어 있습니다. 자세한 내용은 [키 값 저장소를 위한 도우미 메서드](functions-custom-methods.md) 섹션을 참조하세요.

# 키 값 저장소 생성
<a name="kvs-with-functions-create"></a>



키 값 저장소와 키 값 페어를 동시에 생성할 수 있습니다. 또한 비어 있는 키 값 저장소를 만든 다음 나중에 키 값 페어를 추가할 수 있습니다.

**참고**  
Amazon S3 버킷에서 데이터 소스를 지정하는 경우 해당 버킷에 대한 `s3:GetObject` 및 `s3:GetBucketLocation` 권한이 있어야 합니다. 이러한 권한이 없는 경우 CloudFront는 키 값 저장소를 성공적으로 생성할 수 없습니다.

키 값 저장소를 생성하면서 키 값 페어를 동시에 추가할지 여부를 결정하세요. CloudFront 콘솔, CloudFront API 또는 AWS SDK를 사용하여 키 값 페어를 가져올 수 있습니다. 그러나 키 값 저장소를 **처음 만들 때만 키 값 페어 파일을 가져올 수 있습니다.

키 값 페어로 구성된 파일을 생성하려면 [키 값 페어의 파일 형식](kvs-with-functions-create-s3-kvp.md) 섹션을 참조하세요.

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

**키 값 저장소를 생성하려면**

1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)에 있는 CloudFront 콘솔에서 **함수** 페이지를 엽니다.

1. **KeyValueStores** 탭을 선택한 다음 **KeyValueStore 생성**을 선택합니다.

1. 키 값 저장소 이름을 입력하고 필요한 경우 설명을 입력합니다.

1. **S3 URI** 작성: 
   + 키 값 페어 파일이 있는 경우 파일을 저장한 Amazon S3 버킷의 경로를 입력합니다.
   + 키 값 페어를 수동으로 입력하려는 경우 이 필드를 비워 두세요.

1. **생성(Create)**을 선택합니다. 키 값 저장소가 생겼습니다.

   새로운 키 값 저장소의 세부 정보 페이지가 나타납니다. 페이지의 정보에는 키 값 저장소의 ID 및 ARN이 포함됩니다.
   + ID는 AWS 계정에서 고유한 임의의 문자열입니다.
   + ARN의 구문은 다음과 같습니다.

     *AWS 계정*`:key-value-store/`*키 값 저장소 ID*

1. **키 값 페어** 섹션을 살펴보세요. 파일을 가져온 경우 이 섹션에 일부 키 값 페어가 표시됩니다. 다음을 수행할 수 있습니다.
   + 파일을 가져온 경우 직접 값을 더 추가할 수도 있습니다.
   + Amazon S3 버킷에서 파일을 가져오지 않았고 지금 키 값 페어를 추가하려는 경우 다음 단계를 완료하면 됩니다.
   + 이 단계를 건너뛰고 나중에 키 값 페어를 추가할 수 있습니다.

1. 지금 페어를 추가하려면 다음 단계를 따르세요.

   1. **키 값 페어 추가**를 선택합니다.

   1. **페어 추가**를 선택하고 이름과 값을 입력합니다. 태그를 더 추가하려면 이 단계를 반복합니다.

   1. 작업을 마쳤으면 **변경 사항 저장**을 선택하여 모든 키 값 페어를 키 값 저장소에 저장합니다. 나타나는 대화 상자에서 **완료**를 선택합니다.

1. 지금 키 값 저장소를 함수와 연결하려면 **연결된 함수** 섹션을 완료하세요. 자세한 내용은 [함수 생성](create-function.md) 또는 [함수 업데이트](update-function.md) 섹션을 참조하세요.

   나중에 이 키 값 저장소 세부 정보 페이지 또는 함수 세부 정보 페이지에서 함수를 연결할 수도 있습니다.

------
#### [ AWS CLI ]

**키 값 저장소를 생성하려면**
+ 다음 명령을 실행하여 키 값 저장소를 생성하고 Amazon S3 버킷에서 키 값 페어를 가져옵니다.

  ```
  aws cloudfront create-key-value-store \
      --name=keyvaluestore1 \
      --comment="This is my key value store file" \
      --import-source=SourceType=S3,SourceARN=arn:aws:s3:::amzn-s3-demo-bucket1/kvs-input.json
  ```

  **응답**

  ```
  {
      "ETag": "ETVABCEXAMPLE",
      "Location": "https://cloudfront.amazonaws.com/2020-05-31/key-value-store/arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
      "KeyValueStore": {
          "Name": "keyvaluestore1",
          "Id": "8aa76c93-3198-462c-aaf6-example",
          "Comment": "This is my key value store file",
          "ARN": "arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
          "Status": "PROVISIONING",
          "LastModifiedTime": "2024-08-06T22:19:10.813000+00:00"
      }
  }
  ```

------
#### [ API ]

**키 값 저장소를 생성하려면**

1. [CloudFront CreateKeyValueStore](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateKeyValueStore.html) 작업을 사용합니다. 이 작업에는 다음과 같은 몇 가지 파라미터가 사용됩니다.
   + 키 값 저장소의 `name`
   + 설명이 포함된 `comment` 파라미터
   + Amazon S3 버킷에 저장된 파일에서 키 값 페어를 가져올 수 있는 `import-source` 파라미터. 키 값 저장소를 처음 만들 때만 파일에서 키 값 페어를 가져올 수 있습니다. 파일 구조에 대한 자세한 내용은 [키 값 페어의 파일 형식](kvs-with-functions-create-s3-kvp.md) 섹션을 참조하세요.

작업 응답에는 다음 정보가 포함됩니다.
+ 지정한 이름을 포함하여 요청에 전달된 값
+ 생성 시간 등의 데이터
+ `ETag`(예: `ETVABCEXAMPLE`), 키 값 저장소의 이름을 포함하는 ARN(예: `arn:aws:cloudfront::123456789012:key-value-store/keyvaluestore1`) 

  `ETag`, ARN 및 이름을 조합하여 키 값 저장소를 프로그래밍 방식으로 사용할 수 있습니다.

------

## 키 값 저장소 상태
<a name="key-value-store-status"></a>

키 값 저장소를 생성할 때 데이터 저장소는 다음과 같은 상태 값을 가질 수 있습니다.


****  

| 값 | 설명 | 
| --- | --- | 
|  **프로비저닝**  |  키 값 저장소가 생성되었으며 CloudFront는 지정된 데이터 소스를 처리하고 있습니다.  | 
|  **준비됨**  |  키 값 저장소가 생성되고 CloudFront가 지정한 데이터 소스를 성공적으로 처리했습니다.  | 
|  **가져오기에 실패했습니다**  |  CloudFront는 지정한 데이터 소스를 처리하지 못했습니다. 파일 형식이 유효하지 않거나 크기 제한을 초과하는 경우 이 상태가 나타날 수 있습니다. 자세한 내용은 [키 값 페어의 파일 형식](kvs-with-functions-create-s3-kvp.md) 섹션을 참조하세요.  | 

# 키 값 저장소를 함수와 연결
<a name="kvs-with-functions-associate"></a>

키 값 저장소를 생성한 후 함수를 업데이트하여 키 값 저장소와 연결할 수 있습니다. 해당 함수에서 해당 저장소의 키 값 페어를 사용하려면 이 연결을 만들어야 합니다. 다음 규칙이 적용됩니다.
+ 함수 하나에는 키 값 저장소가 하나만 있을 수 있습니다.
+ 동일한 키 값 저장소를 여러 함수와 연결할 수 있습니다.

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

**키 값 저장소를 함수와 연결하려면**

1. CloudFront 콘솔([https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions))에 로그인하고 **함수** 페이지를 엽니다.

1. 함수 이름을 선택합니다.

1. **KeyValueStore 연결** 섹션에서 **기존 KeyValueStore 연결**을 선택합니다.

1. 함수의 키 값 페어가 들어 있는 키 값 저장소를 선택한 다음 **KeyValueStore 연결**을 선택합니다.

   CloudFront는 저장소를 함수와 즉시 연결하므로 함수를 저장하지 않아도 됩니다.

1. 다른 키 값 저장소를 지정하려면 **연결된 KeyValueStore 업데이트**를 선택하고 다른 키 값 저장소 이름을 선택한 다음 **KeyValueStore 연결**을 선택합니다.

자세한 내용은 [함수 업데이트](update-function.md) 섹션을 참조하세요.

------
#### [ AWS CLI ]

**키 값 저장소를 함수와 연결하려면**
+ 다음 명령을 실행하여 `MaxAge` 함수를 업데이트하고 키 값 저장소 리소스를 연결합니다.

  ```
  aws cloudfront update-function \
      --name MaxAge \
      --function-config '{"Comment":"Max Age 2 years","Runtime":"cloudfront-js-2.0","KeyValueStoreAssociations":{"Quantity":1,"Items":[{"KeyValueStoreARN":"arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example"}]}}' \
      --function-code fileb://function-max-age-v1.js \
      --if-match ETVABCEXAMPLE
  ```
+ 키 값 저장소를 함수와 연결하려면 `KeyValueStoreAssociations` 파라미터 및 키 값 저장소 ARN을 지정합니다.
+ 연결을 변경하려면 다른 키 값 저장소의 이름을 지정합니다.
+ 연결을 제거하려면 `KeyValueStoreAssociations` 파라미터를 제거합니다.

자세한 내용은 [함수 업데이트](update-function.md) 섹션을 참조하세요.

------
#### [ API ]

**키 값 저장소를 함수와 연결하려면**
+ [UpdateFunction](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateFunction.html) API 작업을 사용합니다. 자세한 내용은 [함수 업데이트](update-function.md) 섹션을 참조하세요.

------

**참고**  
키 값 페어를 변경하지 않고 키 값 저장소를 수정하거나 키 값 저장소에서 키 값 페어만 수정하는 경우 키 값 저장소를 다시 연결할 필요가 없습니다. 또한 함수를 다시 게시할 필요도 없습니다.  
그러나 함수를 테스트하여 예상대로 작동하는지 확인하는 것이 좋습니다. 자세한 내용은 [함수 테스트](test-function.md) 섹션을 참조하세요.
특정 키 값 저장소를 사용하는 모든 함수를 확인할 수 있습니다. CloudFront 콘솔에서 키 값 저장소 세부 정보 페이지를 선택합니다.

# 키 값 저장소 업데이트
<a name="kvs-with-functions-edit"></a>

키 값 저장소를 업데이트하는 경우 키 값 페어를 변경하거나 키 값 저장소와 함수 간의 연결을 변경할 수 있습니다.

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

**키 값 저장소를 업데이트하려면**

1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)에 있는 CloudFront 콘솔에서 **함수** 페이지를 엽니다.

1. **KeyValueStore** 탭을 선택합니다.

1.  업데이트할 키 값 저장소를 선택합니다.
   + 키 값 페어를 업데이트하려면 **키 값 페어** 섹션에서 **편집**을 선택합니다. 키 값 페어를 추가하거나 삭제할 수 있습니다. 기존 키 값 페어의 값을 변경할 수도 있습니다. 작업을 마쳤으면 **변경 내용 저장**을 선택합니다.
   + 이 키 값 저장소에 대한 연결을 업데이트하려면 **함수로 이동**을 선택합니다. 자세한 내용은 [키 값 저장소를 함수와 연결](kvs-with-functions-associate.md) 섹션을 참조하세요.

------
#### [ AWS CLI ]

**키 값 저장소를 업데이트하려면**

1. **키 값 페어 변경** - 키 값 페어를 더 추가하고, 하나 이상의 키 값 페어를 삭제하고, 기존 키 값 페어의 값을 변경할 수 있습니다. 자세한 내용은 [키 값 데이터로 작업](kvs-with-functions-kvp.md) 섹션을 참조하세요.

1. **키 값 저장소의 함수 연결 변경** - 키 값 저장소의 함수 연결을 업데이트하려면 [키 값 저장소를 함수와 연결](kvs-with-functions-associate.md) 섹션을 참조하세요.
**작은 정보**  
키 값 저장소의 ARN이 필요합니다. 자세한 내용은 [키 값 저장소에 대한 참조 가져오기](kvs-with-functions-get-reference.md) 섹션을 참조하세요.

------
#### [ API ]

**키 값 저장소를 업데이트하려면**

1. **키 값 페어 변경** - 키 값 페어를 더 추가하고, 하나 이상의 키 값 페어를 삭제하고, 기존 키 값 페어의 값을 변경할 수 있습니다. 자세한 내용은 [키 값 데이터로 작업](kvs-with-functions-kvp.md) 섹션을 참조하세요.

1. **키 값 저장소의 함수 연결 변경** - 키 값 저장소의 함수 연결을 업데이트하려면 [UpdateFunction](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateFunction.html) API 작업을 사용하세요. 자세한 내용은 [함수 업데이트](update-function.md) 섹션을 참조하세요.
**작은 정보**  
키 값 저장소의 ARN이 필요합니다. 자세한 내용은 [키 값 저장소에 대한 참조 가져오기](kvs-with-functions-get-reference.md) 섹션을 참조하세요.

------

# 키 값 저장소에 대한 참조 가져오기
<a name="kvs-with-functions-get-reference"></a>

프로그래밍 방식으로 키 값 저장소를 사용하려면 `ETag`와 키 값 저장소의 이름이 필요합니다.

두 값을 모두 가져오려면 AWS Command Line Interface(AWS CLI) 또는 CloudFront API를 사용할 수 있습니다.

------
#### [ AWS CLI ]

**키 값 저장소 참조를 가져오려면**

1. 키 값 저장소 목록을 반환하려면 다음 명령을 실행합니다. 변경할 키 값 저장소의 이름을 찾습니다.

   ```
   aws cloudfront list-key-value-stores
   ```

1. 응답에서 원하는 키 값 저장소의 이름을 찾습니다.

   **응답**

   ```
   {
       "KeyValueStoreList": {
           "Items": [
               {
                   "Name": "keyvaluestore3",
                   "Id": "37435e19-c205-4271-9e5c-example3",
                   "ARN": "arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example3",
                   "Status": "READY",
                   "LastModifiedTime": "2024-05-08T14:50:18.876000+00:00"
               },
               {
                   "Name": "keyvaluestore2",
                   "Id": "47970d59-6408-474d-b850-example2",
                   "ARN": "arn:aws:cloudfront::123456789012:key-value-store/47970d59-6408-474d-b850-example2",
                   "Status": "READY",
                   "LastModifiedTime": "2024-05-30T21:06:22.113000+00:00"
               },
               {
                   "Name": "keyvaluestore1",
                   "Id": "8aa76c93-3198-462c-aaf6-example",
                   "ARN": "arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
                   "Status": "READY",
                   "LastModifiedTime": "2024-08-06T22:19:30.510000+00:00"
               }
           ]
       }
   }
   ```

1. 다음 명령을 실행하여 지정된 키 값 저장소의 `ETag`를 반환합니다.

   ```
   aws cloudfront describe-key-value-store \
       --name=keyvaluestore1
   ```

   **응답**

   ```
   {
       "ETag": "E3UN6WX5RRO2AG",
       "KeyValueStore": {
           "Name": "keyvaluestore1",
           "Id": "8aa76c93-3198-462c-aaf6-example",
           "Comment": "This is an example KVS",
           "ARN": "arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example",
           "Status": "READY",
           "LastModifiedTime": "2024-08-06T22:19:30.510000+00:00"
       }
   }
   ```

------
#### [ API ]

**키 값 저장소 참조를 가져오려면**

1. [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html) API 작업을 사용하여 키 값 저장소 목록을 반환합니다. 변경할 키 값 저장소의 이름을 찾습니다.

1. [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DescribeKeyValueStore.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DescribeKeyValueStore.html) API 작업을 사용하여 이전 단계에서 반환한 키 값 저장소의 이름을 지정합니다.

------

응답에는 UUID, 키 값 저장소의 ARN, 키 값 저장소의 `ETag`가 포함됩니다.
+ `ETag`(예: `E3UN6WX5RRO2AG`)
+ UUID는 128비트임(예: `8aa76c93-3198-462c-aaf6-example`)
+ 다음 예와 같이 ARN에는 AWS 계정 번호, 상수 `key-value-store`, UUID가 포함됩니다.

  `arn:aws:cloudfront::123456789012:key-value-store/8aa76c93-3198-462c-aaf6-example`

`DescribeKeyValueStore` 작업에 대한 자세한 내용은 [CloudFront KeyValueStore 소개](kvs-with-functions-kvp.md#kvs-with-functions-api-describe) 섹션을 참조하세요.

# 키 값 저장소 삭제
<a name="kvs-with-functions-delete"></a>

Amazon CloudFront 콘솔 또는 API를 사용하여 키 값 저장소를 삭제할 수 있습니다.

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

**키 값 저장소를 삭제하려면**

1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)에 있는 CloudFront 콘솔에서 **함수** 페이지를 엽니다.

1. 함수 이름을 선택합니다.

1. **연결된 KeyValueStore** 섹션에서 키 값 저장소가 함수와 연결되어 있는지 확인합니다. 연결되어 있는 경우 **KeyValueStore 연결 해제**를 선택한 다음 **연결 제거**를 선택하여 연결을 제거합니다.

1. 탐색 창에서 **함수** 페이지를 선택한 다음 **KeyValueStores** 탭을 선택합니다.

1. 삭제하려는 키 값 저장소를 선택한 다음 **삭제**를 선택합니다.

------
#### [ AWS CLI ]

**키 값 저장소를 삭제하려면**

1. `ETag`와 키 값 저장소의 이름을 가져옵니다. 자세한 내용은 [키 값 저장소에 대한 참조 가져오기](kvs-with-functions-get-reference.md) 섹션을 참조하세요.

1. 키 값 저장소가 함수와 연결되어 있는지 확인합니다. 연결되어 있는 경우 연결이 삭제됩니다. 이 두 단계에 대한 자세한 내용은 [함수 업데이트](update-function.md) 섹션을 참조하세요.

1. 키 값 저장소의 이름과 `ETag`를 가져왔고 키 값 저장소가 함수와 더 이상 연결되지 않은 경우 해당 저장소를 삭제할 수 있습니다.

   다음 명령을 실행하여 지정된 키 값 저장소를 삭제합니다.

   ```
   aws cloudfront delete-key-value-store \
       --name=keyvaluestore1 \
       --if-match=E3UN6WX5RRO2AG
   ```

------
#### [ API ]

**키 값 저장소를 삭제하려면**

1. `ETag`와 키 값 저장소의 이름을 가져옵니다. 자세한 내용은 [키 값 저장소에 대한 참조 가져오기](kvs-with-functions-get-reference.md) 섹션을 참조하세요.

1. 키 값 저장소가 함수와 연결되어 있는지 확인합니다. 연결되어 있는 경우 연결이 삭제됩니다. 이 두 단계에 대한 자세한 내용은 [함수 업데이트](update-function.md) 섹션을 참조하세요.

1. 키 값 저장소를 삭제하려면 CloudFront [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DeleteKeyValueStore.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_DeleteKeyValueStore.html) API 작업을 사용하세요.

------

# 키 값 페어의 파일 형식
<a name="kvs-with-functions-create-s3-kvp"></a>

UTF-8 인코딩 파일을 만들 때는 다음 JSON 형식을 사용합니다.

```
{
  "data":[
    {
      "key":"key1",
      "value":"value"
    },
    {
      "key":"key2",
      "value":"value"
    }
  ]
}
```

파일에 중복 키를 포함할 수 없습니다. Amazon S3 버킷에 잘못된 파일을 지정한 경우 파일을 업데이트하여 중복 파일을 제거한 다음 키 값 저장소를 다시 생성해 볼 수 있습니다.

자세한 내용은 [키 값 저장소 생성](kvs-with-functions-create.md) 섹션을 참조하세요.

**참고**  
데이터 소스 및 해당 키-값 페어의 파일에는 다음과 같은 한도가 있습니다.  
파일 크기 - 5MB
키 크기 - 512자
키 크기 - 1,024자

# 키 값 데이터로 작업
<a name="kvs-with-functions-kvp"></a>

이 주제에서는 기존 키 값 저장소에 키 값 페어를 추가하는 방법을 설명합니다. 키 값 저장소를 처음 생성할 때 키 값 페어를 포함하려면 [키 값 저장소 생성](kvs-with-functions-create.md) 섹션을 참조하세요.

**Topics**
+ [키 값 페어 작업(콘솔)](#kvs-with-functions-kvp-using-console)
+ [CloudFront KeyValueStore 소개](#kvs-with-functions-api-describe)
+ [키 값 페어 작업(AWS CLI)](#work-with-kvs-cli-keys)
+ [키 값 페어 작업(API)](#kvs-with-functions-kvp-using-api)

## 키 값 페어 작업(콘솔)
<a name="kvs-with-functions-kvp-using-console"></a>

CloudFront 콘솔을 사용하여 키 값 페어로 작업할 수 있습니다.

**키-값 페어로 작업하려면**

1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/cloudfront/v4/home#/functions](https://console.aws.amazon.com/cloudfront/v4/home#/functions)에 있는 CloudFront 콘솔에서 **함수** 페이지를 엽니다.

1. **KeyValueStore** 탭을 선택합니다.

1. 변경할 키 값 저장소를 선택합니다.

1. **키 값 페어** 섹션에서 **편집** 버튼을 선택합니다.

1. 키 값 페어를 추가하거나, 키 값 페어를 삭제하거나, 기존 키 값 페어의 값을 변경할 수 있습니다.

1. 작업을 마쳤으면 **변경 내용 저장**을 선택합니다.

## CloudFront KeyValueStore 소개
<a name="kvs-with-functions-api-describe"></a>

**작은 정보**  
CloudFront KeyValueStore API는 인증에 서명 버전 4A(SigV4A)를 사용하는 글로벌 서비스입니다. SigV4A에서 임시 자격 증명을 사용하려면 버전 2 세션 토큰이 필요합니다. 자세한 내용은 [CloudFront KeyValueStore API에 임시 자격 증명 사용](cloudfront-function-restrictions.md#regional-endpoint-for-key-value-store) 섹션을 참조하세요.

AWS Command Line Interface(AWS CLI) 또는 자체 코드를 사용하여 CloudFront KeyValueStore API를 직접 호출하는 경우 다음 섹션을 참조하세요.

키 값 저장소와 해당 키 값 페어를 사용할 때 직접적으로 호출하는 서비스는 사용 사례에 따라 달라집니다.
+ **기존 키 값 저장소에서 키 값 페어를 사용하려면 CloudFront KeyValueStore 서비스를 사용합니다.
+ 키 값 저장소를 처음 생성할 때 키 값 저장소에 키 값 페어를 포함하려면 CloudFront 서비스를 사용합니다.**

CloudFront API와 CloudFront KeyValueStore API에는 모두 `DescribeKeyValueStore` 작업이 있습니다. 직접 호출하는 이유는 여러 가지 입니다. 차이점을 이해하려면 다음 테이블을 참조하세요.


|  | CloudFront DescribeKeyValueStore API | CloudFront KeyValueStore DescribeKeyValueStore API | 
| --- | --- | --- | 
| 키 값 저장소 관련 데이터 |  키 값 저장소 자체가 마지막으로 수정된 상태 및 날짜와 같은 데이터를 반환합니다.  |  스토리지 리소스의 **콘텐츠(저장소의 키 값 페어, 콘텐츠 크기)에 대한 데이터를 제공합니다.  | 
| 키 값 저장소를 식별하는 데이터 |  키 값 저장소의 `ETag`, UUID, ARN을 반환합니다.  |  키 값 저장소의 `ETag`, ARN을 반환합니다.  | 

**참고**  
각 DescribeKeyValueStore 작업은 서로 다른 **`ETag`를 반환합니다. `ETags`는 서로 바꿔서 사용할 수 없습니다.
API 작업을 직접적으로 호출하여 작업을 완료할 때는 적절한 API에서 `ETag`를 지정해야 합니다. 예를 들어 CloudFront KeyValueStore [DeleteKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DeleteKey.html) 작업에서는 CloudFront KeyValueStore [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DescribeKeyValueStore.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DescribeKeyValueStore.html) 작업에서 반환한 `ETag`를 지정합니다.
CloudFront KeyValueStore를 사용하여 CloudFront Functions을 호출하는 경우 함수 호출 중에 키 값 저장소의 값이 업데이트되거나 변경되지 않습니다. 업데이트는 함수 호출 사이에 처리됩니다.

## 키 값 페어 작업(AWS CLI)
<a name="work-with-kvs-cli-keys"></a>

CloudFront KeyValueStore에 대해 다음 AWS Command Line Interface 명령을 실행할 수 있습니다.

**Contents**
+ [키 값 페어 나열](#kvs-cli-list-keys)
+ [키 값 페어 가져오기](#kvs-cli-get-keys)
+ [키 값 저장소 설명](#kvs-cli-describe-keys)
+ [키 값 페어 생성](#kvs-cli-create-keys)
+ [키 값 페어 삭제](#kvs-cli-delete-keys)
+ [키 값 페어 업데이트](#kvs-cli-update-key)

### 키 값 페어 나열
<a name="kvs-cli-list-keys"></a>

키 값 저장소의 키 값 페어를 나열하려면 다음 명령을 실행합니다.

```
aws cloudfront-keyvaluestore list-keys \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**응답**

```
{
    "Items": [
        {
            "Key": "key1",
            "Value": "value1"
        }
    ]
}
```

### 키 값 페어 가져오기
<a name="kvs-cli-get-keys"></a>

키 값 저장소의 키 값 페어를 가져오려면 다음 명령을 실행합니다.

```
aws cloudfront-keyvaluestore get-key \
    --key=key1 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**응답**

```
{
    "Key": "key1",
    "Value": "value1",
    "ItemCount": 1,
    "TotalSizeInBytes": 11
}
```

### 키 값 저장소 설명
<a name="kvs-cli-describe-keys"></a>

키 값 저장소를 설명하려면 다음 명령을 실행합니다.

```
aws cloudfront-keyvaluestore describe-key-value-store \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**응답**

```
{
    "ETag": "KV1F83G8C2ARO7P",
    "ItemCount": 1,
    "TotalSizeInBytes": 11,
    "KvsARN": "arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example",
    "Created": "2024-05-08T07:48:45.381000-07:00",
    "LastModified": "2024-08-05T13:50:58.843000-07:00",
    "Status": "READY"
}
```

### 키 값 페어 생성
<a name="kvs-cli-create-keys"></a>

키 값 저장소에 키 값 페어를 생성하려면 다음 명령을 실행합니다.

```
aws cloudfront-keyvaluestore put-key \
    --if-match=KV1PA6795UKMFR9 \
    --key=key2 \
    --value=value2 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**응답**

```
{
    "ETag": "KV13V1IB3VIYZZH",
    "ItemCount": 3,
    "TotalSizeInBytes": 31
}
```

### 키 값 페어 삭제
<a name="kvs-cli-delete-keys"></a>

키 값 페어를 삭제하려면 다음 명령을 실행합니다.

```
aws cloudfront-keyvaluestore delete-key \
    --if-match=KV13V1IB3VIYZZH \
    --key=key1 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example
```

**출력**

```
{
    "ETag": "KV1VC38T7YXB528",
    "ItemCount": 2,
    "TotalSizeInBytes": 22
}
```

### 키 값 페어 업데이트
<a name="kvs-cli-update-key"></a>

`update-keys` 명령을 사용하여 둘 이상의 키 값 페어를 업데이트할 수 있습니다. 예를 들어 기존 키 값 페어를 삭제하고 다른 키 값 페어를 만들려면 다음 명령을 실행합니다.

```
aws cloudfront-keyvaluestore update-keys \
    --if-match=KV2EUQ1WTGCTBG2 \
    --kvs-arn=arn:aws:cloudfront::123456789012:key-value-store/37435e19-c205-4271-9e5c-example \
    --deletes '[{"Key":"key2"}]' \
    --puts '[{"Key":"key3","Value":"value3"}]'
```

**응답**

```
{
    "ETag": "KV3AEGXETSR30VB",
    "ItemCount": 3,
    "TotalSizeInBytes": 28
}
```

## 키 값 페어 작업(API)
<a name="kvs-with-functions-kvp-using-api"></a>

이 섹션을 따라 프로그래밍 방식으로 키 값 페어 작업 

**Contents**
+ [키 값 저장소에 대한 참조 가져오기](#kvs-with-functions-api-ref)
+ [키 값 저장소의 키 값 페어 변경](#kvs-with-functions-api-actions)
+ [CloudFront 키 값 저장소 예제 코드](#example-code-key-value-store)

### 키 값 저장소에 대한 참조 가져오기
<a name="kvs-with-functions-api-ref"></a>

CloudFront KeyValueStore API를 사용하여 쓰기 작업을 직접적으로 호출할 때는 키 값 저장소의 ARN과 `ETag`를 지정해야 합니다. 이 데이터를 가져오려면 다음 작업을 수행합니다.

**키 값 저장소에 대한 참조를 가져오려면**

1. [https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListKeyValueStores.html) API 작업을 사용하여 키 값 저장소 목록을 가져옵니다. 변경할 키 값 저장소를 찾습니다.

1. [CloudFrontKeyValueStore DescribeKeyValueStore API 작업](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DescribeKeyValueStore.html)을 사용하여 이전 단계의 키 값 저장소를 지정합니다.

   응답에는 키 값 저장소의 ARN과 `ETag`가 포함됩니다.
   + 다음 예와 같이 ARN에는 AWS 계정 번호, 상수 `key-value-store`, UUID가 포함됩니다.

     `arn:aws:cloudfront::123456789012:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111`
   + `ETag`는 다음 예와 같습니다.

     `ETVABCEXAMPLE2`

### 키 값 저장소의 키 값 페어 변경
<a name="kvs-with-functions-api-actions"></a>

업데이트하려는 키 값 페어가 들어 있는 키 값 저장소를 지정할 수 있습니다.

다음 CloudFront KeyValueStore API 작업을 참조하세요.
+ [CloudFrontKeyValueStore DeleteKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_DeleteKey.html) – 키 값 페어를 삭제합니다.
+ [CloudFrontKeyValueStore GetKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_GetKey.html) – 키 값 페어를 반환합니다.
+ [CloudFrontKeyValueStore ListKeys](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_ListKeys.html) – 키 값 페어 목록을 반환합니다.
+ [CloudFrontKeyValueStore PutKey](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_PutKey.html) – 다음과 같은 작업을 수행할 수 있습니다.
  + 새 키 이름과 값을 지정하여 하나의 키 값 저장소에 키 값 페어를 생성합니다.
  + 기존 키 이름과 새 키 값을 지정하여 기존 키 값 페어에 다른 값을 설정합니다.
+ [CloudFrontKeyValueStore UpdateKeys](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_kvs_UpdateKeys.html) - 전부 또는 전무 작업 하나로 다음 작업 중 하나 이상을 수행할 수 있습니다.
  + 하나 이상의 키 값 페어 삭제
  + 새 키 값 페어를 하나 이상 생성
  + 하나 이상의 기존 키 값 페어에 다른 값 설정

### CloudFront 키 값 저장소 예제 코드
<a name="example-code-key-value-store"></a>

**Example**  
다음 코드는 키 값 저장소에 대한 `DescribeKeyValueStore` API 작업을 직접적으로 호출하는 방법을 보여줍니다.  

```
const {
  CloudFrontKeyValueStoreClient,
  DescribeKeyValueStoreCommand,
} = require("@aws-sdk/client-cloudfront-keyvaluestore");

require("@aws-sdk/signature-v4-crt");

(async () => {
  try {
    const client = new CloudFrontKeyValueStoreClient({
      region: "us-east-1"
    });
    const input = {
      KvsARN: "arn:aws:cloudfront::123456789012:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111",
    };
    const command = new DescribeKeyValueStoreCommand(input);

    const response = await client.send(command);
  } catch (e) {
    console.log(e);
  }
})();
```

# CloudFront 연결 함수를 사용하여 사용자 지정
<a name="customize-connections-validation-with-connection-functions"></a>

CloudFront 연결 함수를 사용하면 mTLS 인증서 검증 및 사용자 지정 인증 로직을 위한 경량 JavaScript 함수를 작성할 수 있습니다. 연결 함수는 mTLS 연결 설정 중에 실행되어 클라이언트 인증서를 검증하고, 디바이스별 인증 규칙을 구현하고, 인증서 해지 시나리오를 처리합니다. 연결 함수 런타임 환경은 밀리초 미만의 시작 시간을 제공하고 초당 수백만 건의 연결을 처리할 수 있도록 즉시 확장되며 매우 안전합니다. 연결 함수는 CloudFront의 기본 기능입니다. 즉, CloudFront 내에서 완전히 코드를 빌드, 테스트 및 배포할 수 있습니다.

연결 함수를 mTLS 지원 CloudFront 배포와 연결하면 CloudFront는 CloudFront 엣지 로케이션에서 TLS 연결 요청을 가로채고 인증서 정보를 함수에 전달합니다. 다음 이벤트가 발생할 때 연결 함수를 간접 호출할 수 있습니다.
+ TLS 연결 설정(연결 요청) 중 - 상호 TLS(mTLS) 연결용

연결 함수에 대한 자세한 내용은 다음 주제를 참조하세요.

**Topics**
+ [개요 및 워크플로](connection-functions-overview.md)
+ [구성 및 제한 사항](connection-function-configuration-limits.md)
+ [상호 TLS(뷰어) 검증을 위한 CloudFront 연결 함수 생성](create-connection-functions.md)
+ [상호 TLS(뷰어) 검증을 위한 CloudFront 연결 함수 코드 쓰기](write-connection-function-code.md)
+ [배포 전에 CloudFront 연결 함수 테스트](test-connection-functions.md)
+ [배포에 연결 함수 연결](associate-connection-functions.md)
+ [CloudFront Functions 및 KeyValueStore를 사용하여 상호 TLS(뷰어)에 대한 인증서 해지 구현](implement-certificate-revocation.md)

# 개요 및 워크플로
<a name="connection-functions-overview"></a>

CloudFront 연결 함수는 클라이언트가 mTLS 연결을 설정하려고 할 때 TLS 핸드셰이크 중에 실행되는 특수한 유형의 CloudFront Functions입니다. 연결 함수는 클라이언트 인증서 정보, mTLS 구성 파라미터, 인증서 해지 검사 결과 및 클라이언트 IP 주소에 액세스할 수 있습니다.

CloudFront가 표준 인증서 검증(신뢰 체인, 만료, 서명 확인)을 수행한 후 연결 함수가 간접적으로 호출되지만 인증서 해지 확인에 실패하더라도 실행될 수 있습니다. 이렇게 하면 해지된 인증서를 처리하거나 추가 검증 기준을 추가하기 위한 사용자 지정 로직을 구현할 수 있습니다.

연결 함수를 생성하고 게시한 후에는 mTLS 지원 배포에 연결 요청 이벤트 유형에 대한 연결을 추가해야 합니다. 이렇게 하면 클라이언트가 CloudFront와 mTLS 연결을 설정하려고 할 때마다 함수가 실행됩니다.

CloudFront 연결 함수는 프로덕션에 배포하기 전에 함수를 개발하고 테스트할 수 있는 2단계 수명 주기를 따릅니다. 이 워크플로는 연결 함수가 라이브 트래픽에 영향을 미치기 전에 올바르게 작동하도록 합니다.

**Topics**
+ [함수 단계](#connection-function-stages)
+ [개발 워크플로](#connection-function-development-workflow)
+ [다른 함수 유형과의 차이점](#connection-function-differences)

## 함수 단계
<a name="connection-function-stages"></a>

연결 함수는 다음 두 단계 중 하나로 존재합니다.
+ **개발** - 이 단계의 함수를 수정, 테스트 및 업데이트할 수 있습니다. 함수 코드를 작성하고 디버깅하려면 이 단계를 사용합니다.
+ **라이브** - 이 단계의 함수는 읽기 전용이며 프로덕션 트래픽을 처리합니다. 라이브 단계에서는 함수를 직접 수정할 수 없습니다.

새 연결 함수를 생성하면 **개발** 단계에서 시작됩니다. 테스트 및 검증 후 함수를 게시하여 **라이브** 단계로 이동합니다.

## 개발 워크플로
<a name="connection-function-development-workflow"></a>

다음 워크플로에 따라 연결 함수를 개발하고 배포합니다.

1. **생성** - 초기 코드 및 구성을 사용하여 개발 단계에서 새 연결 함수를 생성합니다.

1. **테스트** - 테스트 기능을 사용하여 배포 전에 샘플 연결 이벤트로 함수를 검증합니다.

1. **업데이트** - 테스트 결과를 바탕으로 필요에 따라 함수 코드 및 구성을 수정합니다.

1. **게시** - 프로덕션 준비가 되면 함수를 게시하여 개발 단계에서 라이브 단계로 이동합니다.

1. **연결** - 게시된 함수를 mTLS 지원 배포와 연결하여 라이브 연결을 처리합니다.

라이브 함수를 변경하려면 개발 버전을 업데이트하고 다시 게시해야 합니다. 그러면 라이브 단계에서 새 버전이 생성됩니다.

## 다른 함수 유형과의 차이점
<a name="connection-function-differences"></a>

연결 함수는 다음과 같은 몇 가지 중요한 측면에서 뷰어 요청 및 뷰어 응답 함수와 다릅니다.
+ 연결 함수는 mTLS 핸드셰이크 이후 HTTP 처리가 발생하기 전에 실행됩니다.
+ 연결 함수는 HTTP 요청/응답 데이터 대신 TLS 인증서 정보에 액세스할 수 있습니다.
+ 연결 함수는 HTTP 데이터를 수정하지 않고 연결만 허용하거나 거부할 수 있습니다.
+ 연결 함수는 연결 재사용이 아닌 새 TLS 연결에 대해서만 간접적으로 호출됩니다.
+ TLS 세션 재개는 모든 연결에서 인증서 검증이 이루어지도록 mTLS에서 지원되지 않습니다.
+ 연결 함수는 표준 뷰어 요청 및 뷰어 응답 함수 외에도 실행됩니다.
+ 연결 함수는 캐시 동작 수준이 아닌 배포 수준에서 연결합니다.
+ 연결 함수는 JavaScript 런타임 2.0만 지원합니다.

# 구성 및 제한 사항
<a name="connection-function-configuration-limits"></a>

CloudFront 연결 함수에는 TLS 연결 검증에서의 특수한 역할과 엣지 컴퓨팅의 성능 요구 사항으로 인해 특정한 구성 요구 사항 및 서비스 제한이 있습니다.

**Topics**
+ [함수 코드 요구 사항](#connection-function-code-requirements)
+ [서비스 한도](#connection-function-service-limits)
+ [함수 필터링 옵션](#connection-function-filtering-options)

## 함수 코드 요구 사항
<a name="connection-function-code-requirements"></a>

연결 함수에는 TLS 연결 이벤트를 처리하는 JavaScript 코드가 필요합니다. 함수 코드는 다음을 충족해야 합니다.
+ JavaScript로 작성
+ 연결 이벤트 처리 및 허용/거부 결정
+ 제한 시간 내에 실행 완료
+ 인증서 및 연결 검증 로직 처리

## 서비스 한도
<a name="connection-function-service-limits"></a>

연결 함수에는 다음 제한이 적용됩니다.
+ **함수 크기** - 함수 코드 및 구성의 크기가 제한됩니다.
+ **실행 시간** - 함수에는 TLS 연결 처리에 대한 엄격한 실행 시간 제한이 있습니다.
+ **연결 제한** - 각 배포에는 연결 함수가 하나만 연결될 수 있습니다.
+ **단계 제한** - 라이브 단계 함수만 배포와 연결할 수 있습니다.

## 함수 필터링 옵션
<a name="connection-function-filtering-options"></a>

연결 함수를 나열할 때 다음 필터를 사용할 수 있습니다.
+ **단계 필터** - 개발 또는 라이브 단계를 기준으로 필터링합니다.
+ **연결 필터** - 배포 ID 또는 키-값 저장소 ID 연결을 기준으로 필터링합니다.

이러한 필터를 사용하면 다양한 환경 및 사용 사례에서 연결 함수를 구성하고 관리할 수 있습니다.

# 상호 TLS(뷰어) 검증을 위한 CloudFront 연결 함수 생성
<a name="create-connection-functions"></a>

CloudFront 연결 함수는 다음 두 단계로 생성합니다.

1. 함수 코드를 JavaScript로 생성합니다. CloudFront 콘솔의 기본 예제를 사용하거나, 직접 작성할 수 있습니다. 자세한 내용은 다음 항목을 참조하세요.
   + mTLS 검증을 위한 CloudFront 연결 함수 코드 작성
   + CloudFront 연결 함수 이벤트 구조 및 응답 형식
   + 연결 함수 코드 예제

1. CloudFront를 사용하여 연결 함수를 생성하고 코드를 포함합니다. 코드는 함수 내에 존재합니다(참조용이 아님).

**Topics**
+ [CloudFront 콘솔](#create-connection-function-console)
+ [AWS CLI](#create-connection-function-cli)

## CloudFront 콘솔
<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. AWS 계정 내에서 고유한 함수 이름을 입력하고 함수 유형으로 **연결 함수**를 선택한 다음 **계속**을 선택합니다.

1. 새 연결 함수의 세부 정보 페이지가 나타납니다.
**참고**  
연결 함수는 JavaScript 런타임 2.0만 지원합니다. 함수에서 CloudFront 연결 함수 KeyValueStore 통합을 사용하려면 이 런타임 버전을 사용해야 합니다.

1. **함수 코드** 섹션에서 **빌드** 탭을 선택하고 연결 함수 코드를 입력합니다. 빌드 탭에 포함된 샘플 코드는 연결 함수 코드의 기본 구문을 보여줍니다.

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

1. 연결 함수 코드가 인증서 해지 확인 또는 디바이스 검증에 KeyValueStore를 사용하는 경우 KeyValueStore를 연결해야 합니다.

   함수를 처음 생성할 때 KeyValueStore를 연결할 수 있습니다. 또는 연결 함수를 연결하여 나중에 연결할 수 있습니다.

   지금 KeyValueStore를 연결하려면 다음 단계를 따르세요.
   + **KeyValueStore 연결** 섹션에서 **기존 KeyValueStore 연결**을 선택합니다.
   + 연결 함수의 인증서 데이터가 포함된 KeyValueStore를 선택한 다음 **KeyValueStore 연결**을 선택합니다.

   CloudFront는 저장소를 함수와 즉시 연결하므로 함수를 저장하지 않아도 됩니다.

## AWS CLI
<a name="create-connection-function-cli"></a>

AWS CLI를 사용하는 경우 일반적으로 먼저 파일에 연결 함수 코드를 생성한 다음 AWS CLI로 함수를 생성합니다.

**연결 함수를 생성하려면**

1. 연결 함수 코드를 파일로 만든 다음 컴퓨터가 연결할 수 있는 디렉터리에 저장합니다.

1. 다음 예제와 같이 명령을 실행합니다. 이 예제에서는 `fileb://` 표기법을 사용하여 파일을 전달합니다. 명령을 더 쉽게 읽을 수 있도록 줄 바꿈도 포함되어 있습니다.

   ```
   aws cloudfront create-connection-function \
       --name CertificateValidator \
       --connection-function-config '{
           "Comment":"Device certificate validation",
           "Runtime":"cloudfront-js-2.0",
           "KeyValueStoreAssociations":{
               "Quantity":1,
               "Items":[{
                   "KeyValueStoreARN":"arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111"
               }]
           }
       }' \
       --connection-function-code fileb://certificate-validator.js
   ```
**참고**  
**런타임** - 연결 함수는 JavaScript 런타임 2.0(cloudfront-js-2.0)만 지원합니다.
**KeyValueStoreAssociations** - 연결 함수가 인증서 검증에 KeyValueStore를 사용하는 경우, 함수를 처음 생성할 때 KeyValueStore를 연결할 수 있습니다. 또는 update-connection-function을 사용하여 나중에 연결할 수 있습니다. 각 연결 함수에 KeyValueStore가 하나만 연결될 수 있기 때문에 수량은 항상 1입니다.

1. 명령이 제대로 실행되면 다음과 비슷한 출력이 표시됩니다.

   ```
   ETag: ETVABCEXAMPLE
   ConnectionFunctionSummary:
     ConnectionFunctionConfig:
       Comment: Device certificate validation
       Runtime: cloudfront-js-2.0
       KeyValueStoreAssociations:
         Quantity: 1
         Items:
           - KeyValueStoreARN: arn:aws:cloudfront::111122223333:key-value-store/a1b2c3d4-5678-90ab-cdef-EXAMPLE11111
     ConnectionFunctionMetadata:
       CreatedTime: '2024-09-04T16:32:54.292000+00:00'
       ConnectionFunctionARN: arn:aws:cloudfront::111122223333:connection-function/CertificateValidator
       LastModifiedTime: '2024-09-04T16:32:54.292000+00:00'
       Stage: DEVELOPMENT
     Name: CertificateValidator
     Status: UNPUBLISHED
   Location: https://cloudfront.amazonaws.com/2020-05-31/connection-function/arn:aws:cloudfront:::connection-function/CertificateValidator
   ```

   대부분의 정보는 요청에서 반복된 내용입니다. 기타 정보는 CloudFront에 의해 추가됩니다.
**참고**  
**ETag** - 이 값은 연결 함수를 수정할 때마다 변경됩니다. 함수를 업데이트하거나 게시하려면 이 값이 필요합니다.
**단계** - 새 연결 함수는 개발 단계에서 시작됩니다. 함수를 배포와 연결하기 전에 함수를 게시하여 라이브 단계로 이동해야 합니다.
**상태** - 라이브 단계에 게시할 때까지 함수 상태는 ‘게시되지 않음’입니다.

# 상호 TLS(뷰어) 검증을 위한 CloudFront 연결 함수 코드 쓰기
<a name="write-connection-function-code"></a>

CloudFront 연결 함수를 사용하면 mTLS 인증서 검증 및 사용자 지정 인증 로직을 위한 경량 JavaScript 함수를 작성할 수 있습니다. 연결 함수 코드는 클라이언트 인증서를 검증하고, 디바이스별 인증 규칙을 구현하고, 인증서 해지 시나리오를 처리하고, 전 세계 CloudFront 엣지 로케이션에서 TLS 연결에 대한 허용/거부 결정을 내릴 수 있습니다.

연결 함수는 자체 비즈니스 로직을 사용하여 CloudFront의 기본 제공 인증서 검증을 확장하는 강력한 방법을 제공합니다. HTTP 데이터를 처리하는 뷰어 요청 및 뷰어 응답 함수와 달리, 연결 함수는 TLS 계층에서 작동하며 인증서 정보, 클라이언트 IP 주소 및 TLS 연결 세부 정보에 액세스할 수 있습니다. 따라서 표준 PKI 검증을 넘어 제로 트러스트 보안 모델, 디바이스 인증 시스템 및 사용자 지정 인증서 검증 정책을 구현하는 데 이상적입니다.

연결 함수 코드는 시작 시간이 밀리초 미만인 안전하고 격리된 환경에서 실행되며 초당 수백만 개의 연결을 처리하도록 확장할 수 있습니다. 런타임은 인증서 검증 워크로드에 최적화되어 있으며 실시간 데이터 조회 작업을 위해 CloudFront KeyValueStore와 기본적으로 통합되어 인증서 해지 목록 확인 및 디바이스 허용 목록 검증과 같은 정교한 인증 시나리오를 지원합니다.

효과적인 연결 함수 코드를 작성하는 데 도움이 되도록 다음 주제를 참조하세요. 전체 코드 예제와 단계별 자습서는 이 가이드의 자습서 섹션을 참조하고 CloudFront 콘솔에서 사용할 수 있는 연결 함수 예제를 살펴보세요.

**Topics**
+ [CloudFront 연결 함수 사용 사례 및 용도](#connection-function-use-cases)
+ [CloudFront 연결 함수 이벤트 구조 및 응답 형식](#connection-function-event-structure)
+ [CloudFront 연결 함수 JavaScript 런타임 기능](#connection-function-javascript-runtime)
+ [CloudFront 연결 함수 헬퍼 메서드 및 API](#connection-function-helper-methods)
+ [CloudFront 연결 함수 KeyValueStore 통합](#connection-function-kvs-integration)
+ [async 및 await 사용](#connection-function-async-await)
+ [연결 함수 코드 예제](#connection-function-code-examples)

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

CloudFront 연결 함수를 작성하기 전에 구현해야 하는 인증서 검증 또는 인증 로직 유형을 신중하게 결정합니다. 연결 함수는 표준 PKI 인증서 검사 외에 사용자 지정 검증이 필요한 특정 사용 사례에 맞게 설계되었습니다. 사용 사례를 이해하면 최적의 성능을 유지하면서 보안 요구 사항을 충족하는 효율적인 코드를 설계할 수 있습니다.

일반적인 연결 함수 사용 사례는 다음과 같습니다.
+ **인증서 해지 처리** - 인증서 교체 유예 기간, 내부 디바이스에 대한 신뢰할 수 있는 네트워크 예외 또는 해지된 인증서에 임시 액세스가 필요할 수 있는 긴급 액세스 시나리오를 포함하여 해지된 인증서를 처리하기 위한 사용자 지정 정책을 구현합니다.
+ **선택적 mTLS 지원** - 서로 다른 인증 정책으로 mTLS 및 비mTLS 연결을 모두 처리하여 레거시 클라이언트와의 호환성을 유지하면서 인증서를 지원하는 클라이언트에 더 나은 보안을 제공할 수 있습니다.
+ **IP 기반 인증 -** 클라이언트 IP 주소 확인과 인증서 검증을 결합하여 특정 지리적 리전, 회사 네트워크 또는 알려진 악성 IP 범위에서 액세스를 제한하는 등 보안을 강화합니다.
+ **다중 테넌트 인증서 검증 -** 클라이언트 인증서 발급자 또는 주체 속성에 따라 다른 인증 기관 또는 검증 기준이 적용되는 테넌트별 검증 규칙을 구현합니다.
+ **시간 기반 액세스 제어** - 인증서 자체가 만료되지 않은 경우에도 특정 시간, 유지 관리 기간 또는 업무 기간 동안에만 인증서가 유효한 시간 기반 제한을 적용합니다.

연결 함수는 CloudFront가 표준 인증서 검증(신뢰 체인 확인, 만료 확인 및 서명 검증)을 수행한 후 TLS 연결이 설정되기 전에 실행됩니다. 이 타이밍을 사용하면 CloudFront의 내장 인증서 검증을 활용하면서 사용자 지정 검증 기준을 유연하게 추가할 수 있습니다. 함수는 표준 검증 결과를 수신하고 정보를 바탕으로 표준 및 사용자 지정 기준에 따라 연결을 허용할지 또는 거부할지를 결정할 수 있습니다.

연결 함수를 설계할 때는 검증 로직의 성능 영향을 고려하세요. 함수의 실행 한도는 5밀리초이므로 복잡한 작업은 속도에 맞게 최적화해야 합니다. 복잡한 계산 대신 빠른 데이터 조회에 KeyValueStore를 사용하고 잘못된 인증서는 빠르게 실패하도록 검증 로직을 구성합니다.

## CloudFront 연결 함수 이벤트 구조 및 응답 형식
<a name="connection-function-event-structure"></a>

CloudFront 연결 함수는 뷰어 요청 및 뷰어 응답 함수와 다른 이벤트 구조를 수신합니다. 연결 함수는 HTTP 요청/응답 데이터 대신 인증 결정에 사용할 수 있는 인증서 및 연결 정보를 수신합니다.

**Topics**
+ [연결 함수의 이벤트 구조](#connection-function-event-structure-details)
+ [연결 함수 응답 형식](#connection-function-response-format)

### 연결 함수의 이벤트 구조
<a name="connection-function-event-structure-details"></a>

연결 함수는 인증서 및 연결 정보가 포함된 이벤트 객체를 수신합니다. 함수의 이벤트 구조는 다음과 같습니다.

```
{
  "clientCertificate": {
    "certificates": {
      "leaf": {
        "serialNumber": "string",
        "issuer": "string",
        "subject": "string",
        "validity": {
          "notBefore": "string",
          "notAfter": "string",
        },
        "sha256Fingerprint": "string"
      }
    }
  },
  "clientIp": "string",
  "endpoint": "string",
  "distributionId": "string",
  "connectionId": "string"
}
```

다음은 이벤트 객체 구조의 예입니다.

```
{
  "clientCertificate": {
    "certificates": {
      "leaf": {
        "serialNumber": "00:9e:2a:af:16:56:e5:47:25:7d:2e:38:c3:f9:9d:57:fa",
        "issuer": "C=US, O=Ram, OU=Edge, ST=WA, CN=mTLS-CA, L=Snoqualmie",
        "subject": "C=US, O=Ram, OU=Edge, ST=WA, CN=mTLS-CA, L=Snoqualmie",
        "validity": {
          "notBefore": "2025-09-10T23:43:10Z",
          "notAfter": "2055-09-11T00:43:02Z"
        },
        "sha256Fingerprint": "_w6bJ7aOAlGOj7NUhJxTfsfee-ONg_xop3_PTgTJpqs="
      }
    }
  },
  "clientIp": "127.0.0.1",
  "endpoint": "d3lch071jze0cb.cloudfront.net",
  "distributionId": "E1NXS4MQZH501R",
  "connectionId": "NpvTe1925xfj24a67sPQr7ae42BIq03FGhJJKfrQYWZcWZFp96SIIg=="
}
```

### 연결 함수 응답 형식
<a name="connection-function-response-format"></a>

연결 함수는 연결을 허용할지 또는 거부할지를 나타내는 응답 객체를 반환해야 합니다. 다음과 같이 헬퍼 메서드를 사용하여 연결 결정을 내립니다.

```
function connectionHandler(connection) {
    // Helper methods to allow or deny connections
    if (/* some logic to determine if function should allow connection */) {
        connection.allow();
    } else {
        connection.deny();
    }
}
```

뷰어 요청 및 뷰어 응답 함수와 달리 연결 함수는 HTTP 요청 또는 응답을 수정할 수 없습니다. TLS 연결만 허용하거나 거부할 수 있습니다.

## CloudFront 연결 함수 JavaScript 런타임 기능
<a name="connection-function-javascript-runtime"></a>

CloudFront 연결 함수는 인증서 검증 워크로드에 특별히 최적화된 안전한 고성능 환경을 제공하는 CloudFront Functions JavaScript 런타임 2.0을 사용합니다. 런타임은 수 밀리초 이내에 시작하고 CloudFront의 글로벌 엣지 네트워크에서 수백만 개의 동시 실행을 처리하도록 설계되었습니다.

런타임 환경에는 다음과 같이 포괄적인 JavaScript 언어 지원이 포함됩니다.
+ **ECMAScript 2020(ES11) 지원** - 선택적 연결(?.), nullish 병합(??) 및 대용량 인증서 일련 번호 처리를 위한 BigInt를 포함한 최신 JavaScript 기능
+ **기본 제공 객체** - 객체, 배열, JSON, 수학 및 날짜와 같은 표준 JavaScript 객체
+ **콘솔 로깅** - console.log()를 사용하여 인증서 검증 결정을 디버깅하고 모니터링합니다. 테스트 중에 로그를 실시간으로 사용할 수 있으며 개발 중인 검증 로직 문제를 해결하는 데 도움이 될 수 있습니다.
+ **KeyValueStore 통합** - 초고속 데이터 조회 작업을 위한 CloudFront KeyValueStore에 대한 기본 액세스로 실시간 인증서 해지 확인, 디바이스 허용 목록 검증 및 테넌트별 구성 검색 활성화

연결 함수는 인증서 검증 시나리오를 위한 고성능에 최적화되어 있습니다. 런타임은 메모리 관리, 폐영역 회수 및 리소스 정리를 자동으로 처리하여 수백만 개의 동시 연결에서 일관된 성능을 보장합니다. 모든 작업은 결정적이고 빠르게 진행되도록 설계되었으며 KeyValueStore 조회는 일반적으로 마이크로초 단위로 완료됩니다.

런타임 환경은 함수 실행 간에 완전히 격리되므로 서로 다른 클라이언트 연결 간에 데이터가 유출되지 않습니다. 각 함수 실행은 정상 상태로 시작되며 이전 실행 결과 또는 다른 연결의 클라이언트 데이터에 액세스할 수 없습니다.

## CloudFront 연결 함수 헬퍼 메서드 및 API
<a name="connection-function-helper-methods"></a>

CloudFront 연결 함수는 인증서 검증 결정을 간소화하고 관찰성을 향상하도록 설계된 특수 헬퍼 메서드를 제공합니다. 이러한 방법은 연결 검증 워크플로에 최적화되어 있으며 CloudFront의 연결 로깅 및 모니터링 시스템과 원활하게 통합됩니다.
+ **connection.allow()** - TLS 연결이 진행되도록 허용합니다. 이 방법은 CloudFront에 신호를 보내어 TLS 핸드셰이크를 완료하고 클라이언트가 연결을 설정할 수 있도록 합니다. 인증서 검증을 통과하고 사용자 지정 인증 로직이 충족될 때 사용
+ **connection.deny()** - TLS 연결을 거부하고 핸드셰이크를 종료합니다. 이 방법은 연결을 즉시 닫고 HTTP 트래픽이 흐르지 않도록 합니다. 클라이언트에 TLS 연결 오류가 발생합니다. 잘못된 인증서, 인증 실패 또는 정책 위반에 사용
+ **connection.logCustomData()** - 연결 로그에 사용자 지정 데이터를 추가합니다(최대 800바이트의 UTF-8 텍스트). 이 방법을 사용하면 보안 모니터링, 규정 준수 감사 및 문제 해결을 위해 CloudFront 연결 로그에 검증 결과, 인증서 세부 정보 또는 결정 근거를 포함할 수 있습니다.

이러한 메서드는 연결 결정을 내리고 모니터링 및 디버깅과 관련된 정보를 로깅하는 데 필요한 깔끔하고 선언적인 인터페이스를 제공합니다. 허용/거부 패턴은 함수의 의도가 명확하고 CloudFront가 결정에 따라 연결 처리를 최적화할 수 있도록 합니다. 사용자 지정 로깅 데이터는 CloudFront 연결 로그에서 즉시 사용할 수 있으며, 보안 모니터링 및 운영 인사이트를 위한 로그 분석 도구와 함께 사용할 수 있습니다.

함수가 완료되기 전에 항상 connection.allow() 또는 connection.deny()를 직접 호출합니다. 두 메서드가 모두 직접 호출되지 않으면 CloudFront는 보안 예방 조치로 기본적으로 연결을 거부합니다.

## CloudFront 연결 함수 KeyValueStore 통합
<a name="connection-function-kvs-integration"></a>

CloudFront 연결 함수는 CloudFront KeyValueStore를 사용하여 인증서 검증 시나리오에서 초고속 데이터 조회를 수행할 수 있습니다. KeyValueStore는 모든 CloudFront 엣지 로케이션에서 최종적으로 일관된 전역 데이터 액세스를 마이크로초 수준의 조회 시간으로 제공하므로 연결 함수에 특히 유용합니다. 따라서 TLS 핸드셰이크 중에 액세스해야 하는 인증서 해지 목록, 디바이스 허용 목록, 테넌트 구성 및 기타 검증 데이터를 유지하는 데 이상적입니다.

KeyValueStore 통합은 고성능 연결 검증 워크플로를 위해 특별히 설계되었습니다.
+ **kvsHandle.exists(key)** - 값을 검색하지 않고 KeyValueStore에 키가 있는지 확인합니다. 인증서 해지 확인과 같은 이진 검증 시나리오에서 인증서 일련 번호가 해지 목록에 있는지 여부만 알면 되는 가장 효율적인 방법입니다.
+ **kvsHandle.get(key)** - 더 복잡한 검증 시나리오를 위해 KeyValueStore에서 값을 검색합니다. 인증서 또는 디바이스 식별자와 연결된 구성 데이터, 검증 규칙 또는 메타데이터에 액세스해야 할 때 사용합니다.

KeyValueStore 작업은 비동기식이며 비동기/대기 구문과 함께 사용해야 합니다. KeyValueStore는 총 크기 제한이 10MB이며 최대 1천만 개의 키-값 페어를 지원합니다. KeyValueStore 데이터는 모든 엣지 로케이션에서 최종적으로 일관되며 업데이트는 일반적으로 몇 초 이내에 전파됩니다.

최적의 성능을 위해 KeyValueStore 키를 구성하여 조회 작업을 최소화합니다. 인증서 일련 번호를 간단한 해지 확인을 위한 키로 사용하거나 다중 CA 환경의 발급자 해시와 일련 번호를 결합한 복합 키를 생성합니다. 데이터 구조를 설계할 때 키 복잡성과 KeyValueStore 용량 간의 장단점을 고려합니다.

## async 및 await 사용
<a name="connection-function-async-await"></a>

연결 함수는 KeyValueStore 작업 또는 기타 비동기 작업으로 작업할 때 필수적인 비동기/대기 구문을 사용하는 비동기 작업을 지원합니다. 비동기/대기 패턴을 사용하면 TLS 핸드셰이크 처리에 필요한 고성능 특성을 유지하면서 연결 결정을 내리기에 앞서 함수가 KeyValueStore 조회가 완료될 때까지 대기할 수 있습니다.

KeyValueStore 작업은 매우 빠르지만 CloudFront의 분산 인프라 전반에서 조정이 필요한 네트워크 작업이므로 연결 함수에는 적절한 비동기/대기 사용이 중요합니다. 런타임은 promise 해석을 자동으로 처리하고 함수가 5밀리초 실행 한도 내에서 완료되도록 합니다.

**Example : KeyValueStore와 비동기 연결 함수**  

```
import cf from 'cloudfront';

async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    
    // Async operation to check KeyValueStore for certificate revocation
    const isRevoked = await kvsHandle.exists(connection.clientCertificate.certificates.leaf.serialNumber);
    
    if (isRevoked) {
        // Log the revocation decision with certificate details
        connection.logCustomData(`REVOKED_CERT:${connection.clientCertificate.certificates.leaf.serialNumber}:${connection.clientCertificate.certificates.leaf.issuer}`);
        console.log(`Denying connection for revoked certificate: ${connection.clientCertificate.certificates.leaf.serialNumber}`);
        return connection.deny();
    }
    
    // Log successful validation for monitoring
    connection.logCustomData(`VALID_CERT:${connection.clientCertificate.certificates.leaf.serialNumber}`);
    console.log(`Allowing connection for valid certificate: ${connection.clientCertificate.certificates.leaf.serialNumber}`);
    return connection.allow();
}
```

KeyValueStore 메서드 또는 기타 비동기 작업을 직접 호출할 때는 항상 비동기/대기를 사용합니다. 연결 함수 런타임은 promise 해석을 자동으로 처리하고 TLS 핸드셰이크 처리의 엄격한 타이밍 제약 내에서 적절한 실행 흐름을 보장합니다. async/await는 연결 함수 환경에서 더 명확한 오류 처리와 더 나은 성능을 제공하므로 .then() 또는 콜백 패턴을 사용하지 마세요.

비동기 연결 함수를 설계할 때 KeyValueStore 작업 수를 최소화하고 검증 로직에서 가능한 한 빨리 수행하도록 코드를 구성합니다. 이렇게 하면 성능을 극대화하고 트래픽이 많은 기간 동안 제한 시간 문제의 위험을 줄일 수 있습니다. 관련 검증 검사를 일괄 처리하고 사용 사례에 가장 효율적인 KeyValueStore 메서드(exists() vs get())를 사용하는 것이 좋습니다.

## 연결 함수 코드 예제
<a name="connection-function-code-examples"></a>

다음 예제는 다양한 검증 시나리오에 일반적인 연결 함수 패턴을 보여줍니다. 다음 예제를 자체 연결 함수 구현의 시작점으로 사용합니다.

**Example : 디바이스 인증서 검증**  
이 예제에서는 IoT 디바이스, 게임 콘솔 및 기타 클라이언트 인증 시나리오에 대한 디바이스 일련 번호 및 인증서 제목 필드를 검증합니다.  

```
async function connectionHandler(connection) {
    // Custom validation: check device serial number format
    const serialNumber = connection.clientCertificate.certificates.leaf.serialNumber;
    if (!serialNumber.startsWith("DEV")) {
        connection.logCustomData(`INVALID_SERIAL:${serialNumber}`);
        return connection.deny();
    }
    
    // Validate certificate subject contains required organizational unit
    const subject = connection.clientCertificate.certificates.leaf.subject;
    if (!subject.includes("OU=AuthorizedDevices")) {
        connection.logCustomData(`INVALID_OU:${subject}`);
        return connection.deny();
    }
    
    // Allow connection for valid devices
    connection.logCustomData(`VALID_DEVICE:${serialNumber}`);
    return connection.allow();
}
```
이 함수는 디바이스 일련 번호 형식 및 조직 단위 확인을 포함하여 표준 인증서 검증 외에도 여러 검증 검사를 수행합니다.

**Example : 혼합 인증을 사용하는 선택적 mTLS**  
이 예제에서는 서로 다른 인증 정책을 사용하여 mTLS 연결과 비mTLS 연결을 모두 처리합니다.  

```
async function connectionHandler(connection) {
    if (connection.clientCertificate) {
        // mTLS connection - enhanced validation for certificate holders
        const subject = connection.clientCertificate.certificates.leaf.subject;
        connection.logCustomData(`MTLS_SUCCESS:${subject}:${connection.clientIp}`);
        console.log(`mTLS connection from: ${subject}`);
        return connection.allow();
    } else {
        // Non-mTLS connection - apply IP-based restrictions
        const clientIp = connection.clientIp;
        
        // Only allow non-mTLS from specific IP ranges
        if (clientIp.startsWith("203.0.113.") || clientIp.startsWith("198.51.100.")) {
            connection.logCustomData(`NON_MTLS_ALLOWED:${clientIp}`);
            console.log(`Non-mTLS connection allowed from: ${clientIp}`);
            return connection.allow();
        }
        
        connection.logCustomData(`NON_MTLS_DENIED:${clientIp}`);
        return connection.deny();
    }
}
```
이 함수는 신뢰할 수 있는 IP 범위의 레거시 클라이언트와의 호환성을 유지하면서 인증서를 통해 클라이언트에 향상된 보안을 제공합니다.

# 배포 전에 CloudFront 연결 함수 테스트
<a name="test-connection-functions"></a>

TestConnectionFunction API 작업을 사용하여 개발 단계에서 CloudFront 연결 함수를 테스트할 수 있습니다. 테스트를 통해 라이브 단계에 게시하기 전에 샘플 연결 이벤트로 함수 로직을 검증할 수 있습니다.

**Topics**
+ [테스트 프로세스](#connection-function-testing-process)
+ [테스트 결과](#connection-function-test-results)
+ [연결 테스트 객체](#connection-test-object)

## 테스트 프로세스
<a name="connection-function-testing-process"></a>

연결 함수를 테스트하려면:

1. 개발 단계에서 연결 함수 생성

1. TLS 연결 이벤트를 나타내는 테스트 연결 객체 준비

1. TestConnectionFunction API 작업을 사용하여 테스트 데이터로 함수 실행

1. 함수 출력, 실행 로그 및 오류 메시지를 포함한 테스트 결과 검토

1. 필요에 따라 함수 코드를 업데이트하고 테스트 프로세스를 반복합니다.

## 테스트 결과
<a name="connection-function-test-results"></a>

연결 함수를 테스트할 때 결과는 다음과 같습니다.
+ **함수 요약** - 테스트된 함수에 대한 메타데이터
+ **컴퓨팅 사용률** - 리소스 사용량을 보여주는 성능 지표
+ **실행 로그** - 로깅 문을 포함하여 함수의 콘솔 출력
+ **함수 출력** - 함수가 반환한 결과
+ **오류 메시지** - 실행 중에 발생한 모든 런타임 오류 또는 예외

## 연결 테스트 객체
<a name="connection-test-object"></a>

연결 테스트 객체는 함수가 처리할 TLS 연결 이벤트를 나타내는 이진 BLOB(최대 40KB)입니다. 이 객체에는 함수가 인증 결정을 내리는 데 사용하는 인증서 및 연결 정보가 포함되어 있습니다.

**참고**  
연결 테스트 객체의 특정 구조 및 형식은 CloudFront 연결 함수 런타임에 의해 정의됩니다. 사용 사례에 적합한 테스트 객체를 생성하는 방법에 대한 자세한 내용은 CloudFront Functions 설명서를 참조하거나 AWS Support에 문의하세요.

연결 함수를 생성한 후 다음을 수행할 수 있습니다.
+ **함수 테스트** - 콘솔 또는 CLI의 테스트 기능을 사용하여 샘플 연결 이벤트로 함수를 검증합니다. 자세한 정보는 연결 함수 테스트를 참조하세요.
+ **함수 업데이트** - 필요에 따라 함수 코드 및 구성을 수정합니다. 개발 단계의 연결 함수는 언제든지 업데이트할 수 있습니다.
+ **함수 게시** - 프로덕션 준비가 되면 함수를 게시하여 개발 단계에서 라이브 단계로 이동합니다. 자세한 내용은 연결 함수 연결을 참조하세요.
+ **배포와 연결** - 게시된 함수를 mTLS 지원 배포와 연결하여 라이브 연결을 처리합니다. 자세한 내용은 연결 함수 연결을 참조하세요.

# 배포에 연결 함수 연결
<a name="associate-connection-functions"></a>

연결 함수를 라이브 단계에 게시한 후에는 이를 mTLS 지원 배포와 연결하여 라이브 연결을 처리해야 합니다. 연결 함수는 캐시 동작과 연결된 뷰어 요청 및 뷰어 응답 함수와 달리 배포 수준에서 연결됩니다.

**Topics**
+ [연결 요구 사항](#connection-function-association-requirements)
+ [필터를 사용하여 함수 구성](#connection-function-organizing-filters)
+ [배포 고려 사항](#connection-function-deployment-considerations)

## 연결 요구 사항
<a name="connection-function-association-requirements"></a>

연결 함수를 배포와 연결하려면:
+ 함수는 라이브 단계에 있어야 함
+ 배포에 mTLS가 활성화되어 있어야 함
+ 배포에 유효한 트러스트 스토어가 구성되어 있어야 함
+ 배포당 하나의 연결 함수만 연결할 수 있음

## 필터를 사용하여 함수 구성
<a name="connection-function-organizing-filters"></a>

CloudFront는 연결 함수를 구성하고 관리하는 데 도움이 되는 필터링 기능을 제공합니다.
+ **배포 ID 필터** - 특정 배포와 연결된 함수 찾기
+ **키-값 저장소 필터** - 데이터 조회에 특정 키-값 저장소를 사용하는 함수 찾기
+ **단계 필터** - 개발 또는 라이브 단계의 함수 나열

이러한 필터는 다양한 배포 또는 개발 환경에서 여러 연결 함수를 관리할 때 사용합니다.

## 배포 고려 사항
<a name="connection-function-deployment-considerations"></a>

연결 함수를 배포할 때는 다음 요소를 고려하세요.
+ **글로벌 배포** - 연결 함수가 전 세계 모든 CloudFront 엣지 로케이션에 배포되므로 몇 분 정도 걸릴 수 있습니다.
+ **버전 관리** - 게시된 각 버전은 이전 버전을 대체하는 새 라이브 함수를 생성합니다.
+ **롤백 전략** - 함수 코드의 이전 작동 버전을 유지하여 롤백을 계획합니다.
+ **프로덕션 환경에서 테스트** - 스테이징 및 프로덕션 환경에 별도의 배포를 사용하는 것이 좋습니다.

# CloudFront Functions 및 KeyValueStore를 사용하여 상호 TLS(뷰어)에 대한 인증서 해지 구현
<a name="implement-certificate-revocation"></a>

CloudFront 연결 함수를 KeyValueStore와 함께 사용하여 인증서 해지 확인을 구현할 수 있습니다. 이렇게 하면 해지된 인증서 일련 번호 목록을 유지하고 TLS 핸드셰이크 중에 이 목록과 비교하여 클라이언트 인증서를 확인할 수 있습니다.

인증서 해지를 구현하려면 다음 구성 요소가 필요합니다.
+ 뷰어 mTLS로 구성된 배포
+ 해지된 인증서 일련 번호가 포함된 KeyValueStore
+ KeyValueStore를 쿼리하여 인증서 상태를 확인하는 연결 함수

클라이언트가 연결되면 CloudFront는 트러스트 스토어에 대해 인증서를 검증한 다음 연결 함수를 실행합니다. 함수는 KeyValueStore에 대해 인증서 일련 번호를 확인하고 연결을 허용하거나 거부합니다.

**Topics**
+ [1단계: 해지된 인증서에 대한 KeyValueStore 생성](create-kvs-revoked-certificates.md)
+ [2단계: 해지 연결 함수 생성](create-revocation-connection-function.md)
+ [3단계: 해지 함수 테스트](test-revocation-function.md)
+ [4단계: 배포에 함수 연결](associate-function-distribution.md)
+ [고급 해지 시나리오](advanced-revocation-scenarios.md)

# 1단계: 해지된 인증서에 대한 KeyValueStore 생성
<a name="create-kvs-revoked-certificates"></a>

KeyValueStore를 생성하여 mTLS 연결 중에 연결 함수가 확인할 수 있는 해지된 인증서 일련 번호를 저장합니다.

먼저 해지된 인증서 일련 번호를 JSON 형식으로 준비합니다.

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

이 JSON 파일을 S3 버킷에 업로드한 다음 KeyValueStore를 생성합니다.

```
aws s3 cp revoked-serials.json s3://your-bucket-name/revoked-serials.json
aws cloudfront create-key-value-store \
  --name revoked-serials-kvs \
  --import-source '{
    "SourceType": "S3",
    "SourceARN": "arn:aws:s3:::your-bucket-name/revoked-serials.json"
  }'
```

KeyValueStore가 프로비저닝을 완료할 때까지 기다립니다. 다음을 통해 상태를 확인합니다.

```
aws cloudfront get-key-value-store --name "revoked-serials-kvs"
```

# 2단계: 해지 연결 함수 생성
<a name="create-revocation-connection-function"></a>

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

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

```
aws cloudfront create-connection-function \
  --name "revocation-control" \
  --connection-function-config file://connection-function-config.json \
  --connection-function-code file://connection-function-code.txt
```

구성 파일은 KeyValueStore 연결을 지정합니다.

```
{
  "Runtime": "cloudfront-js-2.0",
  "Comment": "A function that implements revocation control via KVS",
  "KeyValueStoreAssociations": {
    "Quantity": 1,
    "Items": [
      {
        "KeyValueStoreArn": "arn:aws:cloudfront::account-id:key-value-store/kvs-id"
      }
    ]
  }
}
```

연결 함수 코드는 KeyValueStore에서 해지된 인증서를 확인합니다.

```
import cf from 'cloudfront';

async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    
    // Get parsed client serial number from client certificate
    const clientSerialNumber = connection.clientCertInfo.serialNumber;
    
    // Check KVS to see if serial number exists as a key
    const serialNumberExistsInKvs = await kvsHandle.exists(clientSerialNumber);
    
    // Deny connection if serial number exists in KVS
    if (serialNumberExistsInKvs) {
        console.log("Connection denied - certificate revoked");
        return connection.deny();
    }
    
    // Allow connections that don't exist in kvs
    console.log("Connection allowed");
    return connection.allow();
}
```

# 3단계: 해지 함수 테스트
<a name="test-revocation-function"></a>

CloudFront 콘솔을 사용하여 샘플 인증서로 연결 함수를 테스트합니다. 콘솔에서 연결 함수로 이동하여 테스트 탭을 사용합니다.

**샘플 인증서로 테스트**

1. 테스트 인터페이스에 PEM 형식의 샘플 인증서 붙여넣기

1. 선택적으로 IP 기반 로직을 테스트하기 위한 클라이언트 IP 주소 지정

1. **함수 테스트**를 선택하여 실행 결과를 확인합니다.

1. 실행 로그를 검토하여 함수 로직 확인

유효한 인증서와 해지된 인증서를 모두 사용해 테스트하여 함수가 두 시나리오를 올바르게 처리하는지 확인합니다. 실행 로그에는 console.log 출력과 함수 실행 중에 발생하는 모든 오류가 표시됩니다.

# 4단계: 배포에 함수 연결
<a name="associate-function-distribution"></a>

연결 함수를 게시한 후 mTLS 지원 배포와 연결하여 인증서 해지 확인을 활성화합니다.

배포 설정 페이지 또는 연결 함수의 연결된 배포 테이블에서 함수를 연결할 수 있습니다. 배포 설정으로 이동하여 **뷰어 상호 인증(mTLS)** 섹션으로 스크롤한 후 연결 함수를 선택하고 변경 사항을 저장합니다.

# 고급 해지 시나리오
<a name="advanced-revocation-scenarios"></a>

더 복잡한 인증서 해지 요구 사항을 보려면 다음과 같은 추가 구성을 고려하세요.

**Topics**
+ [인증서 해지 목록(CRL)을 KeyValueStore 형식으로 변환](#convert-crl-kvs-format)
+ [여러 인증 기관 처리](#handle-multiple-cas)
+ [연결 로그에 사용자 지정 데이터 추가](#add-custom-data-logs)
+ [CRL 업데이트 관리](#manage-crl-updates)
+ [KeyValueStore 용량 계획](#plan-kvs-capacity)

## 인증서 해지 목록(CRL)을 KeyValueStore 형식으로 변환
<a name="convert-crl-kvs-format"></a>

인증서 해지 목록(CRL) 파일이 있는 경우 OpenSSL 및 jq를 사용하여 KeyValueStore JSON 형식으로 변환할 수 있습니다.

**CRL을 KeyValueStore 형식으로 변환**

다음과 같이 CRL 파일에서 일련 번호를 추출합니다.

```
openssl crl -text -noout -in rfc5280_CRL.crl | \
  awk '/Serial Number:/ {print $3}' | \
  cut -d'=' -f2 | \
  sed 's/../&:/g;s/:$//' >> serialnumbers.txt
```

일련 번호를 KeyValueStore JSON 형식으로 변환합니다.

```
jq -R -s 'split("\n") | map(select(length > 0)) | {data: map({"key": ., "value": ""})}' \
  serialnumbers.txt >> serialnumbers_kvs.json
```

형식이 지정된 파일을 S3에 업로드하고 1단계에 설명된 대로 KeyValueStore를 생성합니다.

## 여러 인증 기관 처리
<a name="handle-multiple-cas"></a>

TrustStore에 여러 인증 기관(CA)이 포함된 경우 KeyValueStore 키에 발급자 정보를 포함하여 일련 번호가 같을 수 있는 다른 CA의 인증서 간 충돌을 방지합니다.

다중 CA 시나리오의 경우 발급자의 SHA1 해시와 일련 번호를 키로 조합하여 사용합니다.

```
import cf from 'cloudfront';

async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    const clientCert = connection.clientCertInfo;
    
    // Create composite key with issuer hash and serial number
    const issuer = clientCert.issuer.replace(/[^a-zA-Z0-9]/g, '').substring(0, 20);
    const serialno = clientCert.serialNumber;
    const compositeKey = `${issuer}_${serialno}`;
    
    const cert_revoked = await kvsHandle.exists(compositeKey);
    
    if (cert_revoked) {
        console.log(`Blocking revoked cert: ${serialno} from issuer: ${issuer}`);
        connection.deny();
    } else {
        connection.allow();
    }
}
```

**참고**  
발급자 식별자 \$1 일련 번호를 사용하면 키가 더 길어져 KeyValueStore에 저장할 수 있는 총 항목 수가 줄어들 수 있습니다.

## 연결 로그에 사용자 지정 데이터 추가
<a name="add-custom-data-logs"></a>

연결 함수는 logCustomData 메서드를 사용하여 CloudFront 연결 로그에 사용자 지정 데이터를 추가할 수 있습니다. 이렇게 하면 해지 확인 결과, 인증서 정보 또는 기타 관련 데이터를 로그에 포함할 수 있습니다.

```
async function connectionHandler(connection) {
    const kvsHandle = cf.kvs();
    const clientSerialNumber = connection.clientCertInfo.serialNumber;
    const serialNumberExistsInKvs = await kvsHandle.exists(clientSerialNumber);
    
    if (serialNumberExistsInKvs) {
        // Log revocation details to connection logs
        connection.logCustomData(`REVOKED:${clientSerialNumber}:DENIED`);
        console.log("Connection denied - certificate revoked");
        return connection.deny();
    }
    
    // Log successful validation
    connection.logCustomData(`VALID:${clientSerialNumber}:ALLOWED`);
    console.log("Connection allowed");
    return connection.allow();
}
```

사용자 지정 데이터는 800바이트의 유효한 UTF-8 텍스트로 제한됩니다. 이 제한을 초과하면 CloudFront는 데이터를 가장 가까운 유효한 UTF-8 경계로 잘라냅니다.

**참고**  
사용자 지정 데이터 로깅은 배포에 연결 로그가 활성화된 경우에만 작동합니다. 연결 로그가 구성되지 않은 경우 logCustomData 메서드는 no-op입니다.

## CRL 업데이트 관리
<a name="manage-crl-updates"></a>

인증 기관은 두 가지 유형의 CRL을 발급할 수 있습니다.
+ **전체 CRL**: 해지된 모든 인증서의 전체 목록 포함
+ **델타 CRL**: 마지막 전체 CRL 이후 해지된 인증서만 나열

전체 CRL 업데이트의 경우 업데이트된 데이터로 새 KeyValueStore를 생성하고 연결 함수 연결을 새 KeyValueStore로 리디렉션합니다. 이 접근 방식은 차이를 계산하고 증분 업데이트를 수행하는 것보다 더 간단합니다.

델타 CRL 업데이트의 경우 update-keys 명령을 사용하여 해지된 새 인증서를 기존 KeyValueStore에 추가합니다.

```
aws cloudfront update-key-value-store \
  --name "revoked-serials-kvs" \
  --if-match "current-etag" \
  --put file://delta-revoked-serials.json
```

## KeyValueStore 용량 계획
<a name="plan-kvs-capacity"></a>

KeyValueStore는 크기 제한이 5MB이며 최대 1천만 개의 키-값 페어를 지원합니다. 키 형식 및 데이터 크기에 따라 취소 목록 용량을 계획합니다.
+ **일련 번호만 해당**: 간단한 해지 확인을 위한 효율적인 스토리지
+ **발급자 식별자 \$1 일련 번호**: 다중 CA 환경을 위한 더 긴 키

대규모 해지 목록의 경우 다양한 인증서 범주 또는 기간에 대해 별도의 KeyValueStores를 유지하는 계층형 접근 방식을 구현하는 것이 좋습니다.

# Lambda@Edge를 사용하여 엣지에서 사용자 지정
<a name="lambda-at-the-edge"></a>

Lambda@Edge는 AWS Lambda의 확장된 기능입니다. Lambda@Edge는 Amazon CloudFront를 통해 전달되는 콘텐츠를 사용자 지정하는 함수를 실행할 수 있게 해 주는 컴퓨팅 서비스입니다. 미국 동부(버지니아 북부) AWS 리전 한 곳에서 Lambda 콘솔을 사용하여 Node.js 또는 Python 함수를 작성할 수 있습니다.

함수를 만든 후에 Lambda 콘솔 또는 CloudFront 콘솔에 트리거를 추가하여 서버를 프로비저닝하거나 관리하지 않고도 뷰어에 더 가까운 AWS 위치에서 함수를 실행합니다. 선택적으로 Lambda 및 CloudFront API 작업을 사용하여 프로그래밍 방식으로 함수와 트리거를 설정할 수 있습니다.

Lambda@Edge는 하루 몇 번의 요청에서 초당 수천 개의 요청으로 자동 확장됩니다. 오리진 서버가 아니라 최종 사용자에게 가까운 AWS 위치에서 요청을 처리하므로 지연 시간이 크게 단축되고 사용자 경험이 상당히 개선됩니다.

**참고**  
Lambda@Edge는 gRPC 요청에서 지원되지 않습니다. 자세한 내용은 [CloudFront 배포에 gRPC 사용](distribution-using-grpc.md) 섹션을 참조하시기 바랍니다.

**Topics**
+ [Lambda@Edge가 요청 및 응답을 처리하는 방법](lambda-edge-event-request-response.md)
+ [Lambda@Edge 사용 방법](lambda-edge-ways-to-use.md)
+ [Lambda@Edge 함수 시작(콘솔)](lambda-edge-how-it-works.md)
+ [Lambda@Edge에 대한 IAM 권한 및 역할 설정](lambda-edge-permissions.md)
+ [Lambda@Edge 함수 작성 및 생성](lambda-edge-create-function.md)
+ [Lambda@Edge 함수에 대한 트리거 추가](lambda-edge-add-triggers.md)
+ [Lambda@Edge 함수 테스트 및 디버깅](lambda-edge-testing-debugging.md)
+ [Lambda@Edge 함수 및 복제본 삭제](lambda-edge-delete-replicas.md)
+ [Lambda@Edge 이벤트 구조](lambda-event-structure.md)
+ [요청 및 응답 작업 수행](lambda-generating-http-responses.md)
+ [Lambda@Edge 예제 함수](lambda-examples.md)

# Lambda@Edge가 요청 및 응답을 처리하는 방법
<a name="lambda-edge-event-request-response"></a>

CloudFront 배포를 Lambda@Edge 함수와 연결하면 CloudFront가 CloudFront 엣지 로케이션에서 요청 및 응답을 가로챕니다. 다음과 같은 CloudFront 이벤트가 발생할 때 Lambda 함수를 실행할 수 있습니다.
+ CloudFront가 최종 사용자의 요청을 수신할 때(최종 사용자 요청)
+ CloudFront가 오리진에 요청을 전달하기 전(오리진 요청)
+ CloudFront가 오리진의 응답을 수신할 때(오리진 응답)
+ CloudFront가 최종 사용자에게 응답을 반환하기 전(최종 사용자 응답)

AWS WAF를 사용하는 경우, Lambda@Edge 최종 사용자 요청은 AWS WAF 규칙이 적용된 후에 실행됩니다.

자세한 내용은 [요청 및 응답 작업 수행](lambda-generating-http-responses.md) 및 [Lambda@Edge 이벤트 구조](lambda-event-structure.md)(을)를 참조하세요.

# Lambda@Edge 사용 방법
<a name="lambda-edge-ways-to-use"></a>

다음 예와 같이 Amazon CloudFront 배포에서 Lambda@Edge 처리는 여러 용도로 사용됩니다.
+ Lambda 함수는 사용자가 A/B 테스트를 위해 사이트의 다양한 버전을 볼 수 있도록 쿠키를 검사하고 URL을 다시 작성합니다.
+ CloudFront는 `User-Agent` 헤더를 확인하여 사용 중인 디바이스를 기반으로 디바이스에 대한 정보를 포함하여 최종 사용자에게 다양한 객체를 반환할 수 있습니다. 예를 들어, CloudFront는 디바이스의 화면 크기에 따라 다른 이미지를 반환할 수 있습니다. 마찬가지로 함수는 `Referer` 헤더 값을 고려하여 CloudFront가 사용 가능한 최저 해상도의 이미지를 봇에 반환하게 할 수 있습니다.
+ 아니면 다른 기준으로 쿠키를 검사할 수 있습니다. 예를 들어, 의류를 판매하는 소매 웹 사이트에서 사용자가 재킷에 대해 선택한 색상을 표시하기 위해 쿠키를 사용하는 경우 Lambda 함수는 CloudFront가 선택된 색상으로 재킷 이미지를 반환하도록 요청을 변경할 수 있습니다.
+ Lambda 함수는 CloudFront 최종 사용자 요청 또는 오리진 요청 이벤트가 발생할 때 HTTP 응답을 생성할 수 있습니다.
+ 함수는 헤더 또는 권한 부여 토큰을 검사하고, CloudFront가 오리진으로 요청을 전달하기 전에 헤더를 삽입하여 콘텐츠에 대한 액세스 권한을 제어할 수 있습니다.
+ 또한 Lambda 함수는 외부 리소스에 대한 네트워크 호출을 생성하여 사용자 자격 증명을 확인하거나 추가 콘텐츠를 가져와 응답을 사용자 지정할 수 있습니다.

예제 코드를 포함한 자세한 내용은 [Lambda@Edge 예제 함수](lambda-examples.md) 섹션을 참조하세요.

콘솔의 Lambda@Edge 설정에 대한 자세한 내용은 [자습서: 기본 Lambda@Edge 함수 만들기(콘솔)](lambda-edge-how-it-works-tutorial.md) 섹션을 참조하세요.

# Lambda@Edge 함수 시작(콘솔)
<a name="lambda-edge-how-it-works"></a>

Lambda@Edge에서 CloudFront 트리거를 사용하여 Lambda 함수를 간접 호출할 수 있습니다. CloudFront 배포를 Lambda 함수와 연결하면 CloudFront가 CloudFront 엣지 로케이션에서 [요청 및 응답을 가로채고](https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html) 함수를 실행합니다. Lambda 함수로 보안을 강화하거나 뷰어와 더 관련성 있는 정보가 표시되도록 사용자 지정하여 성능을 높일 수 있습니다.

다음 목록은 CloudFront에서 Lambda 함수를 생성 및 사용하는 방법에 대한 기본적인 개요를 제공합니다.

**개요: CloudFront를 통한 Lambda 함수 생성 및 사용**

1. 미국 동부(버지니아 북부) 리전에 Lambda 함수를 생성합니다.

1. 번호가 지정된 함수 버전을 저장하고 게시합니다.

   함수를 변경하려면 미국 동부(버지니아 북부)에서 \$1LATEST 버전의 함수를 편집해야 합니다. 그런 다음 번호가 지정된 새 버전을 게시하고 CloudFront와 연동되도록 설정합니다.

1. 함수를 CloudFront 배포 및 캐시 동작에 연결합니다. 그런 다음 함수를 실행시키는 하나 이상의 CloudFront 이벤트(*트리거*)를 지정합니다. 예를 들어, CloudFront가 최종 사용자의 요청을 받으면 함수가 실행되도록 하는 트리거를 생성할 수 있습니다.

1. 트리거를 생성하면 Lambda가 해당 함수를 전 세계의 AWS 위치에 복제를 생성합니다.

**작은 정보**  
자세한 내용은 [함수 생성 및 업데이트](lambda-edge-create-function.md), [이벤트 구조](lambda-event-structure.md)와 [CloudFront 트리거 추가](lambda-edge-add-triggers.md)를 참조하세요. 또한 [Lambda@Edge 예제 함수](lambda-examples.md)에서 다양한 아이디어와 코드 샘플도 다룹니다.

단계별 자습서는 다음 주제를 참조하세요.

**Topics**
+ [자습서: 기본 Lambda@Edge 함수 만들기(콘솔)](lambda-edge-how-it-works-tutorial.md)

# 자습서: 기본 Lambda@Edge 함수 만들기(콘솔)
<a name="lambda-edge-how-it-works-tutorial"></a>

이 자습서에서는 CloudFront에서 실행되는 예제 Node.js 함수를 만들고 구성하여 Lambda@Edge를 시작하는 방법을 보여줍니다. 이 예시에서는 CloudFront가 파일을 검색할 때 HTTP 보안 헤더를 응답에 추가합니다. (이를 통해 웹 사이트의 보안 및 개인 정보 보호를 개선할 수 있음)

이 자습서에는 자체 웹 사이트가 필요하지 않습니다. 그러나 자체 Lambda@Edge 솔루션을 생성하는 경우 비슷한 단계를 따르고 동일한 옵션 중에서 선택합니다.

**Topics**
+ [1단계: AWS 계정 가입](#lambda-edge-how-it-works-tutorial-AWS)
+ [2단계: CloudFront 배포 생성](#lambda-edge-how-it-works-tutorial-cloudfront)
+ [3단계: 함수 생성](#lambda-edge-how-it-works-tutorial-create-function)
+ [4단계: 함수를 실행할 CloudFront 트리거 추가](#lambda-edge-how-it-works-tutorial-add-trigger)
+ [5단계: 함수 실행 확인](#lambda-edge-how-it-works-tutorial-verify)
+ [6단계: 문제 해결](#lambda-edge-how-it-works-tutorial-troubleshoot)
+ [7단계: 예제 리소스 정리](#lambda-edge-how-it-works-tutorial-cleanup-resources)
+ [관련 정보](#lambda-edge-how-it-works-tutorial-resources)

## 1단계: AWS 계정 가입
<a name="lambda-edge-how-it-works-tutorial-AWS"></a>

아직 계정에 가입하지 않았다면 AWS 계정에 가입하세요. 자세한 내용은 [AWS 계정에 가입](setting-up-cloudfront.md#sign-up-for-aws) 단원을 참조합니다.

## 2단계: CloudFront 배포 생성
<a name="lambda-edge-how-it-works-tutorial-cloudfront"></a>

예제 Lambda@Edge 함수를 만들려면 먼저 콘텐츠를 제공할 오리진이 있는 CloudFront 환경부터 갖춰야 합니다.

이 예제에서는 Amazon S3 버킷을 배포의 오리진으로 사용하는 CloudFront 배포를 만듭니다. 사용할 환경이 이미 있는 경우 이 단계를 건너뛸 수 있습니다.<a name="lambda-edge-how-it-works-tutorial-cf-proc"></a>

**Amazon S3 오리진을 사용하여 CloudFront 배포를 생성하려면**

1. 이미지 파일 등 샘플 콘텐츠가 될 파일 한두 개로 Amazon S3 버킷을 만듭니다. [Amazon S3에 콘텐츠 업로드](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/GettingStarted.html#GettingStartedUploadContent)의 단계를 따르면 됩니다. 버킷의 객체에 대한 퍼블릭 읽기 액세스를 허용하는 권한을 설정해야 합니다.

1. [CloudFront 웹 배포 생성](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/GettingStarted.html#GettingStartedCreateDistribution)의 단계에 따라 CloudFront 배포를 만들고 오리진으로 S3 버킷을 추가합니다. 이미 배포가 있다면 버킷을 그 배포의 오리진으로 추가할 수 있습니다.
**작은 정보**  
배포 ID를 기록해 둡니다. 이 자습서 후반부에서 함수의 CloudFront 트리거를 추가할 때 드롭다운 목록에서 배포 ID(예: `E653W22221KDDL`)를 선택해야 합니다.

## 3단계: 함수 생성
<a name="lambda-edge-how-it-works-tutorial-create-function"></a>

이 단계에서는 Lambda 콘솔에 있는 청사진 템플릿에서 Lambda 함수를 생성합니다. 이 함수는 CloudFront 배포의 보안 헤더를 업데이트하는 코드를 추가합니다.<a name="lambda-edge-how-it-works-tutorial-create-function-blueprint-proc"></a>

**Lambda 함수를 생성하려면**

1. AWS Management Console에 로그인한 다음 AWS Lambda에서 [https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/) 콘솔을 엽니다.
**중요**  
현재 **US-East-1(버지니아 북부)** AWS 리전(**us-east-1**)에 있는지 확인합니다. 이 리전에 있어야 Lambda@Edge 함수를 만들 수 있습니다.

1. **함수 생성**을 선택합니다.

1. **함수 생성** 페이지에서 **청사진 사용**을 선택한 다음 검색 필드에 **cloudfront**를 입력하여 CloudFront 청사진을 필터링합니다.
**참고**  
CloudFront 청사진은 **US-East-1(버지니아 북부)** 리전(**us-east-1**)에서만 사용 가능합니다.

1. 함수에 대한 템플릿으로 **HTTP 응답 헤더 수정** 청사진을 선택합니다.

1. 다음과 같이 함수에 대한 정보를 입력합니다.
   + **함수 이름** - 함수의 이름을 입력합니다.
   + **실행 역할** - 함수에 대한 권한 설정 방법을 선택합니다. 권장되는 기본 Lambda@Edge 권한 정책 템플릿을 사용하려면 **AWS 정책 템플릿에서 새 역할 생성**을 선택합니다.
   + **역할 이름** - 정책 템플릿이 생성하는 역할 이름을 입력합니다.
   + **정책 템플릿** - CloudFront 청사진을 함수의 기본으로 선택했으므로 Lambda는 정책 템플릿 **기본 Lambda@Edge 권한**을 자동으로 추가합니다. 이 정책 템플릿은 CloudFront가 전 세계 CloudFront 로케이션에서 Lambda 함수를 실행할 수 있도록 하는 실행 역할 권한을 추가합니다. 자세한 내용은 [Lambda@Edge에 대한 IAM 권한 및 역할 설정](lambda-edge-permissions.md) 섹션을 참조하세요.

1. 페이지 하단에서 **함수 생성**을 선택합니다.

1. **Lambda@Edge에 배포 창**이 나타나면 **취소**를 선택합니다. (이 자습서에서는 함수를 Lambda@Edge에 배포하기 전에 함수 코드를 수정해야 합니다.)

1. 아래로 스크롤하여 페이지의 **코드 소스** 섹션으로 이동합니다.

1. 템플릿 코드를 오리진에서 반환하는 보안 헤더를 수정하는 함수로 바꿉니다. 예를 들면 다음과 비슷한 코드를 사용할 수 있습니다.

   ```
   'use strict';
   export const handler = (event, context, callback) => {
   
       //Get contents of response
       const response = event.Records[0].cf.response;
       const headers = response.headers;
   
       //Set new headers
       headers['strict-transport-security'] = [{key: 'Strict-Transport-Security', value: 'max-age= 63072000; includeSubdomains; preload'}];
       headers['content-security-policy'] = [{key: 'Content-Security-Policy', value: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'"}];
       headers['x-content-type-options'] = [{key: 'X-Content-Type-Options', value: 'nosniff'}];
       headers['x-frame-options'] = [{key: 'X-Frame-Options', value: 'DENY'}];
       headers['x-xss-protection'] = [{key: 'X-XSS-Protection', value: '1; mode=block'}];
       headers['referrer-policy'] = [{key: 'Referrer-Policy', value: 'same-origin'}];
   
       //Return modified response
       callback(null, response);
   };
   ```

1. **파일**을 선택하여 **저장**하고 업데이트된 코드를 저장합니다.

1. **배포(Deploy)**를 선택합니다.

다음 섹션으로 이동하여 함수를 실행할 CloudFront 트리거를 추가합니다.

## 4단계: 함수를 실행할 CloudFront 트리거 추가
<a name="lambda-edge-how-it-works-tutorial-add-trigger"></a>

이제 보안 헤더를 업데이트할 Lambda 함수가 생성되었으므로, 그 함수를 실행하여 오리진에서 해당 배포에 대해 CloudFront로 보내는 모든 응답에 헤더를 추가할 CloudFront 트리거를 구성해야 합니다.<a name="lambda-edge-how-it-works-tutorial-add-trigger-proc"></a>

**함수의 CloudFront 트리거를 구성하려면**

1. Lambda 콘솔의 **함수 개요** 페이지에서 해당 함수에 대한 함수 개요 페이지에서 **트리거 추가**를 선택합니다.

1. **트리거 구성**에서 **CloudFront**를 선택합니다.

1. **Lambda@Edge에 배포**를 선택합니다.

1. **Lambda@Edge 배포** 창에서 **CloudFront 트리거 구성** 아래에 다음 정보를 입력합니다.
   + **배포** - 함수와 연결할 CloudFront 배포 ID입니다. 드롭다운 목록에서 배포 ID를 선택합니다.
   + **캐시 동작** - 트리거에 사용할 캐시 동작입니다. 이 예제에서는 **\$1**로 설정된 값을 그대로 둡니다. 이 값은 해당 배포의 기본 캐시 동작을 의미합니다. 자세한 내용은 [캐시 동작 설정](DownloadDistValuesCacheBehavior.md) 주제에서 [모든 배포 설정 참조](distribution-web-values-specify.md) 섹션을 참조하세요.
   + **CloudFront 이벤트** - 언제 함수를 실행할지 지정하는 트리거입니다. 여기서는 CloudFront가 오리진에서 응답을 반환할 때마다 보안 헤더 함수가 실행되도록 하겠습니다. 드롭다운 목록에서 **오리진 응답**을 선택합니다. 자세한 내용은 [Lambda@Edge 함수에 대한 트리거 추가](lambda-edge-add-triggers.md) 섹션을 참조하세요.

1. **Lambda@Edge로의 배포 확인**의 확인란을 선택합니다.

1. **배포**를 선택하여 트리거를 추가하고 함수를 전 세계 AWS 위치에 복제합니다.

1. 함수가 복제될 때까지 기다립니다. 일반적으로 몇 분 정도 걸립니다.

    [CloudFront 콘솔로 이동](https://console.aws.amazon.com/cloudfront/v4/home)하여 해당 배포를 보고 복제가 완료되었는지 확인할 수 있습니다. 배포 상태가 **배포 중**에서 날짜 및 시간으로 변경될 때까지 기다립니다. 이는 함수가 복제되었음을 의미합니다. 함수가 작동하는지 확인하려면 다음 단원의 단계를 따릅니다.

## 5단계: 함수 실행 확인
<a name="lambda-edge-how-it-works-tutorial-verify"></a>

Lambda 함수를 만들고 CloudFront 배포에 대해 이를 실행하는 트리거를 구성했으니 이제 이 함수가 원하는 결과를 달성하는지 확인해야 합니다. 이 예제에서는 CloudFront가 반환하는 HTTP 헤더를 확인하여 보안 헤더가 추가되었는지 알아봅니다.<a name="lambda-edge-how-it-works-tutorial-verify-proc"></a>

**Lambda@Edge 함수가 보안 헤더를 추가하는지 확인하려면**

1. 브라우저에서 S3 버킷에 있는 파일의 URL을 입력합니다. 예를 들면 `https://d111111abcdef8.cloudfront.net/image.jpg`와 비슷한 URL을 사용할 수 있습니다.

   파일 URL에 사용할 CloudFront 도메인 이름에 대한 자세한 내용은 [CloudFront에서 파일에 대한 URL 형식 사용자 지정](LinkFormat.md) 단원을 참조하세요.

1. 브라우저에서 웹 개발자 도구 모음을 엽니다. 예를 들어 Chrome 브라우저 창에서는 컨텍스트(마우스 오른쪽 버튼 클릭) 메뉴를 연 다음 **Inspect(검사)**를 선택합니다.

1. **네트워크** 탭을 선택합니다.

1. 페이지를 새로 고쳐 이미지를 확인한 다음 왼쪽 창에서 HTTP 요청을 선택합니다. HTTP 헤더가 별도의 창에 표시됩니다.

1. HTTP 헤더 목록을 살펴보면서 원하는 보안 헤더가 목록에 포함되어 있는지 확인합니다. 예를 들어 다음 스크린샷에 표시된 것과 비슷한 헤더가 보일 것입니다.  
![\[원하는 보안 헤더가 강조 표시된 HTTP 헤더 목록.\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/lambda-at-edge-security-headers-list.png)

추가한 보안 헤더가 헤더 목록에 있으면 완료된 것입니다. 첫 번째 Lambda@Edge 함수가 생성되었습니다. CloudFront에서 오류를 반환하거나 다른 문제가 있는 경우에는 계속해서 다음 단계로 넘어가 문제를 해결하세요.

## 6단계: 문제 해결
<a name="lambda-edge-how-it-works-tutorial-troubleshoot"></a>

CloudFront가 오류를 반환하거나 원하는 보안 헤더를 추가하지 않는 경우, CloudWatch Logs를 조사하여 함수의 실행 상태를 확인할 수 있습니다. 함수를 실행한 위치와 가장 가까운 AWS 위치에 저장된 로그를 사용해야 합니다.

예를 들어, 런던에서 파일을 볼 때는 CloudWatch 콘솔에서 리전을 유럽(런던)으로 변경해야 합니다.<a name="lambda-edge-how-it-works-tutorial-cloudwatch-proc"></a>

**Lambda@Edge 함수에 대한 CloudWatch 로그를 검사하려면**

1. AWS Management Console에 로그인하고 [https://console.aws.amazon.com/cloudwatch/](https://console.aws.amazon.com/cloudwatch/)에서 CloudWatch 콘솔을 엽니다.

1. **리전**을 브라우저에서 파일을 볼 때 표시되는 위치로 변경합니다. 이는 함수가 실행되고 있는 리전입니다.

1. 왼쪽 창에서 **로그**를 선택하여 해당 배포의 로그를 봅니다.

자세한 내용은 [Amazon CloudWatch를 사용한 CloudFront 지표 모니터링](monitoring-using-cloudwatch.md) 단원을 참조하세요.

## 7단계: 예제 리소스 정리
<a name="lambda-edge-how-it-works-tutorial-cleanup-resources"></a>

이 자습서에 사용할 용도로만 Amazon S3 버킷과 CloudFront 배포를 만들었다면 할당한 AWS 리소스를 삭제하여 더 이상 요금이 발생하지 않도록 하세요. AWS 리소스를 삭제한 뒤에는 추가한 콘텐츠를 이용할 수 없게 됩니다.

**업무**
+ [S3 버킷 삭제](#lambda-edge-how-it-works-tutorial-delete-bucket) 
+ [Lambda 함수 삭제](#lambda-edge-how-it-works-tutorial-delete-function)
+ [CloudFront 배포 삭제](#lambda-edge-how-it-works-tutorial-delete-distribution)

### S3 버킷 삭제
<a name="lambda-edge-how-it-works-tutorial-delete-bucket"></a>

Amazon S3 버킷을 삭제하기 전에 버킷에 대한 로깅이 비활성화되어 있는지 확인하세요. 그렇지 않으면 삭제해도 AWS가 해당 버킷에 계속 로그를 기록합니다.<a name="lambda-edge-how-it-works-tutorial-delete-bucket-proc"></a>

**버킷에 대한 로깅 사용 중지**

1. [https://console.aws.amazon.com/s3/](https://console.aws.amazon.com/s3/)에서 Amazon S3 콘솔을 엽니다.

1. 버킷을 선택한 다음, **속성**를 선택합니다.

1. **속성**에서 **로깅**을 선택합니다.

1. **사용(Enabled)** 확인란의 선택을 취소합니다.

1. **저장**을 선택합니다.

이제 버킷을 삭제할 수 있습니다. 자세한 내용은 *Amazon Simple Storage Service Console 사용 설명서*의 [ 버킷 삭제](https://docs.aws.amazon.com/AmazonS3/latest/userguide/delete-bucket.html)를 참조하십시오.

### Lambda 함수 삭제
<a name="lambda-edge-how-it-works-tutorial-delete-function"></a>

Lambda 함수 연결 및 선택적으로 함수 자체를 삭제하는 지침은 [Lambda@Edge 함수 및 복제본 삭제](lambda-edge-delete-replicas.md) 단원을 참조합니다.

### CloudFront 배포 삭제
<a name="lambda-edge-how-it-works-tutorial-delete-distribution"></a>

CloudFront 배포를 삭제하기 전에 반드시 배포를 비활성화해야 합니다. 비활성화된 배포가 작동하지 않아 요금이 발생하지 않습니다. 언제든지 비활성화된 배포를 활성화할 수 있습니다. 비활성화된 배포를 삭제한 뒤에는 사용할 수 없습니다.<a name="lambda-edge-how-it-works-tutorial-delete-distribution-proc"></a>

**CloudFront 배포를 사용하지 않도록 설정하고 삭제하려면**

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

1. 사용 중지하려는 배포를 선택한 후 **사용 중지**를 선택합니다.

1. 확인 메시지가 표시되면 **예, 사용 중지**를 선택합니다.

1. 사용 중지된 배포를 선택한 후 **삭제**를 선택합니다.

1. 확인 메시지가 나타나면 **예, 삭제합니다**를 선택합니다.

## 관련 정보
<a name="lambda-edge-how-it-works-tutorial-resources"></a>

Lambda@Edge 함수의 작동 방식에 대한 기본적인 내용을 배웠습니다. 이제 다음 자료를 읽고 자세히 알아보십시오.
+ [Lambda@Edge 예제 함수](lambda-examples.md)
+ [Lambda@Edge 설계 모범 사례](https://aws.amazon.com/blogs/networking-and-content-delivery/lambdaedge-design-best-practices/)
+ [Lambda@Edge로 대기 시간 감소 및 컴퓨팅 작업을 엣지로 이전](https://aws.amazon.com/blogs/networking-and-content-delivery/reducing-latency-and-shifting-compute-to-the-edge-with-lambdaedge/)

# Lambda@Edge에 대한 IAM 권한 및 역할 설정
<a name="lambda-edge-permissions"></a>

Lambda@Edge를 구성하려면 AWS Lambda에 대한 다음 IAM 권한과 역할이 있어야 합니다.
+ [IAM 권한](#lambda-edge-permissions-required) - 이러한 권한을 통해 Lambda 함수를 생성하고 CloudFront 배포와 연결할 수 있습니다.
+ [Lambda 함수 실행 역할](#lambda-edge-permissions-function-execution)(IAM 역할) – Lambda 서비스 보안 주체가 이 역할을 맡아 함수를 실행합니다.
+ [Lambda@Edge 서비스 연결 역할](#using-service-linked-roles-lambda-edge) - 서비스 연결 역할은 특정 AWS 서비스가 Lambda 함수를 AWS 리전에 복제하고 CloudWatch가 CloudFront 로그 파일을 사용할 수 있도록 합니다.

## Lambda@Edge 함수를 CloudFront 배포와 연결하는 데 필요한 IAM 권한
<a name="lambda-edge-permissions-required"></a>

사용자가 Lambda 함수를 CloudFront 배포와 연결하려면 Lambda에 필요한 IAM 권한 외에 다음과 같은 권한이 필요합니다.
+ `lambda:GetFunction` – 함수가 포함된 `.zip` 파일을 다운로드하기 위한 미리 서명된 URL과 Lambda 함수에 대한 구성 정보를 가져오기 위한 권한을 부여합니다.
+ `lambda:EnableReplication*` – Lambda 복제 서비스가 함수 코드 및 구성을 가져올 수 있도록 리소스 정책에 대한 권한을 부여합니다.
+ `lambda:DisableReplication*` – Lambda 복제 서비스가 함수를 삭제할 수 있도록 리소스 정책에 대한 권한을 부여합니다.
**중요**  
`lambda:EnableReplication*` 및 `lambda:DisableReplication*` 작업 끝에 별표(`*`)를 추가해야 합니다.
+ 리소스의 경우, 다음 예시와 같이 CloudFront 이벤트가 발생할 때 실행할 함수 버전의 ARN을 지정합니다.

  `arn:aws:lambda:us-east-1:123456789012:function:TestFunction:2`
+ `iam:CreateServiceLinkedRole` – Lambda@Edge가 CloudFront에서 Lambda 함수를 복제하는 데 사용하는 서비스 연결 역할을 생성하기 위한 권한을 부여합니다. Lambda@Edge를 처음으로 구성한 후 서비스 연결 역할이 자동으로 생성됩니다. Lambda@Edge를 사용하는 다른 배포에는 이 권한을 추가할 필요가 없습니다.

  
+ `cloudfront:UpdateDistribution` 또는 `cloudfront:CreateDistribution` – 배포를 업데이트 또는 생성하기 위한 권한을 부여합니다.

자세한 내용은 다음 항목을 참조하세요.
+ [Amazon CloudFront용 Identity and Access Management](security-iam.md)
+ **AWS Lambda 개발자 안내서의 [Lambda 리소스 액세스 권한](https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role)

## 서비스 보안 주체에 대한 함수 실행 역할
<a name="lambda-edge-permissions-function-execution"></a>

함수를 실행할 때 `lambda.amazonaws.com` 및 `edgelambda.amazonaws.com` 서비스 보안 주체가 맡을 수 있는 IAM 역할을 생성해야 합니다.

**작은 정보**  
Lambda 콘솔에서 함수를 생성할 때 AWS 정책 템플릿을 사용하여 새로운 실행 역할을 생성할 수 있습니다. 이 단계는 함수를 실행하는 데 필요한 Lambda@Edge 권한을 *자동으로* 추가합니다. [자습서의 5단계: 간단한 Lambda@Edge 함수 생성](lambda-edge-how-it-works-tutorial.md#lambda-edge-how-it-works-tutorial-create-function)을 참조하세요.

IAM 역할 수동 생성에 대한 자세한 내용은 **IAM 사용 설명서의 [역할 생성 및 정책 연결(콘솔)](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions_create-policies.html)을 참조하세요.

**Example 예시: 역할 신뢰 정책**  
IAM 콘솔의 **신뢰 관계** 탭에서 이 역할을 추가할 수 있습니다. **권한** 탭 아래에 이 정책을 추가하지 마세요.    
****  

```
{
   "Version":"2012-10-17",		 	 	 
   "Statement": [
      {
         "Effect": "Allow",
         "Principal": {
            "Service": [
               "lambda.amazonaws.com",
               "edgelambda.amazonaws.com"
            ]
         },
         "Action": "sts:AssumeRole"
      }
   ]
}
```

실행 역할에 부여해야 하는 권한에 대한 자세한 내용은 **AWS Lambda 개발자 안내서의 [Lambda 리소스 액세스 권한](https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html#lambda-intro-execution-role)을 참조하세요.

**참고**  
기본적으로 CloudFront 이벤트가 Lambda 함수를 트리거할 때마다 데이터는 CloudWatch Logs에 기록됩니다. 이러한 로그를 사용하려면 실행 역할에 CloudWatch Logs에 데이터를 기록할 권한이 있어야 합니다. 사전 정의된 AWSLambdaBasicExecutionRole을 사용하여 실행 역할에 대한 권한을 부여할 수 있습니다.  
CloudWatch Logs에 대한 자세한 내용은 [엣지 함수 로그](edge-functions-logs.md) 섹션을 참조하세요.
Lambda 함수 코드가 S3 버킷에서 객체를 읽는 것처럼 다른 AWS 리소스에 액세스하는 경우 실행 역할에는 해당 작업을 수행할 수 있는 권한이 필요합니다.

## Lambda@Edge의 서비스 연결 역할
<a name="using-service-linked-roles-lambda-edge"></a>

Lambda@Edge는 IAM [서비스 연결 역할](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html#iam-term-service-linked-role)을 사용합니다. 서비스 연결 역할은 서비스에 직접 연결된 고유한 유형의 IAM 역할입니다. 서비스 연결 역할은 해당 서비스에서 사전 정의하며 서비스에서 사용자를 대신하여 다른 AWS 서비스를 호출하기 위해 필요한 모든 권한을 포함합니다.

Lambda@Edge는 다음 IAM 서비스 연결 역할을 사용합니다.
+ **AWSServiceRoleForLambdaReplicator** - Lambda@Edge에서는 이 역할을 사용해 Lambda@Edge가 AWS 리전에 함수를 복제하도록 합니다.

  CloudFront에 Lambda@Edge 트리거를 처음 추가할 때 AWSServiceRoleForLambdaReplicator라는 역할이 자동으로 생성되어 Lambda@Edge가 AWS 리전에 함수를 복제할 수 있도록 합니다. Lambda@Edge 함수를 사용하려면 이 역할이 필요합니다. AWSServiceRoleForLambdaReplicator 역할에 대한 ARN은 다음 예시와 같을 수 있습니다.

  `arn:aws:iam::123456789012:role/aws-service-role/replicator.lambda.amazonaws.com/AWSServiceRoleForLambdaReplicator`
+ **AWSServiceRoleForCloudFrontLogger** – CloudFront는 이 역할을 사용하여 CloudWatch에 로그 파일을 푸시합니다. 로그 파일을 사용하여 Lambda@Edge 검증 오류를 디버깅할 수 있습니다.

  AWSServiceRoleForCloudFrontLogger 역할은 CloudFront에서 Lambda@Edge 오류 로그 파일을 CloudWatch로 푸시하도록 허용하기 위해 Lambda@Edge 함수 연결을 추가한 경우 자동으로 생성됩니다. AWSServiceRoleForCloudFrontLogger 역할의 ARN의 모양은 다음과 같습니다.

  `arn:aws:iam::account_number:role/aws-service-role/logger.cloudfront.amazonaws.com/AWSServiceRoleForCloudFrontLogger`

서비스 연결 역할이 있으면 필요한 권한을 수동으로 추가할 필요가 없으므로 Lambda@Edge를 설정 및 사용하기가 쉽습니다. 서비스 연결 역할의 권한은 Lambda@Edge에서 정의하며, Lambda@Edge만이 그 역할을 맡을 수 있습니다. 정의된 권한에는 신뢰 정책과 권한 정책이 포함됩니다. 권한 정책은 다른 어떤 IAM 엔터티에도 연결할 수 없습니다.

서비스 연결 역할을 삭제하려면 먼저 연결된 CloudFront 또는 Lambda@Edge 리소스를 제거해야 합니다. 그러면 활성 리소스에 액세스하는 데 필요한 서비스 연결 역할을 제거하지 않고 Lambda@Edge 리소스를 보호할 수 있습니다.

서비스 연결 역할에 대한 자세한 내용은 [CloudFront 서비스 연결 역할](security_iam_service-with-iam.md#security_iam_service-with-iam-roles-service-linked)를 참조하세요.

### Lambda@Edge의 서비스 연결 역할 권한
<a name="slr-permissions-lambda-edge"></a>

Lambda@Edge는 **AWSServiceRoleForLambdaReplicator** 및 **AWSServiceRoleForCloudFrontLogger**이라는 서비스 연결 역할을 사용합니다. 다음 단원에서는 이러한 각 역할에 대한 권한을 설명합니다.

**Contents**
+ [Lambda Replicator의 서비스 연결 역할 권한](#slr-permissions-lambda-replicator)
+ [CloudFront Logger에 대한 서비스 연결 역할 권한](#slr-permissions-cloudfront-logger)

#### Lambda Replicator의 서비스 연결 역할 권한
<a name="slr-permissions-lambda-replicator"></a>

이 서비스 연결 역할을 통해 Lambda는 Lambda@Edge 함수를 AWS 리전에 복제할 수 있습니다.

AWSServiceRoleForLambdaReplicator 서비스 연결 역할은 역할을 수임하기 위해 `replicator.lambda.amazonaws.com`서비스를 신뢰합니다.

역할 권한 정책에서는 Lambda@Edge가 지정된 리소스에서 다음 작업을 완료할 수 있도록 허용합니다.
+ `lambda:CreateFunction`​의 `arn:aws:lambda:*:*:function:*`
+ `lambda:DeleteFunction`​의 `arn:aws:lambda:*:*:function:*`
+ `lambda:DisableReplication`​의 `arn:aws:lambda:*:*:function:*`
+ `iam:PassRole`​의 `all AWS resources`
+  `cloudfront:ListDistributionsByLambdaFunction`​의 `all AWS resources`

#### CloudFront Logger에 대한 서비스 연결 역할 권한
<a name="slr-permissions-cloudfront-logger"></a>

이 서비스 연결 역할을 사용하면 Lambda@Edge 검증 오류를 디버깅하기 위해 CloudFront에서 CloudWatch로 로그 파일을 푸시할 수 있습니다.

AWSServiceRoleForCloudFrontLogger 서비스 연결 역할은 역할을 수임하기 위해 `logger.cloudfront.amazonaws.com`서비스를 신뢰합니다.

역할 권한 정책에서는 Lambda@Edge가 지정된 `arn:aws:logs:*:*:log-group:/aws/cloudfront/*` 리소스에서 다음 작업을 완료할 수 있도록 허용합니다.
+ `logs:CreateLogGroup` ``
+ `logs:CreateLogStream`
+ `logs:PutLogEvents`

IAM 엔터티(예: 사용자, 그룹 또는 역할)가 Lambda@Edge 서비스 연결 역할을 삭제할 수 있도록 권한을 구성해야 합니다. 자세한 내용은 *IAM 사용 설명서*의 [서비스 연결 역할 권한](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html#service-linked-role-permissions)을 참조하세요.

### Lambda@Edge의 서비스 연결 역할 생성
<a name="create-slr-lambda-edge"></a>

일반적으로 Lambda@Edge에 대한 서비스 연결 역할은 수동으로 생성하지 않습니다. 다음 시나리오에서 서비스는 역할을 자동으로 생성합니다.
+ 트리거를 처음으로 생성할 때, 이 서비스에서는 AWSServiceRoleForLambdaReplicator 역할이 없는 경우 해당 역할을 생성합니다. 이 역할을 통해 Lambda는 Lambda@Edge 함수를 AWS 리전에 복제할 수 있습니다.

  서비스 연결 역할을 삭제하는 경우, 배포에서 Lambda@Edge의 새 트리거를 추가할 때 이 역할이 다시 생성됩니다.
+ Lambda@Edge 연결이 있는 CloudFront 배포를 업데이트 또는 생성할 때, 이 서비스에서는 AWSServiceRoleForCloudFrontLogger라는 역할이 없는 경우 해당 역할을 생성합니다. 이 정책은 CloudFront에서 로그 파일을 CloudFront로 푸시할 수 있도록 허용합니다.

  서비스 연결 역할을 삭제했다 하더라도, Lambda@Edge 연결이 있는 CloudFront 배포를 업데이트 또는 생성하는 경우 해당 역할이 다시 생성됩니다.

이러한 서비스 연결 역할을 수동으로 만들어야 하는 경우 다음 AWS Command Line Interface(AWS CLI) 명령을 실행합니다.

**AWSServiceRoleForLambdaReplicator 역할을 만들려면**
+ 다음 명령을 실행합니다.

  ```
  aws iam create-service-linked-role --aws-service-name replicator.lambda.amazonaws.com
  ```

**AWSServiceRoleForCloudFrontLogger 역할을 만들려면**
+ 다음 명령을 실행합니다.

  ```
  aws iam create-service-linked-role --aws-service-name logger.cloudfront.amazonaws.com
  ```

### Lambda@Edge 서비스 연결 역할 편집
<a name="edit-slr-lambda-edge"></a>

Lambda@Edge에서는 AWSServiceRoleForLambdaReplicator 또는 AWSServiceRoleForCloudFrontLogger 서비스 연결 역할을 편집할 수 없습니다. 서비스에서 서비스 연결 역할을 만든 후에는 다양한 엔터티가 역할을 참조할 수 있기 때문에 역할 이름을 변경할 수 없습니다. 그러나 IAM을 사용하여 역할 설명을 편집할 수는 있습니다. 자세한 내용은 *IAM 사용 설명서*의 [서비스 연결 역할 편집](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html#edit-service-linked-role)을 참조하세요.

### Lambda@Edge 서비스 연결 역할에 대해 지원되는 AWS 리전
<a name="slr-regions-lambda-edge"></a>

CloudFront는 다음 AWS 리전에서 Lambda@Edge에 대한 서비스 연결 역할 사용을 지원합니다.
+ 미국 동부(버지니아 북부) – `us-east-1`
+ 미국 동부(오하이오) – `us-east-2`
+ 미국 서부(캘리포니아 북부) – `us-west-1`
+ 미국 서부(오리건) – `us-west-2`
+ 아시아 태평양(뭄바이) – `ap-south-1`
+ 아시아 태평양(서울) – `ap-northeast-2`
+ 아시아 태평양(싱가포르) – `ap-southeast-1`
+ 아시아 태평양(시드니) – `ap-southeast-2`
+ 아시아 태평양(도쿄) – `ap-northeast-1`
+ 유럽(프랑크푸르트) – `eu-central-1`
+ 유럽(아일랜드) – `eu-west-1`
+ 유럽(런던) – `eu-west-2`
+ 남아메리카(상파울루) – `sa-east-1`

# Lambda@Edge 함수 작성 및 생성
<a name="lambda-edge-create-function"></a>

Lambda@Edge를 사용하려면 AWS Lambda 함수에 대한 코드를 *작성*해야 합니다. Lambda@Edge 함수를 작성하는 데 도움이 되도록 다음 리소스를 참조하세요.
+  [Lambda@Edge 이벤트 구조](lambda-event-structure.md) – Lambda@Edge와 함께 사용할 이벤트 구조를 이해합니다.
+ [Lambda@Edge 예제 함수](lambda-examples.md) – A/B 테스트 및 HTTP 리디렉션 생성 등의 예시 함수입니다.

Lambda@Edge에서 Node.js 또는 Python을 사용하는 프로그래밍 AWS 리전에서 Lambda를 사용하는 것과 동일합니다. 자세한 내용은 **AWS Lambda 개발자 안내서의 [Node.js를 사용하여 Lambda 함수 작성](https://docs.aws.amazon.com/lambda/latest/dg/lambda-nodejs.html) 또는 [Python을 사용하여 Lambda 함수 작성](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python.html)을 참조하세요.

Lambda@Edge 함수에 `callback` 파라미터를 포함하고 요청 또는 응답 이벤트에 해당되는 객체를 반환합니다.
+ **요청 이벤트** - 응답에 `cf.request` 객체를 포함합니다.

  응답을 생성하는 경우 응답에 `cf.response` 객체를 포함합니다. 자세한 내용은 [요청 트리거에서 HTTP 응답 생성](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests) 단원을 참조하세요.
+ **응답 이벤트** - 응답에 `cf.response` 객체를 포함합니다.

코드를 직접 작성하거나 예제 중 하나를 사용한 후 Lambda에서 함수를 생성합니다. 함수를 생성하거나 기존 함수를 편집하려면 다음 주제를 참조하세요.

**Topics**
+ [Lambda@Edge 함수 생성](lambda-edge-create-in-lambda-console.md)
+ [Lambda 함수 편집](lambda-edge-edit-function.md)

 Lambda에서 함수를 생성한 후에는 *triggers*라고 하는 특정 CloudFront 이벤트를 기반으로 함수를 실행하도록 Lambda를 설정합니다. 자세한 내용은 [Lambda@Edge 함수에 대한 트리거 추가](lambda-edge-add-triggers.md) 섹션을 참조하세요.

# Lambda@Edge 함수 생성
<a name="lambda-edge-create-in-lambda-console"></a>

CloudFront 이벤트를 기반으로 한 Lambda 함수를 실행하도록 AWS Lambda를 설정하려면 다음 절차를 수행합니다.<a name="lambda-edge-create-function-procedure"></a>

**Lambda@Edge 함수를 생성하려면**

1. AWS Management Console에 로그인하고 AWS Lambdahttps://console.aws.amazon.com/lambda/[에서 ](https://console.aws.amazon.com/lambda/) 콘솔을 엽니다.

1. 이미 하나 이상의 Lambda 함수가 있는 경우에는 **함수 생성**을 선택합니다.

   아무 함수도 없는 경우 **Get Started Now**(지금 시작하기)를 선택합니다.

1. 페이지 상단의 리전 목록에서 **미국 동부(버지니아 북부)(US East (N. Virginia))**를 선택합니다.

1. 자체 코드를 사용하여 함수를 생성하거나 CloudFront 청사진으로 시작하는 함수를 생성합니다.
   + 자체 코드를 사용하여 함수를 생성하려면 **새로 작성**을 선택합니다.
   + CloudFront용 청사진 목록을 표시하려면 필터 필드에 **cloudfront**를 입력한 다음, **Enter** 키를 누릅니다.

     사용할 청사진을 찾은 경우 청사진 이름을 선택합니다.

1. **기본 정보** 섹션에서 다음 값을 지정합니다.

   1. **이름** – 함수의 이름을 입력합니다.

   1. **역할** - 빠르게 시작하려면 **템플릿에서 새 역할 만들기**를 선택합니다. **기존 역할 선택** 또는 **사용자 지정 역할 생성**을 선택한 다음 지시에 따라 이 섹션의 정보를 작성할 수도 있습니다.

   1. **역할 이름** – 역할의 이름을 입력합니다.

   1. **정책 템플릿** – **기본 Edge Lambda 권한**을 선택합니다.

1. 4단계에서 **새로 작성**을 선택한 경우 7단계로 건너뜁니다.

   4단계에서 청사진을 선택한 경우 **cloudfront** 단원에서 이 함수를 CloudFront 배포 및 CloudFront 이벤트의 캐시와 연결하는 트리거를 하나 생성할 수 있습니다. 이때 함수 생성 시 트리거가 없도록 **제거**를 선택하는 것이 좋습니다. 그런 다음, 나중에 트리거를 추가할 수 있습니다.
**작은 정보**  
트리거를 추가하기 전에 함수를 테스트하고 디버깅하는 것이 좋습니다. 지금 트리거를 추가하면 함수가 생성되어 전 세계의 AWS 위치로 복제를 완료하고 난 후 해당 배포가 배포되는 즉시 함수가 실행됩니다.

1. **함수 생성**을 선택합니다.

   Lambda는 함수의 두 버전인 \$1LATEST와 Version 1을 생성합니다. \$1LATEST 버전만 편집할 수 있지만 콘솔에 처음에는 Version 1이 표시됩니다.

1. 함수를 편집하려면 페이지 위쪽의, 함수 ARN 아래에서 **Version 1**을 선택합니다. 그런 다음, **버전** 탭에서 **\$1LATEST**를 선택합니다. 함수에서 나간 후 다시 돌아오면 버튼 레이블이 **한정자**로 바뀌어 있습니다.

1. **구성** 탭에서 해당하는 **코드 입력 유형**을 선택합니다. 그런 다음, 프롬프트의 메시지를 따라 코드를 편집하거나 업로드합니다.

1. **실행 시간**에서 함수 코드를 기반으로 값을 선택합니다.

1. **태그** 섹션에서 해당하는 태그를 추가합니다.

1. **작업**을 선택한 다음, **Publish new version**(새 버전 게시)을 선택합니다.

1. 새 함수 버전의 설명을 입력합니다.

1. [**Publish**]를 선택합니다.

1. 함수를 테스트하고 디버깅합니다. Lambda 콘솔 테스트에 대한 자세한 내용은 AWS Lambda 개발자 안내서**에서 [콘솔을 사용하여 Lambda 함수 호출](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html#get-started-invoke-manually)을 참조하세요.

1. CloudFront 이벤트에 대해 함수를 실행할 준비가 되면 다른 버전을 게시하고 함수를 편집하여 트리거를 추가합니다. 자세한 내용은 [Lambda@Edge 함수에 대한 트리거 추가](lambda-edge-add-triggers.md) 섹션을 참조하세요.

# Lambda 함수 편집
<a name="lambda-edge-edit-function"></a>

Lambda@Edge 함수를 생성한 후 Lambda 콘솔을 사용하여 편집할 수 있습니다.

**참고**  
원래 버전은 \$1LATEST라고 표시되어 있습니다.
\$1LATEST 버전만 편집할 수 있습니다.
\$1LATEST 버전을 편집할 때마다 번호가 지정된 새 버전을 게시해야 합니다.
\$1LATEST에 대한 트리거는 생성할 수 없습니다.
새 버전의 함수를 게시하면 Lambda는 이전 버전의 트리거를 새 버전으로 자동 복사하지 않습니다. 새 버전에 대한 트리거를 다시 생성해야 합니다.
CloudFront 이벤트에 대한 트리거를 함수에 추가할 때 동일한 함수의 이전 버전에 대해 동일한 배포, 캐시 동작 및 이벤트에 대한 트리거가 이미 존재하면 Lambda는 이전 버전에서 트리거를 삭제합니다.
트리거를 추가하는 등 CloudFront 배포를 업데이트한 후에는 변경 사항이 엣지 로케이션으로 전파될 때까지 기다려야만 트리거에서 지정한 함수가 작동합니다.<a name="lambda-edge-edit-function-procedure"></a>

**Lambda 함수를 편집하려면**

1. AWS Management Console에 로그인하고 AWS Lambdahttps://console.aws.amazon.com/lambda/[에서 ](https://console.aws.amazon.com/lambda/) 콘솔을 엽니다.

1. 페이지 상단의 리전 목록에서 **미국 동부(버지니아 북부)(US East (N. Virginia))**를 선택합니다.

1. 함수 목록에서 함수의 이름을 선택합니다.

   기본 설정 사용 시, \$1LATEST 버전이 콘솔에 표시됩니다. 이전 버전을 볼 수 있지만(**한정자** 선택) \$1LATEST만 편집할 수 있습니다.

1. **코드(Code)** 탭의 **코드 입력 유형(Code entry type)**에서 브라우저에서 코드를 편집하거나, .zip 파일을 업로드하거나, Amazon S3에서 파일을 업로드하도록 선택합니다.

1. **저장** 또는 **저장 및 테스트**를 선택합니다.

1. **작업** 및 **Publish new version**(새 버전 게시)을 차례대로 선택합니다.

1. **\$1LATEST의 새 버전 게시** 대화 상자에서 새 버전 설명을 입력합니다. 이 설명은 자동으로 생성된 버전 번호와 함께 버전 목록에 표시됩니다.

1. [**Publish**]를 선택합니다.

   새 버전은 자동으로 최신 버전이 됩니다. 버전 번호는 페이지 왼쪽 상단 모서리의 **버전**에 표시됩니다.
**참고**  
함수에 트리거를 아직 추가하지 않았다면 [Lambda@Edge 함수에 대한 트리거 추가](lambda-edge-add-triggers.md) 섹션을 참조하세요.

1. **트리거** 탭을 선택합니다.

1. **트리거 추가**를 선택합니다.

1. **트리거 추가(Add trigger)** 대화 상자에서 점선으로 된 상자를 선택한 다음, **CloudFront**를 선택합니다.
**참고**  
함수에 대해 하나 이상의 트리거를 이미 만든 경우 CloudFront가 기본 서비스입니다.

1. 다음 값을 지정하여 Lambda 함수를 실행할 시기를 나타냅니다.

   1. **배포 ID** – 트리거를 추가할 배포의 ID를 선택합니다.

   1. **캐시 동작** – 함수를 실행할 객체를 지정하는 캐시 동작을 선택합니다.

   1. **CloudFront 이벤트** – 함수를 실행시키는 CloudFront 이벤트를 선택합니다.

   1. **트리거 활성화 및 복제** – 이 확인란을 선택하면 Lambda가 전 세계 AWS 리전으로 함수를 복제합니다.

1. **제출**을 선택합니다.

1. 이 함수에 대한 트리거를 추가하려면 10\$113단계를 반복합니다.

Lambda 콘솔에서 함수를 테스트하고 디버깅하는 방법에 대한 자세한 내용은 AWS Lambda 개발자 안내서**에서 [콘솔을 사용하여 Lambda 함수 호출](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html#get-started-invoke-manually)을 참조하세요.

CloudFront 이벤트에 대해 함수를 실행할 준비가 되면 다른 버전을 게시하고 함수를 편집하여 트리거를 추가합니다. 자세한 내용은 [Lambda@Edge 함수에 대한 트리거 추가](lambda-edge-add-triggers.md) 섹션을 참조하세요.

# Lambda@Edge 함수에 대한 트리거 추가
<a name="lambda-edge-add-triggers"></a>

Lambda@Edge 트리거는 CloudFront 배포, 캐시 동작, 그리고 함수 실행을 유도하는 이벤트를 하나로 조합한 것입니다. 예를 들어, 최종 사용자가 해당 배포에 설정된 특정 캐시 동작을 CloudFront에 요청하면 함수가 실행되도록 하는 트리거를 생성할 수 있습니다. 하나 이상의 CloudFront 트리거를 지정할 수 있습니다.

**작은 정보**  
CloudFront 배포를 생성할 때 다른 요청을 수신할 때 응답하는 방법을 CloudFront에게 알려주는 설정을 지정합니다. 기본 설정을 배포에 대한 *기본 캐시 동작*이라고 합니다. CloudFront가 특정한 상황(예를 들어, 특정 파일 유형에 대한 요청을 수신할 때)에서 응답하는 방법을 정의하는 추가 캐시 동작을 설정할 수 있습니다. 자세한 내용은 [캐시 동작 설정](DownloadDistValuesCacheBehavior.md) 섹션을 참조하세요.

Lambda 함수를 처음 생성할 때는 트리거를 *하나*만 지정할 수 있습니다. 나중에 Lambda 콘솔을 사용하거나 CloudFront 콘솔에서 배포를 편집하여 동일한 함수에 더 많은 트리거를 추가할 수 있습니다.
+ Lambda 콘솔을 사용하는 방법은 동일한 CloudFront 배포에 대한 함수에 트리거를 더 추가하려는 경우에 적합합니다.
+ CloudFront 콘솔을 사용하는 방법은 업데이트하려는 배포를 쉽게 찾을 수 있기 때문에 여러 배포에 대한 트리거를 추가하려는 경우에 더 적합할 수 있습니다. 또한 동시에 다른 CloudFront 설정을 업데이트할 수 있습니다.

**Topics**
+ [Lambda@Edge 함수를 트리거할 수 있는 CloudFront 이벤트](lambda-cloudfront-trigger-events.md)
+ [함수를 트리거할 이벤트를 선택합니다.](lambda-how-to-choose-event.md)
+ [Lambda@Edge 함수에 트리거 추가](lambda-edge-add-triggers-console.md)

# Lambda@Edge 함수를 트리거할 수 있는 CloudFront 이벤트
<a name="lambda-cloudfront-trigger-events"></a>

특정한 CloudFront 이벤트가 발생하면 Lambda 함수가 실행되도록 하는 트리거(연결)를 Amazon CloudFront 배포의 각 캐시 동작에 대해 4개까지 추가할 수 있습니다. CloudFront 트리거는 아래 그림의 네 가지 CloudFront 이벤트 중 하나를 토대로 합니다.

![\[Lambda 함수의 CloudFront 트리거 이벤트가 CloudFront와 통합되는 방법을 보여 주는 개념 그림.\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/cloudfront-events-that-trigger-lambda-functions.png)


Lambda@Edge 함수를 트리거하는 데 사용할 수 있는 CloudFront 이벤트는 다음과 같습니다.

**최종 사용자 요청**  
이 함수는 CloudFront가 최종 사용자로부터 요청을 수신하면 실행되며, 요청된 객체가 CloudFront 캐시에 있는지를 확인합니다.  
다음과 같은 경우에는 함수가 실행되지 않습니다.  
+ 사용자 지정 오류 페이지를 가져오는 경우.
+ CloudFront가 자동으로 HTTP 요청을 HTTPS로 리디렉션하는 경우([뷰어 프로토콜 정책](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy) 값이 **Redirect HTTP to HTTPS**일 경우).

**오리진 요청**  
이 함수는 CloudFront가 오리진으로 요청을 전달할 *경우에만* 실행됩니다. 요청된 객체가 CloudFront 캐시에 저장되어 있으면 함수는 실행되지 않습니다.

**오리진 응답**  
이 함수는 CloudFront가 오리진으로부터 응답을 수신한 후 실행되어 응답의 객체를 캐싱합니다. 오리진에서 오류가 반환되는 경우에도 함수는 실행됩니다.  
다음과 같은 경우에는 함수가 실행되지 않습니다.  
+ 요청된 파일이 CloudFront 캐시에 있고 만료되지 않은 경우.
+ 오리진 요청 이벤트가 트리거한 함수로부터 응답이 생성되는 경우.

**최종 사용자 응답**  
요청된 파일을 최종 사용자에게 반환하기 전에 함수가 실행됩니다. 이때 함수는 해당 파일이 이미 CloudFront 캐시에 있는지 여부와 상관없이 실행됩니다.  
다음과 같은 경우에는 함수가 실행되지 않습니다.  
+ 오리진이 400 이상의 HTTP 상태 코드 반환하는 경우
+ 사용자 지정 오류 페이지가 반환될 때.
+ 최종 사용자 요청 이벤트가 트리거한 함수로부터 응답이 생성되는 경우.
+ CloudFront가 자동으로 HTTP 요청을 HTTPS로 리디렉션하는 경우([뷰어 프로토콜 정책](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy) 값이 **Redirect HTTP to HTTPS**일 경우).

한 캐시 동작에 여러 트리거를 추가하는 경우, 이를 사용하여 동일한 함수를 실행하거나 트리거마다 다른 함수를 실행할 수 있습니다. 또한 복수의 배포에 동일한 함수를 연결할 수도 있습니다.

**참고**  
CloudFront 이벤트가 Lambda 함수의 실행을 트리거하면 CloudFront가 계속되기 **전에 함수가 완료되어야 합니다.  
예를 들어, CloudFront 최종 사용자 요청 이벤트에 따라 Lambda 함수가 트리거되면 CloudFront는 Lambda 함수 실행이 완료될 때까지 최종 사용자에게 응답을 반환하거나 오리진에 요청을 전달하지 않습니다.  
다시 말해, Lambda 함수를 트리거하는 각 요청은 요청 지연 시간을 증가시키므로 최대한 빨리 함수가 실행되도록 해야 합니다.

# 함수를 트리거할 이벤트를 선택합니다.
<a name="lambda-how-to-choose-event"></a>

Lambda 함수를 트리거하는 데 사용할 CloudFront 이벤트를 결정할 때 다음 사항을 고려해야 합니다.

**CloudFront에서 Lambda 함수가 변경한 객체를 캐싱하고자 함**  
CloudFront가 Lambda 함수로 수정된 객체를 캐싱하여 다음에 해당 객체가 요청될 경우 엣지 로케이션의 객체에 CloudFront가 서비스를 제공할 수 있게 하려면 **오리진 요청 또는 **오리진 응답 이벤트를 사용합니다.  
그러면 오리진에 대한 로드가 감소하고, 이후 요청의 지연 시간이 단축되며, 이후 요청에서 Lambda@Edge를 호출하는 비용이 절감됩니다.  
예를 들어, 오리진에 의해 반환되는 객체의 헤더를 추가, 제거 또는 변경하고 CloudFront에서 해당 결과를 캐싱하게 하려는 경우 오리진 응답 이벤트를 사용합니다.

**모든 요청에 대해 함수를 실행하고자 함**  
CloudFront가 배포에 대해 수신하는 모든 요청에서 함수를 실행하려면 **뷰어 요청 또는 **뷰어 응답 이벤트를 사용합니다.  
오리진 요청 및 오리진 응답 이벤트는 요청된 객체가 엣지 로케이션에 캐싱되지 않고 CloudFront가 오리진으로 요청을 전달하는 경우에만 발생합니다.

**함수가 캐시 키를 변경하고자 함**  
함수가 캐싱의 기준으로 사용되는 값을 변경하게 하려면 **뷰어 요청 이벤트를 사용합니다.  
예를 들어, 함수가 URL을 변경하여 경로에 언어 약자를 포함시키는 경우(예를 들어, 사용자가 드롭다운 목록에서 언어를 선택했기 때문) 최종 사용자 요청 이벤트를 사용합니다.  
+ **최종 사용자 요청 내 URL** - https://example.com/en/index.html
+ **요청이 독일 내 IP 주소로부터 온 경우의 URL** - https://example.com/de/index.html
쿠키 또는 요청 헤더를 기준으로 캐싱하는 경우에도 최종 사용자 요청 이벤트를 사용합니다.  
함수가 쿠키 또는 헤더를 변경하는 경우 CloudFront가 요청의 해당 부분을 오리진으로 전달하도록 구성합니다. 자세한 내용은 다음 항목을 참조하세요.  
+ [쿠키 기반의 콘텐츠 캐싱](Cookies.md)
+ [요청 헤더 기반의 콘텐츠 캐싱](header-caching.md)

**함수가 오리진의 응답에 영향을 미침**  
함수가 오리진의 응답에 영향을 미치는 방식으로 요청을 변경하려면 **오리진 요청 이벤트를 사용합니다.  
일반적으로 대부분의 뷰어 요청 이벤트는 오리진으로 전달되지 않습니다. CloudFront는 이미 엣지 캐시에 저장된 객체를 사용하여 요청에 응답합니다. 함수가 오리진 요청 이벤트를 기준으로 요청을 변경하는 경우 CloudFront가 변경된 오리진 요청에 대한 응답을 캐싱합니다.

# Lambda@Edge 함수에 트리거 추가
<a name="lambda-edge-add-triggers-console"></a>

Lambda@Edge 함수에 트리거를 추가하기 위해 AWS Lambda 콘솔 또는 Amazon CloudFront 콘솔을 사용할 수 있습니다.

**중요**  
번호가 매겨진 함수 버전에 대해서만 트리거를 생성할 수 있습니다(**\$1LATEST** 제외).

------
#### [ Lambda console ]<a name="lambda-edge-add-triggers-procedure"></a>

**Lambda@Edge 함수에 CloudFront 이벤트에 대한 트리거를 추가하려면**

1. AWS Management Console에 로그인하고 AWS Lambdahttps://console.aws.amazon.com/lambda/[에서 ](https://console.aws.amazon.com/lambda/) 콘솔을 엽니다.

1. 페이지 상단의 리전 목록에서 **미국 동부(버지니아 북부)(US East (N. Virginia))**를 선택합니다.

1. **함수** 페이지에서 트리거를 추가할 함수의 이름을 선택합니다.

1. **함수 개요** 페이지에서 **버전** 탭을 선택합니다.

1. 트리거를 추가할 버전을 선택합니다.

   버전을 선택한 후 버튼의 이름이 **버전: \$1LATEST** 또는 **버전:** *버전 번호*로 변경됩니다.

1. **트리거** 탭을 선택합니다.

1. **트리거 추가**를 선택합니다.

1. **트리거 구성**에서 **소스 선택**을 선택하고 **cloudfront**를 입력한 다음 **CloudFront**를 선택합니다.
**참고**  
하나 이상의 트리거를 이미 만든 경우 CloudFront가 기본 서비스입니다.

1. 다음 값을 지정하여 Lambda 함수를 실행할 시기를 나타냅니다.

   1. **배포** – 트리거를 추가할 배포를 선택합니다.

   1. **캐시 동작** – 함수를 실행할 객체를 지정하는 캐시 동작을 선택합니다.
**참고**  
캐시 동작에 `*`를 지정하는 경우 Lambda 함수는 기본 캐시 동작으로 배포됩니다.

   1. **CloudFront 이벤트** – 함수를 실행시키는 CloudFront 이벤트를 선택합니다.

   1. **본문 포함** – 함수의 요청 본문에 액세스하려는 경우 이 확인란을 선택합니다.

   1. **Lambda@Edge로 배포 확인** - 이 확인란을 선택하면 AWS Lambda가 전 세계 AWS 리전으로 함수를 복제합니다.

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

   업데이트된 CloudFront 배포가 배포되면 함수가 지정된 CloudFront 이벤트에 대한 요청을 처리하기 시작합니다. 배포가 배포되었는지 확인하려면 탐색 창에서 **배포**를 선택합니다. 배포가 되면 배포에 대한 **상태** 열의 값이 **배포 중**에서 배포 날짜 및 시간으로 변경됩니다.

------
#### [ CloudFront console ]<a name="lambda-create-functions-add-triggers-cloudfront-console-procedure"></a>

**Lambda@Edge 함수에 CloudFront 이벤트에 대한 트리거를 추가하려면**

1. 트리거를 추가하려는 Lambda 함수의 ARN을 얻습니다.

   1. AWS Management Console에 로그인하고 AWS Lambdahttps://console.aws.amazon.com/lambda/[에서 ](https://console.aws.amazon.com/lambda/) 콘솔을 엽니다.

   1. 페이지 상단의 리전 목록에서 **미국 동부(버지니아 북부)(US East (N. Virginia))**를 선택합니다.

   1. 함수 목록에서 트리거를 추가하려는 함수의 이름을 선택합니다.

   1. **함수 개요** 페이지에서 **버전** 탭을 선택하고 트리거를 추가할 번호가 매겨진 버전을 선택합니다.

   1. **ARN 복사** 버튼을 선택하여 ARN을 클립보드에 복사합니다. Lambda 함수의 ARN은 다음과 같은 형태입니다.

      `arn:aws:lambda:us-east-1:123456789012:function:TestFunction:2`

      끝부분의 숫자(이 예제에서는 **2**)가 함수의 버전 번호입니다.

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

1. 배포 목록에서 트리거를 추가하려는 배포의 ID를 선택합니다.

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

1. 트리거를 추가하려는 캐시 동작을 선택한 다음 **편집**을 클릭합니다.

1. **함수 연결**에서, **함수 유형** 목록에서 함수를 실행할 시점, 즉 최종 사용자 요청, 최종 사용자 응답, 오리진 요청 또는 오리진 응답 중에 **Lambda@Edge**를 선택합니다.

   자세한 내용은 [함수를 트리거할 이벤트를 선택합니다.](lambda-how-to-choose-event.md) 섹션을 참조하세요.

1. **함수 ARN/이름** 텍스트 상자에 선택한 이벤트가 발생할 때 실행하려는 Lambda 함수의 ARN을 붙여넣습니다. Lambda 콘솔에서 복사한 값입니다.

1. 함수의 요청 본문에 액세스하려는 경우 **본문 포함**을 선택합니다.

   요청 본문을 바꾸기만 하려는 경우에는 이 옵션을 선택할 필요가 없습니다.

1. 더 많은 이벤트 유형에 대해 동일한 함수를 실행하려면 6 및 7단계를 반복합니다.

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

1. 이 배포에 대한 다른 캐시 동작에 트리거를 추가하려면 5\$110단계를 반복합니다.

   업데이트된 CloudFront 배포가 배포되면 함수가 지정된 CloudFront 이벤트에 대한 요청을 처리하기 시작합니다. 배포가 배포되었는지 확인하려면 탐색 창에서 **배포**를 선택합니다. 배포판이 배포되면 배포에 대한 **상태** 열의 값이 **배포 중**에서 배포 시간 및 날짜로 변경됩니다.

------

# Lambda@Edge 함수 테스트 및 디버깅
<a name="lambda-edge-testing-debugging"></a>

의도한 작업을 완료하는지 확인하기 위해서는 Lambda@Edge 함수 코드를 단독으로 테스트해야 하고, 함수가 CloudFront와 함께 잘 작동하는지 확인하기 위해서는 통합 테스트를 수행해야 합니다.

통합 테스트 중 또는 함수 배포 완료 후 HTTP 5xx 오류 등과 같은 CloudFront 오류를 디버깅해야 할 수 있습니다. Lambda 함수에서 반환되는 잘못된 응답, 함수 실행 시 발생하는 실행 오류 또는 Lambda 서비스의 실행 조절로 인한 오류 등이 있을 수 있습니다. 이 주제의 단원에서는 이러한 문제가 어떤 유형의 실패인지 확인한 다음 각 문제를 해결하기 위해 수행할 수 있는 단계에 대해 설명합니다.

**참고**  
오류를 해결하기 위해 CloudWatch 로그 파일 또는 지표를 검토할 때 함수가 실행된 위치에 가장 가까운 AWS 리전에 로그 파일 또는 지표가 표시 또는 저장된다는 점에 유의하세요. 예를 들어, 영국 내 사용자가 있는 웹 사이트 또는 웹 애플리케이션이 있고 배포와 연결된 Lambda 함수가 있는 경우 런던 AWS 리전 리전에 대한 CloudWatch 지표 또는 로그 파일을 볼 수 있도록 리전을 변경해야 합니다. 자세한 내용은 [Lambda@Edge 리전 확인](#lambda-edge-testing-debugging-determine-region) 섹션을 참조하세요.

**Topics**
+ [Lambda@Edge 함수 테스트](#lambda-edge-testing-debugging-test-function)
+ [CloudFront에서 Lambda@Edge 함수 오류 식별](#lambda-edge-identifying-function-errors)
+ [잘못된 Lambda@Edge 함수 응답(검증 오류) 문제 해결](#lambda-edge-testing-debugging-troubleshooting-invalid-responses)
+ [Lambda@Edge 함수 실행 오류 문제 해결](#lambda-edge-testing-debugging-execution-errors)
+ [Lambda@Edge 리전 확인](#lambda-edge-testing-debugging-determine-region)
+ [계정이 CloudWatch로 로그를 푸시하는지 확인](#lambda-edge-testing-debugging-cloudwatch-logs-enabled)

## Lambda@Edge 함수 테스트
<a name="lambda-edge-testing-debugging-test-function"></a>

Lambda 함수 테스트에는 독립 실행형 테스트와 통합 테스트, 이렇게 두 가지 단계가 있습니다.

**독립 실행형 기능 테스트**  
CloudFront에 Lambda 함수를 추가하기 전에 Lambda 콘솔의 테스트 기능을 사용하거나 다른 방법을 사용하여 기능을 먼저 테스트해야 합니다. Lambda 콘솔 테스트에 대한 자세한 내용은 AWS Lambda 개발자 안내서**에서 [콘솔을 사용하여 Lambda 함수 호출](https://docs.aws.amazon.com/lambda/latest/dg/getting-started.html#get-started-invoke-manually)을 참조하세요.

**CloudFront에서 함수의 작동 상태를 보기 위한 테스트**  
함수가 배포와 연결되어 있고 CloudFront 이벤트를 기반으로 실행되는 경우에는 통합 테스트를 반드시 완료해야 합니다. 함수가 올바른 이벤트 발생 시 실행되고 CloudFront에 대해 올바른 응답을 반환하는지 확인합니다. 예를 들어, 이벤트 구조가 올바른지, 유효한 헤더만 포함되어 있는지 등을 확인합니다.  
Lambda 콘솔에서 함수의 통합 테스트를 반복하는 것처럼 코드를 수정하거나 함수를 호출하는 CloudFront 트리거를 변경할 때 Lambda@Edge 자습서의 단계를 참조하세요. 예를 들어, 본 자습서의 단계([4단계: 함수를 실행할 CloudFront 트리거 추가](lambda-edge-how-it-works-tutorial.md#lambda-edge-how-it-works-tutorial-add-trigger))에서 설명하는 것처럼 다양한 버전의 함수에서 작동하는지 확인합니다.  
함수를 변경하고 배포할 때 업데이트된 함수 및 CloudFront 트리거가 모든 리전에서 복제되는 데 몇 분 정도 걸릴 수 있습니다. 일반적으로 몇 분이면 되지만 최대 15분까지 걸릴 수 있습니다.  
CloudFront 콘솔로 이동하여 해당 배포를 보고 복제가 완료되었는지 확인할 수 있습니다.  

**복제본 배포가 완료되었는지 확인하려면**

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

1. 배포 이름을 선택합니다.

1. 배포 상태가 **진행 중**에서 다시 **배포 완료**로 바뀌었는지 확인합니다. 이것은 함수가 복제되었다는 의미입니다. 이제 다음 단원의 단계에 따라 함수가 작동하는지 확인합니다.
콘솔의 테스트는 함수의 로직만 확인하며, Lambda@Edge에 고유한 모든 서비스 할당량(이전에는 제한이라고 함)은 적용하지 않습니다.

## CloudFront에서 Lambda@Edge 함수 오류 식별
<a name="lambda-edge-identifying-function-errors"></a>

함수 로직이 올바르게 작동하는지 확인한 후 CloudFront에서 함수 실행 시 HTTP 5xx 오류가 나타날 수 있습니다. HTTP 5xx 오류는 여러 가지 이유로 반환될 수 있습니다. 여기에는 Lambda 함수 오류 또는 CloudFront의 다른 문제가 포함될 수 있습니다.
+ Lambda@Edge 함수를 사용하는 경우 CloudFront 콘솔의 그래프를 사용하여 오류의 원인을 추적하고 문제를 해결할 수 있습니다. 예를 들어, HTTP 5xx 오류가 CloudFront 또는 Lambda 함수에 의해 발생한 것인지를 확인한 다음 특정 함수에 대해 관련 로그 파일을 검토하여 문제를 조사할 수 있습니다.
+ CloudFront에서 일반적인 HTTP 오류 문제를 해결하려면 [CloudFront의 오류 응답 상태 코드 문제 해결](troubleshooting-response-errors.md) 주제의 문제 해결 단계를 참조하세요.

### CloudFront에서 Lambda@Edge 함수 오류를 일으키는 원인
<a name="lambda-edge-testing-debugging-function-errors"></a>

Lambda 함수가 HTTP 5xx 오류를 일으키는 원인에는 여러 가지가 있으며, 수행해야 할 문제 해결 단계는 오류 유형에 따라 달라집니다. 오류는 다음과 같이 분류할 수 있습니다.

**Lambda 함수 실행 오류**  
함수에 처리되지 않은 예외가 있거나 코드에 오류가 있기 때문에 CloudFront가 Lambda에서 응답을 받지 못한 경우 실행 오류가 발생합니다. 예: 코드에 콜백이 포함된 경우(오류)

**잘못된 Lambda 함수 응답이 CloudFront로 반환됨**  
함수 실행 후 CloudFront가 Lambda에서 응답을 수신했습니다. 응답의 객체 구조가 [Lambda@Edge 이벤트 구조](lambda-event-structure.md)를 따르지 않거나 응답에 잘못된 헤더 또는 기타 잘못된 필드가 포함되어 있는 경우 오류가 반환됩니다.

**Lambda 서비스 할당량(이전에는 제한이라고 함)으로 인해 CloudFront에서의 실행이 제한됨**  
Lambda 서비스는 각 리전에서 실행을 조절하는데 할당량을 초과하면 오류를 반환합니다. 자세한 내용은 [Lambda@Edge에 대한 할당량](cloudfront-limits.md#limits-lambda-at-edge) 섹션을 참조하세요.

### 실패 유형을 결정하는 방법
<a name="lambda-edge-testing-debugging-failure-type"></a>

디버깅할 때 집중할 위치를 결정하고 CloudFront에서 반환한 오류를 해결하려면 CloudFront에서 HTTP 오류가 반환된 이유를 파악하는 것이 좋습니다. 시작하려면 AWS Management Console의 CloudFront 콘솔에 있는 **모니터링** 섹션에 제공된 그래프를 사용합니다. CloudFront 콘솔의 **모니터링(Monitoring)** 섹션에서 그래프를 보는 방법에 대한 자세한 내용은 [Amazon CloudWatch를 사용한 CloudFront 지표 모니터링](monitoring-using-cloudwatch.md) 단원을 참조하세요.

다음 그래프는 오리진 또는 Lambda 함수로 오류를 반환하는지 여부를 추적하고 Lambda 함수의 오류일 경우 문제 유형의 범위를 좁히려 할 때 특히 유용합니다.

**오류 발생율 그래프**  
각 배포의 **개요** 탭에서 볼 수 있는 그래프 중에는 **오류 발생율** 그래프가 있습니다. 이 그래프는 배포에 들어오는 총 요청의 백분율로 오류 발생율을 표시합니다. 그래프는 총 오류 발생율, 총 4xx 오류, 총 5xx 오류 및 Lambda 함수의 총 5xx 오류를 보여줍니다. 오류 유형 및 볼륨에 따라 원인을 조사하고 문제를 해결할 수 있는 단계를 수행할 수 있습니다.  

![\[CloudFront 배포에 대한 오류 발생율 그래프\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/Distribution-error-rate-pct-full.png)

+ Lambda 오류가 표시되면 함수가 반환하는 특정 유형의 오류를 확인하여 추가 조사를 수행할 수 있습니다. **Lambda@Edge errors(Lambda@Edge 오류)** 탭에는 함수 오류를 유형별로 분류하여 특정 함수에 대한 문제를 찾아낼 수 있는 그래프가 포함되어 있습니다.
+ CloudFront 오류가 표시되면 문제를 해결하고 오리진 오류를 수정하거나 CloudFront 구성을 변경할 수 있습니다. 자세한 내용은 [CloudFront의 오류 응답 상태 코드 문제 해결](troubleshooting-response-errors.md) 단원을 참조하세요.

**실행 오류 및 잘못된 함수 응답 그래프**  
**Lambda@Edge errors(Lambda@Edge 오류)** 탭에는 특정 배포에 대한 Lambda@Edge 오류를 유형별로 분류하는 그래프가 포함되어 있습니다. 예를 들어, 한 그래프는 모든 실행 오류를 AWS 리전별로 표시합니다.  
문제를 쉽게 해결할 수 있도록 특정 함수에 대한 로그 파일을 열고 리전별로 검토하여 특정 문제를 찾을 수 있습니다.  

**리전별로 특정 함수의 로그 파일을 보려면**

1. **Lambda@Edge 오류** 탭의 **관련 Lambda@Edge 함수**에서 함수 이름을 선택한 다음 **지표 보기**를 선택합니다.

1. 그런 다음, 함수 이름이 있는 페이지의 오른쪽 상단 모서리에서 **함수 로그 보기**를 선택한 다음 리전을 선택합니다.

   예를 들어 미국 서부(오레곤) 리전에 대한 **오류** 그래프에 문제가 있는 경우 드롭다운 목록에서 해당 리전을 선택합니다. 그러면 Amazon CloudWatch 콘솔이 열립니다.

1. 해당 리전의 CloudWatch 콘솔에서 **로그 스트림** 아래의 로그 스트림을 선택하여 함수에 대한 이벤트를 확인합니다.
또한 이 장의 다음 단원에서 오류 해결 및 수정에 대한 추가 권장 사항을 읽으십시오.

**제한 그래프**  
**Lambda@Edge errors(Lambda@Edge 오류)** 탭에는 **제한** 그래프도 있습니다. 경우에 따라 리전 동시성 할당량(이전에는 제한이라고 함)에 도달하면 Lambda 서비스가 리전별로 함수 호출을 제한합니다. 제한 초과 오류가 발생한 경우는 리전에서의 실행에 대해 Lambda 서비스가 부과한 할당량에 도달한 것입니다. 이러한 할당량을 늘리기 위한 요청 방법을 비롯한 자세한 내용은 [Lambda@Edge에 대한 할당량](cloudfront-limits.md#limits-lambda-at-edge) 단원을 참조하세요.  

![\[Lambda@Edge 함수 실행에 대한 제한 그래프\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/images/Lambda-throttles-page.png)


이 정보를 사용하여 HTTP 오류 문제를 해결하는 방법에 대한 예제는 [AWS에서 콘텐츠 전송을 디버깅하기 위한 네 가지 단계](https://aws.amazon.com/blogs/networking-and-content-delivery/four-steps-for-debugging-your-content-delivery-on-aws/)를 참조하세요.

## 잘못된 Lambda@Edge 함수 응답(검증 오류) 문제 해결
<a name="lambda-edge-testing-debugging-troubleshooting-invalid-responses"></a>

Lambda 확인 오류가 문제라고 파악한 경우는 Lambda 함수가 CloudFront에 잘못된 응답을 반환하고 있다는 의미입니다. 이 단원의 지침에 따라 함수를 검토하는 단계를 수행한 다음 응답이 CloudFront 요구 사항을 따르는지 확인하세요.

CloudFront는 다음 두 가지 방법으로 Lambda 함수의 응답을 확인합니다.
+ **Lambda 응답은 필수 객체 구조를 따라야 합니다.** 잘못된 객체 구조의 예에는 구문 분석이 불가능한 JSON, 필수 필드 누락 및 응답에 포함된 잘못된 객체 등이 있습니다. 자세한 내용은 [Lambda@Edge 이벤트 구조](lambda-event-structure.md) 단원을 참조하세요.
+ **응답에는 올바른 객체만 포함되어 있어야 합니다.** 응답에 올바른 객체가 포함되어 있는데 그 값이 지원되지 않는 경우에는 오류가 발생합니다. 등록된 헤더 또는 읽기 전용 헤더를 추가 또는 업데이트하는 경우([엣지 함수에 대한 제한 사항](edge-functions-restrictions.md) 참조), 최대 본문 크기 초과(Lambda@Edge [오류](lambda-generating-http-responses.md#lambda-generating-http-responses-errors) 주제에서 *생성된 응답 크기 제한* 참조) 및 잘못된 문자 또는 값([Lambda@Edge 이벤트 구조](lambda-event-structure.md) 참조) 등을 예로 들 수 있습니다.

Lambda가 CloudFront에 대해 유효하지 않은 응답을 반환하면 CloudFront가 Lambda 함수가 실행된 리전의 CloudWatch에 푸시하는 로그 파일에 오류 메시지가 기록됩니다. 잘못된 응답이 있는 경우 CloudWatch로 로그 파일을 보내는 것은 기본 동작입니다. 그러나 Lambda 함수를 릴리스하기 전에 CloudFront와 연결한 경우에는 함수에 대해 활성화되지 않을 수 있습니다. 자세한 내용은 이 주제 뒷부분에 나오는 *계정이 CloudWatch로 로그를 푸시하는지 확인*을 참조하세요.

CloudFront는 배포와 연결된 로그 그룹 내에서 함수가 실행되는 위치에 해당하는 리전으로 로그 파일을 푸시합니다. 로그 그룹의 형식은 `/aws/cloudfront/LambdaEdge/DistributionId`인데, 여기서 *DistributionId*는 배포 ID입니다. CloudWatch 로그 파일을 찾을 수 있는 리전을 확인하려면 이 주제 뒷부분에 나오는 *Lambda@Edge 리전 확인*을 참조하세요.

오류를 재현할 수 있는 경우 오류가 발생하는 새로운 요청을 생성한 다음 실패한 CloudFront 응답(`X-Amz-Cf-Id` 헤더)에서 해당 요청 ID를 찾아 로그 파일에서 단일 실패를 확인할 수 있습니다. 로그 파일 항목에는 오류가 반환된 이유를 파악하는 데 도움이 되는 정보가 포함되어 있고 해당하는 Lambda 요청 ID가 나열되어 있기 때문에 단일 요청의 컨텍스트 내에서 근본 원인을 분석할 수 있습니다.

오류가 간헐적으로 발생하는 경우에는 CloudFront 액세스 로그를 사용하여 실패한 요청의 요청 ID를 찾은 다음 CloudWatch 로그에서 해당하는 오류 메시지를 검색할 수 있습니다. 자세한 내용은 앞의 *실패 유형 확인* 단원을 참조하십시오.

## Lambda@Edge 함수 실행 오류 문제 해결
<a name="lambda-edge-testing-debugging-execution-errors"></a>

Lambda 실행 오류가 문제인 경우에는 Lambda 함수에 대한 로깅 문을 생성해 CloudWatch 로그 파일에 CloudFront에서 함수의 실행을 모니터링하는 메시지를 작성한 다음 예상대로 작동하는지 확인하면 도움이 될 수 있습니다. 그런 다음 CloudWatch 로그 파일에서 해당 문을 검색해 함수가 작동 중인지 확인할 수 있습니다.

**참고**  
Lambda@Edge 함수를 변경하지 않은 경우에도 Lambda 함수 실행 환경에 대한 업데이트가 영향을 줄 수 있으며, 실행 오류가 반환될 수 있습니다. 테스트 및 이후 버전으로의 마이그레이션에 대한 자세한 내용은 [AWS Lambda 및 AWS Lambda@Edge 실행 환경](https://aws.amazon.com/blogs/compute/upcoming-updates-to-the-aws-lambda-execution-environment/)에 대해 예정된 업데이트를 참조하세요.

## Lambda@Edge 리전 확인
<a name="lambda-edge-testing-debugging-determine-region"></a>

Lambda@Edge 함수가 트래픽을 수신하는 리전을 보려면 에서 CloudFront 콘솔의 함수에 대한 지표를 확인하세요AWS Management Console 지표는 각 AWS 리전별로 표시됩니다. 동일한 페이지에서 리전을 선택하고 해당 리전의 로그 파일을 확인하여 문제를 조사할 수 있습니다. CloudFront에서 Lambda 함수를 실행할 때 생성된 로그 파일을 확인하려면 올바른 AWS 리전의 CloudWatch Logs 파일을 검토해야 합니다.

CloudFront 콘솔의 **모니터링(Monitoring)** 섹션에서 그래프를 보는 방법에 대한 자세한 내용은 [Amazon CloudWatch를 사용한 CloudFront 지표 모니터링](monitoring-using-cloudwatch.md) 단원을 참조하세요.

## 계정이 CloudWatch로 로그를 푸시하는지 확인
<a name="lambda-edge-testing-debugging-cloudwatch-logs-enabled"></a>

기본적으로 CloudFront는 잘못된 Lambda 함수 응답 로깅을 활성화하고 [Lambda@Edge의 서비스 연결 역할](lambda-edge-permissions.md#using-service-linked-roles-lambda-edge) 중 하나를 수행해 로그 파일을 CloudWatch로 푸시합니다. 잘못된 Lambda 함수 응답 로그 기능이 활성화되기 전에 CloudFront에 Lambda@Edge 함수를 추가한 경우에는 예를 들어, CloudFront 트리거 추가 등과 같이 다음에 Lambda@Edge 구성을 업데이트하는 경우 로깅이 활성화됩니다.

다음을 수행해 계정에 대해 CloudWatch로 로그 파일 푸시 기능이 활성화되어 있는지 확인할 수 있습니다.
+ **CloudWatch에 로그가 나타나는지 확인** - Lambda @Edge 함수가 실행된 리전에서 로그 파일을 확인해야 합니다. 자세한 내용은 [Lambda@Edge 리전 확인](#lambda-edge-testing-debugging-determine-region) 섹션을 참조하세요.
+ **IAM의 계정에 관련 서비스 연결 역할이 있는지 확인** - 계정에 IAM 역할 `AWSServiceRoleForCloudFrontLogger`가 있어야 합니다. 이에 대한 자세한 내용은 [Lambda@Edge의 서비스 연결 역할](lambda-edge-permissions.md#using-service-linked-roles-lambda-edge) 섹션을 참조하세요.

# Lambda@Edge 함수 및 복제본 삭제
<a name="lambda-edge-delete-replicas"></a>

CloudFront에서 함수의 복제본이 삭제된 경우에만 Lambda@Edge 함수를 삭제할 수 있습니다. 다음과 같은 상황에서 Lambda 함수 복제본이 자동으로 삭제됩니다.
+ 함수의 복제본은 함수에 대한 마지막 연결을 모든 CloudFront 배포에서 제거한 후에 자동으로 삭제됩니다. 둘 이상의 배포에서 함수를 사용할 경우 마지막 배포에서 함수 연결이 제거된 후에만 복제본이 삭제됩니다.
+ 함수에 연결된 마지막 배포를 삭제한 후에도 복제본이 제거됩니다.

복제본은 일반적으로 몇 시간 내에 삭제됩니다. Lambda@Edge 함수 복제본은 수동으로 삭제할 수 없습니다. 따라서 아직 사용 중인 복제본이 삭제되어 오류가 발생하는 상황을 방지할 수 있습니다.

**주의**  
CloudFront 외부에서 Lambda@Edge 함수 복제본을 사용하는 애플리케이션을 빌드하지 마세요. 이러한 복제본은 배포와의 연결이 제거되거나 배포 자체가 삭제될 때 삭제됩니다. 이 경우 외부 애플리케이션에서 사용하는 복제본이 경고도 없이 제거되어 오류가 발생할 수 있습니다.

**CloudFront 배포에서 Lambda@Edge 함수 연결을 삭제하려면**

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

1. 삭제할 Lambda@Edge 함수 연결이 있는 배포의 ID를 선택합니다.

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

1. 삭제할 Lambda@Edge 함수 연결이 있는 캐시 동작을 선택한 다음 **편집**을 선택합니다.

1. **함수 연결**, **함수 유형**에서, **연결 없음**을 선택하여 Lambda@Edge 함수 연결을 삭제합니다.

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

CloudFront 배포에서 Lambda@Edge 함수 연결을 삭제한 후 선택적으로 에서 Lambda 함수 또는 함수 버전을 삭제할 수 있습니다AWS Lambda Lambda@Edge 함수 복제본을 정리할 수 있도록 함수 연결을 삭제한 후 몇 시간 정도 기다립니다. 그런 다음 Lambda 콘솔, AWS CLI, Lambda API 또는 AWS SDK를 사용하여 함수를 삭제할 수 있습니다.

버전에 연결된 CloudFront 배포가 없는 경우에는 특정 버전의 Lambda 함수를 삭제할 수도 있습니다.** Lambda 함수 버전에서 모든 연결을 제거한 뒤 몇 시간 정도 기다려 주세요. 그러면 해당 함수 버전을 삭제할 수 있습니다.

# Lambda@Edge 이벤트 구조
<a name="lambda-event-structure"></a>

다음 주제에서는 트리거될 때 CloudFront가 Lambda@Edge 함수에 전달하는 요청 및 응답 이벤트 객체에 대해 설명합니다.

**Topics**
+ [동적 원본 선택](#lambda-event-content-based-routing)
+ [이벤트 요청](#lambda-event-structure-request)
+ [응답 이벤트](#lambda-event-structure-response)

## 동적 원본 선택
<a name="lambda-event-content-based-routing"></a>

[캐시 동작의 경로 패턴](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern)을 사용하여 `images/*.jpg`와 같이 요청된 객체의 경로와 이름을 기반으로 오리진에 요청을 라우팅할 수 있습니다. 또한 Lambda@Edge를 사용하여 요청 헤더의 값과 같은 기타 특성을 기반으로 오리진에 요청을 라우팅할 수 있습니다.

여러 경우에 이러한 동적 오리진 선택이 유용할 수 있습니다. 예를 들어, 각기 다른 지리 영역에 있는 오리진에 걸쳐 요청을 배포하여 전역 로드 밸런싱에 도움이 될 수 있습니다. 또는 봇 처리, SEO 최적화, 인증 등과 같은 특정 기능을 서비스하는 각기 다른 오리진에 요청을 선택적으로 라우팅할 수 있습니다. 이 기능을 사용하는 방법을 보여주는 코드 예제는 [콘텐츠 기반 동적 원본 선택 - 예제](lambda-examples.md#lambda-examples-content-based-routing-examples) 단원을 참조하세요.

CloudFront 오리진 요청 이벤트에서 이벤트 구조의 오리진 `origin` 객체에는 요청이 경로 패턴을 기반으로 라우팅될 오리진에 대한 정보가 들어 있습니다. `origin` 객체의 값을 업데이트하여 요청을 다른 오리진으로 라우팅할 수 있습니다. `origin` 객체를 업데이트할 때 배포에서 오리진을 정의할 필요가 없습니다. 또한 Amazon S3 오리진 객체를 사용자 지정 오리진 객체로 바꿀 수 있으며, 그 반대의 경우도 마찬가지입니다. 요청당 하나의 오리진만 지정할 수 있습니다. 즉, 사용자 지정 오리진 또는 Amazon S3 오리진 중 하나를 지정할 수 있지만 둘 모두 지정할 수는 없습니다.

## 이벤트 요청
<a name="lambda-event-structure-request"></a>

다음 주제에서는 CloudFront가 [최종 사용자 및 오리진 요청 이벤트](lambda-cloudfront-trigger-events.md)에 대한 Lambda 함수에 전달하는 객체의 구조를 보여줍니다. 이 예제에서는 본문이 없는 `GET` 요청을 보여줍니다. 다음 예제는 최종 사용자 및 오리진 요청 이벤트에서 가능한 모든 필드의 목록입니다.

**Topics**
+ [뷰어 요청 예제](#example-viewer-request)
+ [원본 요청 예제](#example-origin-request)
+ [요청 이벤트 필드](#request-event-fields)

### 뷰어 요청 예제
<a name="example-viewer-request"></a>

다음 예제에서는 최종 사용자 요청 이벤트 객체를 보여줍니다.

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "viewer-request",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "host": [
              {
                "key": "Host",
                "value": "d111111abcdef8.cloudfront.net"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "curl/7.66.0"
              }
            ],
            "accept": [
              {
                "key": "accept",
                "value": "*/*"
              }
            ]
          },
          "method": "GET",
          "querystring": "",
          "uri": "/"
        }
      }
    }
  ]
}
```

### 원본 요청 예제
<a name="example-origin-request"></a>

다음 예제에서는 오리진 요청 이벤트 객체를 보여줍니다.

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "origin-request",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "x-forwarded-for": [
              {
                "key": "X-Forwarded-For",
                "value": "203.0.113.178"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "Amazon CloudFront"
              }
            ],
            "via": [
              {
                "key": "Via",
                "value": "2.0 2afae0d44e2540f472c0635ab62c232b.cloudfront.net (CloudFront)"
              }
            ],
            "host": [
              {
                "key": "Host",
                "value": "example.org"
              }
            ],
            "cache-control": [
              {
                "key": "Cache-Control",
                "value": "no-cache"
              }
            ]
          },
          "method": "GET",
          "origin": {
            "custom": {
              "customHeaders": {},
              "domainName": "example.org",
              "keepaliveTimeout": 5,
              "path": "",
              "port": 443,
              "protocol": "https",
              "readTimeout": 30,
              "responseCompletionTimeout": 30,
              "sslProtocols": [
                "TLSv1",
                "TLSv1.1",
                "TLSv1.2"
              ]
            }
          },
          "querystring": "",
          "uri": "/"
        }
      }
    }
  ]
}
```

### 요청 이벤트 필드
<a name="request-event-fields"></a>

요청 이벤트 객체 데이터는 두 개의 하위 객체(`config`(`Records.cf.config`) 및 `request`(`Records.cf.request`))에 포함되어 있습니다. 다음 목록에서는 각 하위 객체의 필드에 대해 설명합니다.

#### 구성 객체의 필드
<a name="request-event-fields-config"></a>

다음 표에서는 `config` 객체(`Records.cf.config`)의 필드에 대해 설명합니다.

**`distributionDomainName`(읽기 전용)**  
요청과 연결된 배포의 도메인 이름입니다.

**`distributionID`(읽기 전용)**  
요청과 관련이 있는 배포의 ID입니다.

**`eventType`(읽기 전용)**  
요청(`viewer-request` 또는 `origin-request`)과 관련된 트리거의 유형입니다.

**`requestId`(읽기 전용)**  
최종 사용자 요청/CloudFront 요청을 고유하게 식별하는 암호화된 문자열입니다. 또한 `requestId` 값은 CloudFront 액세스 로그에 `x-edge-request-id`로 표시됩니다. 자세한 내용은 [액세스 로그(표준 로그)](AccessLogs.md) 및 [로그 파일 필드](standard-logs-reference.md#BasicDistributionFileFormat) 단원을 참조하세요.

#### 요청 객체의 필드
<a name="request-event-fields-request"></a>

다음 표에서는 `request` 객체(`Records.cf.request`)의 필드에 대해 설명합니다.

**`clientIp`(읽기 전용)**  
요청을 생성한 최종 사용자의 IP 주소입니다. 최종 사용자가 HTTP 프록시 또는 로드 밸런서를 사용하여 요청을 전송한 경우 이 값은 프록시 또는 로드 밸런서의 IP 주소입니다.

**headers(읽기/쓰기)**  
요청의 헤더입니다. 다음을 참조하십시오.  
+ `headers` 객체 내 키는 표준 HTTP 헤더 이름의 소문자 버전입니다. 소문자 키를 사용하여 대/소문자를 구분하지 않고 헤더 값에 액세스할 수 있습니다.
+ 각 헤더 객체(예: `headers["accept"]` 또는 `headers["host"]`)는 키–값 페어의 어레이입니다. 해당 헤더에 대해 어레이에는 요청의 각 값에 대한 하나의 키–값 페어를 포함합니다.
+ `key`에는 HTTP 요청에 표시되는 헤더의 이름(대/소문자 구분)이 포함됩니다(예: `Host`, `User-Agent`, `X-Forwarded-For`, `Cookie` 등).
+ `value`에는 HTTP 요청에 표시되는 헤더 값을 포함합니다.
+ Lambda 함수가 요청 헤더를 추가하거나 수정하고 사용자가 헤더 `key` 필드를 포함시키지 않으면, Lambda@Edge는 사용자가 입력한 헤더 이름을 사용하여 헤더 `key`를 자동으로 삽입합니다. 헤더 이름의 형식을 어떻게 지정했든 상관없이, 자동으로 삽입된 헤더 키는 각 부분의 첫 문자가 대문자로 지정되고 각 부분이 하이픈(-)으로 구분됩니다.

  예를 들어 헤더를 다음과 같이 헤더 `key` 없이 추가할 수 있습니다.

  ```
  "user-agent": [
    {
      "value": "ExampleCustomUserAgent/1.X.0"
    }
  ]
  ```

  이 예제에서는 Lambda@Edge가 자동으로 `"key": "User-Agent"`을 삽입합니다.
헤더 사용 시 제한 사항에 대한 자세한 내용은 [엣지 함수에 대한 제한 사항](edge-functions-restrictions.md) 단원을 참조하십시오.

**`method`(읽기 전용)**  
요청의 HTTP 메서드.

**`querystring`(읽기/쓰기)**  
요청의 쿼리 문자열입니다(있는 경우). 요청에 쿼리 문자열이 포함되지 않더라도 이벤트 객체에는 여전히 빈 값과 함께 `querystring`이 포함됩니다. 쿼리 문자열에 대한 자세한 내용은 [쿼리 문자열 파라미터 기반의 콘텐츠 캐싱](QueryStringParameters.md) 단원을 참조하십시오.

**`uri`(읽기/쓰기)**  
요청된 객체의 상대 경로입니다. Lambda 함수가 `uri` 값을 수정하는 경우 다음 사항에 유의하십시오.  
+ 새 `uri` 값은 슬래시(/) 로 시작해야 합니다.
+ 함수가 `uri` 값을 변경하는 경우 이로 인해 최종 사용자가 요청 중인 객체가 변경됩니다.
+ 함수가 `uri` 값을 변경하는 경우 이로 인해 요청 또는 요청이 전송되는 오리진에 대한 캐시 동작이 *변경되지 않습니다*.

**`body`(읽기/쓰기)**  
HTTP 요청의 본문입니다. `body` 구조에는 다음과 같은 필드가 포함될 수 있습니다.    
**`inputTruncated`(읽기 전용)**  
Lambda@Edge가 본문을 잘랐는지 여부를 나타내는 부울 플래그. 자세한 내용은 [본문 포함 옵션이 적용된 요청 본문에 대한 제한 사항](lambda-at-edge-function-restrictions.md#lambda-at-edge-restrictions-request-body) 단원을 참조하세요.  
**`action`(읽기/쓰기)**  
본문을 사용해 수행하고자 한 작업. `action`의 옵션은 다음과 같습니다.  
+ `read-only:` 이 값이 기본값입니다. Lambda 함수에서 응답이 반환되었는데 `action`이 read-only이면, Lambda@Edge는 `encoding` 또는 `data`에 대한 모든 변경 사항을 무시합니다.
+ `replace:` 오리진으로 전송된 본문을 바꾸려는 경우 이 옵션을 지정합니다.  
**`encoding`(읽기/쓰기)**  
본문에 대한 인코딩. Lambda@Edge가 Lambda 함수에 본문을 노출시키는 경우 먼저 본문을 base64-encoding으로 변환합니다. 본문을 바꾸기 위해 `replace`에 `action`를 선택한 경우 `base64`(기본값) 또는 `text` 인코딩을 사용하도록 선택할 수 있습니다. `encoding`을 `base64`로 지정했지만 본문이 유효한 base64가 아닌 경우 CloudFront는 오류를 반환합니다.  
**`data`(읽기/쓰기)**  
요청 본문의 내용 

**`origin`(읽기/쓰기) (오리진 이벤트만 해당)**  
요청을 전송할 오리진입니다. `origin` 구조에는 *정확히 하나의 오리진*만 포함되어야 합니다. 즉, 오리진은 사용자 지정 오리진 또는 Amazon S3 오리진일 수 있습니다.  
지정하는 오리진 유형(사용자 지정 또는 Amazon S3 오리진)에 따라 요청에 다음 필드를 지정해야 합니다.    
**`customHeaders`(읽기/쓰기)(사용자 지정 및 Amazon S3 오리진)**  
(선택 사항) 각 사용자 지정 헤더에 대한 헤더 이름 및 값 페어를 지정하여 요청을 포함한 사용자 지정 헤더를 포함할 수 있습니다. 허용되지 않는 헤더는 추가할 수 없으며 동일한 이름의 헤더가 `Records.cf.request.headers`에 존재할 수 없습니다. [요청 헤더에 대한 노트](#request-event-fields-request-headers)는 사용자 지정 헤더에도 적용됩니다. 자세한 내용은 [CloudFront에서 오리진 요청에 추가할 수 없는 사용자 지정 헤더](add-origin-custom-headers.md#add-origin-custom-headers-denylist) 및 [엣지 함수에 대한 제한 사항](edge-functions-restrictions.md) 단원을 참조하세요.  
**`domainName`(읽기/쓰기)(사용자 지정 및 Amazon S3 오리진)**  
오리진의 도메인 이름입니다. 도메인 이름은 비워둘 수 없습니다.  
+ **사용자 지정 오리진의 경우** – DNS 도메인 이름을 지정합니다(예: `www.example.com`). 도메인 이름에는 콜론(:)이 포함될 수 없으며 IP 주소가 될 수 없습니다. 도메인 이름은 최대 253자일 수 있습니다.
+ **Amazon S3 오리진의 경우** – Amazon S3 버킷의 DNS 도메인 이름을 지정합니다(예: `amzn-s3-demo-bucket.s3.eu-west-1.amazonaws.com`). 이름은 최대 128자여야 하며, 모두 소문자여야 합니다.  
**`path`(읽기/쓰기)(사용자 지정 및 Amazon S3 오리진)**  
요청이 콘텐츠를 찾아야 하는 오리진의 디렉터리 경로입니다. 경로는 슬래시(/)로 시작해야 하지만 슬래시 하나로 끝나지 않아야 합니다(예: `example-path/`와 같이 끝나면 안 됨). 사용자 지정 오리진의 경우만, 경로는 URL로 인코딩되어야 하고 최대 길이는 255자여야 합니다.  
**`keepaliveTimeout`(읽기/쓰기) (사용자 지정 오리진만 해당)**  
CloudFront가 응답의 마지막 패킷을 수신한 후 오리진 연결을 유지하기 위해 시도해야 하는 시간(초)입니다. 값은 1\$1120(경계값 포함) 사이의 숫자여야 합니다.  
**`port`(읽기/쓰기) (사용자 지정 오리진만 해당)**  
CloudFront가 사용자 지정 오리진에서 연결해야 하는 포트입니다. 포트는 80, 443 또는 1024\$165535(경계값 포함) 사이의 숫자여야 합니다.  
**`protocol`(읽기/쓰기) (사용자 지정 오리진만 해당)**  
오리진에 연결할 때 CloudFront가 사용해야 하는 연결 프로토콜입니다. `http` 또는 `https` 값을 가질 수 있습니다.  
**`readTimeout`(읽기/쓰기)(사용자 지정 및 Amazon S3 오리진)**  
요청을 오리진으로 전송한 후 CloudFront가 응답을 대기해야 하는 시간(초)입니다. 또한 다음 패킷을 수신하기 전에 응답 패킷을 수신한 후 CloudFront가 대기해야 하는 시간도 지정합니다. 값은 1\$1120(경계값 포함) 사이의 숫자여야 합니다.  
더 높은 할당량이 필요한 경우 [오리진당 응답 제한 시간](cloudfront-limits.md#limits-web-distributions)을 참조하세요.  
**`responseCompletionTimeout`(읽기/쓰기)(사용자 지정 및 Amazon S3 오리진)**  
CloudFront에서 오리진으로의 요청이 열려 있고 응답을 기다릴 수 있는 시간(초). 이 시간까지 오리진에서 완전한 응답을 받지 못하면 CloudFront는 연결을 종료합니다.  
`responseCompletionTimeout` 값은 `readTimeout` 값과 같거나 이보다 커야 합니다. 이 값을 0으로 설정하면 이전에 설정한 모든 값이 제거되고 기본값으로 돌아갑니다. 이벤트 요청에서 `responseCompletionTimeout` 필드를 삭제하여 이 작업을 수행할 수도 있습니다.  
**`sslProtocols`(읽기/쓰기) (사용자 지정 오리진만 해당)**  
오리진과의 HTTPS 연결을 설정할 때 CloudFront가 사용할 수 있는 최소 SSL/TLS 프로토콜입니다. 값은 `TLSv1.2`, `TLSv1.1`, `TLSv1` 또는 `SSLv3` 중 하나일 수 있습니다.  
**`authMethod`(읽기/쓰기)(Amazon S3 오리진만 해당)**  
[오리진 액세스 ID(OAI)](private-content-restricting-access-to-s3.md#private-content-restricting-access-to-s3-oai)를 사용하는 경우 이 필드를 `origin-access-identity`로 설정합니다. OAI를 사용하지 않는 경우 `none`으로 설정합니다. `authMethod`를 `origin-access-identity`로 설정하면 다음과 같은 몇 가지 요구 사항이 있습니다.  
+ `region`을 지정해야 합니다(다음 필드 참조).
+ 하나의 Amazon S3 오리진에서 다른 오리진으로 요청을 변경할 때 동일한 OAI를 사용해야 합니다.
+ 사용자 지정 오리진에서 Amazon S3 오리진으로 요청을 변경할 때 OAI를 사용할 수 없습니다.
이 필드는 [오리진 액세스 제어(OAC)](private-content-restricting-access-to-s3.md)를 지원하지 않습니다.  
**`region`(읽기/쓰기)(Amazon S3 오리진만 해당)**  
Amazon S3 버킷의 AWS 리전입니다. 이 작업은 `authMethod`를 `origin-access-identity`로 설정한 경우에만 필요합니다.

## 응답 이벤트
<a name="lambda-event-structure-response"></a>

다음 주제에서는 CloudFront가 [최종 사용자 및 오리진 응답 이벤트](lambda-cloudfront-trigger-events.md)에 대한 Lambda 함수에 전달하는 객체의 구조를 보여줍니다. 다음 예제는 최종 사용자 및 오리진 응답 이벤트에서 가능한 모든 필드의 목록입니다.

**Topics**
+ [원본 응답 예제](#lambda-event-structure-response-origin)
+ [뷰어 응답 예제](#lambda-event-structure-response-viewer)
+ [응답 이벤트 필드](#response-event-fields)

### 원본 응답 예제
<a name="lambda-event-structure-response-origin"></a>

다음 예제에서는 오리진 응답 이벤트 객체를 보여줍니다.

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "origin-response",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "x-forwarded-for": [
              {
                "key": "X-Forwarded-For",
                "value": "203.0.113.178"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "Amazon CloudFront"
              }
            ],
            "via": [
              {
                "key": "Via",
                "value": "2.0 8f22423015641505b8c857a37450d6c0.cloudfront.net (CloudFront)"
              }
            ],
            "host": [
              {
                "key": "Host",
                "value": "example.org"
              }
            ],
            "cache-control": [
              {
                "key": "Cache-Control",
                "value": "no-cache"
              }
            ]
          },
          "method": "GET",
          "origin": {
            "custom": {
              "customHeaders": {},
              "domainName": "example.org",
              "keepaliveTimeout": 5,
              "path": "",
              "port": 443,
              "protocol": "https",
              "readTimeout": 30,
              "responseCompletionTimeout": 30,
              "sslProtocols": [
                "TLSv1",
                "TLSv1.1",
                "TLSv1.2"
              ]
            }
          },
          "querystring": "",
          "uri": "/"
        },
        "response": {
          "headers": {
            "access-control-allow-credentials": [
              {
                "key": "Access-Control-Allow-Credentials",
                "value": "true"
              }
            ],
            "access-control-allow-origin": [
              {
                "key": "Access-Control-Allow-Origin",
                "value": "*"
              }
            ],
            "date": [
              {
                "key": "Date",
                "value": "Mon, 13 Jan 2020 20:12:38 GMT"
              }
            ],
            "referrer-policy": [
              {
                "key": "Referrer-Policy",
                "value": "no-referrer-when-downgrade"
              }
            ],
            "server": [
              {
                "key": "Server",
                "value": "ExampleCustomOriginServer"
              }
            ],
            "x-content-type-options": [
              {
                "key": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ],
            "x-frame-options": [
              {
                "key": "X-Frame-Options",
                "value": "DENY"
              }
            ],
            "x-xss-protection": [
              {
                "key": "X-XSS-Protection",
                "value": "1; mode=block"
              }
            ],
            "content-type": [
              {
                "key": "Content-Type",
                "value": "text/html; charset=utf-8"
              }
            ],
            "content-length": [
              {
                "key": "Content-Length",
                "value": "9593"
              }
            ]
          },
          "status": "200",
          "statusDescription": "OK"
        }
      }
    }
  ]
}
```

### 뷰어 응답 예제
<a name="lambda-event-structure-response-viewer"></a>

다음 예제에서는 최종 사용자 응답 이벤트 객체를 보여줍니다.

```
{
  "Records": [
    {
      "cf": {
        "config": {
          "distributionDomainName": "d111111abcdef8.cloudfront.net",
          "distributionId": "EDFDVBD6EXAMPLE",
          "eventType": "viewer-response",
          "requestId": "4TyzHTaYWb1GX1qTfsHhEqV6HUDd_BzoBZnwfnvQc_1oF26ClkoUSEQ=="
        },
        "request": {
          "clientIp": "203.0.113.178",
          "headers": {
            "host": [
              {
                "key": "Host",
                "value": "d111111abcdef8.cloudfront.net"
              }
            ],
            "user-agent": [
              {
                "key": "User-Agent",
                "value": "curl/7.66.0"
              }
            ],
            "accept": [
              {
                "key": "accept",
                "value": "*/*"
              }
            ]
          },
          "method": "GET",
          "querystring": "",
          "uri": "/"
        },
        "response": {
          "headers": {
            "access-control-allow-credentials": [
              {
                "key": "Access-Control-Allow-Credentials",
                "value": "true"
              }
            ],
            "access-control-allow-origin": [
              {
                "key": "Access-Control-Allow-Origin",
                "value": "*"
              }
            ],
            "date": [
              {
                "key": "Date",
                "value": "Mon, 13 Jan 2020 20:14:56 GMT"
              }
            ],
            "referrer-policy": [
              {
                "key": "Referrer-Policy",
                "value": "no-referrer-when-downgrade"
              }
            ],
            "server": [
              {
                "key": "Server",
                "value": "ExampleCustomOriginServer"
              }
            ],
            "x-content-type-options": [
              {
                "key": "X-Content-Type-Options",
                "value": "nosniff"
              }
            ],
            "x-frame-options": [
              {
                "key": "X-Frame-Options",
                "value": "DENY"
              }
            ],
            "x-xss-protection": [
              {
                "key": "X-XSS-Protection",
                "value": "1; mode=block"
              }
            ],
            "age": [
              {
                "key": "Age",
                "value": "2402"
              }
            ],
            "content-type": [
              {
                "key": "Content-Type",
                "value": "text/html; charset=utf-8"
              }
            ],
            "content-length": [
              {
                "key": "Content-Length",
                "value": "9593"
              }
            ]
          },
          "status": "200",
          "statusDescription": "OK"
        }
      }
    }
  ]
}
```

### 응답 이벤트 필드
<a name="response-event-fields"></a>

응답 이벤트 객체 데이터는 세 개의 하위 객체(`config`(`Records.cf.config`), `request`(`Records.cf.request`) 및 `response`(`Records.cf.response`))에 포함되어 있습니다. 요청 객체의 필드에 대한 자세한 내용은 [요청 객체의 필드](#request-event-fields-request) 단원을 참조하세요. 다음 목록에서는 `config` 및 `response` 하위 객체의 필드에 대해 설명합니다.

#### 구성 객체의 필드
<a name="response-event-fields-config"></a>

다음 표에서는 `config` 객체(`Records.cf.config`)의 필드에 대해 설명합니다.

**`distributionDomainName`(읽기 전용)**  
응답과 연결된 배포의 도메인 이름입니다.

**`distributionID`(읽기 전용)**  
응답과 관련이 있는 배포의 ID입니다.

**`eventType`(읽기 전용)**  
응답과 관련된 트리거의 유형입니다(`origin-response` 또는 `viewer-response`).

**`requestId`(읽기 전용)**  
이 응답이 연결된 최종 사용자 요청/CloudFront 요청을 고유하게 식별하는 암호화된 문자열입니다. 또한 `requestId` 값은 CloudFront 액세스 로그에 `x-edge-request-id`로 표시됩니다. 자세한 내용은 [액세스 로그(표준 로그)](AccessLogs.md) 및 [로그 파일 필드](standard-logs-reference.md#BasicDistributionFileFormat) 단원을 참조하세요.

#### 응답 객체의 필드
<a name="response-event-fields-response"></a>

다음 표에서는 `response` 객체(`Records.cf.response`)의 필드에 대해 설명합니다. Lambda@Edge 함수를 사용하여 HTTP 응답을 생성하는 방법에 대한 자세한 내용은 [요청 트리거에서 HTTP 응답 생성](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests) 단원을 참조하세요.

**`headers`(읽기/쓰기)**  
응답의 헤더입니다. 다음을 참조하십시오.  
+ `headers` 객체 내 키는 표준 HTTP 헤더 이름의 소문자 버전입니다. 소문자 키를 사용하여 대/소문자를 구분하지 않고 헤더 값에 액세스할 수 있습니다.
+ 각 헤더 객체(예: `headers["content-type"]` 또는 `headers["content-length"]`)는 키–값 페어의 어레이입니다. 해당 헤더에 대해 어레이에는 응답의 각 값에 대한 하나의 키–값 페어를 포함합니다.
+ `key`에는 HTTP 응답에 표시되는 헤더의 대/소문자 구분 이름을 포함합니다(예: `Content-Type`, `Content-Length`, `Cookie`, 등).
+ `value`에는 HTTP 응답에 표시되는 헤더 값을 포함합니다.
+ Lambda 함수가 응답 헤더를 추가하거나 수정하고 사용자가 헤더 `key` 필드를 포함시키지 않으면, Lambda@Edge는 사용자가 입력한 헤더 이름을 사용하여 헤더 `key`를 자동으로 삽입합니다. 헤더 이름의 형식을 어떻게 지정했든 상관없이, 자동으로 삽입된 헤더 키는 각 부분의 첫 문자가 대문자로 지정되고 각 부분이 하이픈(-)으로 구분됩니다.

  예를 들어 헤더를 다음과 같이 헤더 `key` 없이 추가할 수 있습니다.

  ```
  "content-type": [
    {
      "value": "text/html;charset=UTF-8"
    }
  ]
  ```

  이 예제에서는 Lambda@Edge가 자동으로 `"key": "Content-Type"`을 삽입합니다.
헤더 사용 시 제한 사항에 대한 자세한 내용은 [엣지 함수에 대한 제한 사항](edge-functions-restrictions.md) 단원을 참조하십시오.

**`status`**  
응답의 HTTP 상태 코드입니다.

**`statusDescription`**  
응답의 HTTP 상태 설명입니다.

# 요청 및 응답 작업 수행
<a name="lambda-generating-http-responses"></a>

Lambda@Edge 요청 및 응답을 사용하려면 다음 주제를 참조하세요.

**Topics**
+ [오리진 장애 조치와 함께 Lambda@Edge 함수 사용](#lambda-and-origin-failover)
+ [요청 트리거에서 HTTP 응답 생성](#lambda-generating-http-responses-in-requests)
+ [오리진 응답 트리거에서 HTTP 응답 업데이트](#lambda-updating-http-responses)
+ [본문 포함 옵션을 선택해 요청 본문에 액세스](#lambda-include-body-access)

## 오리진 장애 조치와 함께 Lambda@Edge 함수 사용
<a name="lambda-and-origin-failover"></a>

예를 들어 고가용성 확보를 위해 구성하는 오리진 장애 조치에 대하여 오리진 그룹과 함께 설정한 CloudFront 배포와 함께 Lambda@Edge 함수를 사용할 수 있습니다. 오리진 그룹과 함께 Lambda 함수를 사용하려면, 캐시 동작을 생성할 때 오리진 그룹에 대한 오리진 요청 또는 오리진 응답 트리거에 함수를 지정합니다.

자세한 내용은 다음을 참조하세요.
+ **오리진 그룹 만들기:** [오리진 그룹 생성](high_availability_origin_failover.md#concept_origin_groups.creating)
+ **오리진 장애 조치가 Lambda@Edge와 함께 작동하는 방식:** [Lambda@Edge 함수와 함께 오리진 장애 조치 사용](high_availability_origin_failover.md#concept_origin_groups.lambda)

## 요청 트리거에서 HTTP 응답 생성
<a name="lambda-generating-http-responses-in-requests"></a>

CloudFront 요청을 수신할 때 Lambda 함수를 사용하여 CloudFront가 오리진에 응답을 전달하지 않고 최종 사용자에게 직접 반환하는 HTTP 응답을 생성할 수 있습니다. HTTP 응답을 생성하면 오리진에 대한 로드가 감소하고 일반적으로 최종 사용자에 대한 지연 시간 또한 감소합니다.

HTTP 응답 생성의 몇 가지 일반 시나리오는 다음을 포함합니다.
+ 최종 사용자에게 소규모 웹 페이지 반환
+ HTTP 301 또는 302 상태 코드를 반환하여 다른 웹 페이지로 사용자를 리디렉션
+ 사용자가 인증되지 않았을 때 최종 사용자에게 HTTP 401 상태 코드 반환

Lambda@Edge 함수는 다음 CloudFront 이벤트가 발생할 때 HTTP 응답을 생성할 수 있습니다.

**최종 사용자 요청 이벤트**  
최종 사용자 요청 이벤트에 의해 함수가 트리거될 때 CloudFront는 최종 사용자에게 응답을 반환하고 이를 캐싱하지 않습니다.

**오리진 요청 이벤트**  
오리진 요청 이벤트에 의해 함수가 트리거될 때 CloudFront는 함수에 의해 이전에 생성된 응답에 대한 엣지 캐시를 확인합니다.  
+ 응답이 캐시에 있는 경우 함수는 실행되지 않고 CloudFront는 캐싱된 응답을 최종 사용자에게 반환합니다.
+ 응답이 캐시에 없는 경우 함수는 실행되고 CloudFront는 캐싱된 응답을 최종 사용자에게 반환하며 이를 캐싱합니다.

HTTP 응답을 생성하는 몇 가지 샘플 코드를 보려면 [Lambda@Edge 예제 함수](lambda-examples.md) 단원을 참조합니다. 응답 트리거에서 HTTP 응답을 바꿀 수도 있습니다. 자세한 내용은 [오리진 응답 트리거에서 HTTP 응답 업데이트](#lambda-updating-http-responses) 단원을 참조합니다.

### 프로그래밍 모델
<a name="lambda-generating-http-responses-programming-model"></a>

이 단원에서는 Lambda@Edge를 사용하여 HTTP 응답을 생성하기 위한 프로그래밍 모델을 설명합니다.

**Topics**
+ [응답 객체](#lambda-generating-http-responses-object)
+ [오류](#lambda-generating-http-responses-errors)
+ [필수 필드](#lambda-generating-http-responses-required-fields)

#### 응답 객체
<a name="lambda-generating-http-responses-object"></a>

`result` 메서드의 `callback`파라미터로 반환한 응답은 다음 구조를 가져야 합니다(`status` 필드만이 필요함).

```
const response = {
    body: 'content',
    bodyEncoding: 'text' | 'base64',
    headers: {
        'header name in lowercase': [{
            key: 'header name in standard case',
            value: 'header value'
         }],
         ...
    },
    status: 'HTTP status code (string)',
    statusDescription: 'status description'
};
```

응답 객체에는 다음 값이 포함될 수 있습니다.

**`body`**  
CloudFront가 생성된 응답에서 반환하고자 하는 본문입니다.

**`bodyEncoding`**  
`body`에서 지정한 값에 대한 인코딩입니다. 유일하게 유효한 인코딩은 `text`과 `base64`입니다. `body` 객체에 `response`를 포함했지만 `bodyEncoding`을 누락한 경우 CloudFront는 본문을 텍스트로 처리합니다.  
`bodyEncoding`을 `base64`로 지정하지만 본문이 유효한 base64가 아닌 경우 CloudFront는 오류를 반환합니다.

**`headers`**  
CloudFront가 생성된 응답에서 반환하고자 하는 헤더입니다. 다음을 참조하십시오.  
+ `headers` 객체 내 키는 표준 HTTP 헤더 이름의 소문자 버전입니다. 소문자 키를 사용하여 대/소문자를 구분하지 않고 헤더 값에 액세스할 수 있습니다.
+ 각 헤더(예: `headers["accept"]` 또는 `headers["host"]`)는 키-값 페어의 어레이입니다. 해당 헤더에 대해 어레이에는 생성된 응답의 각 값에 대한 하나의 키-값 페어를 포함합니다.
+ `key`(선택사항)는 HTTP 요청에 표시되는 헤더의 대/소문자 구분 이름입니다(예: `accept` 또는 `host`).
+ `value`를 헤더 값으로 지정합니다.
+ 키-값 페어의 헤더 키 부분을 포함시키지 않으면 Lambda@Edge는 사용자가 입력한 헤더 이름을 사용하여 헤더 키를 자동으로 삽입합니다. 헤더 이름의 형식을 어떻게 지정했든 상관없이, 삽입된 헤더 키는 하이픈(-)으로 구분된 각 부분의 첫 문자가 자동으로 대문자로 지정됩니다.

  예를 들어 헤더를 다음과 같이 헤더 키 없이 추가할 수 있습니다. `'content-type': [{ value: 'text/html;charset=UTF-8' }]` 

  이 예제에서 Lambda@Edge는 다음과 같은 헤더 키를 생성합니다. `Content-Type` 
헤더 사용 시 제한 사항에 대한 자세한 내용은 [엣지 함수에 대한 제한 사항](edge-functions-restrictions.md) 단원을 참조하십시오.

**`status`**  
HTTP 상태 코드. 상태 코드를 문자열로 제공합니다. CloudFront는 다음에 대해 제공된 상태 코드를 사용합니다.  
+ 응답 시 반환
+ 오리진 요청 이벤트에 의해 트리거된 함수에 의해 응답이 생성되었을 때의 CloudFront 엣지 캐시에 있는 캐시
+ CloudFront [액세스 로그(표준 로그)](AccessLogs.md)에 로그인
`status` 값이 200\$1599가 아닌 경우 CloudFront는 최종 사용자에게 오류를 반환합니다.

**`statusDescription`**  
CloudFront가 응답에서 반환하고 HTTP 상태 코드를 포함하고자 하는 설명입니다. HTTP 상태 코드 200에 대해 `OK`와 같은 표준 설명을 사용할 필요는 없습니다.

#### 오류
<a name="lambda-generating-http-responses-errors"></a>

다음은 생성된 HTTP 응답에서 발생할 수 있는 오류입니다.

**본문을 포함하고 상태에 대해 204(콘텐츠 없음)을 지정한 응답**  
최종 사용자 요청 이벤트에 의해 함수가 트리거될 때 CloudFront는 다음 두 가지가 모두 true일 경우 HTTP 502 상태 코드(잘못된 게이트웨이)를 반환합니다.  
+ `status`의 기본값이 204(콘텐츠 없음)임
+ 응답에 `body`에 대한 값이 포함
이는 Lambda@Edge가 `HTTP 204` 응답에 메시지 본문이 포함될 필요가 없다고 명시한 RFC 2616의 선택적인 제한을 부과하기 때문입니다.

**생성된 응답의 크기 제한**  
Lambda 함수가 생성하는 응답의 최대 크기는 함수를 트리거한 이벤트에 따라 다릅니다.  
+ **최종 사용자 요청 이벤트** - 40KB
+ **오리진 요청 이벤트** - 1MB
응답이 허용된 크기보다 큰 경우 CloudFront는 최종 사용자에게 HTTP 502 상태 코드(잘못된 게이트웨이)를 반환합니다.

#### 필수 필드
<a name="lambda-generating-http-responses-required-fields"></a>

`status` 필드는 필수입니다.

다른 모든 필드는 선택 사항입니다.

## 오리진 응답 트리거에서 HTTP 응답 업데이트
<a name="lambda-updating-http-responses"></a>

CloudFront가 오리진 서버에서 HTTP 응답을 수신할 때 오리진 응답 트리거가 캐시 동작과 연결된 경우 HTTP 응답을 수정하여 오리진에서 반환된 것을 재정의할 수 있습니다.

HTTP 응답 업데이트의 몇 가지 일반 시나리오는 다음을 포함합니다.
+ 오리진이 오류 상태 코드(4xx 또는 5xx)를 반환할 때 상태를 변경하여 HTTP 200 상태 코드를 설정하고 정적 본문 콘텐츠를 생성하여 최종 사용자에게 반환합니다. 샘플 코드에 대한 내용은 [예시: 오리진 응답 트리거를 사용하여 오류 상태 코드를 200으로 업데이트](lambda-examples.md#lambda-examples-custom-error-static-body)를 참조하십시오.
+ 오리진이 오류 상태 코드(4xx 또는 5xx)를 반환할 때 상태를 변경하여 HTTP 301 또는 HTTP 302 상태 코드를 설정하고 사용자를 다른 웹 사이트로 리디렉션합니다. 샘플 코드에 대한 내용은 [예시: 오리진 응답 트리거를 사용하여 오류 상태 코드를 302로 업데이트](lambda-examples.md#lambda-examples-custom-error-new-site)를 참조하십시오.

**참고**  
함수는 `200`\$1`599`(경계값 포함) 사이의 상태 값을 반환해야 합니다. 그렇지 않으면 CloudFront가 최종 사용자에게 오류를 반환합니다.

최종 사용자 및 오리진 요청 이벤트에서 HTTP 응답을 바꿀 수도 있습니다. 자세한 내용은 [요청 트리거에서 HTTP 응답 생성](#lambda-generating-http-responses-in-requests) 섹션을 참조하세요.

HTTP 응답을 사용하여 작업 중일 때 Lambda@Edge는 오리진 서버에 의해 오리진 응답 트리거로 반환되는 본문을 공개하지 않습니다. 원하는 값으로 설정하여 정적 콘텐츠 본문을 생성하거나 값을 비어 있음으로 설정하여 함수 내부의 본문을 제거할 수 있습니다. 함수의 본문 필드를 업데이트하지 않은 경우 오리진 서버에서 반환된 원래 본문이 최종 사용자에게 반환됩니다.

## 본문 포함 옵션을 선택해 요청 본문에 액세스
<a name="lambda-include-body-access"></a>

Lambda 함수에서 액세스할 수 있도록 Lambda@Edge가 본문에 쓰기 가능한 HTTP 메서드(POST, PUT, DELETE 등)에 대한 요청을 노출하도록 선택할 수 있습니다. 읽기 전용 액세스 권한을 선택하거나 본문을 바꾸도록 지정할 수 있습니다.

이 옵션을 활성화하려면 함수에 대해 최종 사용자 요청 또는 오리진 요청 이벤트에 대해 실행되는 CloudFront 트리거를 생성할 때 **본문 포함**을 선택합니다. 자세한 내용은 [Lambda@Edge 함수에 대한 트리거 추가](lambda-edge-add-triggers.md) 단원을 참조하고, 함수에서 **본문 포함**을 사용하는 방법을 알아보려면 [Lambda@Edge 이벤트 구조](lambda-event-structure.md) 단원을 참조하세요.

이 기능을 사용하려는 시나리오는 다음과 같을 수 있습니다.
+ 오리진 서버로 고객 입력 데이터를 다시 보내지 않는 웹 양식(예: "문의처") 처리
+ 최종 사용자의 브라우저가 보낸 웹 비콘 데이터를 수집해 엣지에서 처리

샘플 코드에 대한 내용은 [Lambda@Edge 예제 함수](lambda-examples.md)를 참조하십시오.

**참고**  
요청 본문이 크면 Lambda@Edge가 자릅니다. 최대 크기 및 잘림에 대한 자세한 내용은 [본문 포함 옵션이 적용된 요청 본문에 대한 제한 사항](lambda-at-edge-function-restrictions.md#lambda-at-edge-restrictions-request-body) 단원을 참조하세요.

# Lambda@Edge 예제 함수
<a name="lambda-examples"></a>

Amazon CloudFront에서 Lambda 함수를 사용하려면 다음 예시를 참조하세요.

**참고**  
Lambda@Edge 함수에 대해 런타임 Node.js 18 이상을 선택하면 `index.mjs` 파일이 자동으로 생성됩니다. 다음 코드 예제를 사용하려면 `index.mjs` 파일의 이름을 `index.js`로 바꿉니다.

**Topics**
+ [일반 예제](#lambda-examples-general-examples)
+ [응답 생성 - 예시](#lambda-examples-generated-response-examples)
+ [쿼리 문자열 - 예시](#lambda-examples-query-string-examples)
+ [국가 또는 디바이스 유형 헤더별 콘텐츠 개인화 - 예제](#lambda-examples-redirecting-examples)
+ [콘텐츠 기반 동적 원본 선택 - 예제](#lambda-examples-content-based-routing-examples)
+ [오류 상태 업데이트 - 예시](#lambda-examples-update-error-status-examples)
+ [요청 본문 액세스 - 예시](#lambda-examples-access-request-body-examples)

## 일반 예제
<a name="lambda-examples-general-examples"></a>

다음 예시에서는 CloudFront에서 Lambda@Edge 를 사용하는 일반적인 방법을 보여줍니다.

**Topics**
+ [예: A/B 테스트](#lambda-examples-a-b-testing)
+ [예시: 응답 헤더 재정의](#lambda-examples-overriding-response-header)

### 예: A/B 테스트
<a name="lambda-examples-a-b-testing"></a>

다음 예제를 사용하여 리디렉션을 만들거나 URL을 변경하지 않고 두 가지 다른 버전의 이미지를 테스트할 수 있습니다. 이 예제는 최종 사용자 요청의 쿠키를 읽고 그에 따라 요청 URL을 수정합니다. 최종 사용자가 예상 값 중 하나와 함께 쿠키를 보내지 않는 경우, 이 예제에서는 최종 사용자를 URL 중 하나에 임의로 할당합니다.

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    if (request.uri !== '/experiment-pixel.jpg') {
        // do not process if this is not an A-B test request
        callback(null, request);
        return;
    }

    const cookieExperimentA = 'X-Experiment-Name=A';
    const cookieExperimentB = 'X-Experiment-Name=B';
    const pathExperimentA = '/experiment-group/control-pixel.jpg';
    const pathExperimentB = '/experiment-group/treatment-pixel.jpg';

    /*
     * Lambda at the Edge headers are array objects.
     *
     * Client may send multiple Cookie headers, i.e.:
     * > GET /viewerRes/test HTTP/1.1
     * > User-Agent: curl/7.18.1 (x86_64-unknown-linux-gnu) libcurl/7.18.1 OpenSSL/1.0.1u zlib/1.2.3
     * > Cookie: First=1; Second=2
     * > Cookie: ClientCode=abc
     * > Host: example.com
     *
     * You can access the first Cookie header at headers["cookie"][0].value
     * and the second at headers["cookie"][1].value.
     *
     * Header values are not parsed. In the example above,
     * headers["cookie"][0].value is equal to "First=1; Second=2"
     */
    let experimentUri;
    if (headers.cookie) {
        for (let i = 0; i < headers.cookie.length; i++) {
            if (headers.cookie[i].value.indexOf(cookieExperimentA) >= 0) {
                console.log('Experiment A cookie found');
                experimentUri = pathExperimentA;
                break;
            } else if (headers.cookie[i].value.indexOf(cookieExperimentB) >= 0) {
                console.log('Experiment B cookie found');
                experimentUri = pathExperimentB;
                break;
            }
        }
    }

    if (!experimentUri) {
        console.log('Experiment cookie has not been found. Throwing dice...');
        if (Math.random() < 0.75) {
            experimentUri = pathExperimentA;
        } else {
            experimentUri = pathExperimentB;
        }
    }

    request.uri = experimentUri;
    console.log(`Request uri set to "${request.uri}"`);
    callback(null, request);
};
```

------
#### [ Python ]

```
import json
import random

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    if request['uri'] != '/experiment-pixel.jpg':
        # Not an A/B Test
        return request

    cookieExperimentA, cookieExperimentB = 'X-Experiment-Name=A', 'X-Experiment-Name=B'
    pathExperimentA, pathExperimentB = '/experiment-group/control-pixel.jpg', '/experiment-group/treatment-pixel.jpg'

    '''
    Lambda at the Edge headers are array objects.

    Client may send multiple cookie headers. For example:
    > GET /viewerRes/test HTTP/1.1
    > User-Agent: curl/7.18.1 (x86_64-unknown-linux-gnu) libcurl/7.18.1 OpenSSL/1.0.1u zlib/1.2.3
    > Cookie: First=1; Second=2
    > Cookie: ClientCode=abc
    > Host: example.com

    You can access the first Cookie header at headers["cookie"][0].value
    and the second at headers["cookie"][1].value.

    Header values are not parsed. In the example above,
    headers["cookie"][0].value is equal to "First=1; Second=2"
    '''

    experimentUri = ""

    for cookie in headers.get('cookie', []):
        if cookieExperimentA in cookie['value']:
            print("Experiment A cookie found")
            experimentUri = pathExperimentA
            break
        elif cookieExperimentB in cookie['value']:
            print("Experiment B cookie found")
            experimentUri = pathExperimentB
            break

    if not experimentUri:
        print("Experiment cookie has not been found. Throwing dice...")
        if random.random() < 0.75:
            experimentUri = pathExperimentA
        else:
            experimentUri = pathExperimentB

    request['uri'] = experimentUri
    print(f"Request uri set to {experimentUri}")
    return request
```

------

### 예시: 응답 헤더 재정의
<a name="lambda-examples-overriding-response-header"></a>

다음 예제는 다른 헤더의 값을 기준으로 응답 헤더의 값을 변경하는 방법을 보여줍니다.

------
#### [ Node.js ]

```
export const handler = async (event) => {
    const response = event.Records[0].cf.response;
    const headers = response.headers;

    const headerNameSrc = 'X-Amz-Meta-Last-Modified';
    const headerNameDst = 'Last-Modified';

    if (headers[headerNameSrc.toLowerCase()]) {
        headers[headerNameDst.toLowerCase()] = [{
            key: headerNameDst,
            value: headers[headerNameSrc.toLowerCase()][0].value,
        }];
        console.log(`Response header "${headerNameDst}" was set to ` +
                    `"${headers[headerNameDst.toLowerCase()][0].value}"`);
    }

    return response;
};
```

------
#### [ Python ]

```
import json 

def lambda_handler(event, context):
    response = event['Records'][0]['cf']['response']
    headers = response['headers']
    
    header_name_src = 'X-Amz-Meta-Last-Modified'
    header_name_dst = 'Last-Modified'
    
    if headers.get(header_name_src.lower()):
        headers[header_name_dst.lower()] = [{
            'key': header_name_dst,
            'value': headers[header_name_src.lower()][0]['value']
        }]
        print(f'Response header "{header_name_dst}" was set to '
              f'"{headers[header_name_dst.lower()][0]["value"]}"')
    
    return response
```

------

## 응답 생성 - 예시
<a name="lambda-examples-generated-response-examples"></a>

다음 예시에서는 Lambda@Edge를 사용하여 응답을 생성하는 방법을 보여줍니다.

**Topics**
+ [예시: 정적 콘텐츠 제공(생성된 응답)](#lambda-examples-static-web-server)
+ [예: HTTP 리디렉션 생성(생성된 응답)](#lambda-examples-http-redirect)

### 예시: 정적 콘텐츠 제공(생성된 응답)
<a name="lambda-examples-static-web-server"></a>

다음 예제는 Lambda 함수를 사용하여 정적 웹사이트 콘텐츠를 서비스하는 방법을 보여줍니다. 이는 오리진 서버에 대한 로드를 줄이고 전체 지연 시간을 단축합니다.

**참고**  
최종 사용자 요청 및 오리진 요청 이벤트에 대해 HTTP 응답을 만들 수 있습니다. 자세한 내용은 [요청 트리거에서 HTTP 응답 생성](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests) 섹션을 참조하세요.  
원본 응답 이벤트에서 HTTP 응답의 본문을 바꾸거나 제거할 수도 있습니다. 자세한 내용은 [오리진 응답 트리거에서 HTTP 응답 업데이트](lambda-generating-http-responses.md#lambda-updating-http-responses) 섹션을 참조하세요.

------
#### [ Node.js ]

```
'use strict';

const content = `
<\!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Simple Lambda@Edge Static Content Response</title>
  </head>
  <body>
    <p>Hello from Lambda@Edge!</p>
  </body>
</html>
`;

exports.handler = (event, context, callback) => {
    /*
     * Generate HTTP OK response using 200 status code with HTML body.
     */
    const response = {
        status: '200',
        statusDescription: 'OK',
        headers: {
            'cache-control': [{
                key: 'Cache-Control',
                value: 'max-age=100'
            }],
            'content-type': [{
                key: 'Content-Type',
                value: 'text/html'
            }]
        },
        body: content,
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
import json

CONTENT = """
<\!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Simple Lambda@Edge Static Content Response</title>
</head>
<body>
    <p>Hello from Lambda@Edge!</p>
</body>
</html>
"""

def lambda_handler(event, context):
    # Generate HTTP OK response using 200 status code with HTML body.
    response = {
        'status': '200',
        'statusDescription': 'OK',
        'headers': {
            'cache-control': [
                {
                    'key': 'Cache-Control',
                    'value': 'max-age=100'
                }
            ],
            "content-type": [
                {
                    'key': 'Content-Type',
                    'value': 'text/html'
                }
            ]
        },
        'body': CONTENT
    }
    return response
```

------

### 예: HTTP 리디렉션 생성(생성된 응답)
<a name="lambda-examples-http-redirect"></a>

다음 예제는 HTTP 리디렉션을 만드는 방법을 보여줍니다.

**참고**  
최종 사용자 요청 및 오리진 요청 이벤트에 대해 HTTP 응답을 만들 수 있습니다. 자세한 내용은 [요청 트리거에서 HTTP 응답 생성](lambda-generating-http-responses.md#lambda-generating-http-responses-in-requests) 섹션을 참조하세요.

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    /*
     * Generate HTTP redirect response with 302 status code and Location header.
     */
    const response = {
        status: '302',
        statusDescription: 'Found',
        headers: {
            location: [{
                key: 'Location',
                value: 'https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html',
            }],
        },
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):

    # Generate HTTP redirect response with 302 status code and Location header.

    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': 'https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html'
            }]
        }
    }

    return response
```

------

## 쿼리 문자열 - 예시
<a name="lambda-examples-query-string-examples"></a>

다음 예시에서는 Lambda@Edge를 쿼리 문자열과 함께 사용할 수 있는 방법이 포함되어 있습니다.

**Topics**
+ [예시: 쿼리 문자열 파라미터를 기반으로 헤더 추가](#lambda-examples-header-based-on-query-string)
+ [예시: 쿼리 문자열 파라미터를 정규화하여 캐시 적중률 향상](#lambda-examples-normalize-query-string-parameters)
+ [예시: 인증되지 않은 사용자를 로그인 페이지로 리디렉션](#lambda-examples-redirect-to-signin-page)

### 예시: 쿼리 문자열 파라미터를 기반으로 헤더 추가
<a name="lambda-examples-header-based-on-query-string"></a>

다음 예제에서는 쿼리 문자열 파라미터의 키-값 페어를 가져오고 그 값을 토대로 헤더를 추가하는 방법을 보여줍니다.

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    
    /* When a request contains a query string key-value pair but the origin server
     * expects the value in a header, you can use this Lambda function to
     * convert the key-value pair to a header. Here's what the function does:
     * 1. Parses the query string and gets the key-value pair.
     * 2. Adds a header to the request using the key-value pair that the function got in step 1.
     */

    /* Parse request querystring to get javascript object */
    const params = querystring.parse(request.querystring);

    /* Move auth param from querystring to headers */
    const headerName = 'Auth-Header';
    request.headers[headerName.toLowerCase()] = [{ key: headerName, value: params.auth }];
    delete params.auth;

    /* Update request querystring */
    request.querystring = querystring.stringify(params);

    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs, urlencode

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    '''
    When a request contains a query string key-value pair but the origin server
    expects the value in a header, you can use this Lambda function to
    convert the key-value pair to a header. Here's what the function does:
        1. Parses the query string and gets the key-value pair.
        2. Adds a header to the request using the key-value pair that the function got in step 1.
    '''

    # Parse request querystring to get dictionary/json
    params = {k : v[0] for k, v in parse_qs(request['querystring']).items()}

    # Move auth param from querystring to headers
    headerName = 'Auth-Header'
    request['headers'][headerName.lower()] = [{'key': headerName, 'value': params['auth']}]
    del params['auth']

    # Update request querystring
    request['querystring'] = urlencode(params)

    return request
```

------

### 예시: 쿼리 문자열 파라미터를 정규화하여 캐시 적중률 향상
<a name="lambda-examples-normalize-query-string-parameters"></a>

다음 예제에서는 CloudFront가 요청을 오리진에 전달하기 전에 쿼리 문자열을 다음과 같이 변경하여 캐시 적중률을 향상하는 방법을 보여 줍니다.
+ 파라미터 이름을 기준으로 키-값 페어를 알파벳순으로 정렬
+ 키-값 페어의 대/소문자를 소문자로 변경

자세한 내용은 [쿼리 문자열 파라미터 기반의 콘텐츠 캐싱](QueryStringParameters.md) 섹션을 참조하세요.

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    /* When you configure a distribution to forward query strings to the origin and
     * to cache based on an allowlist of query string parameters, we recommend
     * the following to improve the cache-hit ratio:
     * - Always list parameters in the same order.
     * - Use the same case for parameter names and values.
     *
     * This function normalizes query strings so that parameter names and values
     * are lowercase and parameter names are in alphabetical order.
     *
     * For more information, see:
     * https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html
     */

    console.log('Query String: ', request.querystring);

    /* Parse request query string to get javascript object */
    const params = querystring.parse(request.querystring.toLowerCase());
    const sortedParams = {};

    /* Sort param keys */
    Object.keys(params).sort().forEach(key => {
        sortedParams[key] = params[key];
    });

    /* Update request querystring with normalized  */
    request.querystring = querystring.stringify(sortedParams);

    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs, urlencode

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    '''
    When you configure a distribution to forward query strings to the origin and
    to cache based on an allowlist of query string parameters, we recommend
    the following to improve the cache-hit ratio:
    Always list parameters in the same order.
    - Use the same case for parameter names and values.

    This function normalizes query strings so that parameter names and values
    are lowercase and parameter names are in alphabetical order.

    For more information, see:
    https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/QueryStringParameters.html
    '''
    print("Query string: ", request["querystring"])

    # Parse request query string to get js object
    params = {k : v[0] for k, v in parse_qs(request['querystring'].lower()).items()}

    # Sort param keys
    sortedParams = sorted(params.items(), key=lambda x: x[0])

    # Update request querystring with normalized
    request['querystring'] = urlencode(sortedParams)
    
    return request
```

------

### 예시: 인증되지 않은 사용자를 로그인 페이지로 리디렉션
<a name="lambda-examples-redirect-to-signin-page"></a>

다음 예제에서는 사용자가 자격 증명을 입력하지 않은 경우 사용자를 로그인 페이지로 리디렉션하는 방법을 보여 줍니다.

------
#### [ Node.js ]

```
'use strict';

function parseCookies(headers) {
    const parsedCookie = {};
    if (headers.cookie) {
        headers.cookie[0].value.split(';').forEach((cookie) => {
            if (cookie) {
                const parts = cookie.split('=');
                parsedCookie[parts[0].trim()] = parts[1].trim();
            }
        });
    }
    return parsedCookie;
}

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    /* Check for session-id in request cookie in viewer-request event,
     * if session-id is absent, redirect the user to sign in page with original
     * request sent as redirect_url in query params.
     */

    /* Check for session-id in cookie, if present then proceed with request */
    const parsedCookies = parseCookies(headers);
    if (parsedCookies && parsedCookies['session-id']) {
        callback(null, request);
        return;
    }

    /* URI encode the original request to be sent as redirect_url in query params */
    const encodedRedirectUrl = encodeURIComponent(`https://${headers.host[0].value}${request.uri}?${request.querystring}`);
    const response = {
        status: '302',
        statusDescription: 'Found',
        headers: {
            location: [{
                key: 'Location',
                value: `https://www.example.com/signin?redirect_url=${encodedRedirectUrl}`,
            }],
        },
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
import urllib

def parseCookies(headers):
    parsedCookie = {}
    if headers.get('cookie'):
        for cookie in headers['cookie'][0]['value'].split(';'):
            if cookie:
                parts = cookie.split('=')
                parsedCookie[parts[0].strip()] = parts[1].strip()
    return parsedCookie

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    '''
    Check for session-id in request cookie in viewer-request event,
    if session-id is absent, redirect the user to sign in page with original
    request sent as redirect_url in query params.
    '''

    # Check for session-id in cookie, if present, then proceed with request
    parsedCookies = parseCookies(headers)

    if parsedCookies and parsedCookies['session-id']:
        return request

    # URI encode the original request to be sent as redirect_url in query params
    redirectUrl = "https://%s%s?%s" % (headers['host'][0]['value'], request['uri'], request['querystring'])
    encodedRedirectUrl = urllib.parse.quote_plus(redirectUrl.encode('utf-8'))

    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': 'https://www.example.com/signin?redirect_url=%s' % encodedRedirectUrl
            }]
        }
    }
    return response
```

------

## 국가 또는 디바이스 유형 헤더별 콘텐츠 개인화 - 예제
<a name="lambda-examples-redirecting-examples"></a>

다음 예시에서는 Lambda@Edge를 사용하여 뷰어가 사용하는 위치나 장치 유형에 따라 동작을 사용자 정의하는 방법을 보여줍니다.

**Topics**
+ [예시: 최종 사용자 요청을 국가별 URL로 리디렉션](#lambda-examples-redirect-based-on-country)
+ [예시: 디바이스를 기반으로 객체의 다양한 버전 제공](#lambda-examples-vary-on-device-type)

### 예시: 최종 사용자 요청을 국가별 URL로 리디렉션
<a name="lambda-examples-redirect-based-on-country"></a>

다음 예제에서는 국가별 URL이 포함된 HTTP 리디렉션 응답을 생성하고 해당 응답을 최종 사용자에게 반환하는 방법을 보여 줍니다. 이 작업은 국가별 응답을 제공하려는 경우에 유용합니다. 예:
+ 국가별 하위 도메인이 있는 경우(예: us.example.com 및 tw.example.com) 최종 사용자가 example.com을 요청할 때 리디렉션 응답을 생성할 수 있습니다.
+ 비디오를 스트리밍하지만 특정 국가에서 콘텐츠를 스트리밍할 권한이 없는 경우 비디오를 볼 수 없는 이유를 설명하는 페이지로 해당 국가의 사용자를 리디렉션할 수 있습니다.

다음을 참조하십시오.
+ `CloudFront-Viewer-Country` 헤더 값을 기반으로 캐시하도록 배포를 구성해야 합니다. 자세한 내용은 [선택한 요청 헤더 기반의 캐시](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders) 단원을 참조하세요.
+ CloudFront는 최종 사용자 요청 이벤트 뒤에 `CloudFront-Viewer-Country` 헤더를 추가합니다. 이 예제를 사용하려면 오리진 요청 이벤트에 대한 트리거를 생성해야 합니다.

------
#### [ Node.js ]

```
'use strict';

/* This is an origin request function */
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    /*
     * Based on the value of the CloudFront-Viewer-Country header, generate an
     * HTTP status code 302 (Redirect) response, and return a country-specific
     * URL in the Location header.
     * NOTE: 1. You must configure your distribution to cache based on the
     *          CloudFront-Viewer-Country header. For more information, see
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
     *       2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
     *          request event. To use this example, you must create a trigger for the
     *          origin request event.
     */

    let url = 'https://example.com/';
    if (headers['cloudfront-viewer-country']) {
        const countryCode = headers['cloudfront-viewer-country'][0].value;
        if (countryCode === 'TW') {
            url = 'https://tw.example.com/';
        } else if (countryCode === 'US') {
            url = 'https://us.example.com/';
        }
    }

    const response = {
        status: '302',
        statusDescription: 'Found',
        headers: {
            location: [{
                key: 'Location',
                value: url,
            }],
        },
    };
    callback(null, response);
};
```

------
#### [ Python ]

```
# This is an origin request function

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    '''
    Based on the value of the CloudFront-Viewer-Country header, generate an
    HTTP status code 302 (Redirect) response, and return a country-specific
    URL in the Location header.
    NOTE: 1. You must configure your distribution to cache based on the
            CloudFront-Viewer-Country header. For more information, see
            https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
          2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
            request event. To use this example, you must create a trigger for the
            origin request event.
    '''

    url = 'https://example.com/'
    viewerCountry = headers.get('cloudfront-viewer-country')
    if viewerCountry:
        countryCode = viewerCountry[0]['value']
        if countryCode == 'TW':
            url = 'https://tw.example.com/'
        elif countryCode == 'US':
            url = 'https://us.example.com/'

    response = {
        'status': '302',
        'statusDescription': 'Found',
        'headers': {
            'location': [{
                'key': 'Location',
                'value': url
            }]
        }
    }

    return response
```

------

### 예시: 디바이스를 기반으로 객체의 다양한 버전 제공
<a name="lambda-examples-vary-on-device-type"></a>

다음 예제에서는 사용자가 사용 중인 디바이스 유형(예: 모바일 디바이스 또는 태블릿)을 기반으로 객체의 다양한 버전을 서비스하는 방법을 보여 줍니다. 다음을 참조하십시오.
+ `CloudFront-Is-*-Viewer` 헤더 값을 기반으로 캐시하도록 배포를 구성해야 합니다. 자세한 내용은 [선택한 요청 헤더 기반의 캐시](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders) 단원을 참조하세요.
+ CloudFront는 최종 사용자 요청 이벤트 뒤에 `CloudFront-Is-*-Viewer` 헤더를 추가합니다. 이 예제를 사용하려면 오리진 요청 이벤트에 대한 트리거를 생성해야 합니다.

------
#### [ Node.js ]

```
'use strict';

/* This is an origin request function */
exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    /*
     * Serve different versions of an object based on the device type.
     * NOTE: 1. You must configure your distribution to cache based on the
     *          CloudFront-Is-*-Viewer headers. For more information, see
     *          the following documentation:
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-device-type
     *       2. CloudFront adds the CloudFront-Is-*-Viewer headers after the viewer
     *          request event. To use this example, you must create a trigger for the
     *          origin request event.
     */

    const desktopPath = '/desktop';
    const mobilePath = '/mobile';
    const tabletPath = '/tablet';
    const smarttvPath = '/smarttv';

    if (headers['cloudfront-is-desktop-viewer']
        && headers['cloudfront-is-desktop-viewer'][0].value === 'true') {
        request.uri = desktopPath + request.uri;
    } else if (headers['cloudfront-is-mobile-viewer']
               && headers['cloudfront-is-mobile-viewer'][0].value === 'true') {
        request.uri = mobilePath + request.uri;
    } else if (headers['cloudfront-is-tablet-viewer']
               && headers['cloudfront-is-tablet-viewer'][0].value === 'true') {
        request.uri = tabletPath + request.uri;
    } else if (headers['cloudfront-is-smarttv-viewer']
               && headers['cloudfront-is-smarttv-viewer'][0].value === 'true') {
        request.uri = smarttvPath + request.uri;
    }
    console.log(`Request uri set to "${request.uri}"`);

    callback(null, request);
};
```

------
#### [ Python ]

```
# This is an origin request function
def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    '''
    Serve different versions of an object based on the device type.
    NOTE: 1. You must configure your distribution to cache based on the
            CloudFront-Is-*-Viewer headers. For more information, see
            the following documentation:
            https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
            https://docs.aws.amazon.com/console/cloudfront/cache-on-device-type
          2. CloudFront adds the CloudFront-Is-*-Viewer headers after the viewer
            request event. To use this example, you must create a trigger for the
            origin request event.
    '''

    desktopPath = '/desktop';
    mobilePath = '/mobile';
    tabletPath = '/tablet';
    smarttvPath = '/smarttv';

    if 'cloudfront-is-desktop-viewer' in headers and headers['cloudfront-is-desktop-viewer'][0]['value'] == 'true':
        request['uri'] = desktopPath + request['uri']
    elif 'cloudfront-is-mobile-viewer' in headers and headers['cloudfront-is-mobile-viewer'][0]['value'] == 'true':
        request['uri'] = mobilePath + request['uri']
    elif 'cloudfront-is-tablet-viewer' in headers and headers['cloudfront-is-tablet-viewer'][0]['value'] == 'true':
        request['uri'] = tabletPath + request['uri']
    elif 'cloudfront-is-smarttv-viewer' in headers and headers['cloudfront-is-smarttv-viewer'][0]['value'] == 'true':
        request['uri'] = smarttvPath + request['uri']

    print("Request uri set to %s" % request['uri'])

    return request
```

------

## 콘텐츠 기반 동적 원본 선택 - 예제
<a name="lambda-examples-content-based-routing-examples"></a>

다음 예시에서는 Lambda@Edge를 사용하여 요청 정보를 기반으로 다른 오리진으로 라우팅하는 방법을 보여줍니다.

**Topics**
+ [예시: 오리진 요청 트리거를 사용하여 사용자 지정 오리진에서 Amazon S3 오리진으로 변경](#lambda-examples-content-based-S3-origin-based-on-query)
+ [예시: 오리진 요청 트리거를 사용하여 Amazon S3 오리진 리전 변경](#lambda-examples-content-based-S3-origin-request-trigger)
+ [예시: 오리진 요청 트리거를 사용하여 Amazon S3 오리진에서 사용자 지정 오리진으로 변경](#lambda-examples-content-based-custom-origin-request-trigger)
+ [예시: 오리진 요청 트리거를 사용하여 하나의 Amazon S3 버킷에서 다른 버킷으로 점진적으로 트래픽 전송](#lambda-examples-content-based-gradual-traffic-transfer)
+ [예시: 오리진 요청 트리거를 사용하여 국가 헤더를 기반으로 오리진 도메인 이름 변경](#lambda-examples-content-based-geo-header)

### 예시: 오리진 요청 트리거를 사용하여 사용자 지정 오리진에서 Amazon S3 오리진으로 변경
<a name="lambda-examples-content-based-S3-origin-based-on-query"></a>

이 함수는 오리진 요청 트리거를 사용하여 사용자 지정 오리진에서 콘텐츠를 요청 속성을 기반으로 가져오는 Amazon S3 오리진으로 변경하는 방법을 보여줍니다.

------
#### [ Node.js ]

```
'use strict';

 const querystring = require('querystring');
 
 exports.handler = (event, context, callback) => {
     const request = event.Records[0].cf.request;
 
     /**
      * Reads query string to check if S3 origin should be used, and
      * if true, sets S3 origin properties.
      */
 
     const params = querystring.parse(request.querystring);
 
     if (params['useS3Origin']) {
         if (params['useS3Origin'] === 'true') {
             const s3DomainName = 'amzn-s3-demo-bucket.s3.amazonaws.com';
 
             /* Set S3 origin fields */
             request.origin = {
                 s3: {
                     domainName: s3DomainName,
                     region: '',
                     authMethod: 'origin-access-identity',
                     path: '',
                     customHeaders: {}
                 }
             };
             request.headers['host'] = [{ key: 'host', value: s3DomainName}];
         }
     }
     
    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    '''
    Reads query string to check if S3 origin should be used, and
    if true, sets S3 origin properties
    '''
    params = {k: v[0] for k, v in parse_qs(request['querystring']).items()}
    if params.get('useS3Origin') == 'true':
        s3DomainName = 'amzn-s3-demo-bucket.s3.amazonaws.com'

        # Set S3 origin fields
        request['origin'] = {
            's3': {
                'domainName': s3DomainName,
                'region': '',
                'authMethod': 'origin-access-identity',
                'path': '',
                'customHeaders': {}
            }
        }
        request['headers']['host'] = [{'key': 'host', 'value': s3DomainName}]
    return request
```

------

### 예시: 오리진 요청 트리거를 사용하여 Amazon S3 오리진 리전 변경
<a name="lambda-examples-content-based-S3-origin-request-trigger"></a>

이 함수는 오리진 요청 트리거를 사용하여 콘텐츠를 요청 속성을 기반으로 가져오는 Amazon S3 오리진을 변경하는 방법을 보여줍니다.

이 예제에서는 `CloudFront-Viewer-Country` 헤더 값을 사용하여 뷰어에게 더 가까운 리전의 버킷으로 S3 버킷 도메인 이름을 업데이트합니다. 이는 여러 방법에서 유용할 수 있습니다.
+ 지정된 리전이 최종 사용자의 국가와 더욱 근접할 때 지연 시간을 감소합니다.
+ 데이터가 요청이 온 곳과 동일한 국가에 있는 리전에서 서비스되는지 확인함으로써 데이터 주권을 제공합니다.

이 예제를 활용하려면 다음과 같이 해야 합니다.
+ `CloudFront-Viewer-Country` 헤더를 기반으로 캐시하도록 배포를 구성합니다. 자세한 내용은 [선택한 요청 헤더 기반의 캐시](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders) 섹션을 참조하세요.
+ 오리진 요청 이벤트에서 이 함수에 대한 트리거를 생성합니다. CloudFront는 뷰어 요청 이벤트 뒤에 `CloudFront-Viewer-Country` 헤더를 추가하므로 이 예제를 사용하려면 함수가 원본 요청에 대해 실행되는지 확인해야 합니다.

**참고**  
다음 예제 코드는 오리진에 사용 중인 모든 S3 버킷에 대해 동일한 오리진 액세스 ID(OAI)를 사용합니다. 자세한 내용은 [오리진 액세스 ID](private-content-restricting-access-to-s3.md#private-content-restricting-access-to-s3-oai) 섹션을 참조하세요.

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    /**
     * This blueprint demonstrates how an origin-request trigger can be used to
     * change the origin from which the content is fetched, based on request properties.
     * In this example, we use the value of the CloudFront-Viewer-Country header
     * to update the S3 bucket domain name to a bucket in a Region that is closer to
     * the viewer.
     * 
     * This can be useful in several ways:
     *      1) Reduces latencies when the Region specified is nearer to the viewer's
     *         country.
     *      2) Provides data sovereignty by making sure that data is served from an
     *         origin that's in the same country that the request came from.
     * 
     * NOTE: 1. You must configure your distribution to cache based on the
     *          CloudFront-Viewer-Country header. For more information, see
     *          https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
     *       2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
     *          request event. To use this example, you must create a trigger for the
     *          origin request event.
     */

    const countryToRegion = {
        'DE': 'eu-central-1',
        'IE': 'eu-west-1',
        'GB': 'eu-west-2',
        'FR': 'eu-west-3',
        'JP': 'ap-northeast-1',
        'IN': 'ap-south-1'
    };

    if (request.headers['cloudfront-viewer-country']) {
        const countryCode = request.headers['cloudfront-viewer-country'][0].value;
        const region = countryToRegion[countryCode];
        
        /**
         * If the viewer's country is not in the list you specify, the request
         * goes to the default S3 bucket you've configured.
         */  
        if (region) {
            /**
             * If you've set up OAI, the bucket policy in the destination bucket
             * should allow the OAI GetObject operation, as configured by default
             * for an S3 origin with OAI. Another requirement with OAI is to provide
             * the Region so it can be used for the SIGV4 signature. Otherwise, the
             * Region is not required.
             */
            request.origin.s3.region = region;
            const domainName = `amzn-s3-demo-bucket-in-${region}.s3.${region}.amazonaws.com`;
            request.origin.s3.domainName = domainName;
            request.headers['host'] = [{ key: 'host', value: domainName }];
        }
    }

    callback(null, request);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    '''
    This blueprint demonstrates how an origin-request trigger can be used to
    change the origin from which the content is fetched, based on request properties.
    In this example, we use the value of the CloudFront-Viewer-Country header
    to update the S3 bucket domain name to a bucket in a Region that is closer to
    the viewer.
    
    This can be useful in several ways:
        1) Reduces latencies when the Region specified is nearer to the viewer's
            country.
        2) Provides data sovereignty by making sure that data is served from an
            origin that's in the same country that the request came from.
    
    NOTE: 1. You must configure your distribution to cache based on the
            CloudFront-Viewer-Country header. For more information, see
            https://docs.aws.amazon.com/console/cloudfront/cache-on-selected-headers
          2. CloudFront adds the CloudFront-Viewer-Country header after the viewer
            request event. To use this example, you must create a trigger for the
            origin request event.
    '''

    countryToRegion = {
        'DE': 'eu-central-1',
        'IE': 'eu-west-1',
        'GB': 'eu-west-2',
        'FR': 'eu-west-3',
        'JP': 'ap-northeast-1',
        'IN': 'ap-south-1'
    }

    viewerCountry = request['headers'].get('cloudfront-viewer-country')
    if viewerCountry:
        countryCode = viewerCountry[0]['value']
        region = countryToRegion.get(countryCode)

        # If the viewer's country in not in the list you specify, the request
        # goes to the default S3 bucket you've configured
        if region:
            '''
            If you've set up OAI, the bucket policy in the destination bucket
            should allow the OAI GetObject operation, as configured by default
            for an S3 origin with OAI. Another requirement with OAI is to provide
            the Region so it can be used for the SIGV4 signature. Otherwise, the
            Region is not required.
            '''
            request['origin']['s3']['region'] = region
            domainName = 'amzn-s3-demo-bucket-in-{0}.s3.{0}.amazonaws.com'.format(region)
            request['origin']['s3']['domainName'] = domainName
            request['headers']['host'] = [{'key': 'host', 'value': domainName}]

    return request
```

------

### 예시: 오리진 요청 트리거를 사용하여 Amazon S3 오리진에서 사용자 지정 오리진으로 변경
<a name="lambda-examples-content-based-custom-origin-request-trigger"></a>

이 함수는 오리진 요청 트리거를 사용하여 콘텐츠를 요청 속성을 기반으로 가져오는 사용자 지정 오리진을 변경하는 방법을 보여줍니다.

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');
 
 exports.handler = (event, context, callback) => {
     const request = event.Records[0].cf.request;
 
     /**
      * Reads query string to check if custom origin should be used, and
      * if true, sets custom origin properties.
      */
 
     const params = querystring.parse(request.querystring);
 
     if (params['useCustomOrigin']) {
         if (params['useCustomOrigin'] === 'true') {
 
             /* Set custom origin fields*/
             request.origin = {
                 custom: {
                     domainName: 'www.example.com',
                     port: 443,
                     protocol: 'https',
                     path: '',
                     sslProtocols: ['TLSv1', 'TLSv1.1'],
                     readTimeout: 5,
                     keepaliveTimeout: 5,
                     customHeaders: {}
                 }
             };
             request.headers['host'] = [{ key: 'host', value: 'www.example.com'}];
         }
     }
    callback(null, request);
};
```

------
#### [ Python ]

```
from urllib.parse import parse_qs

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    # Reads query string to check if custom origin should be used, and
    # if true, sets custom origin properties

    params = {k: v[0] for k, v in parse_qs(request['querystring']).items()}

    if params.get('useCustomOrigin') == 'true':
            # Set custom origin fields
            request['origin'] = {
                'custom': {
                    'domainName': 'www.example.com',
                    'port': 443,
                    'protocol': 'https',
                    'path': '',
                    'sslProtocols': ['TLSv1', 'TLSv1.1'],
                    'readTimeout': 5,
                    'keepaliveTimeout': 5,
                    'customHeaders': {}
                }
            }
            request['headers']['host'] = [{'key': 'host', 'value': 'www.example.com'}]

    return request
```

------

### 예시: 오리진 요청 트리거를 사용하여 하나의 Amazon S3 버킷에서 다른 버킷으로 점진적으로 트래픽 전송
<a name="lambda-examples-content-based-gradual-traffic-transfer"></a>

이 함수는 통제된 방법을 통해 하나의 Amazon S3 버킷에서 다른 버킷으로 점진적으로 트래픽을 전송하는 방법을 보여 줍니다.

------
#### [ Node.js ]

```
'use strict';

    function getRandomInt(min, max) {
        /* Random number is inclusive of min and max*/
        return Math.floor(Math.random() * (max - min + 1)) + min;
 }

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const BLUE_TRAFFIC_PERCENTAGE = 80;

    /**
      * This Lambda function demonstrates how to gradually transfer traffic from
      * one S3 bucket to another in a controlled way.
      * We define a variable BLUE_TRAFFIC_PERCENTAGE which can take values from
      * 1 to 100. If the generated randomNumber less than or equal to BLUE_TRAFFIC_PERCENTAGE, traffic
      * is re-directed to blue-bucket. If not, the default bucket that we've configured
      * is used.
      */

    const randomNumber = getRandomInt(1, 100);

if (randomNumber <= BLUE_TRAFFIC_PERCENTAGE) {
         const domainName = 'blue-bucket.s3.amazonaws.com';
         request.origin.s3.domainName = domainName;
         request.headers['host'] = [{ key: 'host', value: domainName}];
     }
    callback(null, request);
};
```

------
#### [ Python ]

```
import math
import random

def getRandomInt(min, max):
    # Random number is inclusive of min and max
    return math.floor(random.random() * (max - min + 1)) + min

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    BLUE_TRAFFIC_PERCENTAGE = 80

    '''
    This Lambda function demonstrates how to gradually transfer traffic from
    one S3 bucket to another in a controlled way.
    We define a variable BLUE_TRAFFIC_PERCENTAGE which can take values from
    1 to 100. If the generated randomNumber less than or equal to BLUE_TRAFFIC_PERCENTAGE, traffic
    is re-directed to blue-bucket. If not, the default bucket that we've configured
    is used.
    '''

    randomNumber = getRandomInt(1, 100)

    if randomNumber <= BLUE_TRAFFIC_PERCENTAGE:
        domainName = 'blue-bucket.s3.amazonaws.com'
        request['origin']['s3']['domainName'] = domainName
        request['headers']['host'] = [{'key': 'host', 'value': domainName}]

    return request
```

------

### 예시: 오리진 요청 트리거를 사용하여 국가 헤더를 기반으로 오리진 도메인 이름 변경
<a name="lambda-examples-content-based-geo-header"></a>

이 함수는 `CloudFront-Viewer-Country` 헤더를 기반으로 원본 도메인 이름을 변경하여 뷰어의 국가에 더 가까운 원본에서 콘텐츠를 제공하는 방법을 보여줍니다.

배포에서 이 기능을 구현하면 다음과 같은 이점을 누릴 수 있습니다.
+ 지정된 리전이 최종 사용자의 국가와 더욱 근접할 때 지연 시간이 감소
+ 데이터가 요청이 온 곳과 동일한 국가에 있는 오리진에서 서비스되는지 확인함으로써 데이터 주권을 제공

이 함수를 사용하려면 `CloudFront-Viewer-Country` 헤더를 기반으로 캐시하도록 배포를 구성해야 합니다. 자세한 내용은 [선택한 요청 헤더 기반의 캐시](DownloadDistValuesCacheBehavior.md#DownloadDistValuesForwardHeaders) 섹션을 참조하세요.

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
     const request = event.Records[0].cf.request;
     
  if (request.headers['cloudfront-viewer-country']) {
         const countryCode = request.headers['cloudfront-viewer-country'][0].value;
         if (countryCode === 'GB' || countryCode === 'DE' || countryCode === 'IE' ) {
             const domainName = 'eu.example.com';
             request.origin.custom.domainName = domainName;
             request.headers['host'] = [{key: 'host', value: domainName}];
         } 
     }
     
    callback(null, request);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    viewerCountry = request['headers'].get('cloudfront-viewer-country')
    if viewerCountry:
        countryCode = viewerCountry[0]['value']
        if countryCode == 'GB' or countryCode == 'DE' or countryCode == 'IE':
            domainName = 'eu.example.com'
            request['origin']['custom']['domainName'] = domainName
            request['headers']['host'] = [{'key': 'host', 'value': domainName}]
    return request
```

------

## 오류 상태 업데이트 - 예시
<a name="lambda-examples-update-error-status-examples"></a>

다음 예시에서는 Lambda@Edge를 사용하여 사용자에게 반환되는 오류의 상태를 변경하는 방법에 대한 지침을 제공합니다.

**Topics**
+ [예시: 오리진 응답 트리거를 사용하여 오류 상태 코드를 200으로 업데이트](#lambda-examples-custom-error-static-body)
+ [예시: 오리진 응답 트리거를 사용하여 오류 상태 코드를 302로 업데이트](#lambda-examples-custom-error-new-site)

### 예시: 오리진 응답 트리거를 사용하여 오류 상태 코드를 200으로 업데이트
<a name="lambda-examples-custom-error-static-body"></a>

이 함수는 응답 상태를 200으로 업데이트하고 정적 본문 콘텐츠를 생성하여 다음 시나리오에서 최종 사용자에게 반환하는 방법을 보여줍니다.
+ 함수가 오리진 응답에서 트리거됩니다.
+ 오리진 서버의 응답 상태는 오류 상태 코드(4xx 또는 5xx)입니다.

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;

    /**
     * This function updates the response status to 200 and generates static
     * body content to return to the viewer in the following scenario:
     * 1. The function is triggered in an origin response
     * 2. The response status from the origin server is an error status code (4xx or 5xx)
     */

    if (response.status >= 400 && response.status <= 599) {
        response.status = 200;
        response.statusDescription = 'OK';
        response.body = 'Body generation example';
    }

    callback(null, response);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    response = event['Records'][0]['cf']['response']

    '''
    This function updates the response status to 200 and generates static
    body content to return to the viewer in the following scenario:
    1. The function is triggered in an origin response
    2. The response status from the origin server is an error status code (4xx or 5xx)
    '''

    if int(response['status']) >= 400 and int(response['status']) <= 599:
        response['status'] = 200
        response['statusDescription'] = 'OK'
        response['body'] = 'Body generation example'
    return response
```

------

### 예시: 오리진 응답 트리거를 사용하여 오류 상태 코드를 302로 업데이트
<a name="lambda-examples-custom-error-new-site"></a>

이 함수는 HTTP 상태 코드를 302로 업데이트하여 다른 오리진이 구성된 다른 경로(캐시 동작)로 리디렉션하는 방법을 보여줍니다. 다음을 참조하십시오.
+ 함수가 오리진 응답에서 트리거됩니다.
+ 오리진 서버의 응답 상태는 오류 상태 코드(4xx 또는 5xx)입니다.

------
#### [ Node.js ]

```
'use strict';

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    const request = event.Records[0].cf.request;

    /**
     * This function updates the HTTP status code in the response to 302, to redirect to another
     * path (cache behavior) that has a different origin configured. Note the following:
     * 1. The function is triggered in an origin response
     * 2. The response status from the origin server is an error status code (4xx or 5xx)
     */

    if (response.status >= 400 && response.status <= 599) {
        const redirect_path = `/plan-b/path?${request.querystring}`;

        response.status = 302;
        response.statusDescription = 'Found';

        /* Drop the body, as it is not required for redirects */
        response.body = '';
        response.headers['location'] = [{ key: 'Location', value: redirect_path }];
    }

    callback(null, response);
};
```

------
#### [ Python ]

```
def lambda_handler(event, context):
    response = event['Records'][0]['cf']['response']
    request = event['Records'][0]['cf']['request']

    '''
    This function updates the HTTP status code in the response to 302, to redirect to another
    path (cache behavior) that has a different origin configured. Note the following:
    1. The function is triggered in an origin response
    2. The response status from the origin server is an error status code (4xx or 5xx)
    '''

    if int(response['status']) >= 400 and int(response['status']) <= 599:
        redirect_path = '/plan-b/path?%s' % request['querystring']

        response['status'] = 302
        response['statusDescription'] = 'Found'

        # Drop the body as it is not required for redirects
        response['body'] = ''
        response['headers']['location'] = [{'key': 'Location', 'value': redirect_path}]

    return response
```

------

## 요청 본문 액세스 - 예시
<a name="lambda-examples-access-request-body-examples"></a>

다음 예시에서는 Lambda@Edge를 사용하여 POST 요청을 처리하는 방법을 보여줍니다.

**참고**  
이러한 예제를 사용하려면 배포의 Lambda 함수 연결에서 *본문 포함* 옵션을 활성화해야 합니다. 기본적으로 활성화되어 있지 않습니다.  
CloudFront 콘솔에서 이 설정을 활성화하려면 **Lambda 함수 연결(Lambda Function Association)**에서 **본문 포함(Include Body)** 확인란을 선택하세요.
CloudFront API 또는 CloudFormation에서 이 설정을 활성화하려면 `LambdaFunctionAssociation`에서 `IncludeBody` 필드를 `true`로 설정합니다.

**Topics**
+ [예시: 요청 트리거를 사용하여 HTML 양식 읽기](#lambda-examples-access-request-body-examples-read)
+ [예시: 요청 트리거를 사용하여 HTML 양식 수정](#lambda-examples-access-request-body-examples-replace)

### 예시: 요청 트리거를 사용하여 HTML 양식 읽기
<a name="lambda-examples-access-request-body-examples-read"></a>

이 기능은 "문의처" 양식 등과 같은 HTML 양식(웹 양식)으로 인해 생성된 POST 요청의 본문을 처리할 수 있는 방법을 보여줍니다. 예를 들어, 다음과 같은 HTML 양식이 있을 수 있습니다.

```
<html>
  <form action="https://example.com" method="post">
    Param 1: <input type="text" name="name1"><br>
    Param 2: <input type="text" name="name2"><br>
    input type="submit" value="Submit">
  </form>
</html>
```

예를 들어, 다음 함수는 CloudFront 최종 사용자 요청 또는 오리진 요청 시 실행되어야 합니다.

------
#### [ Node.js ]

```
'use strict';

const querystring = require('querystring');

/**
 * This function demonstrates how you can read the body of a POST request 
 * generated by an HTML form (web form). The function is triggered in a
 * CloudFront viewer request or origin request event type.
 */

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;

    if (request.method === 'POST') {
        /* HTTP body is always passed as base64-encoded string. Decode it. */
        const body = Buffer.from(request.body.data, 'base64').toString();
 
        /* HTML forms send the data in query string format. Parse it. */
        const params = querystring.parse(body);
 
        /* For demonstration purposes, we only log the form fields here.
         * You can put your custom logic here. For example, you can store the 
         * fields in a database, such as Amazon DynamoDB, and generate a response
         * right from your Lambda@Edge function.
         */
        for (let param in params) {
            console.log(`For "${param}" user submitted "${params[param]}".\n`);
        }
    }
    return callback(null, request);
};
```

------
#### [ Python ]

```
import base64
from urllib.parse import parse_qs

'''
Say there is a POST request body generated by an HTML such as:

<html>
<form action="https://example.com" method="post">
    Param 1: <input type="text" name="name1"><br>
    Param 2: <input type="text" name="name2"><br>
    input type="submit" value="Submit">
</form>
</html>

'''

'''
This function demonstrates how you can read the body of a POST request 
generated by an HTML form (web form). The function is triggered in a
CloudFront viewer request or origin request event type.
'''

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']

    if request['method'] == 'POST':
        # HTTP body is always passed as base64-encoded string. Decode it
        body = base64.b64decode(request['body']['data'])

        # HTML forms send the data in query string format. Parse it
        params = {k: v[0] for k, v in parse_qs(body).items()}

        '''
        For demonstration purposes, we only log the form fields here.
        You can put your custom logic here. For example, you can store the
        fields in a database, such as Amazon DynamoDB, and generate a response
        right from your Lambda@Edge function.
        '''
        for key, value in params.items():
            print("For %s use submitted %s" % (key, value))
            
    return request
```

------

### 예시: 요청 트리거를 사용하여 HTML 양식 수정
<a name="lambda-examples-access-request-body-examples-replace"></a>

이 기능은 "문의처" 양식 등과 같은 HTML 양식(웹 양식)으로 인해 생성된 POST 요청의 본문을 수정할 수 있는 방법을 보여줍니다. 이 함수는 CloudFront 최종 사용자 요청 또는 오리진 요청 시 실행됩니다.

------
#### [ Node.js ]

```
'use strict';
				
const querystring = require('querystring');

exports.handler = (event, context, callback) => {
    var request = event.Records[0].cf.request;
    if (request.method === 'POST') {
        /* Request body is being replaced. To do this, update the following
        /* three fields:
         *    1) body.action to 'replace'
         *    2) body.encoding to the encoding of the new data.
         *
         *       Set to one of the following values:
         *
         *           text - denotes that the generated body is in text format.
         *               Lambda@Edge will propagate this as is.
         *           base64 - denotes that the generated body is base64 encoded.
         *               Lambda@Edge will base64 decode the data before sending
         *               it to the origin.
         *    3) body.data to the new body.
         */
        request.body.action = 'replace';
        request.body.encoding = 'text';
        request.body.data = getUpdatedBody(request);
    }
    callback(null, request);
};

function getUpdatedBody(request) {
    /* HTTP body is always passed as base64-encoded string. Decode it. */
    const body = Buffer.from(request.body.data, 'base64').toString();

    /* HTML forms send data in query string format. Parse it. */
    const params = querystring.parse(body);

    /* For demonstration purposes, we're adding one more param.
     *
     * You can put your custom logic here. For example, you can truncate long
     * bodies from malicious requests.
     */
    params['new-param-name'] = 'new-param-value';
    return querystring.stringify(params);
}
```

------
#### [ Python ]

```
import base64
from urllib.parse import parse_qs, urlencode

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    if request['method'] == 'POST':
        '''
        Request body is being replaced. To do this, update the following
        three fields:
            1) body.action to 'replace'
            2) body.encoding to the encoding of the new data.
        
            Set to one of the following values:
        
                text - denotes that the generated body is in text format.
                    Lambda@Edge will propagate this as is.
                base64 - denotes that the generated body is base64 encoded.
                    Lambda@Edge will base64 decode the data before sending
                    it to the origin.
            3) body.data to the new body.
        '''
        request['body']['action'] = 'replace'
        request['body']['encoding'] = 'text'
        request['body']['data'] = getUpdatedBody(request)
    return request

def getUpdatedBody(request):
    # HTTP body is always passed as base64-encoded string. Decode it
    body = base64.b64decode(request['body']['data'])

    # HTML forms send data in query string format. Parse it
    params = {k: v[0] for k, v in parse_qs(body).items()}

    # For demonstration purposes, we're adding one more param

    # You can put your custom logic here. For example, you can truncate long
    # bodies from malicious requests
    params['new-param-name'] = 'new-param-value'
    return urlencode(params)
```

------

# 엣지 함수에 대한 제한 사항
<a name="edge-functions-restrictions"></a>

다음 항목에서는 CloudFront 함수 및 Lambda@Edge에 적용되는 제한 사항에 대해 설명합니다. 일부 제한 사항은 모든 엣지 함수에 적용되지만 다른 제한은 CloudFront 함수 또는 Lambda@Edge에만 적용됩니다.

각 주제에서는 CloudFront를 사용하여 엣지 함수를 개발하고 배포할 때 고려해야 하는 제한 사항 및 제약 조건에 대한 자세한 정보를 제공합니다.

이러한 제약 조건을 이해하면 엣지 함수가 예상대로 작동하고 지원되는 기능을 따르도록 하는 데 도움이 됩니다.

**Topics**
+ [모든 엣지 함수에 대한 제한 사항](edge-function-restrictions-all.md)
+ [CloudFront 함수에 대한 제한](cloudfront-function-restrictions.md)
+ [Lambda@Edge에 대한 제한 사항](lambda-at-edge-function-restrictions.md)

할당량(한도라고도 함)에 대한 자세한 내용은 [CloudFront 함수의 할당량](cloudfront-limits.md#limits-functions) 및 [Lambda@Edge에 대한 할당량](cloudfront-limits.md#limits-lambda-at-edge) 섹션을 참조하세요.

# 모든 엣지 함수에 대한 제한 사항
<a name="edge-function-restrictions-all"></a>

다음 제한 사항은 CloudFront 함수와 Lambda@Edge의 모든 엣지 함수에 적용됩니다.

**Topics**
+ [AWS 계정 소유권](#function-restrictions-account-ownership)
+ [CloudFront 함수와 Lambda@Edge 조합](#function-restrictions-combining-functions)
+ [HTTP 상태 코드](#function-restrictions-status-codes)
+ [HTTP 헤더](#function-restrictions-headers)
+ [쿼리 문자열](#function-restrictions-query-strings)
+ [URI](#function-restrictions-uri)
+ [URI, 쿼리 문자열 및 헤더 인코딩](#function-restrictions-encoding)
+ [Microsoft Smooth Streaming](#function-restrictions-microsoft-smooth-streaming)
+ [태그 지정](#function-restrictions-tagging)

## AWS 계정 소유권
<a name="function-restrictions-account-ownership"></a>

엣지 함수를 CloudFront 배포와 연결하려면 동일한 AWS 계정에서 함수와 배포를 소유해야 합니다.

## CloudFront 함수와 Lambda@Edge 조합
<a name="function-restrictions-combining-functions"></a>

지정된 캐시 동작에 대해 다음과 같은 제한이 적용됩니다.
+ 각 이벤트 유형(뷰어 요청, 오리진 요청, 오리진 응답 및 뷰어 응답)은 하나의 엣지 함수 연결만 가질 수 있습니다.
+ 뷰어 이벤트(뷰어 요청 및 뷰어 응답)에는 CloudFront Functions와 Lambda@Edge를 조합할 수 없습니다.

엣지 함수의 다른 모든 조합이 허용됩니다. 다음 표에서는 허용되는 조합에 대해 설명합니다.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/AmazonCloudFront/latest/DeveloperGuide/edge-function-restrictions-all.html)

## HTTP 상태 코드
<a name="function-restrictions-status-codes"></a>

CloudFront는 오리진이 HTTP 상태 코드 400 이상을 반환할 때 뷰어 응답 이벤트에 대해 엣지 함수를 간접적으로 호출하지 않습니다.

오리진 응답 이벤트에 대한 Lambda@Edge 함수는 오리진이 HTTP 상태 코드 400 이상의 코드를 반환하는 경우를 포함한 *모든* 오리진 응답에 대해 호출됩니다. 자세한 내용은 [오리진 응답 트리거에서 HTTP 응답 업데이트](lambda-generating-http-responses.md#lambda-updating-http-responses) 단원을 참조하세요.

## HTTP 헤더
<a name="function-restrictions-headers"></a>

특정 HTTP 헤더는 허용되지 않습니다. 즉, 엣지 함수에 노출되지 않고 함수는 이를 추가할 수 없습니다. 다른 헤더는 읽기 전용이므로 함수가 읽을 수는 있지만 추가, 수정 또는 삭제할 수 없습니다.

**Topics**
+ [허용되지 않는 헤더](#function-restrictions-disallowed-headers)
+ [읽기 전용 헤더](#function-restrictions-read-only-headers)

### 허용되지 않는 헤더
<a name="function-restrictions-disallowed-headers"></a>

다음 HTTP 헤더는 엣지 함수에 노출되지 않으며 함수는 이를 추가할 수 없습니다. 함수가 이러한 헤더 중 하나를 추가하면 CloudFront 유효성 검사에 실패하고 CloudFront가 HTTP 상태 코드 502(Bad Gateway)를 뷰어에게 반환합니다.
+ `Connection` 
+ `Expect`
+ `Keep-Alive`
+ `Proxy-Authenticate`
+ `Proxy-Authorization`
+ `Proxy-Connection`
+ `Trailer`
+ `Upgrade`
+ `X-Accel-Buffering`
+ `X-Accel-Charset`
+ `X-Accel-Limit-Rate`
+ `X-Accel-Redirect`
+ `X-Amz-Cf-*`
+ `X-Amzn-Auth`
+ `X-Amzn-Cf-Billing`
+ `X-Amzn-Cf-Id`
+ `X-Amzn-Cf-Xff`
+ `X-Amzn-Errortype`
+ `X-Amzn-Fle-Profile`
+ `X-Amzn-Header-Count`
+ `X-Amzn-Header-Order`
+ `X-Amzn-Lambda-Integration-Tag`
+ `X-Amzn-RequestId`
+ `X-Cache`
+ `X-Edge-*`
+ `X-Forwarded-Proto`
+ `X-Real-IP`

### 읽기 전용 헤더
<a name="function-restrictions-read-only-headers"></a>

다음 헤더는 읽기 전용입니다. 함수는 이러한 값을 읽고 함수 논리에 대한 입력으로 사용할 수 있지만 값을 변경할 수는 없습니다. 함수가 읽기 전용 헤더를 추가 또는 편집하는 경우 요청은 CloudFront 유효성 검사에 실패하고 CloudFront는 HTTP 상태 코드 502(잘못된 게이트웨이)를 뷰어에게 반환합니다.

#### 뷰어 요청 이벤트의 읽기 전용 헤더
<a name="function-restrictions-read-only-headers-viewer-request"></a>

다음 헤더는 뷰어 요청 이벤트의 읽기 전용 헤더입니다.
+ `Content-Length`
+ `Host`
+ `Transfer-Encoding`
+ `Via`

#### 오리진 요청 이벤트의 읽기 전용 헤더(Lambda@Edge 전용)
<a name="function-restrictions-read-only-headers-origin-request"></a>

다음 헤더는 Lambda@Edge에만 있는 오리진 요청 이벤트에서만 읽을 수 있습니다.
+ `Accept-Encoding`
+ `Content-Length`
+ `If-Modified-Since`
+ `If-None-Match`
+ `If-Range`
+ `If-Unmodified-Since`
+ `Transfer-Encoding`
+ `Via`

#### 오리진 응답 이벤트의 읽기 전용 헤더(Lambda@Edge 전용)
<a name="function-restrictions-read-only-headers-origin-response"></a>

다음 헤더는 Lambda@Edge에만 있는 오리진 응답 이벤트에서만 읽을 수 있습니다.
+ `Transfer-Encoding`
+ `Via`

#### 뷰어 응답 이벤트의 읽기 전용 헤더
<a name="function-restrictions-read-only-headers-viewer-response"></a>

다음 헤더는 CloudFront Functions와 Lambda@Edge에 대한 뷰어 응답 이벤트에서 읽기 전용입니다.
+ `Warning`
+ `Via`

다음 헤더는 Lambda@Edge에 대한 뷰어 응답 이벤트에서 읽기 전용입니다.
+ `Content-Length`
+ `Content-Encoding`
+ `Transfer-Encoding`

## 쿼리 문자열
<a name="function-restrictions-query-strings"></a>

요청 URI에서 쿼리 문자열을 읽거나 업데이트하거나 만드는 함수에는 다음 제한 사항이 적용됩니다.
+ (Lambda@Edge 전용) 오리진 요청 또는 오리진 응답 함수에서 쿼리 문자열에 액세스하려면 캐시 정책 또는 오리진 요청 정책을 **쿼리 문자열**에 대해 **모두(ALL)**로 설정해야 합니다.
+ 함수는 뷰어 요청 및 오리진 요청 이벤트에 대한 쿼리 문자열을 만들거나 업데이트할 수 있습니다(오리진 요청 이벤트는 Lambda@Edge에만 있음).
+ 함수는 쿼리 문자열을 읽을 수 있지만 오리진 응답 및 뷰어 응답 이벤트에 대해 쿼리 문자열을 만들거나 업데이트할 수는 없습니다(오리진 응답 이벤트는 Lambda@Edge에만 있음).
+ 함수가 쿼리 문자열을 만들거나 업데이트하는 경우 다음과 같은 제한이 적용됩니다.
  + 쿼리 문자열에는 공백, 제어 문자 또는 조각 ID(`#`)가 포함될 수 없습니다.
  + 쿼리 문자열을 포함한 URI 및 총 크기는 8,192자 미만이어야 합니다.
  + URI 및 쿼리 문자열에 퍼센트 인코딩을 사용하는 것이 좋습니다. 자세한 내용은 [URI, 쿼리 문자열 및 헤더 인코딩](#function-restrictions-encoding) 섹션을 참조하세요.

## URI
<a name="function-restrictions-uri"></a>

함수가 요청의 URI를 변경하는 경우 이로 인해 요청 또는 요청이 전달되는 오리진에 대한 캐시 동작이 변경되지 않습니다.

쿼리 문자열을 포함한 URI 및 총 크기는 8,192자 미만이어야 합니다.

## URI, 쿼리 문자열 및 헤더 인코딩
<a name="function-restrictions-encoding"></a>

엣지 함수에 전달된 URI, 쿼리 문자열 및 헤더 값은 UTF-8로 인코딩됩니다. 함수는 반환하는 URI, 쿼리 문자열 및 헤더 값에 대해 UTF-8 인코딩을 사용해야 합니다. 퍼센트 인코딩은 UTF-8 인코딩과 호환됩니다.

다음 목록에서는 CloudFront가 URI, 쿼리 문자열 및 헤더 값 인코딩을 처리하는 방법을 설명합니다.
+ 요청의 값이 UTF-8로 인코딩되면 CloudFront는 값을 변경하지 않고 해당 함수로 바로 전달합니다.
+ 요청의 값이 [ISO 8859-1로 인코딩](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)되면 CloudFront는 값을 UTF-8 인코딩으로 변환한 후 함수에 전달합니다.
+ 다른 문자 인코딩을 사용하여 요청의 값이 인코딩되는 경우 CloudFront는 값이 ISO-8859-1로 인코딩된 것으로 가정하고 ISO-8859-1에서 UTF-8로 변환하려고 시도합니다.
**중요**  
변환된 문자는 원래 요청에 있는 값의 부정확한 해석일 수 있습니다. 이 경우 해당 함수 또는 오리진에서 의도하지 않은 결과가 생성될 수 있습니다.

CloudFront가 오리진에 전달하는 URI, 쿼리 문자열 및 헤더 값은 함수가 값을 변경하는지 여부에 따라 달라집니다.
+ 함수가 URI, 쿼리 문자열 또는 헤더를 변경하지 않는 경우 CloudFront는 CloudFront가 요청에서 수신한 값을 오리진으로 전달합니다.
+ 함수가 URI, 쿼리 문자열 또는 헤더를 변경하는 경우 CloudFront는 UTF-8로 인코딩된 값을 전달합니다.

## Microsoft Smooth Streaming
<a name="function-restrictions-microsoft-smooth-streaming"></a>

Microsoft Smooth Streaming 형식으로 변환한 미디어 파일을 스트리밍하는 데 사용하는 CloudFront 배포에는 엣지 함수를 사용할 수 없습니다.

## 태그 지정
<a name="function-restrictions-tagging"></a>

엣지 함수에 태그를 추가할 수 없습니다. CloudFront의 태그 지정에 대한 자세한 내용은 [배포 태깅](tagging.md) 섹션을 참조하세요.

# CloudFront 함수에 대한 제한
<a name="cloudfront-function-restrictions"></a>

다음 제한은 CloudFront 함수에만 적용됩니다.

**Contents**
+ [로그](#cloudfront-function-restrictions-logs)
+ [요청 본문](#cloudfront-function-restrictions-request-body)
+ [CloudFront KeyValueStore API에 임시 자격 증명 사용](#regional-endpoint-for-key-value-store)
+ [런타임](#cloudfront-function-runtime-restrictions)
+ [컴퓨팅 사용률](#cloudfront-function-restrictions-compute-utilization)

할당량(한도라고도 함)에 대한 자세한 내용은 [CloudFront 함수의 할당량](cloudfront-limits.md#limits-functions) 섹션을 참조하세요.

## 로그
<a name="cloudfront-function-restrictions-logs"></a>

CloudFront 함수의 함수 로그는 10KB로 잘립니다.

## 요청 본문
<a name="cloudfront-function-restrictions-request-body"></a>

CloudFront Functions가 HTTP 요청의 본문에 액세스할 수 없습니다.

## CloudFront KeyValueStore API에 임시 자격 증명 사용
<a name="regional-endpoint-for-key-value-store"></a>

AWS Security Token Service(AWS STS)를 사용하여 임시 보안 자격 증명(**세션 토큰이라고도 함)을 생성할 수 있습니다. 세션 토큰을 사용하면 일시적으로 AWS Identity and Access Management(IAM) 역할을 맡아 AWS 서비스에 액세스할 수 있습니다.

[CloudFront KeyValueStore API](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_Operations_Amazon_CloudFront_KeyValueStore.html)를 직접 호출하려면 AWS STS에서 **리전 엔드포인트를 사용하여 버전 2** 세션 토큰을 반환하세요. AWS STS(`sts.amazonaws.com`)에 **글로벌 엔드포인트를 사용하면 AWS STS는 서명 버전 4A(SigV4A)에서 지원하지 않는 **버전 1 세션 토큰을 생성합니다. 따라서 인증 오류가 발생할 수 있습니다.

CloudFront KeyValueStore API를 직접 호출하려면 다음 옵션을 사용할 수 있습니다.

**AWS CLI 및 AWS SDK**  
리전 AWS STS 엔드포인트를 사용하도록 AWS CLI 또는 AWS SDK를 구성할 수 있습니다. 자세한 내용은 **AWS SDK 및 도구 참조 가이드의 [AWS STS Regionalized endpoints](https://docs.aws.amazon.com/sdkref/latest/guide/feature-sts-regionalized-endpoints.html)를 참조하세요.  
사용 가능한 AWS STS 엔드포인트에 대한 자세한 내용은 **IAM 사용 설명서의 [Regions and endpoints](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html#id_credentials_region-endpoints)를 참조하세요.

**SAML**  
리전 AWS STS 엔드포인트를 사용하도록 SAML을 구성할 수 있습니다. 자세한 내용은 [How to use regional SAML endpoints for failover](https://aws.amazon.com/blogs/security/how-to-use-regional-saml-endpoints-for-failover/) 블로그 게시물을 참조하세요.

**`SetSecurityTokenServicePreferences` API**  
리전 AWS STS 엔드포인트를 사용하는 대신 버전 2 세션 토큰을 반환하도록 AWS STS에 대한 글로벌 엔드포인트를 구성할 수 있습니다. 이렇게 하려면 [SetSecurityTokenServicePreferences](https://docs.aws.amazon.com/IAM/latest/APIReference/API_SetSecurityTokenServicePreferences.html) API 작업을 사용하여 AWS 계정을 구성하세요.  

**Example 예: IAM CLI 명령**  

```
aws iam set-security-token-service-preferences --global-endpoint-token-version v2Token
```
이 옵션 대신 AWS STS 리전 엔드포인트를 사용하는 것이 좋습니다. 리전 엔드포인트는 더 높은 가용성 및 장애 조치 시나리오를 제공합니다.

**사용자 지정 ID 제공업체**  
페더레이션을 수행하고 역할을 맡는 사용자 지정 ID 제공업체를 사용하는 경우 세션 토큰 생성을 담당하는 상위 ID 제공업체 시스템에 대한 이전 옵션 중 하나를 사용하세요.

## 런타임
<a name="cloudfront-function-runtime-restrictions"></a>

CloudFront Functions 런타임 환경은 동적 코드 평가를 지원하지 않으며 네트워크, 파일 시스템, 환경 변수, 타이머에 대한 액세스를 제한합니다. 자세한 내용은 [제한된 기능](functions-javascript-runtime-10.md#writing-functions-javascript-features-restricted-features) 섹션을 참조하세요.

**참고**  
[CloudFront KeyValueStore를 사용하려면 CloudFront 함수가 JavaScript 런타임 2.0](functions-javascript-runtime-20.md)을 사용해야 합니다.

## 컴퓨팅 사용률
<a name="cloudfront-function-restrictions-compute-utilization"></a>

CloudFront 함수는 *컴퓨팅 사용률*로 측정되는 실행 시간에 제한이 있습니다. 컴퓨팅 사용률은 함수가 최대 허용 시간의 백분율로 실행되는 데 걸린 시간을 나타내는 0에서 100 사이의 숫자입니다. 예를 들어 컴퓨팅 사용률이 35이면 함수가 최대 허용 시간의 35%에서 완료되었음을 의미합니다.

[함수를 테스트](test-function.md)하면 테스트 이벤트의 출력에서 컴퓨팅 사용률 값을 볼 수 있습니다. 프로덕션 함수의 경우, [CloudFront 콘솔의 모니터링 페이지](https://console.aws.amazon.com/cloudfront/v4/home?#/monitoring) 또는 CloudWatch에서 [컴퓨팅 사용률 지표](viewing-cloudfront-metrics.md#monitoring-console.cloudfront-functions)를 볼 수 있습니다.

# Lambda@Edge에 대한 제한 사항
<a name="lambda-at-edge-function-restrictions"></a>

다음 제한 사항은 Lambda@Edge에만 적용됩니다.

**Contents**
+ [DNS 확인](#lambda-at-edge-restrictions-dns)
+ [HTTP 상태 코드](#lambda-at-edge-restrictions-status-codes)
+ [Lambda 함수 버전](#lambda-at-edge-restrictions-version)
+ [Lambda 리전](#lambda-at-edge-restrictions-region)
+ [Lambda 역할 권한](#lambda-at-edge-restrictions-role-permissions)
+ [Lambda 기능](#lambda-at-edge-restrictions-features)
+ [지원되는 런타임](#lambda-at-edge-restrictions-runtime)
+ [CloudFront 헤더](#lambda-at-edge-restrictions-cloudfront-headers)
+ [본문 포함 옵션이 적용된 요청 본문에 대한 제한 사항](#lambda-at-edge-restrictions-request-body)
+ [응답 제한 시간 및 연결 유지 제한 시간(사용자 지정 오리진만 해당)](#timeout-for-lambda-edge-functions)

 할당량에 대한 자세한 내용은 단원을 참조하세요[Lambda@Edge에 대한 할당량](cloudfront-limits.md#limits-lambda-at-edge)

## DNS 확인
<a name="lambda-at-edge-restrictions-dns"></a>

CloudFront는 오리진 요청 Lambda@Edge 함수를 실행하기 **전에 오리진 도메인 이름에 대해 DNS 확인을 수행합니다. 도메인의 DNS 서비스에 문제가 있고 CloudFront가 도메인 이름을 확인하여 IP 주소를 가져올 수 없는 경우 Lambda@Edge 함수가 간접 호출되지 않습니다. CloudFront는 클라이언트에 [HTTP 502 상태 코드(잘못된 게이트웨이)](http-502-bad-gateway.md)를 반환합니다. 자세한 내용은 [DNS 오류(`NonS3OriginDnsError`)](http-502-bad-gateway.md#http-502-dns-error) 섹션을 참조하세요.

함수 로직이 오리진 도메인 이름을 수정하는 경우 CloudFront는 함수 실행이 완료된 후 업데이트된 도메인 이름에 대해 또 다른 DNS 확인을 수행합니다.

관리에 대한 자세한 내용은 Amazon Route 53 개발자 안내서의 [DNS 장애 조치 구성](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover-configuring.html)을 참조합니다.**

## HTTP 상태 코드
<a name="lambda-at-edge-restrictions-status-codes"></a>

뷰어 응답 이벤트에 대한 Lambda@Edge 함수는 응답이 오리진에서 왔는지, CloudFront 캐시에서 왔는지와 관계없이 응답의 HTTP 상태 코드를 수정할 수 없습니다.

## Lambda 함수 버전
<a name="lambda-at-edge-restrictions-version"></a>

`$LATEST` 또는 별칭이 아니라 번호가 매겨진 Lambda 함수 버전을 사용해야 합니다.

## Lambda 리전
<a name="lambda-at-edge-restrictions-region"></a>

Lambda 함수는 미국 동부(버지니아 북부) 리전에 있어야 합니다.

## Lambda 역할 권한
<a name="lambda-at-edge-restrictions-role-permissions"></a>

Lambda 함수와 연결된 IAM 실행 역할은 서비스 보안 주체 `lambda.amazonaws.com` 및 `edgelambda.amazonaws.com`에서 역할을 수임하도록 허용해야 합니다. 자세한 내용은 [Lambda@Edge에 대한 IAM 권한 및 역할 설정](lambda-edge-permissions.md) 섹션을 참조하세요.

## Lambda 기능
<a name="lambda-at-edge-restrictions-features"></a>

다음 Lambda 함수는 Lambda@Edge에서 지원되지 않습니다.
+ 기본값인 **Auto**(자동)가 아닌 [Lambda 런타임 관리 구성](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html#runtime-management-controls)
+ VPC 내부 리소스에 액세스하도록 Lambda 함수 구성
+ [Lambda 함수 DLQ(Dead Letter Queue](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#dlq)
+ [Lambda 환경 변수](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html)(자동으로 지원되는 예약된 환경 변수 제외)
+ Lambda 함수([계층을 통한 AWS Lambda 종속성 관리](https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html) 포함)
+ [ 사용AWS X-Ray](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html)
+ Lambda 프로비저닝된 동시성
**참고**  
Lambda@Edge 함수는 모든 Lambda 함수와 동일한 [리전 동시성](https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html) 기능을 공유합니다. 자세한 내용은 [Lambda@Edge에 대한 할당량](cloudfront-limits.md#limits-lambda-at-edge) 섹션을 참조하세요.
+ [컨테이너 이미지를 사용하여 Lambda 함수 생성](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html)
+ [arm64 아키텍처를 사용하는 Lambda 함수](https://docs.aws.amazon.com/lambda/latest/dg/foundation-arch.html)
+ 512MB를 초과하는 임시 스토리지가 있는 Lambda 함수
+ [.zip 배포 패키지를 암호화하는 데 고객 관리형 키](https://docs.aws.amazon.com/lambda/latest/dg/encrypt-zip-package.html) 사용

## 지원되는 런타임
<a name="lambda-at-edge-restrictions-runtime"></a>

Lambda@Edge는 최신 버전의 Node.js 및 Python 런타임을 지원합니다. 지원되는 버전 및 향후 사용 중단 날짜 목록은 *AWS Lambda 개발자 안내서*의 [지원되는 런타임](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtimes-supported)을 참조하세요.

**작은 정보**  
성능 향상과 새로운 기능을 위해 제공된 런타임의 최신 버전을 사용하는 것이 가장 좋습니다.
더 이상 사용되지 않는 버전의 Node.js로는 함수를 만들거나 업데이트할 수 없습니다. 기존 함수를 이러한 버전의 CloudFront 배포에만 연결할 수 있습니다. 배포와 관련된 이러한 버전의 함수는 계속 실행됩니다. 그러나 함수를 최신 버전의 Node.js로 옮기는 것이 좋습니다. 자세한 내용은 *AWS Lambda 개발자 안내서*의 [런타임 사용 중단 정책](https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html)과 GitHub의 [Node.js 릴리스 일정](https://github.com/nodejs/Release#release-schedule)을 참조하세요.

## CloudFront 헤더
<a name="lambda-at-edge-restrictions-cloudfront-headers"></a>

Lambda@Edge 함수는 [CloudFront 요청 헤더 추가](adding-cloudfront-headers.md)에 나열된 CloudFront 헤더를 읽고, 편집하고, 제거하거나 추가할 수 있습니다.

**참고**  
CloudFront에서 이러한 헤더를 추가하도록 하려면 [캐시 정책](controlling-the-cache-key.md) 또는 [오리진 요청 정책](controlling-origin-requests.md)을 사용하여 추가하도록 CloudFront를 구성해야 합니다.
CloudFront는 뷰어 요청 이벤트 이후에** 헤더를 추가하므로 뷰어 요청의 Lambda@Edge 함수에서 헤더를 사용할 수 없습니다. 헤더는 오리진 요청 및 오리진 응답의 Lambda@Edge 함수에만 사용할 수 있습니다.
뷰어 요청에 이러한 이름을 가진 헤더가 포함되어 있으면 [캐시 정책](controlling-the-cache-key.md) 또는 [오리진 요청 정책](controlling-origin-requests.md)을 사용하여 해당 헤더를 포함하도록 CloudFront를 구성해야 합니다. 그러면CloudFront는 뷰어 요청에 있었던 헤더 값을 덮어씁니다. 뷰어 방향 함수는 뷰어 요청의 헤더 값을 보는 반면, 오리진 방향 함수는 CloudFront에서 추가한 헤더 값을 확인합니다.
뷰어 요청 함수가 `CloudFront-Viewer-Country` 헤더를 추가하면 유효성 검사에 실패하고 CloudFront는 뷰어에 HTTP 상태 코드 502(잘못된 게이트웨이)를 반환합니다.

## 본문 포함 옵션이 적용된 요청 본문에 대한 제한 사항
<a name="lambda-at-edge-restrictions-request-body"></a>

**본문 포함** 옵션을 선택해 Lambda@Edge 함수에 요청 본문을 노출하면 노출 또는 교체된 본문 부분에 다음 정보 및 크기 제한이 적용됩니다.
+ CloudFront는 항상 요청 본문을 base64로 인코딩한 후 Lambda@Edge에 노출합니다.
+ 요청 본문이 크면 CloudFront는 요청 본문이 Lambda@Edge에 노출되기 전에 다음과 같이 자릅니다.
  + 뷰어 요청 이벤트의 경우 본문은 40KB에서 잘립니다.
  + 오리진 요청 이벤트의 경우 본문은 1MB에서 잘립니다.
+ 요청 본문에 읽기 전용으로 액세스하는 경우 CloudFront는 전체 원본 요청 본문을 오리진으로 반환합니다.
+ Lambda@Edge 함수가 요청 본문을 교체하면 함수가 반환하는 본문에 다음 크기 제한이 적용됩니다.
  + Lambda@Edge 함수가 본문을 일반 텍스트로 반환하는 경우:
    + 뷰어 요청 이벤트의 경우 본문 제한은 40KB입니다.
    + 오리진 요청 이벤트의 경우 본문 제한은 1MB입니다.
  + Lambda@Edge 함수가 본문을 base64로 인코딩된 텍스트로 반환하는 경우:
    + 뷰어 요청 이벤트의 경우 본문 제한은 53.2KB입니다.
    + 오리진 요청 이벤트의 경우 본문 제한은 1.33MB입니다.

**참고**  
Lambda@Edge 함수가 이러한 제한을 초과하는 본문을 반환하는 경우 HTTP 502 상태 코드([Lambda 검증 오류](http-502-bad-gateway.md#http-502-lambda-validation-error))와 함께 요청이 실패합니다. 본문이 이러한 제한을 초과하지 않도록 Lambda@Edge 함수를 업데이트하는 것이 좋습니다.

## 응답 제한 시간 및 연결 유지 제한 시간(사용자 지정 오리진만 해당)
<a name="timeout-for-lambda-edge-functions"></a>

Lambda@Edge 함수를 사용하여 배포 오리진에 대한 응답 제한 시간 또는 연결 유지 제한 시간을 설정하는 경우 오리진이 지원할 수 있는 값을 지정해야 합니다. 자세한 내용은 [응답 및 연결 유지 제한 시간 할당량](DownloadDistValuesOrigin.md#response-keep-alive-timeout-quota) 섹션을 참조하세요.