

# Configure secure access and restrict access to content
<a name="SecurityAndPrivateContent"></a>

CloudFront provides several options for securing content that it delivers. The following are some ways you can use CloudFront to secure and restrict access to content:
+ Configure HTTPS connections
+ Prevent users in specific geographic locations from accessing content
+ Require users to access content using CloudFront signed URLs or signed cookies
+ Set up field-level encryption for specific content fields
+ Use AWS WAF to control access to your content

You should also implement a DDoS-resilient architecture for your infrastructure and applications. For more information, see [AWS Best Practices for DDoS Resiliency](https://docs.aws.amazon.com/whitepapers/latest/aws-best-practices-ddos-resiliency/aws-best-practices-ddos-resiliency.html).

For additional information, see the following:
+ [Securing your content delivery with CloudFront](https://aws.amazon.com/cloudfront/security/)
+ [SIEM on Amazon OpenSearch Service](https://github.com/aws-samples/siem-on-amazon-opensearch-service/blob/main/README.md)

**Topics**
+ [Use HTTPS with CloudFront](using-https.md)
+ [Use alternate domain names and HTTPS](using-https-alternate-domain-names.md)
+ [Mutual TLS authentication with CloudFront (Viewer mTLS)](mtls-authentication.md)
+ [Origin mutual TLS with CloudFront](origin-mtls-authentication.md)
+ [Serve private content with signed URLs and signed cookies](PrivateContent.md)
+ [Restrict access to an AWS origin](private-content-restricting-access-to-origin.md)
+ [Restrict access to Application Load Balancers](restrict-access-to-load-balancer.md)
+ [Restrict the geographic distribution of your content](georestrictions.md)
+ [Use field-level encryption to help protect sensitive data](field-level-encryption.md)

# Use HTTPS with CloudFront
<a name="using-https"></a>

You can configure CloudFront to require that viewers use HTTPS so that connections are encrypted when CloudFront communicates with viewers. You also can configure CloudFront to use HTTPS with your origin so that connections are encrypted when CloudFront communicates with your origin.

If you configure CloudFront to require HTTPS both to communicate with viewers and to communicate with your origin, here’s what happens when CloudFront receives a request:

1. A viewer submits an HTTPS request to CloudFront. There’s some SSL/TLS negotiation here between the viewer and CloudFront. In the end, the viewer submits the request in an encrypted format.

1. If the CloudFront edge location contains a cached response, CloudFront encrypts the response and returns it to the viewer, and the viewer decrypts it.

1. If the CloudFront edge location doesn’t contain a cached response, CloudFront performs SSL/TLS negotiation with your origin and, when the negotiation is complete, forwards the request to your origin in an encrypted format.

1. Your origin decrypts the request, processes it (generates a response), encrypts the response, and returns the response to CloudFront.

1. CloudFront decrypts the response, re-encrypts it, and forwards it to the viewer. CloudFront also caches the response in the edge location so that it’s available the next time it’s requested.

1. The viewer decrypts the response.

The process works basically the same way whether your origin is an Amazon S3 bucket, MediaStore, or a custom origin such as an HTTP/S server.

**Note**  
To help thwart SSL renegotiation-type attacks, CloudFront does not support renegotiation for viewer and origin requests.

Alternatively, you can turn on mutual authentication for your CloudFront distribution. For more information, see [Mutual TLS authentication with CloudFront (Viewer mTLS)Origin mutual TLS with CloudFront](mtls-authentication.md).

For information about how to require HTTPS between viewers and CloudFront, and between CloudFront and your origin, see the following topics.

**Topics**
+ [Require HTTPS between viewers and CloudFront](using-https-viewers-to-cloudfront.md)
+ [Require HTTPS to a custom origin](using-https-cloudfront-to-custom-origin.md)
+ [Require HTTPS to an Amazon S3 origin](using-https-cloudfront-to-s3-origin.md)
+ [Supported protocols and ciphers between viewers and CloudFront](secure-connections-supported-viewer-protocols-ciphers.md)
+ [Supported protocols and ciphers between CloudFront and the origin](secure-connections-supported-ciphers-cloudfront-to-origin.md)

# Require HTTPS for communication between viewers and CloudFront
<a name="using-https-viewers-to-cloudfront"></a>

You can configure one or more cache behaviors in your CloudFront distribution to require HTTPS for communication between viewers and CloudFront. You also can configure one or more cache behaviors to allow both HTTP and HTTPS, so that CloudFront requires HTTPS for some objects but not for others. The configuration steps depend on which domain name you're using in object URLs:
+ If you're using the domain name that CloudFront assigned to your distribution, such as d111111abcdef8.cloudfront.net, you change the **Viewer Protocol Policy** setting for one or more cache behaviors to require HTTPS communication. In that configuration, CloudFront provides the SSL/TLS certificate. 

  To change the value of **Viewer Protocol Policy** by using the CloudFront console, see the procedure later in this section.

  For information about how to use the CloudFront API to change the value of the `ViewerProtocolPolicy` element, see [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html) in the *Amazon CloudFront API Reference*.
+ If you're using your own domain name, such as example.com, you need to change several CloudFront settings. You also need to use an SSL/TLS certificate provided by AWS Certificate Manager (ACM), or import a certificate from a third-party certificate authority into ACM or the IAM certificate store. For more information, see [Use alternate domain names and HTTPS](using-https-alternate-domain-names.md).

**Note**  
If you want to ensure that the objects that viewers get from CloudFront were encrypted when CloudFront got them from your origin, always use HTTPS between CloudFront and your origin. If you recently changed from HTTP to HTTPS between CloudFront and your origin, we recommend that you invalidate objects in CloudFront edge locations. CloudFront will return an object to a viewer regardless of whether the protocol used by the viewer (HTTP or HTTPS) matches the protocol that CloudFront used to get the object. For more information about removing or replacing objects in a distribution, see [Add, remove, or replace content that CloudFront distributes](AddRemoveReplaceObjects.md).

## Require HTTPS for viewers
<a name="configure-cloudfront-HTTPS-viewers"></a>

To require HTTPS between viewers and CloudFront for one or more cache behaviors, perform the following procedure.<a name="using-https-viewers-to-cloudfront-procedure"></a>

**To configure CloudFront to require HTTPS between viewers and CloudFront**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the top pane of the CloudFront console, choose the ID for the distribution that you want to update.

1. On the **Behaviors** tab, select the cache behavior that you want to update, and then choose **Edit**.

1. Specify one of the following values for **Viewer protocol policy**:  
**Redirect HTTP to HTTPS**  
Viewers can use both protocols. HTTP `GET` and `HEAD` requests are automatically redirected to HTTPS requests. CloudFront returns HTTP status code 301 (Moved Permanently) along with the new HTTPS URL. The viewer then resubmits the request to CloudFront using the HTTPS URL.  
If you send `POST`, `PUT`, `DELETE`, `OPTIONS`, or `PATCH` over HTTP with an HTTP to HTTPS cache behavior and a request protocol version of HTTP 1.1 or above, CloudFront redirects the request to a HTTPS location with a HTTP status code 307 (Temporary Redirect). This guarantees that the request is sent again to the new location using the same method and body payload.  
If you send `POST`, `PUT`, `DELETE`, `OPTIONS`, or `PATCH` requests over HTTP to HTTPS cache behavior with a request protocol version below HTTP 1.1, CloudFront returns a HTTP status code 403 (Forbidden).
When a viewer makes an HTTP request that is redirected to an HTTPS request, CloudFront charges for both requests. For the HTTP request, the charge is only for the request and for the headers that CloudFront returns to the viewer. For the HTTPS request, the charge is for the request, and for the headers and the object that are returned by your origin.  
**HTTPS only**  
Viewers can access your content only if they're using HTTPS. If a viewer sends an HTTP request instead of an HTTPS request, CloudFront returns HTTP status code 403 (Forbidden) and does not return the object.

1. Choose **Save changes**.

1. Repeat steps 3 through 5 for each additional cache behavior that you want to require HTTPS for between viewers and CloudFront.

1. Confirm the following before you use the updated configuration in a production environment:
   + The path pattern in each cache behavior applies only to the requests that you want viewers to use HTTPS for.
   + The cache behaviors are listed in the order that you want CloudFront to evaluate them in. For more information, see [Path pattern](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern).
   + The cache behaviors are routing requests to the correct origins. 

# Require HTTPS for communication between CloudFront and your custom origin
<a name="using-https-cloudfront-to-custom-origin"></a>

You can require HTTPS for communication between CloudFront and your origin.

**Note**  
If your origin is an Amazon S3 bucket that’s configured as a website endpoint, you can’t configure CloudFront to use HTTPS with your origin because Amazon S3 doesn’t support HTTPS for website endpoints.

To require HTTPS between CloudFront and your origin, follow the procedures in this topic to do the following:

1. In your distribution, change the **Origin Protocol Policy** setting for the origin.

1. Install an SSL/TLS certificate on your origin server (this isn’t required when you use an Amazon S3 origin or certain other AWS origins).

**Topics**
+ [Require HTTPS for custom origins](#using-https-cloudfront-to-origin-distribution-setting)
+ [Install an SSL/TLS certificate on your custom origin](#using-https-cloudfront-to-origin-certificate)

## Require HTTPS for custom origins
<a name="using-https-cloudfront-to-origin-distribution-setting"></a>

The following procedure explains how to configure CloudFront to use HTTPS to communicate with an Elastic Load Balancing load balancer, an Amazon EC2 instance, or another custom origin. For information about using the CloudFront API to update a distribution, see [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html) in the *Amazon CloudFront API Reference*. <a name="using-https-cloudfront-to-custom-origin-procedure"></a>

**To configure CloudFront to require HTTPS between CloudFront and your custom origin**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the top pane of the CloudFront console, choose the ID for the distribution that you want to update.

1. On the **Behaviors** tab, select the origin that you want to update, and then choose **Edit**.

1. Update the following settings:  
**Origin Protocol Policy**  
Change the **Origin Protocol Policy** for the applicable origins in your distribution:  
   + **HTTPS Only** – CloudFront uses only HTTPS to communicate with your custom origin.
   + **Match Viewer** – CloudFront communicates with your custom origin using HTTP or HTTPS, depending on the protocol of the viewer request. For example, if you choose **Match Viewer** for **Origin Protocol Policy** and the viewer uses HTTPS to request an object from CloudFront, CloudFront also uses HTTPS to forward the request to your origin.

     Choose **Match Viewer** only if you specify **Redirect HTTP to HTTPS** or **HTTPS Only** for **Viewer Protocol Policy**.

     CloudFront caches the object only once even if viewers make requests using both HTTP and HTTPS protocols.  
**Origin SSL Protocols**  
Choose the **Origin SSL Protocols** for the applicable origins in your distribution. The SSLv3 protocol is less secure, so we recommend that you choose SSLv3 only if your origin doesn’t support TLSv1 or later. The TLSv1 handshake is both backwards and forwards compatible with SSLv3, but TLSv1.1 and later are not. When you choose SSLv3, CloudFront *only* sends SSLv3 handshake requests.

1. Choose **Save changes**.

1. Repeat steps 3 through 5 for each additional origin that you want to require HTTPS for between CloudFront and your custom origin.

1. Confirm the following before you use the updated configuration in a production environment:
   + The path pattern in each cache behavior applies only to the requests that you want viewers to use HTTPS for.
   + The cache behaviors are listed in the order that you want CloudFront to evaluate them in. For more information, see [Path pattern](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern).
   + The cache behaviors are routing requests to the origins that you changed the **Origin Protocol Policy** for. 

## Install an SSL/TLS certificate on your custom origin
<a name="using-https-cloudfront-to-origin-certificate"></a>

You can use an SSL/TLS certificate from the following sources on your custom origin:
+ If your origin is an Elastic Load Balancing load balancer, you can use a certificate provided by AWS Certificate Manager (ACM). You also can use a certificate that is signed by a trusted third-party certificate authority and imported into ACM.
+ For origins other than Elastic Load Balancing load balancers, you must use a certificate that is signed by a trusted third-party certificate authority (CA), for example, Comodo, DigiCert, or Symantec.

The certificate returned from the origin must include one of the following domain names:
+ The domain name in the origin’s **Origin domain** field (the `DomainName` field in the CloudFront API).
+ The domain name in the `Host` header, if the cache behavior is configured to forward the `Host` header to the origin.

When CloudFront uses HTTPS to communicate with your origin, CloudFront verifies that the certificate was issued by a trusted certificate authority. CloudFront supports the same certificate authorities that Mozilla does. For the current list, see [Mozilla Included CA Certificate List](https://wiki.mozilla.org/CA/Included_Certificates). You can’t use a self-signed certificate for HTTPS communication between CloudFront and your origin.

**Important**  
If the origin server returns an expired certificate, an invalid certificate, or a self-signed certificate, or if the origin server returns the certificate chain in the wrong order, CloudFront drops the TCP connection, returns HTTP status code 502 (Bad Gateway) to the viewer, and sets the `X-Cache` header to `Error from cloudfront`. Also, if the full chain of certificates, including the intermediate certificate, is not present, CloudFront drops the TCP connection.

# Require HTTPS for communication between CloudFront and your Amazon S3 origin
<a name="using-https-cloudfront-to-s3-origin"></a>

When your origin is an Amazon S3 bucket, your options for using HTTPS for communications with CloudFront depend on how you're using the bucket. If your Amazon S3 bucket is configured as a website endpoint, you can't configure CloudFront to use HTTPS to communicate with your origin because Amazon S3 doesn't support HTTPS connections in that configuration.

When your origin is an Amazon S3 bucket that supports HTTPS communication, CloudFront forwards requests to S3 by using the protocol that viewers used to submit the requests. The default setting for the [Protocol (custom origins only)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy) setting is **Match Viewer** and can't be changed. However, if you enable origin access control (OAC) for your Amazon S3 origin, the communication used between CloudFront and Amazon S3 depends on your settings. For more information, see [Create a new origin access control](private-content-restricting-access-to-s3.md#create-oac-overview-s3).

If you want to require HTTPS for communication between CloudFront and Amazon S3, you must change the value of **Viewer Protocol Policy** to **Redirect HTTP to HTTPS** or **HTTPS Only**. The procedure later in this section explains how to use the CloudFront console to change **Viewer Protocol Policy**. For information about using the CloudFront API to update the `ViewerProtocolPolicy` element for a distribution, see [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html) in the *Amazon CloudFront API Reference*. 

When you use HTTPS with an Amazon S3 bucket that supports HTTPS communication, Amazon S3 provides the SSL/TLS certificate, so you don't have to.

## Require HTTPS for an Amazon S3 origin
<a name="configure-cloudfront-HTTPS-S3-origin"></a>

The following procedure shows you how to configure CloudFront to require HTTPS to your Amazon S3 origin.<a name="using-https-cloudfront-to-s3-origin-procedure"></a>

**To configure CloudFront to require HTTPS to your Amazon S3 origin**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the top pane of the CloudFront console, choose the ID for the distribution that you want to update.

1. On the **Behaviors** tab, choose the cache behavior that you want to update, and then choose **Edit**.

1. Specify one of the following values for **Viewer Protocol Policy**:  
**Redirect HTTP to HTTPS**  
Viewers can use both protocols, but HTTP requests are automatically redirected to HTTPS requests. CloudFront returns HTTP status code 301 (Moved Permanently) along with the new HTTPS URL. The viewer then resubmits the request to CloudFront using the HTTPS URL.  
CloudFront doesn't redirect `DELETE`, `OPTIONS`, `PATCH`, `POST`, or `PUT` requests from HTTP to HTTPS. If you configure a cache behavior to redirect to HTTPS, CloudFront responds to HTTP `DELETE`, `OPTIONS`, `PATCH`, `POST`, or `PUT` requests for that cache behavior with HTTP status code 403 (Forbidden).
When a viewer makes an HTTP request that is redirected to an HTTPS request, CloudFront charges for both requests. For the HTTP request, the charge is only for the request and for the headers that CloudFront returns to the viewer. For the HTTPS request, the charge is for the request, and for the headers and the object returned by your origin.  
**HTTPS Only**  
Viewers can access your content only if they're using HTTPS. If a viewer sends an HTTP request instead of an HTTPS request, CloudFront returns HTTP status code 403 (Forbidden) and does not return the object.

1. Choose **Yes, Edit**.

1. Repeat steps 3 through 5 for each additional cache behavior that you want to require HTTPS for between viewers and CloudFront, and between CloudFront and S3.

1. Confirm the following before you use the updated configuration in a production environment:
   + The path pattern in each cache behavior applies only to the requests that you want viewers to use HTTPS for.
   + The cache behaviors are listed in the order that you want CloudFront to evaluate them in. For more information, see [Path pattern](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern).
   + The cache behaviors are routing requests to the correct origins. 

# Supported protocols and ciphers between viewers and CloudFront
<a name="secure-connections-supported-viewer-protocols-ciphers"></a>

When you [require HTTPS between viewers and your CloudFront distribution](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy), you must choose a [security policy](DownloadDistValuesGeneral.md#DownloadDistValues-security-policy), which determines the following settings:
+ The minimum SSL/TLS protocol that CloudFront uses to communicate with viewers.
+ The ciphers that CloudFront can use to encrypt the communication with viewers.

To choose a security policy, specify the applicable value for [Security policy (minimum SSL/TLS version)](DownloadDistValuesGeneral.md#DownloadDistValues-security-policy). The following table lists the protocols and ciphers that CloudFront can use for each security policy.

A viewer must support at least one of the supported ciphers to establish an HTTPS connection with CloudFront. CloudFront chooses a cipher in the listed order from among the ciphers that the viewer supports. See also [OpenSSL, s2n, and RFC cipher names](#secure-connections-openssl-rfc-cipher-names).


|  | Security policy |  | SSLv3 | TLSv1 | TLSv1\$12016 | TLSv1.1\$12016 | TLSv1.2\$12018 | TLSv1.2\$12019 | TLSv1.2\$12021 | TLSv1.2\$12025 | TLSv1.3\$12025 | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| Supported SSL/TLS protocols | 
| TLSv1.3 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLSv1.2 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| TLSv1.1 | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| TLSv1 | ♦ | ♦ | ♦ |  |  |  |  |  |  | 
| SSLv3 | ♦ |  |  |  |  |  |  |  |  | 
| Supported TLSv1.3 ciphers | 
| TLS\$1AES\$1128\$1GCM\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1AES\$1256\$1GCM\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1CHACHA20\$1POLY1305\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | ♦ | 
| Supported ECDSA ciphers | 
| ECDHE-ECDSA-AES128-GCM-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-ECDSA-AES128-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-ECDSA-AES128-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| ECDHE-ECDSA-AES256-GCM-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-ECDSA-CHACHA20-POLY1305 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| ECDHE-ECDSA-AES256-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-ECDSA-AES256-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| Supported RSA ciphers | 
| ECDHE-RSA-AES128-GCM-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-RSA-AES128-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-RSA-AES128-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| ECDHE-RSA-AES256-GCM-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  | 
| ECDHE-RSA-CHACHA20-POLY1305 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| ECDHE-RSA-AES256-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  | 
| ECDHE-RSA-AES256-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| AES128-GCM-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  |  | 
| AES256-GCM-SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  |  | 
| AES128-SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ |  |  |  |  | 
| AES256-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| AES128-SHA | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| DES-CBC3-SHA | ♦ | ♦ |  |  |  |  |  |  |  | 
| RC4-MD5 | ♦ |  |  |  |  |  |  |  |  | 

## OpenSSL, s2n, and RFC cipher names
<a name="secure-connections-openssl-rfc-cipher-names"></a>

OpenSSL and [s2n](https://github.com/awslabs/s2n) use different names for ciphers than the TLS standards use ([RFC 2246](https://tools.ietf.org/html/rfc2246), [RFC 4346](https://tools.ietf.org/html/rfc4346), [RFC 5246](https://tools.ietf.org/html/rfc5246), and [RFC 8446](https://tools.ietf.org/html/rfc8446)). The following table maps the OpenSSL and s2n names to the RFC name for each cipher.

CloudFront supports both classical and quantum-safe key exchanges. For classical key exchanges using elliptic curves, CloudFront supports the following:
+ `prime256v1`
+ `X25519`
+ `secp384r1`

For quantum-safe key exchanges, CloudFront supports the following:
+ `X25519MLKEM768`
+ `SecP256r1MLKEM768`
**Note**  
Quantum-safe key exchanges are only supported with TLS 1.3. TLS 1.2 and earlier versions do not support quantum-safe key exchanges.

  For more information, see the following topics:
  + [Post-Quantum Cryptography](https://aws.amazon.com/security/post-quantum-cryptography/)
  + [Cryptography algorithms and AWS services](https://docs.aws.amazon.com/prescriptive-guidance/latest/encryption-best-practices/aws-cryptography-services.html#algorithms)
  + [Hybrid key exchange in TLS 1.3](https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/)

For more information about certificate requirements for CloudFront, see [Requirements for using SSL/TLS certificates with CloudFront](cnames-and-https-requirements.md).


| OpenSSL and s2n cipher name | RFC cipher name | 
| --- | --- | 
| Supported TLSv1.3 ciphers | 
| TLS\$1AES\$1128\$1GCM\$1SHA256 | TLS\$1AES\$1128\$1GCM\$1SHA256 | 
| TLS\$1AES\$1256\$1GCM\$1SHA384 | TLS\$1AES\$1256\$1GCM\$1SHA384 | 
| TLS\$1CHACHA20\$1POLY1305\$1SHA256 | TLS\$1CHACHA20\$1POLY1305\$1SHA256 | 
| Supported ECDSA ciphers | 
| ECDHE-ECDSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| ECDHE-ECDSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| ECDHE-ECDSA-CHACHA20-POLY1305 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 | 
| ECDHE-ECDSA-AES256-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384 | 
| ECDHE-ECDSA-AES256-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| Supported RSA ciphers | 
| ECDHE-RSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-RSA-AES128-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256  | 
| ECDHE-RSA-AES128-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| ECDHE-RSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384  | 
| ECDHE-RSA-CHACHA20-POLY1305 | TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 | 
| ECDHE-RSA-AES256-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384  | 
| ECDHE-RSA-AES256-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| AES128-GCM-SHA256 | TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| AES256-GCM-SHA384 | TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| AES128-SHA256 | TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| AES256-SHA | TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| AES128-SHA | TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| DES-CBC3-SHA  | TLS\$1RSA\$1WITH\$13DES\$1EDE\$1CBC\$1SHA  | 
| RC4-MD5 | TLS\$1RSA\$1WITH\$1RC4\$1128\$1MD5 | 

## Supported signature schemes between viewers and CloudFront
<a name="secure-connections-viewer-signature-schemes"></a>

CloudFront supports the following signature schemes for connections between viewers and CloudFront.


|  | Security policy | Signature schemes | SSLv3 | TLSv1 | TLSv1\$12016 | TLSv1.1\$12016 | TLSv1.2\$12018 | TLSv1.2\$12019 |  TLSv1.2\$12021 | TLSv1.2\$12025 | TLSv1.3\$12025 | 
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1PSS\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1PSS\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1PSS\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1RSAE\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1RSAE\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PSS\$1RSAE\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA224 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA512 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA224 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ |  |  | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SECP256R1\$1SHA256 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SECP384R1\$1SHA384 | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | ♦ | 
| TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA1 | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 
| TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA1 | ♦ | ♦ | ♦ | ♦ |  |  |  |  |  | 

# Supported protocols and ciphers between CloudFront and the origin
<a name="secure-connections-supported-ciphers-cloudfront-to-origin"></a>

If you choose to [require HTTPS between CloudFront and your origin](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesOriginProtocolPolicy), you can decide [which SSL/TLS protocol to allow](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesOriginSSLProtocols) for the secure connection, and CloudFront can connect to the origin using any of the ECDSA or RSA ciphers listed in the following table. Your origin must support at least one of these ciphers for CloudFront to establish an HTTPS connection to your origin.

OpenSSL and [s2n](https://github.com/awslabs/s2n) use different names for ciphers than the TLS standards use ([RFC 2246](https://tools.ietf.org/html/rfc2246), [RFC 4346](https://tools.ietf.org/html/rfc4346), [RFC 5246](https://tools.ietf.org/html/rfc5246), and [RFC 8446](https://tools.ietf.org/html/rfc8446)). The following table includes the OpenSSL and s2n name, and the RFC name, for each cipher.

For ciphers with elliptic curve key exchange algorithms, CloudFront supports the following elliptic curves:
+ prime256v1
+ secp384r1
+ X25519


| OpenSSL and s2n cipher name | RFC cipher name | 
| --- | --- | 
| Supported ECDSA ciphers | 
| ECDHE-ECDSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| ECDHE-ECDSA-AES256-SHA384 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384 | 
| ECDHE-ECDSA-AES256-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| ECDHE-ECDSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA256 | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| ECDHE-ECDSA-AES128-SHA | TLS\$1ECDHE\$1ECDSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| Supported RSA ciphers | 
| ECDHE-RSA-AES256-GCM-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 | 
| ECDHE-RSA-AES256-SHA384 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA384 | 
| ECDHE-RSA-AES256-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| ECDHE-RSA-AES128-GCM-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 | 
| ECDHE-RSA-AES128-SHA256 | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 | 
| ECDHE-RSA-AES128-SHA | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| AES256-SHA | TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA | 
| AES128-SHA | TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA | 
| DES-CBC3-SHA | TLS\$1RSA\$1WITH\$13DES\$1EDE\$1CBC\$1SHA | 
| RC4-MD5 | TLS\$1RSA\$1WITH\$1RC4\$1128\$1MD5 | 

**Supported signature schemes between CloudFront and the origin**

CloudFront supports the following signature schemes for connections between CloudFront and the origin.
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA256
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA384
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA512
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA224
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA256
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA384
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA512
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA224
+ TLS\$1SIGNATURE\$1SCHEME\$1RSA\$1PKCS1\$1SHA1
+ TLS\$1SIGNATURE\$1SCHEME\$1ECDSA\$1SHA1

# Use alternate domain names and HTTPS
<a name="using-https-alternate-domain-names"></a>

If you want to use your own domain name in the URLs for your files (for example, `https://www.example.com/image.jpg`) and you want your viewers to use HTTPS, you must complete the steps in the following topics. (If you use the default CloudFront distribution domain name in your URLs, for example, `https://d111111abcdef8.cloudfront.net/image.jpg`, follow the guidance in the following topic instead: [Require HTTPS for communication between viewers and CloudFront](using-https-viewers-to-cloudfront.md).)

**Important**  
When you add a certificate to your distribution, CloudFront immediately propagates the certificate to all of its edge locations. As new edge locations become available, CloudFront propagates the certificate to those locations, too. You can't restrict the edge locations that CloudFront propagates the certificates to.

**Topics**
+ [Choose how CloudFront serves HTTPS requests](cnames-https-dedicated-ip-or-sni.md)
+ [Requirements for using SSL/TLS certificates with CloudFront](cnames-and-https-requirements.md)
+ [Quotas on using SSL/TLS certificates with CloudFront (HTTPS between viewers and CloudFront only)](cnames-and-https-limits.md)
+ [Configure alternate domain names and HTTPS](cnames-and-https-procedures.md)
+ [Determine the size of the public key in an SSL/TLS RSA certificate](cnames-and-https-size-of-public-key.md)
+ [Increase the quotas for SSL/TLS certificates](increasing-the-limit-for-ssl-tls-certificates.md)
+ [Rotate SSL/TLS certificates](cnames-and-https-rotate-certificates.md)
+ [Revert from a custom SSL/TLS certificate to the default CloudFront certificate](cnames-and-https-revert-to-cf-certificate.md)
+ [Switch from a custom SSL/TLS certificate with dedicated IP addresses to SNI](cnames-and-https-switch-dedicated-to-sni.md)

# Choose how CloudFront serves HTTPS requests
<a name="cnames-https-dedicated-ip-or-sni"></a>

If you want your viewers to use HTTPS and to use alternate domain names for your files, choose one of the following options for how CloudFront serves HTTPS requests:
+ Use [Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) – Recommended
+ Use a dedicated IP address in each edge location

This section explains how each option works.

## Use SNI to serve HTTPS requests (works for most clients)
<a name="cnames-https-sni"></a>

[Server Name Indication (SNI)](https://en.wikipedia.org/wiki/Server_Name_Indication) is an extension to the TLS protocol that is supported by browsers and clients released after 2010. If you configure CloudFront to serve HTTPS requests using SNI, CloudFront associates your alternate domain name with an IP address for each edge location. When a viewer submits an HTTPS request for your content, DNS routes the request to the IP address for the correct edge location. The IP address to your domain name is determined during the SSL/TLS handshake negotiation; the IP address isn't dedicated to your distribution.

The SSL/TLS negotiation occurs early in the process of establishing an HTTPS connection. If CloudFront can't immediately determine which domain the request is for, it drops the connection. When a viewer that supports SNI submits an HTTPS request for your content, here's what happens:

1. The viewer automatically gets the domain name from the request URL and adds it to the SNI extension of the TLS client hello message.

1. When CloudFront receives the TLS client hello, it uses the domain name in the SNI extension to find the matching CloudFront distribution and sends back the associated TLS certificate.

1. The viewer and CloudFront perform SSL/TLS negotiation.

1. CloudFront returns the requested content to the viewer.

For a current list of the browsers that support SNI, see the Wikipedia entry [Server Name Indication](https://en.wikipedia.org/wiki/Server_Name_Indication).

If you want to use SNI but some of your users' browsers don't support SNI, you have several options:
+ Configure CloudFront to serve HTTPS requests by using dedicated IP addresses instead of SNI. For more information, see [Use a dedicated IP address to serve HTTPS requests (works for all clients)](#cnames-https-dedicated-ip).
+ Use the CloudFront SSL/TLS certificate instead of a custom certificate. This requires that you use the CloudFront domain name for your distribution in the URLs for your files, for example, `https://d111111abcdef8.cloudfront.net/logo.png`.

  If you use the default CloudFront certificate, viewers must support the SSL protocol TLSv1 or later. CloudFront doesn't support SSLv3 with the default CloudFront certificate.

  You also must change the SSL/TLS certificate that CloudFront is using from a custom certificate to the default CloudFront certificate:
  + If you haven't used your distribution to distribute your content, you can just change the configuration. For more information, see [Update a distribution](HowToUpdateDistribution.md).
  + If you have used your distribution to distribute your content, you must create a new CloudFront distribution and change the URLs for your files to reduce or eliminate the amount of time that your content is unavailable. For more information, see [Revert from a custom SSL/TLS certificate to the default CloudFront certificate](cnames-and-https-revert-to-cf-certificate.md).
+ If you can control which browser your users use, have them upgrade their browser to one that supports SNI.
+ Use HTTP instead of HTTPS.

## Use a dedicated IP address to serve HTTPS requests (works for all clients)
<a name="cnames-https-dedicated-ip"></a>

Server Name Indication (SNI) is one way to associate a request with a domain. Another way is to use a dedicated IP address. If you have users who can't upgrade to a browser or client released after 2010, you can use a dedicated IP address to serve HTTPS requests. For a current list of the browsers that support SNI, see the Wikipedia entry [Server Name Indication](https://en.wikipedia.org/wiki/Server_Name_Indication). 

**Important**  
If you configure CloudFront to serve HTTPS requests using dedicated IP addresses, you incur an additional monthly charge. The charge begins when you associate your SSL/TLS certificate with a distribution and you enable the distribution. For more information about CloudFront pricing, see [Amazon CloudFront Pricing](https://aws.amazon.com/cloudfront/pricing). In addition, see [Using the Same Certificate for Multiple CloudFront Distributions](cnames-and-https-limits.md#cnames-and-https-same-certificate-multiple-distributions).

When you configure CloudFront to serve HTTPS requests by using dedicated IP addresses, CloudFront associates your certificate with a dedicated IP address in each CloudFront edge location. When a viewer submits an HTTPS request for your content, here's what happens:

1. DNS routes the request to the IP address for your distribution in the applicable edge location.

1. If a client request provides the SNI extension in the `ClientHello` message, CloudFront searches for a distribution that is associated with that SNI.
   + If there's a match, CloudFront responds to the request with the SSL/TLS certificate.
   + If there's no match, CloudFront uses the IP address instead to identify your distribution and to determine which SSL/TLS certificate to return to the viewer.

1. The viewer and CloudFront perform SSL/TLS negotiation using your SSL/TLS certificate.

1. CloudFront returns the requested content to the viewer.

This method works for every HTTPS request, regardless of the browser or other viewer that the user is using. 

**Note**  
Dedicated IPs are not static IPs and can change over time. The IP address that is returned for the edge location is allocated dynamically from the IP address ranges of the [CloudFront edge servers list](LocationsOfEdgeServers.md).  
The IP address ranges for CloudFront edge servers are subject to change. To be notified of IP address changes, [subscribe to AWS Public IP Address Changes via Amazon SNS](https://aws.amazon.com/blogs/aws/subscribe-to-aws-public-ip-address-changes-via-amazon-sns/).

## Request permission to use three or more dedicated IP SSL/TLS certificates
<a name="cnames-and-https-multiple-certificates"></a>

If you need permission to permanently associate three or more SSL/TLS dedicated IP certificates with CloudFront, perform the following procedure. For more details about HTTPS requests, see [Choose how CloudFront serves HTTPS requests](#cnames-https-dedicated-ip-or-sni).

**Note**  
This procedure is for using three or more dedicated IP certificates across your CloudFront distributions. The default value is 2. Keep in mind you cannot bind more than one SSL certificate to a distribution.  
You can only associate a single SSL/TLS certificate to a CloudFront distribution at a time. This number is for the total number of dedicated IP SSL certificates you can use across all of your CloudFront distributions.<a name="cnames-and-https-multiple-certificates-procedure"></a>

**To request permission to use three or more certificates with a CloudFront distribution**

1. Go to the [Support Center](https://console.aws.amazon.com/support/home?#/case/create?issueType=service-limit-increase&limitType=service-code-cloudfront-distributions) and create a case.

1. Indicate how many certificates you need permission to use, and describe the circumstances in your request. We'll update your account as soon as possible.

1. Continue with the next procedure.

# Requirements for using SSL/TLS certificates with CloudFront
<a name="cnames-and-https-requirements"></a>

The requirements for SSL/TLS certificates are described in this topic. They apply to both of the following, except as noted:
+ Certificates for using HTTPS between viewers and CloudFront 
+ Certificates for using HTTPS between CloudFront and your origin

**Topics**
+ [Certificate issuer](#https-requirements-certificate-issuer)
+ [AWS Region for AWS Certificate Manager](#https-requirements-aws-region)
+ [Certificate format](#https-requirements-certificate-format)
+ [Intermediate certificates](#https-requirements-intermediate-certificates)
+ [Key type](#https-requirements-key-type)
+ [Private key](#https-requirements-private-key)
+ [Permissions](#https-requirements-permissions)
+ [Size of the certificate key](#https-requirements-size-of-public-key)
+ [Supported types of certificates](#https-requirements-supported-types)
+ [Certificate expiration date and renewal](#https-requirements-cert-expiration)
+ [Domain names in the CloudFront distribution and in the certificate](#https-requirements-domain-names-in-cert)
+ [Minimum SSL/TLS protocol version](#https-requirements-minimum-ssl-protocol-version)
+ [Supported HTTP versions](#https-requirements-supported-http-versions)

## Certificate issuer
<a name="https-requirements-certificate-issuer"></a>

We recommend that you use a public certificate issued by [AWS Certificate Manager (ACM)](https://aws.amazon.com/certificate-manager/). For information about getting a certificate from ACM, see the *[AWS Certificate Manager User Guide](https://docs.aws.amazon.com/acm/latest/userguide/)*. To use an ACM certificate with a CloudFront distribution, make sure you request (or import) the certificate in the US East (N. Virginia) Region (`us-east-1`).

 CloudFront supports the same certificate authorities (CAs) as Mozilla, so if you don’t use ACM, use a certificate issued by a CA on the [Mozilla Included CA Certificate List](https://wiki.mozilla.org/CA/Included_Certificates). 

TLS certificates used by the origin that you specified for your CloudFront distribution also need to be issued from the CA on the Mozilla Included CA Certificate List.

For more information about getting and installing a certificate, refer to the documentation for your HTTP server software and to the documentation for the CA.

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

To use a certificate in AWS Certificate Manager (ACM) to require HTTPS between viewers and CloudFront, make sure you request (or import) the certificate in the US East (N. Virginia) Region (`us-east-1`).

If you want to require HTTPS between CloudFront and your origin, and you’re using a load balancer in Elastic Load Balancing as your origin, you can request or import the certificate in any AWS Region.

## Certificate format
<a name="https-requirements-certificate-format"></a>

The certificate must be in X.509 PEM format. This is the default format if you’re using AWS Certificate Manager.

## Intermediate certificates
<a name="https-requirements-intermediate-certificates"></a>

If you’re using a third-party certificate authority (CA), list all of the intermediate certificates in the certificate chain that’s in the `.pem` file, beginning with one for the CA that signed the certificate for your domain. Typically, you’ll find a file on the CA website that lists intermediate and root certificates in the proper chained order.

**Important**  
Do not include the following: the root certificate, intermediate certificates that are not in the trust path, or your CA’s public key certificate.

Here’s an example:

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

## Key type
<a name="https-requirements-key-type"></a>

CloudFront supports RSA and ECDSA public–private key pairs.

CloudFront supports HTTPS connections to both viewers and origins using RSA and ECDSA certificates. With [AWS Certificate Manager (ACM)](https://console.aws.amazon.com/acm), you can request and import RSA or ECDSA certificates and then associate them with your CloudFront distribution.

For lists of the RSA and ECDSA ciphers supported by CloudFront that you can negotiate in HTTPS connections, see [Supported protocols and ciphers between viewers and CloudFront](secure-connections-supported-viewer-protocols-ciphers.md) and [Supported protocols and ciphers between CloudFront and the origin](secure-connections-supported-ciphers-cloudfront-to-origin.md).

## Private key
<a name="https-requirements-private-key"></a>

If you're using a certificate from a third-party certificate authority (CA), note the following: 
+ The private key must match the public key that is in the certificate.
+ The private key must be in PEM format.
+ The private key cannot be encrypted with a password.

If AWS Certificate Manager (ACM) provided the certificate, ACM doesn’t release the private key. The private key is stored in ACM for use by AWS services that are integrated with ACM.

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

You must have permission to use and import the SSL/TLS certificate. If you’re using AWS Certificate Manager (ACM), we recommend that you use AWS Identity and Access Management permissions to restrict access to the certificates. For more information, see [Identity and access management](https://docs.aws.amazon.com/acm/latest/userguide/security-iam.html) in the *AWS Certificate Manager User Guide*.

## Size of the certificate key
<a name="https-requirements-size-of-public-key"></a>

The certificate key size that CloudFront supports depends on the type of key and certificate.

**For RSA certificates:**  
CloudFront supports 1024-bit, 2048-bit, and 3072-bit, and 4096-bit RSA keys. The maximum key length for an RSA certificate that you use with CloudFront is 4096 bits.  
 Note that ACM issues RSA certificates with up to 2048-bit keys. To use a 3072-bit or 4096-bit RSA certificate, you need to obtain the certificate externally and import it into ACM, after which it will be available for you to use with CloudFront.   
For information about how to determine the size of an RSA key, see [Determine the size of the public key in an SSL/TLS RSA certificate](cnames-and-https-size-of-public-key.md).

**For ECDSA certificates:**  
CloudFront supports 256-bit keys. To use an ECDSA certificate in ACM to require HTTPS between viewers and CloudFront, use the prime256v1 elliptic curve.

## Supported types of certificates
<a name="https-requirements-supported-types"></a>

CloudFront supports all types of certificates issued by a trusted certificate authority.

## Certificate expiration date and renewal
<a name="https-requirements-cert-expiration"></a>

If you’re using certificates that you get from a third-party certificate authority (CA), you must monitor certificate expiration dates and renew the certificates that you import into AWS Certificate Manager (ACM) or upload to the AWS Identity and Access Management certificate store before they expire.

**Important**  
To avoid certificate expiration issues, renew or reimport your certificate at least 24 hours before the `NotAfter` value of your current certificate. If your certificate expires within 24 hours, request a new certificate from ACM or import a new certificate to ACM. Next, associate the new certificate to the CloudFront distribution.  
CloudFront might continue to use the previous certificate while your certificate renewal or reimport is in progress. This is an asynchronous process that can take up to 24 hours before CloudFront shows your changes.

If you’re using ACM provided certificates, ACM manages certificate renewals for you. For more information, see [Managed renewal](https://docs.aws.amazon.com/acm/latest/userguide/managed-renewal.html) in the *AWS Certificate Manager User Guide*.

## Domain names in the CloudFront distribution and in the certificate
<a name="https-requirements-domain-names-in-cert"></a>

When you’re using a custom origin, the SSL/TLS certificate on your origin includes a domain name in the **Common Name** field, and possibly several more in the **Subject Alternative Names** field. (CloudFront supports wildcard characters in certificate domain names.) 

One of the domain names in the certificate must match the domain name that you specify for Origin Domain Name. If no domain name matches, CloudFront returns HTTP status code `502 (Bad Gateway)` to the viewer.

**Important**  
When you add an alternate domain name to a distribution, CloudFront checks that the alternate domain name is covered by the certificate that you’ve attached. The certificate must cover the alternate domain name in the subject alternate name (SAN) field of the certificate. This means the SAN field must contain an exact match for the alternate domain name, or contain a wildcard at the same level of the alternate domain name that you’re adding.  
For more information, see [Requirements for using alternate domain names](CNAMEs.md#alternate-domain-names-requirements).

## Minimum SSL/TLS protocol version
<a name="https-requirements-minimum-ssl-protocol-version"></a>

If you’re using dedicated IP addresses, set the minimum SSL/TLS protocol version for the connection between viewers and CloudFront by choosing a security policy.

For more information, see [Security policy (minimum SSL/TLS version)](DownloadDistValuesGeneral.md#DownloadDistValues-security-policy) in the topic [All distribution settings reference](distribution-web-values-specify.md).

## Supported HTTP versions
<a name="https-requirements-supported-http-versions"></a>

If you associate one certificate with more than one CloudFront distribution, all the distributions associated with the certificate must use the same option for [Supported HTTP versions](DownloadDistValuesGeneral.md#DownloadDistValuesSupportedHTTPVersions). You specify this option when you create or update a CloudFront distribution.

# Quotas on using SSL/TLS certificates with CloudFront (HTTPS between viewers and CloudFront only)
<a name="cnames-and-https-limits"></a>

Note the following quotas on using SSL/TLS certificates with CloudFront. These quotas apply only to the SSL/TLS certificates that you provision by using AWS Certificate Manager (ACM), that you import into ACM, or upload to the IAM certificate store for HTTPS communication between viewers and CloudFront.

For more information, see [Increase the quotas for SSL/TLS certificates](increasing-the-limit-for-ssl-tls-certificates.md).

**Maximum number of certificates per CloudFront distribution**  
You can associate a maximum of one SSL/TLS certificate with each CloudFront distribution.

**Maximum number of certificates that you can import into ACM or upload to the IAM certificate store**  
If you obtained your SSL/TLS certificates from a third-party CA, you must store the certificates in one of the following locations:  
+ **AWS Certificate Manager** – For the current quota on the number of ACM certificates, see [Quotas](https://docs.aws.amazon.com/acm/latest/userguide/acm-limits.html) in the *AWS Certificate Manager User Guide*. The listed quota is a total that includes certificates that you provision by using ACM and certificates that you import into ACM.
+ **IAM certificate store** – For the current quota (formerly known as limit) on the number of certificates that you can upload to the IAM certificate store for an AWS account, see [IAM and STS Limits](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html) in the *IAM User Guide*. You can request a higher quota in the Service Quotas console.

**Maximum number of certificates per AWS account (dedicated IP addresses only)**  
If you want to serve HTTPS requests by using dedicated IP addresses, note the following:  
+ By default, CloudFront gives you permission to use two certificates with your AWS account, one for everyday use and one for when you need to rotate certificates for multiple distributions.
+ If you need more than two custom SSL/TLS certificates for your AWS account, you can request a higher quota in the Service Quotas console.

**Use the same certificate for CloudFront distributions that were created by using different AWS accounts**  
If you're using a third-party CA and you want to use the same certificate with multiple CloudFront distributions that were created by using different AWS accounts, you must import the certificate into ACM or upload it to the IAM certificate store once for each AWS account.  
If you're using certificates provided by ACM, you can't configure CloudFront to use certificates that were created by a different AWS account.

**Use the same certificate for CloudFront and for other AWS services**  
If you bought a certificate from a trusted certificate authority such as Comodo, DigiCert, or Symantec, you can use the same certificate for CloudFront and for other AWS services. If you're importing the certificate into ACM, you need to import it only once to use it for multiple AWS services.  
If you're using certificates provided by ACM, the certificates are stored in ACM.

**Use the same certificate for multiple CloudFront distributions**  
You can use the same certificate for any or all of the CloudFront distributions that you're using to serve HTTPS requests. Note the following:  
+ You can use the same certificate both for serving requests using dedicated IP addresses and for serving requests using SNI. 
+ You can associate only one certificate with each distribution.
+ Each distribution must include one or more alternate domain names that also appear in the **Common Name** field or the **Subject Alternative Names** field in the certificate.
+ If you're serving HTTPS requests using dedicated IP addresses and you created all of your distributions by using the same AWS account, you can significantly reduce your cost by using the same certificate for all distributions. CloudFront charges for each certificate, not for each distribution. 

  For example, suppose you create three distributions by using the same AWS account, and you use the same certificate for all three distributions. You would be charged only one fee for using dedicated IP addresses.

  However, if you're serving HTTPS requests using dedicated IP addresses and using the same certificate to create CloudFront distributions in different AWS accounts, each account is charged the fee for using dedicated IP addresses. For example, if you create three distributions by using three different AWS accounts and you use the same certificate for all three distributions, each account is charged the full fee for using dedicated IP addresses.

# Configure alternate domain names and HTTPS
<a name="cnames-and-https-procedures"></a>

To use alternate domain names in the URLs for your files and to use HTTPS between viewers and CloudFront, perform the applicable procedures.

**Topics**
+ [Get an SSL/TLS certificate](#cnames-and-https-getting-certificates)
+ [Import an SSL/TLS certificate](#cnames-and-https-uploading-certificates)
+ [Update your CloudFront distribution](#cnames-and-https-updating-cloudfront)

## Get an SSL/TLS certificate
<a name="cnames-and-https-getting-certificates"></a>

Get an SSL/TLS certificate if you don’t already have one. For more information, see the applicable documentation:
+ To use a certificate provided by AWS Certificate Manager (ACM), see the [AWS Certificate Manager User Guide](https://docs.aws.amazon.com/acm/latest/userguide/). Then skip to [Update your CloudFront distribution](#cnames-and-https-updating-cloudfront).
**Note**  
We recommend that you use ACM to provision, manage, and deploy SSL/TLS certificates on AWS managed resources. You must request an ACM certificate in the US East (N. Virginia) Region.
+ To get a certificate from a third-party certificate authority (CA), see the documentation provided by the certificate authority. When you have the certificate, continue with the next procedure.

## Import an SSL/TLS certificate
<a name="cnames-and-https-uploading-certificates"></a>

If you got your certificate from a third-party CA, import the certificate into ACM or upload it to the IAM certificate store:

**ACM (recommended)**  
ACM lets you import third-party certificates from the ACM console, as well as programmatically. For information about importing a certificate to ACM, see [Importing Certificates into AWS Certificate Manager](https://docs.aws.amazon.com/acm/latest/userguide/import-certificate.html) in the *AWS Certificate Manager User Guide*. You must import the certificate in the US East (N. Virginia) Region.

**IAM certificate store**  
(Not recommended) Use the following AWS CLI command to upload your third-party certificate to the IAM certificate store.  

```
aws iam upload-server-certificate \
        --server-certificate-name CertificateName \
        --certificate-body file://public_key_certificate_file \
        --private-key file://privatekey.pem \
        --certificate-chain file://certificate_chain_file \
        --path /cloudfront/path/
```
Note the following:  
+ **AWS account** – You must upload the certificate to the IAM certificate store using the same AWS account that you used to create your CloudFront distribution.
+ **--path parameter** – When you upload the certificate to IAM, the value of the `--path` parameter (certificate path) must start with `/cloudfront/`, for example, `/cloudfront/production/` or `/cloudfront/test/`. The path must end with a /.
+ **Existing certificates** – You must specify values for the `--server-certificate-name` and `--path` parameters that are different from the values that are associated with existing certificates.
+ **Using the CloudFront console** – The value that you specify for the `--server-certificate-name` parameter in the AWS CLI, for example, `myServerCertificate`, appears in the **SSL Certificate** list in the CloudFront console.
+ **Using the CloudFront API** – Make note of the alphanumeric string that the AWS CLI returns, for example, `AS1A2M3P4L5E67SIIXR3J`. This is the value that you will specify in the `IAMCertificateId` element. You don't need the IAM ARN, which is also returned by the CLI.
For more information about the AWS CLI, see the [AWS Command Line Interface User Guide](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html) and the [AWS CLI Command Reference](https://docs.aws.amazon.com/cli/latest/reference/).

## Update your CloudFront distribution
<a name="cnames-and-https-updating-cloudfront"></a>

To update settings for your distribution, perform the following procedure:<a name="cnames-and-https-updating-cloudfront-procedure"></a>

**To configure your CloudFront distribution for alternate domain names**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose the ID for the distribution that you want to update.

1. On the **General** tab, choose **Edit**.

1. Update the following values:  
**Alternate domain name (CNAME)**  
Choose **Add item** to add the applicable alternate domain names. Separate domain names with commas, or type each domain name on a new line.  
**Custom SSL certificate**  
Select a certificate from the dropdown list.  
Up to 100 certificates are listed here. If you have more than 100 certificates and you don't see the certificate that you want to add, you can type a certificate ARN in the field to choose it.  
If you uploaded a certificate to the IAM certificate store but it's not listed, and you can't choose it by typing the name in the field, review the procedure [Import an SSL/TLS certificate](#cnames-and-https-uploading-certificates) to confirm that you correctly uploaded the certificate.   
After you associate your SSL/TLS certificate with your CloudFront distribution, do not delete the certificate from ACM or the IAM certificate store until you remove the certificate from all distributions and all the distributions are deployed.

1. Choose **Save changes**.

1. Configure CloudFront to require HTTPS between viewers and CloudFront:

   1. On the **Behaviors** tab, choose the cache behavior that you want to update, and choose **Edit**.

   1. Specify one of the following values for **Viewer Protocol Policy**:  
**Redirect HTTP to HTTPS**  
Viewers can use both protocols, but HTTP requests are automatically redirected to HTTPS requests. CloudFront returns HTTP status code `301 (Moved Permanently)` along with the new HTTPS URL. The viewer then resubmits the request to CloudFront using the HTTPS URL.  
CloudFront doesn't redirect `DELETE`, `OPTIONS`, `PATCH`, `POST`, or `PUT` requests from HTTP to HTTPS. If you configure a cache behavior to redirect to HTTPS, CloudFront responds to HTTP `DELETE`, `OPTIONS`, `PATCH`, `POST`, or `PUT` requests for that cache behavior with HTTP status code `403 (Forbidden)`.
When a viewer makes an HTTP request that is redirected to an HTTPS request, CloudFront charges for both requests. For the HTTP request, the charge is only for the request and for the headers that CloudFront returns to the viewer. For the HTTPS request, the charge is for the request, and for the headers and the file returned by your origin.  
**HTTPS Only**  
Viewers can access your content only if they're using HTTPS. If a viewer sends an HTTP request instead of an HTTPS request, CloudFront returns HTTP status code `403 (Forbidden)` and does not return the file.

   1. Choose **Yes, Edit**.

   1. Repeat steps a through c for each additional cache behavior that you want to require HTTPS for between viewers and CloudFront.

1. Confirm the following before you use the updated configuration in a production environment:
   + The path pattern in each cache behavior applies only to the requests that you want viewers to use HTTPS for.
   + The cache behaviors are listed in the order that you want CloudFront to evaluate them in. For more information, see [Path pattern](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern).
   + The cache behaviors are routing requests to the correct origins. 

# Determine the size of the public key in an SSL/TLS RSA certificate
<a name="cnames-and-https-size-of-public-key"></a>

When you’re using CloudFront alternate domain names and HTTPS, the maximum size of the public key in an SSL/TLS RSA certificate is 4096 bits. (This is the key size, not the number of characters in the public key.) If you use AWS Certificate Manager for your certificates, although ACM supports larger RSA keys, you cannot use the larger keys with CloudFront.

You can determine the size of the RSA public key by running the following OpenSSL command:

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

Where:
+ `-in` specifies the path and file name of your SSL/TLS RSA certificate.
+ `-text` causes OpenSSL to display the length of the RSA public key in bits.
+ `-noout` prevents OpenSSL from displaying the public key.

Example output:

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

# Increase the quotas for SSL/TLS certificates
<a name="increasing-the-limit-for-ssl-tls-certificates"></a>

There are quotas on the number of SSL/TLS certificates that you can import into AWS Certificate Manager (ACM) or upload to AWS Identity and Access Management (IAM). There also is a quota on the number of SSL/TLS certificates that you can use with an AWS account when you configure CloudFront to serve HTTPS requests by using dedicated IP addresses. However, you can request higher quotas.

**Topics**
+ [Increase quota on certificates imported into ACM](#certificates-to-import-into-acm)
+ [Increase quota on certificates uploaded to IAM](#certificates-to-upload-into-iam)
+ [Increase quota on certificates used with dedicated IP addresses](#certificates-using-dedicated-ip-address)

## Increase quota on certificates imported into ACM
<a name="certificates-to-import-into-acm"></a>

For the quota on the number of certificates that you can import into ACM, see [Quotas](https://docs.aws.amazon.com/acm/latest/userguide/acm-limits.html) in the *AWS Certificate Manager User Guide*.

To request a higher quota, use the Service Quotas console. For more information, see [Requesting a quota increase](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html) in the *Service Quotas User Guide*.

## Increase quota on certificates uploaded to IAM
<a name="certificates-to-upload-into-iam"></a>

For the quota (formerly known as limit) on the number of certificates that you can upload to IAM, see [IAM and STS Limits](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_iam-limits.html) in the *IAM User Guide*.

To request a higher quota, use the Service Quotas console. For more information, see [Requesting a quota increase](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html) in the *Service Quotas User Guide*.

## Increase quota on certificates used with dedicated IP addresses
<a name="certificates-using-dedicated-ip-address"></a>

For the quota on the number of SSL certificates that you can use for each AWS account when serving HTTPS requests using dedicated IP addresses, see [Quotas on SSL certificates](cloudfront-limits.md#limits-ssl-certificates).

To request a higher quota, use the Service Quotas console. For more information, see [Requesting a quota increase](https://docs.aws.amazon.com/servicequotas/latest/userguide/request-quota-increase.html) in the *Service Quotas User Guide*.

# Rotate SSL/TLS certificates
<a name="cnames-and-https-rotate-certificates"></a>

When your SSL/TLS certificates are near expiration, you need to rotate them to ensure the security for your distribution and avoid service disruption for your viewers. You can rotate them in the following ways:
+ For SSL/TLS certificates provided by AWS Certificate Manager (ACM), you don't need to rotate them. ACM *automatically* manages certificate renewals for you. For more information, see [Managed certificate renewal](https://docs.aws.amazon.com/acm/latest/userguide/acm-renewal.html) in the *AWS Certificate Manager User Guide*.
+ If you're using a third-party certificate authority and you imported the certificates into ACM (recommended) or uploaded them to the IAM certificate store, you must occasionally replace one certificate with another.

  

**Important**  
ACM doesn't manage certificate renewals for certificates that you acquire from third-party certificate authorities and import into ACM.
If you configured CloudFront to serve HTTPS requests by using dedicated IP addresses, you might incur an additional, pro-rated charge for using one or more additional certificates while you're rotating certificates. We recommend that you update your distributions to minimize the additional charge.

## Rotate SSL/TLS certificates
<a name="rotate-ssl-tls-certificate"></a>

To rotate your certificates, perform the following procedure. Viewers can continue to access your content while you rotate certificates as well as after the process is complete.<a name="rotate-ssl-tls-certificates-proc"></a>

**To rotate SSL/TLS certificates**

1. [Increase the quotas for SSL/TLS certificates](increasing-the-limit-for-ssl-tls-certificates.md) to determine whether you need permission to use more SSL certificates. If so, request permission and wait until permission is granted before you continue with step 2.

1. Import the new certificate into ACM or upload it to IAM. For more information, see [Importing an SSL/TLS Certificate](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-procedures.html#cnames-and-https-uploading-certificates) in the *Amazon CloudFront Developer Guide*.

1. (For IAM certificates only) Update your distributions one at a time to use the new certificate. For more information, see [Update a distribution](HowToUpdateDistribution.md).

1. (Optional) Delete the previous certificate from ACM or IAM.
**Important**  
Don't delete an SSL/TLS certificate until you remove it from all distributions and until the status of the distributions that you have updated has changed to `Deployed`.

# Revert from a custom SSL/TLS certificate to the default CloudFront certificate
<a name="cnames-and-https-revert-to-cf-certificate"></a>

If you configured CloudFront to use HTTPS between viewers and CloudFront, and you configured CloudFront to use a custom SSL/TLS certificate, you can change your configuration to use the default CloudFront SSL/TLS certificate. The process depends on whether you've used your distribution to distribute your content:
+ If you have not used your distribution to distribute your content, you can just change the configuration. For more information, see [Update a distribution](HowToUpdateDistribution.md).
+ If you have used your distribution to distribute your content, you must create a new CloudFront distribution and change the URLs for your files to reduce or eliminate the amount of time that your content is unavailable. To do that, perform the following procedure.

## Revert to default CloudFront certificate
<a name="revert-default-cloudfront-certificate"></a>

The following procedure shows you how to revert from a custom SSL/TLS certificate to the default CloudFront certificate.<a name="cnames-and-https-revert-to-cf-certificate-proc"></a>

**To revert to the default CloudFront certificate**

1. Create a new CloudFront distribution with the desired configuration. For **SSL Certificate**, choose **Default CloudFront Certificate (\$1.cloudfront.net)**. 

   For more information, see [Create a distribution](distribution-web-creating-console.md).

1. For files that you're distributing using CloudFront, update the URLs in your application to use the domain name that CloudFront assigned to the new distribution. For example, change `https://www.example.com/images/logo.png` to `https://d111111abcdef8.cloudfront.net/images/logo.png`.

1. Either delete the distribution that is associated with a custom SSL/TLS certificate, or update the distribution to change the value of **SSL Certificate** to **Default CloudFront Certificate (\$1.cloudfront.net)**. For more information, see [Update a distribution](HowToUpdateDistribution.md).
**Important**  
Until you complete this step, AWS continues to charge you for using a custom SSL/TLS certificate.

1. (Optional) Delete your custom SSL/TLS certificate.

   1. Run the AWS CLI command `list-server-certificates` to get the certificate ID of the certificate that you want to delete. For more information, see [list-server-certificates](https://docs.aws.amazon.com/cli/latest/reference/iam/list-server-certificates.html) in the *AWS CLI Command Reference*.

   1. Run the AWS CLI command `delete-server-certificate` to delete the certificate. For more information, see [delete-server-certificate](https://docs.aws.amazon.com/cli/latest/reference/iam/delete-server-certificate.html) in the *AWS CLI Command Reference*.

# Switch from a custom SSL/TLS certificate with dedicated IP addresses to SNI
<a name="cnames-and-https-switch-dedicated-to-sni"></a>

If you configured CloudFront to use a custom SSL/TLS certificate with dedicated IP addresses, you can switch to using a custom SSL/TLS certificate with SNI instead and eliminate the charge that is associated with dedicated IP addresses.

**Important**  
This update to your CloudFront configuration has no effect on viewers that support SNI. Viewers can access your content before and after the change, as well as while the change is propagating to CloudFront edge locations. Viewers that don't support SNI can't access your content after the change. For more information, see [Choose how CloudFront serves HTTPS requests](cnames-https-dedicated-ip-or-sni.md). 

## Switch from a custom certificate to SNI
<a name="cloudfront-switch-custom-cert-sni"></a>

The following procedure shows you how to switch from a custom SSL/TLS certificate with dedicated IP addresses to SNI.<a name="cnames-and-https-switch-dedicated-to-sni-proc"></a>

**To switch from a custom SSL/TLS certificate with dedicated IP addresses to SNI**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose the ID of the distribution that you want to view or update.

1. Choose **Distribution Settings**.

1. On the **General** tab, choose **Edit**.

1. Under **Custom SSL certification – *optional***, deselect **Legacy clients support**.

1. Choose **Yes, Edit**.

# Mutual TLS authentication with CloudFront (Viewer mTLS)
<a name="mtls-authentication"></a>

Mutual TLS Authentication (Mutual Transport Layer Security Authentication — mTLS) is a security protocol that extends standard TLS authentication by requiring bidirectional certificate-based authentication, where both client and server must prove their identity before establishing a secure connection. Using mutual TLS, you can ensure that only clients presenting trusted TLS certificates gain access to your CloudFront distributions.

## How it works
<a name="how-mtls-works"></a>

In a standard TLS handshake, only the server presents a certificate to prove its identity to the client. With mutual TLS, the authentication process becomes bidirectional. When a client attempts to connect to your CloudFront distribution, CloudFront requests a client certificate during the TLS handshake. The client must present a valid X.509 certificate that CloudFront validates against your configured trust store before establishing the secure connection.

CloudFront performs this certificate validation at AWS edge locations, offloading the authentication complexity from your origin servers while maintaining CloudFront's global performance benefits. You can configure mTLS in two modes: verify mode (which requires all clients to present valid certificates) or optional mode (which validates certificates when presented but also allows connections without certificates).

## Use cases
<a name="mtls-use-cases"></a>

Mutual TLS authentication with CloudFront addresses several critical security scenarios where traditional authentication methods are insufficient:
+ **Device authentication with content caching** - You can authenticate gaming consoles, IoT devices, or corporate hardware before allowing access to firmware updates, game downloads, or internal resources. Each device contains a unique certificate that proves its authenticity while benefiting from CloudFront's caching capabilities.
+ **API-to-API authentication** - You can secure machine-to-machine communication between trusted business partners, payment systems, or micro-services. Certificate-based authentication eliminates the need for shared secrets or API keys while providing strong identity verification for automated data exchanges.

**Topics**
+ [How it works](#how-mtls-works)
+ [Use cases](#mtls-use-cases)
+ [Trust stores and certificate management](trust-stores-certificate-management.md)
+ [Enable mutual TLS for CloudFront distributions](enable-mtls-distributions.md)
+ [Associate a CloudFront Connection Function](connection-functions.md)
+ [Configuring additional settings](configuring-additional-settings.md)
+ [Viewer mTLS headers for cache policies and forwarded to origin](viewer-mtls-headers.md)
+ [Revocation using CloudFront Connection Function and KVS](revocation-connection-function-kvs.md)
+ [Observability using connection logs](connection-logs.md)

# Trust stores and certificate management
<a name="trust-stores-certificate-management"></a>

Creating and configuring a trust store is a mandatory requirement for implementing mutual TLS authentication with CloudFront. Trust stores contain the Certificate Authority (CA) certificates that CloudFront uses to validate client certificates during the authentication process.

## What is a trust store?
<a name="what-is-trust-store"></a>

A trust store is a repository of CA certificates that CloudFront uses to validate client certificates during mutual TLS authentication. Trust stores contain the root and intermediate CA certificates that form the chain of trust for authenticating client certificates.

When you implement mutual TLS with CloudFront, the trust store defines which Certificate Authorities you trust to issue valid client certificates. CloudFront validates each client certificate against your trust store during the TLS handshake. Only clients presenting certificates that chain to one of the CAs in your trust store will be authenticated successfully.

Trust stores in CloudFront are account-level resources that you can associate with multiple distributions. This allows you to maintain consistent certificate validation policies across your entire CloudFront deployment while simplifying CA certificate management.

## Certificate Authority support
<a name="ca-support"></a>

CloudFront supports certificates issued by both AWS Private Certificate Authority and third-party private Certificate Authorities. This flexibility allows you to use your existing certificate infrastructure or leverage AWS managed certificate services based on your organizational requirements.
+ **AWS Private Certificate Authority:** You can use certificates issued by AWS Private CA, which provides a managed private certificate authority service. This integration simplifies certificate lifecycle management and provides seamless integration with other AWS services.
+ **Third-party private Certificate Authorities:** You can also use certificates from your existing private Certificate Authority infrastructure, including enterprise CAs or other third-party certificate providers. This allows you to maintain your current certificate management processes while adding CloudFront's mTLS capabilities.

## Certificate requirements and specifications
<a name="certificate-requirements"></a>

Trust stores have specific requirements for the CA certificates they contain:

### CA certificate format requirements
<a name="ca-cert-format-requirements"></a>
+ **Format:** PEM (Privacy Enhanced Mail) format
+ **Content boundaries:** Certificates must be enclosed within the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- boundaries
+ **Comments:** Must be preceded by a \$1 character and cannot contain any - characters
+ **Line breaks:** No blank lines are allowed between certificates

### Supported certificate specifications
<a name="supported-cert-specs"></a>
+ **Certificate type:** X.509v3
+ **Public key types:**
  + RSA 2048, RSA 3072, RSA 4096
  + ECDSA: secp256r1, secp384r1
+ **Signature algorithms:**
  + SHA256, SHA384, SHA512 with RSA
  + SHA256, SHA384, SHA512 with EC
  + SHA256, SHA384, SHA512 with RSASSA-PSS with MGF1

### Example certificate bundle format
<a name="example-cert-bundle"></a>

Multiple certificates (PEM-encoded):

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

## Create a trust store
<a name="create-trust-store"></a>

Before creating a trust store, you must upload your CA certificate bundle in PEM format to an Amazon S3 bucket. The certificate bundle should contain all the trusted root and intermediate CA certificates needed to validate your client certificates.

The CA certificate bundle is only read once from S3 when creating a trust store. If future changes are made to the CA certificate bundle, then the trust store will have to be manually updated. No sync is maintained between the trust store and the S3 CA certificate bundle.

### Prerequisites
<a name="trust-store-prerequisites"></a>
+ A certificate bundle from your Certificate Authority (CA) uploaded to an Amazon S3 bucket
+ The necessary permissions to create CloudFront resources

### To create a trust store (Console)
<a name="create-trust-store-console"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Trust stores**.

1. Choose **Create trust store**.

1. For **Trust store name**, enter a name for your trust store.

1. For **Certificate authority (CA) bundle**, enter the Amazon S3 path to your PEM-format CA certificate bundle.

1. Choose **Create trust store**.

### To create a trust store (AWS CLI)
<a name="create-trust-store-cli"></a>

```
aws cloudfront create-trust-store \
  --name MyTrustStore \
  --ca-certificates-bundle-source '{"CaCertificatesBundleS3Location":{"Bucket":"my-bucket","Key":"ca-bundle.pem","Region":"bucket-region"}}' \
  --tags Items=[{Key=Environment,Value=Production}]
```

## Associate trust store with distributions
<a name="associate-trust-store"></a>

After creating a trust store, you must associate it with a CloudFront distribution to enable mutual TLS authentication.

### Prerequisites
<a name="associate-prerequisites"></a>
+ An existing CloudFront distribution with HTTPS-only viewer protocol policy enabled and HTTP3 support disabled.

### To associate a trust store (Console)
<a name="associate-trust-store-console"></a>

There are two avenues to associate a trust store within the CloudFront console: through the trust store details page or through the distribution settings page.

**Associating a trust store through the trust store details page:**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Trust stores**.

1. Choose the name of the trust store you want to associate.

1. Choose **Associate to distribution**.

1. Configure the available Viewer mTLS options:
   + **Client certificate validation mode:** Choose between Required and Optional mode. In required mode, all clients are required to present certificates. In optional mode, clients that present certificates are validated, while clients that do not present certificates are permitted access.
   + **Advertise trust store CA names:** Choose whether to advertise the CA names in your trust store to clients during TLS handshake.
   + **Ignore certificate expiration date:** Choose whether to allow connections with expired certificates (other validation criteria still apply).
   + **Connection Function:** An optional Connection Function can be associated to allow/deny connections based on other custom criteria.

1. Select one or more distributions to associate with the trust store. Only distributions with HTTP3 disabled and with HTTPS-only cache behaviors can support Viewer mTLS.

1. Choose **Associate**.

**Associating a trust store through the distribution settings page:**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Select the distribution that you want to associate

1. Under the **General** tab, within the **Settings** container, choose **Edit** in the top right corner

1. Scroll down to the bottom of the page, within the **Connectivity** container, toggle the **Viewer mTLS** switch on

1. Configure the available Viewer mTLS options:
   + **Client certificate validation mode:** Choose between Required and Optional mode. In required mode, all clients are required to present certificates. In optional mode, clients that present certificates are validated, while clients that do not present certificates are permitted access.
   + **Advertise trust store CA names:** Choose whether to advertise the CA names in your trust store to clients during TLS handshake.
   + **Ignore certificate expiration date:** Choose whether to allow connections with expired certificates (other validation criteria still apply).
   + **Connection Function:** An optional Connection Function can be associated to allow/deny connections based on other custom criteria.

1. Choose **Save changes** in the bottom right corner.

### To associate a trust store (AWS CLI)
<a name="associate-trust-store-cli"></a>

Trust stores can be associated to distributions via the DistributionConfig.ViewerMtlsConfig property. This means we first need to fetch the distribution config and then provide the ViewerMtlsConfig in a subsequent UpdateDistribution request.

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

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

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

## Manage trust stores
<a name="manage-trust-stores"></a>

### View trust store details
<a name="view-trust-store-details"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Trust stores**.

1. Choose the name of the trust store to view its details page.

The details page shows:
+ Trust store name and ID
+ Number of CA certificates
+ Creation date and last modified date
+ Associated distributions
+ Tags

### Modify a trust store
<a name="modify-trust-store"></a>

To replace the CA certificate bundle:

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Trust stores**.

1. Choose the name of the trust store.

1. Choose **Actions**, then **Edit**.

1. For **Certificate authority (CA) bundle**, enter the Amazon S3 location of the updated CA bundle PEM file.

1. Choose **Update trust store**.

### Delete a trust store
<a name="delete-trust-store"></a>

**Prerequisites:** You must first disassociate the trust store from all CloudFront distributions.

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Trust stores**.

1. Choose the name of the trust store.

1. Choose **Delete trust store**.

1. Choose **Delete** to confirm.

### Next steps
<a name="trust-store-next-steps"></a>

After creating and associating your trust store with a CloudFront distribution, you can proceed to enable mutual TLS authentication on your distribution and configure additional settings such as forwarding certificate headers to your origins. For detailed instructions on enabling mTLS on your distributions, see [Enable mutual TLS for CloudFront distributions](enable-mtls-distributions.md).

# Enable mutual TLS for CloudFront distributions
<a name="enable-mtls-distributions"></a>

## Prerequisites and requirements
<a name="mtls-prerequisites-requirements"></a>

CloudFront's mutual TLS verify mode requires all clients to present valid certificates during the TLS handshake and rejects connections without valid certificates. Before enabling mutual TLS on a CloudFront distribution, ensure you have:
+ Created a trust store with your Certificate Authority certificates
+ Associated the trust store with your CloudFront distribution
+ Ensured all distribution cache behaviors use an HTTPS-only viewer protocol policy
+ Ensured your distribution is using HTTP/2 (the default setting, Viewer mTLS is not supported on HTTP/3)

**Note**  
Mutual TLS authentication requires HTTPS connections between viewers and CloudFront. You cannot enable mTLS on a distribution with any cache behaviors that support HTTP connections.

## Enable mutual TLS (Console)
<a name="enable-mtls-console"></a>

### For new distributions
<a name="enable-mtls-new-distributions"></a>

Viewer mTLS cannot be configured in the process of creating a new distribution in the CloudFront console. First create the distribution by any means (console, CLI, API), then edit the distribution settings to enable Viewer mTLS per the existing distributions instructions below.

### For existing distributions
<a name="enable-mtls-existing-distributions"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. From the distribution list, select the distribution you want to modify.

1. Ensure the Viewer protocol policy is set to **Redirect HTTP to HTTPS** or **HTTPS Only** for all cache behaviors. (You can choose the **Cache behaviors** tab to view and update any cache behaviors with HTTP protocol policies.)

1. Choose the **General** tab.

1. In the **Settings** section, choose **Edit**.

1. In the **Connectivity** section, find **Viewer mutual authentication (mTLS)**.

1. Toggle **Enable mutual authentication** to On.

1. For **Client certificate validation mode**, select **Required** (all clients must present certificates) or **Optional** (clients can optionally present certificates).

1. For **Trust store**, select your previously created trust store.

1. (Optional) Toggle **Advertise trust store CA names** if you want CloudFront to send CA names to clients during the TLS handshake.

1. (Optional) Toggle **Ignore certificate expiration date** if you want to allow connections with expired certificates.

1. Choose **Save changes**.

## Enable mutual TLS (AWS CLI)
<a name="enable-mtls-cli"></a>

### For new distributions
<a name="enable-mtls-cli-new"></a>

The following example shows how to create a distribution configuration file (distribution-config.json) that includes mTLS settings:

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

Create the distribution with mTLS enabled using the following example command:

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

### For existing distributions
<a name="enable-mtls-cli-existing"></a>

Get the current distribution configuration using the following example command:

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

Edit the file to add mTLS settings. Add the following example section to your distribution configuration:

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

Remove the ETag field from the file but save its value separately.

Update the distribution with the new configuration using the following example command:

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

## Viewer protocol policies
<a name="viewer-protocol-policies"></a>

When using mutual TLS, all distribution cache behaviors must be configured with an HTTPS-only viewer protocol policy:
+ **Redirect HTTP to HTTPS** - Redirects HTTP requests to HTTPS before performing certificate validation.
+ **HTTPS Only** - Only accepts HTTPS requests and performs certificate validation.

**Note**  
The HTTP and HTTPS viewer protocol policy is not supported with mutual TLS since HTTP connections cannot perform certificate validation.

## Next steps
<a name="enable-mtls-next-steps"></a>

After enabling Viewer TLS on your CloudFront distribution, you can associate Connection Functions to implement custom certificate validation logic. Connection Functions allow you to extend the built-in mTLS authentication capabilities with custom validation rules, certificate revocation checking, and logging. For details on creating and associating Connection Functions, see [Associate a CloudFront Connection Function](connection-functions.md).

# Associate a CloudFront Connection Function
<a name="connection-functions"></a>

CloudFront Connection Functions allow you to implement custom certificate validation logic during TLS handshakes, providing extensions to the built-in mTLS authentication capabilities.

## What are Connection Functions?
<a name="what-are-connection-functions"></a>

Connection Functions are JavaScript functions that run during the TLS handshake after client certificates have been validated. The validated client certificate is passed to the Connection Function at which point the Connection Function can make an additional determination on whether to grant access or not. For detailed information about Connection Functions, see [Customize at the edge with CloudFront Functions](cloudfront-functions.md).

## How Connection Functions work with mTLS
<a name="how-connection-functions-work"></a>

When a client attempts to establish an mTLS connection to your CloudFront distribution, the following sequence occurs:

1. Client initiates TLS handshake with CloudFront edge location.

1. CloudFront requests and receives client certificate.

1. CloudFront performs standard certificate validation against trust store.

1. If the certificate passes standard validation, CloudFront invokes your Connection Function. If **IgnoreCertificateExpiry** is enabled within your **ViewerMtlsConfig**, then your expired—but otherwise valid—certificates are also passed to the Connection Function. If the client certificates are invalid, Connection Functions will not be invoked.

1. Your Connection Function receives parsed certificate information and connection details.

1. Your function makes an allow/deny decision based on custom logic.

1. CloudFront completes or terminates the TLS connection based on your decision.

Connection Functions are invoked for both verify mode and optional mode (when clients present certificates).

## Create a Connection Function
<a name="create-connection-function"></a>

You can create Connection Functions using the CloudFront console or AWS CLI.

### To create a Connection Function (Console)
<a name="create-connection-function-console"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Functions**.

1. Choose the **Connection Functions** tab and choose **Create Connection Function**.

1. Enter a function name that is unique within your AWS account.

1. Choose **Continue**.

1. In the function editor, write your JavaScript code for certificate validation. The function handler must call either allow or deny.

1. Optional: a KeyValue store can be associated to the Connection Function to implement revocation control.

1. Choose **Save changes**.

### To create a Connection Function (AWS CLI)
<a name="create-connection-function-cli"></a>

The following example shows how to create a Connection Function:

Write your function code in a separate file, for example code.js:

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

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

## Connection Function code structure
<a name="connection-function-code-structure"></a>

Connection Functions implement connectionHandler function that receives a connection object containing certificate and connection information. Your function must use either `connection.allow()` or `connection.deny()` to make a decision about the connection.

### Basic Connection Function example
<a name="basic-connection-function-example"></a>

The following example shows a simple Connection Function that verifies the subject field of client certificates:

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

The full specification of client certificate properties available on the connection object are available here:

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

## Associate a Connection Function
<a name="associate-connection-function-section"></a>

After creating your Connection Function, you must publish it to the LIVE stage and associate it with your distribution.

### To publish and associate a Connection Function (Console)
<a name="publish-associate-console"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Functions**

1. Choose the **Connection Functions** tab and select your Connection Function.

1. Choose **Publish** to move it to the LIVE stage.

1. Choose **Add association** in the associated distributions table below the publishing section.

1. Select the distribution with Viewer mTLS enabled that you wish to associate.

Alternatively published Connection Functions can also be associated from the distribution details page.

1. Navigate to the console home page where all your distributions are listed.

1. Select the distribution that you wish to associate.

1. Choose the **General** tab.

1. In the **Settings** section, choose **Edit**.

1. In the **Connectivity** section, find **Viewer mutual authentication (mTLS)**.

1. For **Connection Function**, select your function.

1. Choose **Save changes**.

### To associate a Connection Function (AWS CLI)
<a name="associate-connection-function-cli"></a>

The following example shows how to associate a Connection Function with a distribution:

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

## Use cases for Connection Functions
<a name="connection-function-use-cases"></a>

Connection Functions enable several advanced mTLS use cases:
+ **Certificate attribute validation** - Verify specific fields in client certificates like organizational unit requirements or subject alternative name patterns.
+ **Certificate revocation checking** - Implement custom certificate revocation checking using KeyValueStore to store revoked certificate serial numbers.
+ **IP-based certificate policies** - Apply different certificate policies based on client IP addresses or geographic restrictions.
+ **Multi-tenant validation** - Implement tenant-specific validation rules where different certificate requirements apply based on hostnames or certificate attributes.

**Note**  
Connection Functions run once per client connection during the TLS handshake.  
Connection Functions can only allow or deny connections, not modify HTTP requests/responses.  
Only LIVE stage functions (published) can be associated with distributions.  
Each distribution can have at most one Connection Function.

## Next steps
<a name="connection-function-next-steps"></a>

After associating a Connection Function with your CloudFront distribution, you can configure optional settings to customize the behavior of your mTLS implementation. For detailed instructions on configuring additional settings such as an optional client certificate validation mode, see [Configuring additional settings](configuring-additional-settings.md).

# Configuring additional settings
<a name="configuring-additional-settings"></a>

After enabling basic mutual TLS authentication, you can configure additional settings to customize the authentication behavior for specific use cases and requirements.

## Client certificate validation Optional mode
<a name="optional-mode"></a>

CloudFront offers an alternative Optional client certificate validation mode that validates client certificates that are presented but allows access to clients that don't present certificates.

### Optional mode behavior
<a name="optional-mode-behavior"></a>
+ Grants connection to clients with valid certificates, (invalid certificates are denied).
+ Allows connection to clients without certificates
+ Allows mixed client authentication scenarios through a single distribution.

Optional mode is ideal for gradual migration to mTLS authentication, supporting clients with certificates and clients without certificates, or maintaining backward compatibility with legacy clients.

**Note**  
In optional mode, Connection Functions are still invoked even when clients don't present certificates. This allows you to implement custom logic such as logging client IP addresses or applying different policies based on whether certificates are presented.

### To configure optional mode (Console)
<a name="configure-optional-mode-console"></a>

1. In your distribution settings, navigate to the **General** tab, choose **Edit**.

1. Scroll to the **Viewer mutual authentication (mTLS)** section within the **Connectivity** container.

1. For **Client certificate validation mode**, select **Optional**.

1. Save changes.

### To configure optional mode (AWS CLI)
<a name="configure-optional-mode-cli"></a>

The following example shows how to configure optional mode:

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

## Certificate Authority advertisement
<a name="ca-advertisement"></a>

The AdvertiseTrustStoreCaNames field controls whether CloudFront sends the list of trusted CA names to clients during the TLS handshake, helping clients select the appropriate certificate.

### To configure CA advertisement (Console)
<a name="configure-ca-advertisement-console"></a>

1. In your distribution settings, navigate to the **General** tab, choose **Edit**.

1. Scroll to the **Viewer mutual authentication (mTLS)** section within the **Connectivity** container.

1. Select or de-select the **Advertise trust store CA names** checkbox.

1. Choose **Save changes**.

### To configure CA advertisement (AWS CLI)
<a name="configure-ca-advertisement-cli"></a>

The following example shows how to enable CA advertisement:

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

## Certificate expiration handling
<a name="certificate-expiration-handling"></a>

The IgnoreCertificateExpiry property determines how CloudFront responds to expired client certificates. By default, CloudFront rejects expired client certificates, but you can configure it to accept them when necessary. This is typically enabled for devices with expired certificates that cannot be readily updated.

### To configure certificate expiration handling (Console)
<a name="configure-expiration-console"></a>

1. In your distribution settings, navigate to **General** tab, choose **Edit**.

1. Scroll to the **Viewer mutual authentication (mTLS)** section of the **Connectivity** container.

1. Select or deselect the **Ignore certificate expiration date** checkbox.

1. Choose **Save changes**.

### To configure certificate expiration handling (AWS CLI)
<a name="configure-expiration-cli"></a>

The following example shows how to ignore certificate expiration:

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

**Note**  
**IgnoreCertificateExpiry** only applies to the certificates Validity dates. All other certificate validation checks still apply (chain of trust, signature validation).

## Next steps
<a name="additional-settings-next-steps"></a>

After configuring additional settings, you can set up header forwarding to pass certificate information to your origins, implement certificate revocation using Connection Functions and KeyValueStore, and enable connection logs for monitoring. For details on forwarding certificate information to origins, see [Forward Headers to origins](viewer-mtls-headers.md).

# Viewer mTLS headers for cache policies and forwarded to origin
<a name="viewer-mtls-headers"></a>

When using mutual TLS authentication, CloudFront can extract information from client certificates and forward it to your origins as HTTP headers. This allows your origin servers to access certificate details without implementing certificate validation logic.

The following headers are available to for creating cache behaviors:


| Header name | Description | Example value | 
| --- | --- | --- | 
| CloudFront-Viewer-Cert-Serial-Number | Hexadecimal representation of the certificate serial number | 4a:3f:5c:92:d1:e8:7b:6c | 
| CloudFront-Viewer-Cert-Issuer | RFC2253 string representation of the issuer's distinguished name (DN) | CN=rootcamtls.com,OU=rootCA,O=mTLS,L=Seattle,ST=Washington,C=US | 
| CloudFront-Viewer-Cert-Subject | RFC2253 string representation of the subject's distinguished name (DN) | CN=client\$1.com,OU=client-3,O=mTLS,ST=Washington,C=US | 
| CloudFront-Viewer-Cert-Present | Either 1 (present) or 0 (not present) indicating whether the certificate is present. This value is always 1 in Required mode. | 1 | 
| CloudFront-Viewer-Cert-Sha256 | The SHA256 hash of the client certificate | 01fbf94fef5569753420c349f49adbfd80af5275377816e3ab1fb371b29cb586 | 

For origin requests, two additional headers are supplied, in addition to the headers above made available for cache behaviors. Due to potential header size, CloudFront-Viewer-Cert-Pem header is not exposed to edge functions (Lambda@Edge or CloudFront Functions) and is only forwarded to the origin.


| Header name | Description | Example value | 
| --- | --- | --- | 
| CloudFront-Viewer-Cert-Validity | ISO8601 format of the notBefore and notAfter date | CloudFront-Viewer-Cert-Validity: NotBefore=2023-09-21T01:50:17Z;NotAfter=2024-09-20T01:50:17Z | 
| CloudFront-Viewer-Cert-Pem | URL-encoded PEM format of the leaf certificate | CloudFront-Viewer-Cert-Pem: -----BEGIN%20CERTIFICATE-----%0AMIIG<...reduced...>NmrUlw%0A-----END%20CERTIFICATE-----%0A | 

## Configure header forwarding
<a name="configure-header-forwarding"></a>

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

In verify mode, CloudFront automatically adds the CloudFront-Viewer-Cert-\$1 headers to all viewer requests. To forward these headers to your origin:

1. From the main list distributions page, select your distribution with viewer mTLS enabled and go to the **Behaviors** tab

1. Select the cache behavior and choose **Edit**

1. In the **Origin request policy** section, choose **Create policy** or select an existing policy

1. Ensure the following headers are included in the origin request policy:
   + CloudFront-Viewer-Cert-Serial-Number
   + CloudFront-Viewer-Cert-Issuer
   + CloudFront-Viewer-Cert-Subject
   + CloudFront-Viewer-Cert-Present
   + Cloudfront-Viewer-Cert-Sha256
   + CloudFront-Viewer-Cert-Validity
   + CloudFront-Viewer-Cert-Pem

1. Choose **Create** (for new policies) or **Save changes** (for existing policies)

1. Select the policy within your cache behavior and save changes

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

The following example shows how to create an origin request policy that includes mTLS headers for verify mode:

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

## Header processing considerations
<a name="header-processing-considerations"></a>

When working with certificate headers, consider these best practices:
+ **Header validation:** Verify certificate header values at your origin as an additional security measure
+ **Header size limits:** The PEM certificate headers can be large, ensure your origin server can handle them
+ **Cache considerations:** Using certificate headers in your cache key increases cache fragmentation
+ **Cross-origin requests:** If your application uses CORS, then you may need to configure it to allow the certificate headers

## Next steps
<a name="headers-next-steps"></a>

After configuring header forwarding, you can implement certificate revocation checking using CloudFront Connection Functions and KeyValueStore. For details on implementing revocation checks, see [Revocation using CloudFront Connection Function and KVS](revocation-connection-function-kvs.md).

# Revocation using CloudFront Connection Function and KVS
<a name="revocation-connection-function-kvs"></a>

You can implement certificate revocation checking for mutual TLS authentication by combining CloudFront Connection Functions with KeyValueStore. This approach provides a scalable, real-time certificate revocation mechanism that complements CloudFront's built-in certificate validation.

Connection Functions are JavaScript functions that run during TLS connection establishment at CloudFront edge locations and allow you to implement custom certificate validation logic for mTLS authentication. For detailed information about Connection Functions, see [Associate a CloudFront Connection Function](connection-functions.md).

## How certificate revocation works with Connection Functions
<a name="how-revocation-works"></a>

CloudFront's standard certificate validation verifies the certificate chain, signature, and expiration but doesn't include built-in certificate revocation checking. By using Connection Functions, you can implement custom revocation checking during the TLS handshake.

The certificate revocation process works as follows:

1. Store revoked certificate serial numbers in a CloudFront KeyValueStore.

1. When a client presents a certificate, your Connection Function is invoked.

1. The function checks the certificate's serial number against the KeyValueStore.

1. If the serial number is found in the store, the certificate is revoked.

1. Your function denies the connection for revoked certificates.

This approach provides near-real-time revocation checking across CloudFront's global edge network.

## Set up KeyValueStore for revoked certificates
<a name="setup-kvs-revoked-certs"></a>

First, create a KeyValueStore to store the serial numbers of revoked certificates:

### To create a KeyValueStore (Console)
<a name="create-kvs-console"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Key value stores**.

1. Choose **Create key value store**.

1. Enter a name for your key value store (e.g., revoked-certificates).

1. (Optional) Add a description.

1. Choose **Create key value store**.

### To create a KeyValueStore (AWS CLI)
<a name="create-kvs-cli"></a>

The following example shows how to create a KeyValueStore:

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

## Import revoked certificate serial numbers
<a name="import-revoked-serials"></a>

After creating a KeyValueStore, you need to import the serial numbers of revoked certificates:

### Prepare revocation data
<a name="prepare-revocation-data"></a>

Create a JSON file with your revoked certificate serial numbers:

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

### Import from S3
<a name="import-from-s3"></a>

1. Upload the JSON file to an S3 bucket

1. Import the file to your KeyValueStore:

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

## Create a Connection Function for revocation checking
<a name="create-revocation-connection-function"></a>

Create a Connection Function that checks certificate serial numbers against your KeyValueStore:

### Connection Function code example
<a name="revocation-function-example"></a>

The following example shows a Connection Function that performs certificate revocation checking:

```
import cf from 'cloudfront';

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

### To create the Connection Function (AWS CLI)
<a name="create-revocation-function-cli"></a>

The following example shows how to create a Connection Function with KeyValueStore association:

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

## Associate the function with your distribution
<a name="associate-revocation-function"></a>

After creating and publishing your Connection Function, associate it with your mTLS-enabled CloudFront distribution as described in the [Associate a CloudFront Connection Function](connection-functions.md) section.

# Observability using connection logs
<a name="connection-logs"></a>

CloudFront connection logs provide detailed visibility into mutual TLS authentication events, allowing you to monitor certificate validation, track connection attempts, and troubleshoot authentication issues.

## What are connection logs?
<a name="what-are-connection-logs"></a>

Connection logs capture detailed information about TLS handshakes and certificate validation for mutual TLS-enabled distributions. Unlike standard access logs that record HTTP request information, connection logs focus specifically on the TLS connection establishment phase, including:
+ Connection status (success/failure)
+ Client certificate details
+ TLS protocol and cipher information
+ Connection timing metrics
+ Custom data from Connection Functions

These logs provide comprehensive visibility into certificate-based authentication events, helping you monitor security, troubleshoot issues, and meet compliance requirements.

## Enable connection logs
<a name="enable-connection-logs"></a>

Connection logs are available only for distributions with mutual TLS authentication enabled. You can send connection logs to multiple destinations including CloudWatch Logs, Amazon Data Firehose, and Amazon S3.

### Prerequisites
<a name="connection-logs-prerequisites"></a>

Before enabling connection logs:
+ Configure mutual TLS for your CloudFront distribution
+ Enable connection logs for your CloudFront distribution
+ Ensure you have the required permissions for your chosen logging destination
+ For cross-account delivery, configure appropriate IAM policies

### To enable connection logs (Console)
<a name="enable-connection-logs-console"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. From the distribution list, select your mTLS-enabled distribution.

1. Choose the **Logging** tab.

1. Choose **Add**.

1. Select the service to receive your logs:
   + **CloudWatch Logs**
   + **Firehose**
   + **Amazon S3**

1. For **Destination**, select the resource for your chosen service:
   + For CloudWatch Logs, enter the **Log group name**
   + For Firehose, select the **Firehose delivery stream**
   + For Amazon S3, enter the **Bucket name** (optionally with a prefix)

1. (Optional) Configure additional settings:
   + **Field selection:** Select specific log fields to include.
   + **Output format:** Choose from JSON, Plain, w3c, Raw, or Parquet (S3 only).
   + **Field delimiter:** Specify how to separate log fields.

1. Choose **Save changes**

### To enable connection logs (AWS CLI)
<a name="enable-connection-logs-cli"></a>

The following example shows how to enable connection logs using the CloudWatch API:

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

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

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

**Note**  
When using the CloudWatch API, you must specify the US East (N. Virginia) Region (us-east-1) even when delivering logs to other regions.

## Connection log fields
<a name="connection-log-fields"></a>

Connection logs include detailed information about each TLS connection attempt:


| Field | Description | Example | 
| --- | --- | --- | 
| eventTimestamp | ISO 8601 timestamp when the connection was established or failed | 1731620046814 | 
| connectionId | Unique identifier for the TLS connection | oLHiEKbQSn8lkvJfA3D4gFowK3\$1iZ0g4i5nMUjE1Akod8TuAzn5nzg== | 
| connectionStatus |  The status of the mTLS connection attempt.  | Success or Failed | 
| clientIp | IP address of the connecting client | 2001:0db8:85a3:0000:0000:8a2e:0370:7334 | 
| clientPort | Port used by the client | 12137 | 
| serverIp | IP address of the CloudFront edge server | 99.84.71.136 | 
| distributionId | CloudFront distribution ID | E2DX1SLDPK0123 | 
| distributionTenantId | CloudFront distribution tenant ID (when applicable) | dt\$12te1Ura9X3R2iCGNjW123 | 
| tlsProtocol | TLS protocol version used | TLSv1.3 | 
| tlsCipher | TLS cipher suite used for the connection | TLS\$1AES\$1128\$1GCM\$1SHA256 | 
| tlsHandshakeDuration | Duration of the TLS handshake in milliseconds | 153 | 
| tlsSni | Server Name Indication value from the TLS handshake | d111111abcdef8.cloudfront.net | 
| clientLeafCertSerialNumber | Serial number of the client's certificate | 00:b1:43:ed:93:d2:d8:f3:9d | 
| clientLeafCertSubject | Subject field of the client's certificate | C=US, ST=WA, L=Seattle, O=Amazon.com, OU=CloudFront, CN=client.test.mtls.net | 
| clientLeafCertIssuer | Issuer field of the client's certificate | C=US, ST=WA, L=Seattle, O=Amazon.com, OU=CloudFront, CN=test.mtls.net | 
| clientLeafCertValidity | Validity period of the client's certificate | NotBefore=2025-06-05T23:28:21Z;NotAfter=2125-05-12T23:28:21Z | 
| connectionLogCustomData | Custom data added via Connection Functions | REVOKED:00:b1:43:ed:93:d2:d8:f3:9d | 

## Connection error codes
<a name="connection-error-codes"></a>

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

When connections fail, CloudFront records specific reason codes:


| Code | Description | 
| --- | --- | 
| ClientCertMaxChainDepthExceeded | Maximum certificate chain depth exceeded | 
| ClientCertMaxSizeExceeded | Maximum certificate size exceeded | 
| ClientCertUntrusted | Certificate is untrusted | 
| ClientCertNotYetValid | Certificate is not yet valid | 
| ClientCertExpired | Certificate is expired | 
| ClientCertTypeUnsupported | Certificate type is unsupported | 
| ClientCertInvalid | Certificate is invalid | 
| ClientCertIntentInvalid | Certificate intent is invalid | 
| ClientCertRejected | Certificate rejected by custom validation | 
| ClientCertMissing | Certificate is missing | 
| TcpError |  An error occurred while attempting to establish a connection  | 
| TcpTimeout |  The connection was not able to be established within the timeout period  | 
| ConnectionFunctionError |  An uncaught exception was thrown during Connection Function execution  | 
| Internal |  An internal service error occurred  | 
| UnmappedConnectionError |  An error occurred that does not fall into any of the other categories  | 

# Origin mutual TLS with CloudFront
<a name="origin-mtls-authentication"></a>

Mutual TLS Authentication (Mutual Transport Layer Security Authentication — mTLS) is a security protocol that extends standard TLS authentication by requiring bidirectional certificate-based authentication, where both client and server must prove their identity before establishing a secure connection.

## Viewer mTLS vs Origin mTLS
<a name="viewer-mtls-vs-origin-mtls"></a>

Mutual authentication (mTLS) can be enabled between viewers and your CloudFront distribution (viewer mTLS) and/or also between your CloudFront distribution and the origin (origin mTLS). This documentation pertains to origin mTLS configuration. For viewer mTLS configuration refer to: [Mutual TLS authentication with CloudFront (Viewer mTLS)Origin mutual TLS with CloudFront](mtls-authentication.md).

Origin mTLS enables CloudFront to authenticate itself to your origin servers using client certificates. With origin mTLS, you can ensure that only your authorized CloudFront distributions can establish connections with your application servers, helping protect against unauthorized access attempts.

**Note**  
In origin mTLS connections, CloudFront acts as the client and presents its client certificate to your origin server during the TLS handshake. CloudFront does not perform validation of the client certificate's validity or revocation status—this is the responsibility of your origin server. Your origin infrastructure must be configured to validate the client certificate against its trust store, check certificate expiration, and perform revocation checks (such as CRL or OCSP validation) according to your security requirements. CloudFront's role is limited to presenting the certificate; all certificate validation logic and security policies are enforced by your origin servers.

## How it works
<a name="how-origin-mtls-works"></a>

In a standard TLS handshake between CloudFront and an origin, only the origin server presents a certificate to prove its identity to CloudFront. With origin mTLS, the authentication process becomes bidirectional. When CloudFront attempts to connect to your origin server, CloudFront presents a client certificate during the TLS handshake. Your origin server validates this certificate against its trust store before establishing the secure connection.

## Use cases
<a name="origin-mtls-use-cases"></a>

Origin mTLS addresses several critical security scenarios where traditional authentication methods create operational overhead:
+ **Hybrid and multi-cloud security** - You can secure connections between CloudFront and origins hosted outside AWS or public origins on AWS. This eliminates the need to manage IP allowlists or custom header solutions, providing consistent certificate-based authentication across AWS, on-premises data centers, and third-party providers. Media companies, retailers, and enterprises operating distributed infrastructure benefit from standardized security controls across their entire infrastructure.
+ **B2B API and backend security** - You can protect your backend APIs and microservices from direct access attempts while maintaining CloudFront's performance benefits. SaaS platforms, payment processing systems, and enterprise applications with strict authentication requirements can verify that API requests originate only from authorized CloudFront distributions, preventing man-in-the-middle attacks and unauthorized access attempts.

## Important: Origin Server Requirements
<a name="important-origin-server-requirements"></a>

Origin mTLS requires your origin servers to be configured to support mutual TLS authentication. Your origin infrastructure must be capable of:
+ Requesting and validating client certificates during TLS handshakes
+ Maintaining a trust store with the Certificate Authority certificates that issued CloudFront's client certificates
+ Logging and monitoring mutual TLS connection events
+ Managing certificate validation policies and handling authentication failures

CloudFront handles the client-side certificate presentation, but your origin servers are responsible for validating these certificates and managing the mutual TLS connection. Ensure your origin infrastructure is properly configured before enabling origin mTLS in CloudFront.

## Getting started
<a name="how-origin-mtls-getting-started"></a>

To implement origin mTLS with CloudFront, you'll need to import the client certificate in AWS Certificate Manager, configure your origin server to require mutual TLS, and enable origin mTLS on your CloudFront distribution. The following sections provide step-by-step instructions for each configuration task.

**Topics**
+ [Viewer mTLS vs Origin mTLS](#viewer-mtls-vs-origin-mtls)
+ [How it works](#how-origin-mtls-works)
+ [Use cases](#origin-mtls-use-cases)
+ [Important: Origin Server Requirements](#important-origin-server-requirements)
+ [Getting started](#how-origin-mtls-getting-started)
+ [Certificate management with AWS Certificate Manager](origin-certificate-management-certificate-manager.md)
+ [Enable origin mutual TLS for CloudFront distributions](origin-enable-mtls-distributions.md)
+ [Using CloudFront Functions with origin mutual TLS](origin-mtls-cloudfront-functions.md)

# Certificate management with AWS Certificate Manager
<a name="origin-certificate-management-certificate-manager"></a>

[AWS Certificate Manager (ACM)](https://aws.amazon.com/certificate-manager/) stores the client certificates that CloudFront presents to your origin servers during origin mutual TLS authentication.

## Certificate Authority support
<a name="origin-ca-support"></a>

CloudFront origin mTLS requires client certificates with Extended Key Usage (EKU) for TLS Client Authentication. Due to this requirement, you must issue certificates from your Certificate Authority and import them into AWS Certificate Manager. ACM's automatic certificate provisioning and renewal features are not available for origin mTLS client certificates. CloudFront origin mTLS supports client certificates from two sources:
+ **AWS Private Certificate Authority:** You can issue certificates from AWS Private CA using certificate templates that include TLS Client Authentication in the Extended Key Usage field (such as the EndEntityClientAuthCertificate template). After issuing the certificate from AWS Private CA, you must import it into ACM in the US East (N. Virginia) Region (us-east-1). This approach provides the security benefits of AWS Private CA while giving you control over certificate lifecycle management.
+ **Third-party private Certificate Authorities:** You can also issue certificates from your existing private Certificate Authority infrastructure and import them into ACM. This allows you to maintain your current certificate management processes while leveraging CloudFront's origin mTLS capabilities. Certificates must include TLS Client Authentication in the Extended Key Usage field and must be in PEM format with the certificate, private key, and certificate chain.

**Important**  
For both AWS Private CA and third-party CAs, you are responsible for monitoring certificate expiration dates and importing renewed certificates into ACM before expiration. ACM's automatic renewal feature does not apply to imported certificates used for origin mTLS.

## Certificate requirements and specifications
<a name="origin-certificate-requirements"></a>

### Client certificate requirements
<a name="origin-ca-cert-format-requirements"></a>
+ **Format:** PEM (Privacy Enhanced Mail) format
+ **Components:** Certificate, private key, and certificate chain
+ **Maximum certificate chain depth:** 3 (leaf certificate \$1 intermediate certificate \$1 root certificate)
+ **Maximum certificate chain size:** 64 KB
+ **Certificate size:** Cannot exceed 96 KB
+ **Maximum private key size:** 5 KB (ACM restriction)
+ **Maximum unique origin mTLS certificate ARNs that can be added or modified per CloudFront distribution create or update API call:** 5
+ **Region:** Certificates must be stored in ACM in the US East (N. Virginia) Region (us-east-1)

### Supported certificate specifications
<a name="origin-supported-cert-specs"></a>
+ **Certificate type:** X.509v3
+ **Public key algorithms:**
  + RSA: 2048-bit
  + ECDSA: P-256
+ **Signature algorithms:**
  + SHA256, SHA384, SHA512 with RSA
  + SHA256, SHA384, SHA512 with ECDSA
  + SHA256, SHA384, SHA512 with RSASSA-PSS with MGF1
+ **Extended Key Usage (required):** The certificate requires the Extended Key Usage (EKU) extension set to TLS Client Authentication, ensuring it is authorized for mTLS purposes

### Server certificate requirements
<a name="origin-server-certificate-requirements"></a>

Your origin servers must present certificates from publicly trusted Certificate Authorities during the mutual TLS handshake. For complete details on origin server certificate requirements, see [Requirements for using SSL/TLS certificates with CloudFront](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-https-cloudfront-to-custom-origin.html#using-https-cloudfront-to-origin-certificate).

### Request or import a certificate
<a name="origin-request-import-certificate"></a>

Before enabling origin mTLS, you must have a client certificate available in ACM.

#### Request and import a certificate from AWS Private CA
<a name="request-certificate-aws-private-ca"></a>

Prerequisites:
+ An AWS Private Certificate Authority configured in your account
+ Permission to issue certificates from AWS Private CA
+ Permission to import certificates into ACM
+ A [certificate template](https://docs.aws.amazon.com/privateca/latest/userguide/UsingTemplates.html) ARN with `Extended key usage:TLS web client authentication` which suits your use-case
+ Install OpenSSL, AWS CLI, and jq (for parsing JSON).

##### To request a certificate from PCA and import into ACM (AWS CLI)
<a name="request-certificate-cli"></a>

1. Set your Private CA ARN in a variable for easier reuse.

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

1. Use OpenSSL to generate an ECDSA P-256 private key (prime256v1 curve) and Certificate Signing Request (CSR), ensuring the -nodes flag is used to keep the private key unencrypted as required for ACM import.

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

1. Submit the CSR to your AWS Private CA to issue a certificate, which returns the ARN of the newly issued certificate.

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

1. Retrieve the certificate bundle from AWS PCA using the get-certificate command, which returns both the leaf certificate and chain, then use jq to separate them into distinct files.

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

1. Import the unencrypted private key, leaf certificate, and certificate chain into AWS ACM, using the fileb:// protocol to correctly handle binary file data in the CLI.

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

#### Import a certificate from a third-party CA
<a name="import-certificate-third-party-ca"></a>

Prerequisites:
+ A certificate, unencrypted private key, and certificate chain from your Certificate Authority in PEM format
+ The certificate must include Extended Key Usage for TLS Client Authentication
+ Permissions to import certificates into ACM

##### To import a certificate into ACM (AWS CLI)
<a name="import-certificate-cli"></a>

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

#### Next steps
<a name="certificate-next-steps"></a>

After obtaining or importing your client certificate in ACM, you can configure your origin server to require mutual TLS authentication and enable origin mTLS on your CloudFront distribution. For instructions on enabling origin mTLS in CloudFront, see the next section "Enable origin mutual TLS for CloudFront distributions."

# Enable origin mutual TLS for CloudFront distributions
<a name="origin-enable-mtls-distributions"></a>

After obtaining a client certificate through AWS Certificate Manager and configuring your origin server to require mutual TLS, you can enable origin mTLS on your CloudFront distribution.

## Prerequisites and requirements
<a name="origin-mtls-prerequisites-requirements"></a>

Before enabling origin mTLS on a CloudFront distribution, ensure you have:
+ A client certificate stored in AWS Certificate Manager in the US East (N. Virginia) Region (us-east-1)
+ Origin servers configured to require mutual TLS authentication and validate client certificates
+ Origin servers presenting certificates from publicly trusted Certificate Authorities
+ Permissions to modify CloudFront distributions
+ Origin mTLS is only available on Business, Premium plans or Pay as you go pricing plans.

**Note**  
Origin mTLS can be configured for custom origins (including origins hosted outside AWS) and AWS origins that support mutual TLS such as Application Load Balancer and API Gateway.

**Important**  
The following CloudFront features are not supported with origin mTLS:  
**gRPC traffic:** gRPC protocol is not supported for origins with origin mTLS enabled
**WebSocket connections:** WebSocket protocol is not supported for origins with origin mTLS enabled
**VPC origins:** origin mTLS cannot be used with VPC origins
**Origin request and origin response triggers with Lambda@Edge:** Lambda@Edge functions in origin request and origin response positions are not supported with origin mTLS
**Embedded POPs:** origin mTLS is not supported for embedded POPs

## Enable origin mTLS
<a name="origin-enable-mtls-per-origin"></a>

Per-origin configuration allows you to specify different client certificates for different origins within the same distribution. This approach provides maximum flexibility when your origins have different authentication requirements.

### For new distributions (Console)
<a name="origin-enable-mtls-new-distributions"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose **Create distribution**

1. Select a pricing plan: Choose either **Business** or **Premium** or **Pay As You Go** (Origin mTLS is not available on the Free plan)

1. In the Origin settings section, choose Origin Type as Other

1. In the **Origin settings** section, choose **Customize origin settings**

1. Configure your first origin (domain name, protocol, etc.)

1. In the origin configuration, find **mTLS**

1. Toggle **mTLS** to On

1. For **Client certificate**, select your certificate from AWS Certificate Manager

1. (Optional) Add additional origins with their own origin mTLS configurations

1. Complete the remaining distribution settings and choose **Create distribution**

### For existing distributions (Console)
<a name="origin-enable-mtls-existing-distributions"></a>

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. From the distribution list, select the distribution you want to modify. (Note: Ensure your distribution is on a **Pro or Premium or Pay As You Go** pricing plan. If not, you must upgrade your pricing plan before enabling origin mTLS)

1. Choose the **Origins** tab

1. Select the origin you want to configure and choose **Edit**

1. In the origin settings, find **mTLS**

1. Toggle **mTLS** to On

1. For **Client certificate**, select your certificate from AWS Certificate Manager. (Note: Only client certificates with the EKU (Extended Key Usage) property set to "TLS Client Authentication" will be listed)

1. Choose **Save changes**

1. Repeat for additional origins as needed

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

For per-origin configuration, specify the origin mTLS settings within each origin's configuration:

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

**Note**  
CloudFront will not provide the client certificate if the server does not request it, allowing the connection to proceed normally.

## Next steps
<a name="origin-enable-mtls-next-steps"></a>

After enabling origin mTLS on your CloudFront distribution, you can monitor authentication events using CloudFront access logs.

# Using CloudFront Functions with origin mutual TLS
<a name="origin-mtls-cloudfront-functions"></a>

CloudFront Functions provides lightweight, serverless compute at the edge to customize content delivery. When using origin mutual TLS with CloudFront Functions, there are specific behaviors and limitations to be aware of regarding origin selection and manipulation.

## Supported CloudFront Functions operations
<a name="supported-cloudfront-functions-operations"></a>

CloudFront Functions can interact with mTLS-enabled origins in the following ways:

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

The updateRequestOrigin() function supports limited modifications when working with mTLS-enabled origins:
+ **Switching between origin mTLS origins:** You can update the request to route to a different origin that uses origin mTLS, provided both origins use the **same client certificate**. This allows you to implement custom routing logic while maintaining mutual TLS authentication.
+ **Disabling origin mTLS:** You can switch from a mTLS-enabled origin to a non-mTLS origin by setting `mTLSConfig: 'off'` in the function. This provides flexibility to conditionally disable mutual TLS authentication based on request characteristics.

#### Example: Switching between origin mTLS origins with the same certificate
<a name="example-switching-mtls-origins"></a>

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

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

    return request;
}
```

#### Example: Conditionally disabling origin mTLS
<a name="example-disabling-mtls"></a>

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

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

    return request;
}
```

## Unsupported CloudFront Functions operations
<a name="unsupported-cloudfront-functions-operations"></a>

The following CloudFront Functions operations do not support mTLS-enabled origins at general availability:

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

The `selectRequestOriginById()` function cannot select an origin that has origin mTLS enabled. Attempting to select a mTLS-enabled origin using this function will result in a validation error.

If your use case requires dynamic origin selection with origin mTLS, use `updateRequestOrigin()` instead, ensuring all target origins use the same client certificate.

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

The `createRequestOriginGroup()` function does not support creating origin groups that include mTLS-enabled origins. Origin groups with origin mTLS origins cannot be created dynamically through CloudFront Functions.

If you need origin failover capabilities with origin mTLS, configure origin groups directly in your CloudFront distribution settings rather than creating them dynamically in functions.

# Serve private content with signed URLs and signed cookies
<a name="PrivateContent"></a>

Many companies that distribute content over the internet want to restrict access to documents, business data, media streams, or content that is intended for selected users, for example, users who have paid a fee. To securely serve this private content by using CloudFront, you can do the following:
+ Require that your users access your private content by using special CloudFront signed URLs or signed cookies. 
+ Require that your users access your content by using CloudFront URLs, not URLs that access content directly on the origin server (for example, Amazon S3 or a private HTTP server). Requiring CloudFront URLs isn't necessary, but we recommend it to prevent users from bypassing the restrictions that you specify in signed URLs or signed cookies.

For more information, see [Restrict access to files](private-content-overview.md).

## How to serve private content
<a name="private-content-task-list"></a>

To configure CloudFront to serve private content, do the following tasks:

1. (Optional but recommended) Require your users to access your content only through CloudFront. The method that you use depends on whether you're using Amazon S3 or custom origins:
   + **Amazon S3** – See [Restrict access to an Amazon S3 origin](private-content-restricting-access-to-s3.md).
   + **Custom origin** – See [Restrict access to files on custom origins](private-content-overview.md#forward-custom-headers-restrict-access).

   Custom origins include Amazon EC2, Amazon S3 buckets configured as website endpoints, Elastic Load Balancing, and your own HTTP web servers.

1. Specify the *trusted key groups* or *trusted signers* that you want to use to create signed URLs or signed cookies. We recommend that you use trusted key groups. For more information, see [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md).

1. Write your application to respond to requests from authorized users either with signed URLs or with `Set-Cookie` headers that set signed cookies. Follow the steps in one of the following topics: 
   + [Use signed URLs](private-content-signed-urls.md)
   + [Use signed cookies](private-content-signed-cookies.md)

   If you're not sure which method to use, see [Decide to use signed URLs or signed cookies](private-content-choosing-signed-urls-cookies.md).

**Topics**
+ [How to serve private content](#private-content-task-list)
+ [Restrict access to files](private-content-overview.md)
+ [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md)
+ [Decide to use signed URLs or signed cookies](private-content-choosing-signed-urls-cookies.md)
+ [Use signed URLs](private-content-signed-urls.md)
+ [Use signed cookies](private-content-signed-cookies.md)
+ [Linux commands and OpenSSL for base64 encoding and encryption](private-content-linux-openssl.md)
+ [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md)

# Restrict access to files
<a name="private-content-overview"></a>

You can control user access to your private content in two ways:
+ [Restrict access to files in CloudFront caches](#private-content-overview-edge-caches).
+ Restrict access to files in your origin by doing one of the following:
  + [Set up an origin access control (OAC) for your Amazon S3 bucket](private-content-restricting-access-to-s3.md).
  + [Configure custom headers for a private HTTP server (a custom origin)](#forward-custom-headers-restrict-access).

## Restrict access to files in CloudFront caches
<a name="private-content-overview-edge-caches"></a>

You can configure CloudFront to require that users access your files using either *signed URLs* or *signed cookies*. You then develop your application either to create and distribute signed URLs to authenticated users or to send `Set-Cookie` headers that set signed cookies for authenticated users. (To give a few users long-term access to a small number of files, you can also create signed URLs manually.) 

When you create signed URLs or signed cookies to control access to your files, you can specify the following restrictions:
+ An ending date and time, after which the URL is no longer valid. 
+ (Optional) The date and time that the URL becomes valid.
+ (Optional) The IP address or range of addresses of the computers that can be used to access your content. 

One part of a signed URL or a signed cookie is hashed and signed using the private key from a public–private key pair. When someone uses a signed URL or signed cookie to access a file, CloudFront compares the signed and unsigned portions of the URL or cookie. If they don't match, CloudFront doesn't serve the file.

You must use either RSA 2048 or ECDSA 256 private keys for signing URLs or cookies.

## Restrict access to files in Amazon S3 buckets
<a name="private-content-overview-s3"></a>

You can optionally secure the content in your Amazon S3 bucket so that users can access it through the specified CloudFront distribution but cannot access it directly by using Amazon S3 URLs. This prevents someone from bypassing CloudFront and using the Amazon S3 URL to get content that you want to restrict access to. This step isn't required to use signed URLs, but we recommend it.

To require that users access your content through CloudFront URLs, you do the following tasks:
+ Give a CloudFront *origin access control* permission to read the files in the S3 bucket.
+ Create the origin access control and associate it with your CloudFront distribution.
+ Remove permission for anyone else to use Amazon S3 URLs to read the files.

For more information, see [Restrict access to an Amazon S3 origin](private-content-restricting-access-to-s3.md) or [Restrict access to an Amazon S3 Multi-Region Access Point origin](private-content-restricting-access-to-s3-mrap.md).

## Restrict access to files on custom origins
<a name="forward-custom-headers-restrict-access"></a>

If you use a custom origin, you can optionally set up custom headers to restrict access. For CloudFront to get your files from a custom origin, the files must be accessible by CloudFront using a standard HTTP (or HTTPS) request. But by using custom headers, you can further restrict access to your content so that users can access it only through CloudFront, not directly. This step isn't required to use signed URLs, but we recommend it.

To require that users access content through CloudFront, change the following settings in your CloudFront distributions:

**Origin Custom Headers**  
Configure CloudFront to forward custom headers to your origin. See [Configure CloudFront to add custom headers to origin requests](add-origin-custom-headers.md#add-origin-custom-headers-configure).

**Viewer Protocol Policy**  
Configure your distribution to require viewers to use HTTPS to access CloudFront. See [Viewer protocol policy](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy). 

**Origin Protocol Policy**  
Configure your distribution to require CloudFront to use the same protocol as viewers to forward requests to the origin. See [Protocol (custom origins only)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy). 

After you've made these changes, update your application on your custom origin to only accept requests that include the custom headers that you’ve configured CloudFront to send.

The combination of **Viewer Protocol Policy** and **Origin Protocol Policy** ensure that the custom headers are encrypted in transit. However, we recommend that you periodically do the following to rotate the custom headers that CloudFront forwards to your origin:

1. Update your CloudFront distribution to begin forwarding a new header to your custom origin.

1. Update your application to accept the new header as confirmation that the request is coming from CloudFront.

1. When requests no longer include the header that you're replacing, update your application to no longer accept the old header as confirmation that the request is coming from CloudFront.

# Specify signers that can create signed URLs and signed cookies
<a name="private-content-trusted-signers"></a>

**Topics**
+ [Choose between trusted key groups (recommended) and AWS accounts](#choosing-key-groups-or-AWS-accounts)
+ [Create key pairs for your signers](#private-content-creating-cloudfront-key-pairs)
+ [Reformat the private key (.NET and Java only)](#private-content-reformatting-private-key)
+ [Add a signer to a distribution](#private-content-adding-trusted-signers)
+ [Rotating key pairs](#private-content-rotating-key-pairs)

To create signed URLs or signed cookies, you need a *signer*. A signer is either a trusted key group that you create in CloudFront, or an AWS account that contains a CloudFront key pair. We recommend that you use trusted key groups with signed URLs and signed cookies. For more information, see [Choose between trusted key groups (recommended) and AWS accounts](#choosing-key-groups-or-AWS-accounts).

The signer has two purposes:
+ As soon as you add the signer to your distribution, CloudFront starts to require that viewers use signed URLs or signed cookies to access your files.
+ When you create signed URLs or signed cookies, you use the private key from the signer’s key pair to sign a portion of the URL or the cookie. When someone requests a restricted file, CloudFront compares the signature in the URL or cookie with the unsigned URL or cookie, to verify that it hasn’t been tampered with. CloudFront also verifies that the URL or cookie is valid, meaning, for example, that the expiration date and time hasn’t passed.

When you specify a signer, you also indirectly specify the files that require signed URLs or signed cookies by adding the signer to a cache behavior. If your distribution has only one cache behavior, viewers must use signed URLs or signed cookies to access any file in the distribution. If you create multiple cache behaviors and add signers to some cache behaviors and not to others, you can require that viewers use signed URLs or signed cookies to access some files and not others.

To specify the signers (the private keys) that are allowed to create signed URLs or signed cookies, and to add the signers to your CloudFront distribution, do the following tasks:

1. Decide whether to use a trusted key group or an AWS account as the signer. We recommend using a trusted key group. For more information, see [Choose between trusted key groups (recommended) and AWS accounts](#choosing-key-groups-or-AWS-accounts).

1. For the signer that you chose in step 1, create a public–private key pair. For more information, see [Create key pairs for your signers](#private-content-creating-cloudfront-key-pairs).

1. If you’re using .NET or Java to create signed URLs or signed cookies, reformat the private key. For more information, see [Reformat the private key (.NET and Java only)](#private-content-reformatting-private-key).

1. In the distribution for which you’re creating signed URLs or signed cookies, specify the signer. For more information, see [Add a signer to a distribution](#private-content-adding-trusted-signers).

## Choose between trusted key groups (recommended) and AWS accounts
<a name="choosing-key-groups-or-AWS-accounts"></a>

To use signed URLs or signed cookies, you need a *signer*. A signer is either a trusted key group that you create in CloudFront, or an AWS account that contains a CloudFront key pair. We recommend that you use trusted key groups, for the following reasons:
+ With CloudFront key groups, you don’t need to use the AWS account root user to manage the public keys for CloudFront signed URLs and signed cookies. [AWS best practices](https://docs.aws.amazon.com/general/latest/gr/root-vs-iam.html#aws_tasks-that-require-root) recommend that you don’t use the root user when you don’t have to.
+ With CloudFront key groups, you can manage public keys, key groups, and trusted signers using the CloudFront API. You can use the API to automate key creation and key rotation. When you use the AWS root user, you have to use the AWS Management Console to manage CloudFront key pairs, so you can’t automate the process.
+ Because you can manage key groups with the CloudFront API, you can also use AWS Identity and Access Management (IAM) permissions policies to limit what different users are allowed to do. For example, you can allow users to upload public keys, but not delete them. Or you can allow users to delete public keys, but only when certain conditions are met, such as using multi-factor authentication, sending the request from a particular network, or sending the request within a particular date and time range.
+ With CloudFront key groups, you can associate a higher number of public keys with your CloudFront distribution, giving you more flexibility in how you use and manage the public keys. By default, you can associate up to four key groups with a single distribution, and you can have up to five public keys in a key group.

  When you use the AWS account root user to manage CloudFront key pairs, you can only have up to two active CloudFront key pairs per AWS account.

## Create key pairs for your signers
<a name="private-content-creating-cloudfront-key-pairs"></a>

Each signer that you use to create CloudFront signed URLs or signed cookies must have a public–private key pair. The signer uses its private key to sign the URL or cookies, and CloudFront uses the public key to verify the signature.

The way that you create a key pair depends on whether you use a trusted key group as the signer (recommended), or a CloudFront key pair. For more information, see the following sections. The key pair that you create must meet the following requirements:
+ It must be either an SSH-2 RSA 2048 or ECDSA 256 key pair.
+ It must be in base64-encoded PEM format.

To help secure your applications, we recommend that you rotate key pairs periodically. For more information, see [Rotating key pairs](#private-content-rotating-key-pairs).

### Create a key pair for a trusted key group (recommended)
<a name="create-key-pair-and-key-group"></a>

To create a key pair for a trusted key group, perform the following steps:

1. Create the public–private key pair.

1. Upload the public key to CloudFront.

1. Add the public key to a CloudFront key group.

For more information, see the following procedures.<a name="private-content-uploading-cloudfront-public-key-procedure"></a>

**To create a key pair**
**Note**  
The following steps use OpenSSL as an example of one method for creating a key pair. There are many other ways to create an RSA or ECDSA key pair.

1. Run one of the following example commands:
   + The following example command uses OpenSSL to generate an RSA key pair with a length of 2048 bits and save to the file named `private_key.pem`.

     ```
     openssl genrsa -out private_key.pem 2048
     ```
   + The following example command uses OpenSSL to generate an ECDSA key pair with the `prime256v1` curve and save to the file named `private_key.pem`.

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

1. The resulting file contains both the public and the private key. The following example command extracts the public key from the file named `private_key.pem`.

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

   You upload the public key (in the `public_key.pem` file) later, in the following procedure.

**To upload the public key to CloudFront**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation menu, choose **Public keys**.

1. Choose **Create public key**.

1. In the **Create public key** window, do the following:

   1. For **Key name**, type a name to identify the public key.

   1. For **Key value**, paste the public key. If you followed the steps in the preceding procedure, the public key is in the file named `public_key.pem`. To copy and paste the contents of the public key, you can:
      + Use the **cat** command on the macOS or Linux command line, like this:

        ```
        cat public_key.pem
        ```

        Copy the output of that command, then paste it into the **Key value** field.
      + Open the `public_key.pem` file with a plaintext editor like Notepad (on Windows) or TextEdit (on macOS). Copy the contents of the file, then paste it into the **Key value** field.

   1. (Optional) For **Comment**, add a comment to describe the public key.

   When finished, choose **Add**.

1. Record the public key ID. You use it later when you create signed URLs or signed cookies, as the value of the `Key-Pair-Id` field.

**To add the public key to a key group**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation menu, choose **Key groups**.

1. Choose **Add key group**.

1. On the **Create key group** page, do the following:

   1. For **Key group name**, type a name to identify the key group.

   1. (Optional) For **Comment**, type a comment to describe the key group.

   1. For **Public keys**, select the public key to add to the key group, then choose **Add**. Repeat this step for each public key that you want to add to the key group.

1. Choose **Create key group**.

1. Record the key group name. You use it later to associate the key group with a cache behavior in a CloudFront distribution. (In the CloudFront API, you use the key group ID to associate the key group with a cache behavior.)

### Create a CloudFront key pair (not recommended, requires the AWS account root user)
<a name="create-key-pair-aws-account"></a>

**Important**  
We recommend that you create a public key for a trusted key group instead of following these steps. For the recommended way to create public keys for signed URLs and signed cookies, see [Create a key pair for a trusted key group (recommended)](#create-key-pair-and-key-group).

You can create a CloudFront key pair in the following ways:
+ Create a key pair in the AWS Management Console and download the private key. See the following procedure.
+ Create an RSA key pair by using an application such as OpenSSL, and then upload the public key to the AWS Management Console. For more information about creating an RSA key pair, see [Create a key pair for a trusted key group (recommended)](#create-key-pair-and-key-group).<a name="private-content-creating-cloudfront-key-pairs-procedure"></a>

**To create CloudFront key pairs in the AWS Management Console**

1. Sign in to the AWS Management Console using the credentials of the AWS account root user.
**Important**  
IAM users can’t create CloudFront key pairs. You must sign in using root user credentials to create key pairs.

1. Choose your account name, then choose **My Security Credentials**.

1. Choose **CloudFront key pairs**.

1. Confirm that you have no more than one active key pair. You can’t create a key pair if you already have two active key pairs.

1. Choose **Create New Key Pair**.
**Note**  
You can also choose to create your own key pair and upload the public key. CloudFront key pairs support 1024, 2048, or 4096-bit keys.

1. In the **Create Key Pair** dialog box, choose **Download Private Key File**, and then save the file on your computer.
**Important**  
Save the private key for your CloudFront key pair in a secure location, and set permissions on the file so that only the desired administrators can read it. If someone gets your private key, they can generate valid signed URLs and signed cookies and download your content. You cannot get the private key again, so if you lose or delete it, you must create a new CloudFront key pair.

1. Record the key pair ID for your key pair. (In the AWS Management Console, this is called the **Access Key ID**.) You’ll use it when you create signed URLs or signed cookies.

## Reformat the private key (.NET and Java only)
<a name="private-content-reformatting-private-key"></a>

If you’re using .NET or Java to create signed URLs or signed cookies, you cannot use the private key from your key pair in the default PEM format to create the signature. Instead, do the following:
+ **.NET framework** – Convert the private key to the XML format that the .NET framework uses. Several tools are available.
+ **Java** – Convert the private key to DER format. One way to do this is with the following OpenSSL command. In the following command, `private_key.pem` is the name of the file that contains the PEM-formatted private key, and `private_key.der` is the name of the file that contains the DER-formatted private key after you run the command.

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

  To ensure that the encoder works correctly, add the JAR for the Bouncy Castle Java cryptography APIs to your project and then add the Bouncy Castle provider.

## Add a signer to a distribution
<a name="private-content-adding-trusted-signers"></a>

A signer is the trusted key group (recommended) or CloudFront key pair that can create signed URLs and signed cookies for a distribution. To use signed URLs or signed cookies with a CloudFront distribution, you must specify a signer.

Signers are associated with cache behaviors. This allows you to require signed URLs or signed cookies for some files and not for others in the same distribution. A distribution requires signed URLs or cookies only for files that are associated with the corresponding cache behaviors.

Similarly, a signer can only sign URLs or cookies for files that are associated with the corresponding cache behaviors. For example, if you have one signer for one cache behavior and a different signer for a different cache behavior, neither signer can create signed URLs or cookies for files that are associated with the other cache behavior.

**Important**  
Before you add a signer to your distribution, do the following:  
Define the path patterns in cache behaviors and the sequence of cache behaviors carefully so you don’t give users unintended access to your content or prevent them from accessing content that you want to be available to everyone.  
For example, suppose a request matches the path pattern for two cache behaviors. The first cache behavior does not require signed URLs or signed cookies and the second cache behavior does. Users will be able to access the files without using signed URLs or signed cookies because CloudFront processes the cache behavior that is associated with the first match.  
For more information about path patterns, see [Path pattern](DownloadDistValuesCacheBehavior.md#DownloadDistValuesPathPattern).
For a distribution that you’re already using to distribute content, make sure you’re ready to start generating signed URLs and signed cookies before you add a signer. When you add a signer, CloudFront rejects requests that don’t include a valid signed URL or signed cookie.

You can add signers to your distribution using either the CloudFront console or the CloudFront API.

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

The following steps show how to add a trusted key group as a signer. You can also add an AWS account as a trusted signer, but it’s not recommended.<a name="private-content-adding-trusted-signers-console-procedure"></a>

**To add a signer to a distribution using the console**

1. Record the key group ID of the key group that you want to use as a trusted signer. For more information, see [Create a key pair for a trusted key group (recommended)](#create-key-pair-and-key-group).

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose the distribution whose files you want to protect with signed URLs or signed cookies.
**Note**  
To add a signer to a new distribution, you specify the same settings that are described in step 6 when you create the distribution.

1. Choose the **Behaviors** tab.

1. Select the cache behavior whose path pattern matches the files that you want to protect with signed URLs or signed cookies, and then choose **Edit**.

1. On the **Edit Behavior** page, do the following:

   1. For **Restrict Viewer Access (Use Signed URLs or Signed Cookies)**, choose **Yes**.

   1. For **Trusted Key Groups or Trusted Signer**, choose **Trusted Key Groups**.

   1. For **Trusted Key Groups**, choose the key group to add, and then choose **Add**. Repeat if you want to add more than one key group.

1. Choose **Yes, Edit** to update the cache behavior.

------
#### [ API ]

You can use the CloudFront API to add a trusted key group as a signer. You can add a signer to an existing distribution or to a new distribution. In either case, specify the values in the `TrustedKeyGroups` element.

You can also add an AWS account as a trusted signer, but it’s not recommended.

See the following topics in the *Amazon CloudFront API Reference*:
+ **Update an existing distribution** – [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html)
+ **Create a new distribution** – [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html)

------

## Rotating key pairs
<a name="private-content-rotating-key-pairs"></a>

We recommend that you periodically rotate (change) your key pairs for signed URLs and signed cookies. To rotate key pairs that you’re using to create signed URLs or signed cookies without invalidating URLs or cookies that haven’t expired yet, do the following tasks:

1. Create a new key pair, and add the public key to a key group. For more information, see [Create a key pair for a trusted key group (recommended)](#create-key-pair-and-key-group).

1. If you created a new key group in the previous step, [add the key group to the distribution as a signer](#private-content-adding-trusted-signers).
**Important**  
Don’t remove any existing public keys from the key group, or any key groups from the distribution yet. Only add the new ones.

1. Update your application to create signatures using the private key from the new key pair. Confirm that the signed URLs or cookies that are signed with the new private keys are working.

1. Wait until the expiration date has passed in URLs or cookies that were signed using the previous private key. Then remove the old public key from the key group. If you created a new key group in step 2, remove the old key group from your distribution.

# Decide to use signed URLs or signed cookies
<a name="private-content-choosing-signed-urls-cookies"></a>

CloudFront signed URLs and signed cookies provide the same basic functionality: they allow you to control who can access your content. If you want to serve private content through CloudFront and you're trying to decide whether to use signed URLs or signed cookies, consider the following.

Use signed URLs in the following cases:
+ You want to restrict access to individual files, for example, an installation download for your application.
+ Your users are using a client (for example, a custom HTTP client) that doesn't support cookies.

Use signed cookies in the following cases:
+ You want to provide access to multiple restricted files, for example, all of the files for a video in HLS format or all of the files in the subscribers' area of website.
+ You don't want to change your current URLs.

If you are not currently using signed URLs, and if your (unsigned) URLs contain any of the following query string parameters, you cannot use either signed URLs or signed cookies:
+ `Expires`
+ `Policy`
+ `Signature`
+ `Key-Pair-Id`
+ `Hash-Algorithm`

CloudFront assumes that URLs that contain any of those query string parameters are signed URLs, and therefore won't look at signed cookies.

## Use both signed URLs and signed cookies
<a name="private-content-using-signed-urls-and-cookies"></a>

Signed URLs take precedence over signed cookies. If you use both signed URLs and signed cookies to control access to the same files and a viewer uses a signed URL to request a file, CloudFront determines whether to return the file to the viewer based only on the signed URL.

# Use signed URLs
<a name="private-content-signed-urls"></a>

A signed URL includes additional information, for example, an expiration date and time, that gives you more control over access to your content. This additional information appears in a policy statement, which is based on either a canned policy or a custom policy. The differences between canned and custom policies are explained in the next two sections.

**Note**  
You can create some signed URLs using canned policies and create some signed URLs using custom policies for the same distribution.

**Topics**
+ [Decide to use canned or custom policies for signed URLs](#private-content-choosing-canned-custom-policy)
+ [How signed URLs work](#private-content-how-signed-urls-work)
+ [Decide how long signed URLs are valid](#private-content-overview-choosing-duration)
+ [When CloudFront checks expiration date and time in a signed URL](#private-content-check-expiration)
+ [Example code and third-party tools](#private-content-overview-sample-code)
+ [Create a signed URL using a canned policy](private-content-creating-signed-url-canned-policy.md)
+ [Create a signed URL using a custom policy](private-content-creating-signed-url-custom-policy.md)

## Decide to use canned or custom policies for signed URLs
<a name="private-content-choosing-canned-custom-policy"></a>

When you create a signed URL, you write a policy statement in JSON format that specifies the restrictions on the signed URL, for example, how long the URL is valid. You can use either a canned policy or a custom policy. Here's how canned and custom policies compare:


****  

| Description | Canned policy | Custom policy | 
| --- | --- | --- | 
| You can reuse the policy statement for multiple files. To reuse the policy statement, you must use wildcard characters in the `Resource` object. For more information, see [Values that you specify in the policy statement for a signed URL that uses a custom policy](private-content-creating-signed-url-custom-policy.md#private-content-custom-policy-statement-values).)  | No | Yes | 
| You can specify the date and time that users can begin to access your content. | No | Yes (optional) | 
| You can specify the date and time that users can no longer access your content. | Yes | Yes | 
| You can specify the IP address or range of IP addresses of the users who can access your content. | No | Yes (optional) | 
| The signed URL includes a base64-encoded version of the policy, which results in a longer URL. | No | Yes | 

For information about creating signed URLs using a *canned* policy, see [Create a signed URL using a canned policy](private-content-creating-signed-url-canned-policy.md).

For information about creating signed URLs using a *custom* policy, see [Create a signed URL using a custom policy](private-content-creating-signed-url-custom-policy.md).

## How signed URLs work
<a name="private-content-how-signed-urls-work"></a>

Here's an overview of how you configure CloudFront and Amazon S3 for signed URLs and how CloudFront responds when a user uses a signed URL to request a file. 

1. In your CloudFront distribution, specify one or more trusted key groups, which contain the public keys that CloudFront can use to verify the URL signature. You use the corresponding private keys to sign the URLs.

   CloudFront supports signed URLs with RSA 2048 and ECDSA 256 key signatures.

   For more information, see [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md).

1. Develop your application to determine whether a user should have access to your content and to create signed URLs for the files or parts of your application that you want to restrict access to. For more information, see the following topics:
   + [Create a signed URL using a canned policy](private-content-creating-signed-url-canned-policy.md)
   + [Create a signed URL using a custom policy](private-content-creating-signed-url-custom-policy.md)

1. A user requests a file for which you want to require signed URLs.

1. Your application verifies that the user is entitled to access the file: they've signed in, they've paid for access to the content, or they've met some other requirement for access.

1. Your application creates and returns a signed URL to the user.

1. The signed URL allows the user to download or stream the content.

   This step is automatic; the user usually doesn't have to do anything additional to access the content. For example, if a user is accessing your content in a web browser, your application returns the signed URL to the browser. The browser immediately uses the signed URL to access the file in the CloudFront edge cache without any intervention from the user.

1. CloudFront uses the public key to validate the signature and confirm that the URL hasn't been tampered with. If the signature is invalid, the request is rejected. 

   If the signature is valid, CloudFront looks at the policy statement in the URL (or constructs one if you're using a canned policy) to confirm that the request is still valid. For example, if you specified a beginning and ending date and time for the URL, CloudFront confirms that the user is trying to access your content during the time period that you want to allow access. 

   If the request meets the requirements in the policy statement, CloudFront does the standard operations: determines whether the file is already in the edge cache, forwards the request to the origin if necessary, and returns the file to the user.

**Note**  
If an unsigned URL contains query string parameters, make sure you include them in the portion of the URL that you sign. If you add a query string to a signed URL after signing it, the URL returns an HTTP 403 status.

## Decide how long signed URLs are valid
<a name="private-content-overview-choosing-duration"></a>

You can distribute private content using a signed URL that is valid for only a short time—possibly for as little as a few minutes. Signed URLs that are valid for such a short period are good for distributing content on-the-fly to a user for a specific purpose, such as distributing movie rentals or music downloads to customers on demand. If your signed URLs will be valid for just a short period, you'll probably want to generate them automatically using an application that you develop. When the user starts to download a file or starts to play a media file, CloudFront compares the expiration time in the URL with the current time to determine whether the URL is still valid.

You can also distribute private content using a signed URL that is valid for a longer time, possibly for years. Signed URLs that are valid for a longer period are useful for distributing private content to known users, such as distributing a business plan to investors or distributing training materials to employees. You can develop an application to generate these longer-term signed URLs for you.

## When CloudFront checks expiration date and time in a signed URL
<a name="private-content-check-expiration"></a>

CloudFront checks the expiration date and time in a signed URL at the time of the HTTP request. If a client begins to download a large file immediately before the expiration time, the download should complete even if the expiration time passes during the download. If the TCP connection drops and the client tries to restart the download after the expiration time passes, the download will fail.

If a client uses Range GETs to get a file in smaller pieces, any GET request that occurs after the expiration time passes will fail. For more information about Range GETs, see [How CloudFront processes partial requests for an object (range GETs)](RangeGETs.md).

## Example code and third-party tools
<a name="private-content-overview-sample-code"></a>

For example code that creates the hashed and signed part of signed URLs, see the following topics:
+ [Create a URL signature using Perl](CreateURLPerl.md)
+ [Create a URL signature using PHP](CreateURL_PHP.md)
+ [Create a URL signature using C\$1 and the .NET Framework](CreateSignatureInCSharp.md)
+ [Create a URL signature using Java](CFPrivateDistJavaDevelopment.md)

# Create a signed URL using a canned policy
<a name="private-content-creating-signed-url-canned-policy"></a>

To create a signed URL using a canned policy, complete the following steps.<a name="private-content-creating-signed-url-canned-policy-procedure"></a>

**To create a signed URL using a canned policy**

1. If you're using .NET or Java to create signed URLs, and if you haven't reformatted the private key for your key pair from the default .pem format to a format compatible with .NET or with Java, do so now. For more information, see [Reformat the private key (.NET and Java only)](private-content-trusted-signers.md#private-content-reformatting-private-key).

1. Concatenate the following values. You can use the format in this example signed URL. 

   ```
   https://d111111abcdef8.cloudfront.net/image.jpg?color=red&size=medium&Expires=1767290400&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~-ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmatEXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6&Key-Pair-Id=K2JCJMDEHXQW5F&Hash-Algorithm=SHA256
   ```

   Remove all empty spaces (including tabs and newline characters). You might have to include escape characters in the string in application code. All values have a type of `String`.  
**1. *Base URL for the file***  
The base URL is the CloudFront URL that you would use to access the file if you were not using signed URLs, including your own query string parameters, if any. In the preceding example, the base URL is `https://d111111abcdef8.cloudfront.net/image.jpg`. For more information about the format of URLs for distributions, see [Customize the URL format for files in CloudFront](LinkFormat.md).  
   + The following CloudFront URL is for an image file in a distribution (using the CloudFront domain name). Note that `image.jpg` is in an `images` directory. The path to the file in the URL must match the path to the file on your HTTP server or in your Amazon S3 bucket.

     `https://d111111abcdef8.cloudfront.net/images/image.jpg`
   + The following CloudFront URL includes a query string:

     `https://d111111abcdef8.cloudfront.net/images/image.jpg?size=large`
   + The following CloudFront URLs are for image files in a distribution. Both use an alternate domain name. The second one includes a query string:

     `https://www.example.com/images/image.jpg`

     `https://www.example.com/images/image.jpg?color=red`
   + The following CloudFront URL is for an image file in a distribution that uses an alternate domain name and the HTTPS protocol:

     `https://www.example.com/images/image.jpg`  
** 2. `?`**  
The `?` indicates that query parameters follow the base URL. Include the `?` even if you don't specify any query parameters.  
You can specify the following query parameters in any order.  
**3. *Your query string parameters, if any*`&`**  
(Optional) You can enter your own query string parameters. To do so, add an ampersand (`&`) between each one, such as `color=red&size=medium`. You can specify query string parameters in any order within the URL.  
Your query string parameters can't be named `Expires`, `Signature`, `Key-Pair-Id`, or `Hash-Algorithm`.  
** 4. `Expires=`*date and time in Unix time format (in seconds) and Coordinated Universal Time (UTC)***  
The date and time that you want the URL to stop allowing access to the file.  
Specify the expiration date and time in Unix time format (in seconds) and Coordinated Universal Time (UTC). For example, January 1, 2026 10:00 am UTC converts to `1767290400` in Unix time format, as shown in the example at the start of this topic.   
To use epoch time, specify a 64-bit integer for a date that's no later than `9223372036854775807` (Friday, April 11, 2262 at 23:47:16.854 UTC).  
  
For information about UTC, see [RFC 3339, Date and Time on the Internet: Timestamps](https://tools.ietf.org/html/rfc3339).  
** 5. `&Signature=`*hashed and signed version of the policy statement***  
A hashed, signed, and base64-encoded version of the JSON policy statement. For more information, see [Create a signature for a signed URL that uses a canned policy](#private-content-canned-policy-creating-signature).  
** 6. `&Key-Pair-Id=`*public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature***  
The ID for a CloudFront public key, for example, `K2JCJMDEHXQW5F`. The public key ID tells CloudFront which public key to use to validate the signed URL. CloudFront compares the information in the signature with the information in the policy statement to verify that the URL has not been tampered with.  
This public key must belong to a key group that is a trusted signer in the distribution. For more information, see [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md).  
** 7. `&Hash-Algorithm=`*SHA1 or SHA256***  
(Optional) The hash algorithm used to create the signature. Supported values are `SHA1` and `SHA256`. If you don't specify this parameter, CloudFront defaults to `SHA1`.

## Create a signature for a signed URL that uses a canned policy
<a name="private-content-canned-policy-creating-signature"></a>

To create the signature for a signed URL that uses a canned policy, complete the following procedures.

**Topics**
+ [Create a policy statement for a signed URL that uses a canned policy](#private-content-canned-policy-creating-policy-statement)
+ [Create a signature for a signed URL that uses a canned policy](#private-content-canned-policy-signing-policy-statement)

### Create a policy statement for a signed URL that uses a canned policy
<a name="private-content-canned-policy-creating-policy-statement"></a>

When you create a signed URL using a canned policy, the `Signature` parameter is a hashed and signed version of a policy statement. For signed URLs that use a canned policy, you don't include the policy statement in the URL, as you do for signed URLs that use a custom policy. To create the policy statement, do the following procedure.<a name="private-content-canned-policy-creating-policy-statement-procedure"></a>

**To create the policy statement for a signed URL that uses a canned policy**

1. Construct the policy statement using the following JSON format and using UTF-8 character encoding. Include all punctuation and other literal values exactly as specified. For information about the `Resource` and `DateLessThan` parameters, see [Values that you specify in the policy statement for a signed URL that uses a canned policy](#private-content-canned-policy-statement-values).

   ```
   {
       "Statement": [
           {
               "Resource": "base URL or stream name",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime": ending date and time in Unix time format and UTC
                   }
               }
           }
       ]
   }
   ```

1. Remove all empty spaces (including tabs and newline characters) from the policy statement. You might have to include escape characters in the string in application code.

#### Values that you specify in the policy statement for a signed URL that uses a canned policy
<a name="private-content-canned-policy-statement-values"></a>

When you create a policy statement for a canned policy, you specify the following values.

**Resource**  
You can specify only one value for `Resource`.
The base URL including your query strings, if any, but excluding the CloudFront `Expires`, `Signature`, `Key-Pair-Id`, and `Hash-Algorithm` parameters, for example:  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
Note the following:  
+ **Protocol** – The value must begin with `http://` or `https://`.
+ **Query string parameters** – If you have no query string parameters, omit the question mark.
+ **Alternate domain names** – If you specify an alternate domain name (CNAME) in the URL, you must specify the alternate domain name when referencing the file in your webpage or application. Do not specify the Amazon S3 URL for the object.

**DateLessThan**  
The expiration date and time for the URL in Unix time format (in seconds) and Coordinated Universal Time (UTC). For example, January 1, 2026 10:00 am UTC converts to 1767290400 in Unix time format.  
This value must match the value of the `Expires` query string parameter in the signed URL. Do not enclose the value in quotation marks.  
For more information, see [When CloudFront checks expiration date and time in a signed URL](private-content-signed-urls.md#private-content-check-expiration).

#### Example policy statement for a signed URL that uses a canned policy
<a name="private-content-canned-policy-creating-policy-statement-example"></a>

When you use the following example policy statement in a signed URL, a user can access the file `https://d111111abcdef8.cloudfront.net/horizon.jpg` until January 1, 2026 10:00 am UTC:

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/horizon.jpg?size=large&license=yes",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

### Create a signature for a signed URL that uses a canned policy
<a name="private-content-canned-policy-signing-policy-statement"></a>

To create the value for the `Signature` parameter in a signed URL, you hash and sign the policy statement that you created in [Create a policy statement for a signed URL that uses a canned policy](#private-content-canned-policy-creating-policy-statement).

For additional information and examples of how to hash, sign, and encode the policy statement, see:
+ [Linux commands and OpenSSL for base64 encoding and encryption](private-content-linux-openssl.md)
+ [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md)

**Note**  
The linked examples use SHA-1 by default. To use SHA-256 instead, replace `sha1` with `sha256` in the OpenSSL commands and include the `Hash-Algorithm=SHA256` query parameter in the signed URL.<a name="private-content-canned-policy-creating-signature-download-procedure"></a>

**Option 1: To create a signature by using a canned policy**

1. Use the SHA-1 or SHA-256 hash function and the generated RSA or ECDSA private key to hash and sign the policy statement that you created in the procedure [To create the policy statement for a signed URL that uses a canned policy](#private-content-canned-policy-creating-policy-statement-procedure). Use the version of the policy statement that no longer includes empty spaces.

   If you use SHA-256, you must include `&Hash-Algorithm=SHA256` in the signed URL.

   For the private key that is required by the hash function, use a private key whose public key is in an active trusted key group for the distribution.
**Note**  
The method that you use to hash and sign the policy statement depends on your programming language and platform. For sample code, see [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md).

1. Remove empty spaces (including tabs and newline characters) from the hashed and signed string.

1. Base64-encode the string using MIME base64 encoding. For more information, see [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8) in *RFC 2045, MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*.

1. Replace characters that are invalid in a URL query string with characters that are valid. The following table lists invalid and valid characters.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-canned-policy.html)

1. Append the resulting value to your signed URL after `&Signature=`, and return to [To create a signed URL using a canned policy](#private-content-creating-signed-url-canned-policy-procedure) to finish concatenating the parts of your signed URL.

# Create a signed URL using a custom policy
<a name="private-content-creating-signed-url-custom-policy"></a>

To create a signed URL using a custom policy, complete the following procedure.<a name="private-content-creating-signed-url-custom-policy-procedure"></a>

**To create a signed URL using a custom policy**

1. If you're using .NET or Java to create signed URLs, and if you haven't reformatted the private key for your key pair from the default .pem format to a format compatible with .NET or with Java, do so now. For more information, see [Reformat the private key (.NET and Java only)](private-content-trusted-signers.md#private-content-reformatting-private-key).

1. Concatenate the following values. You can use the format in this example signed URL.

   

   ```
   https://d111111abcdef8.cloudfront.net/image.jpg?color=red&size=medium&Policy=eyANCiAgICEXAMPLEW1lbnQiOiBbeyANCiAgICAgICJSZXNvdXJjZSI6Imh0dHA6Ly9kemJlc3FtN3VuMW0wLmNsb3VkZnJvbnQubmV0L2RlbW8ucGhwIiwgDQogICAgICAiQ29uZGl0aW9uIjp7IA0KICAgICAgICAgIklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIyMDcuMTcxLjE4MC4xMDEvMzIifSwNCiAgICAgICAgICJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTI5Njg2MDE3Nn0sDQogICAgICAgICAiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjEyOTY4NjAyMjZ9DQogICAgICB9IA0KICAgfV0gDQp9DQo&Signature=nitfHRCrtziwO2HwPfWw~yYDhUF5EwRunQA-j19DzZrvDh6hQ73lDx~-ar3UocvvRQVw6EkC~GdpGQyyOSKQim-TxAnW7d8F5Kkai9HVx0FIu-5jcQb0UEmatEXAMPLE3ReXySpLSMj0yCd3ZAB4UcBCAqEijkytL6f3fVYNGQI6&Key-Pair-Id=K2JCJMDEHXQW5F&Hash-Algorithm=SHA256
   ```

   Remove all empty spaces (including tabs and newline characters). You might have to include escape characters in the string in application code. All values have a type of `String`.  
**1. *Base URL for the file***  
The base URL is the CloudFront URL that you would use to access the file if you were not using signed URLs, including your own query string parameters, if any. In the preceding example, the base URL is `https://d111111abcdef8.cloudfront.net/image.jpg`. For more information about the format of URLs for distributions, see [Customize the URL format for files in CloudFront](LinkFormat.md).  
The following examples show values that you specify for distributions.  
   + The following CloudFront URL is for an image file in a distribution (using the CloudFront domain name). Note that `image.jpg` is in an `images` directory. The path to the file in the URL must match the path to the file on your HTTP server or in your Amazon S3 bucket.

     `https://d111111abcdef8.cloudfront.net/images/image.jpg`
   + The following CloudFront URL includes a query string:

     `https://d111111abcdef8.cloudfront.net/images/image.jpg?size=large`
   + The following CloudFront URLs are for image files in a distribution. Both use an alternate domain name; the second one includes a query string:

     `https://www.example.com/images/image.jpg`

     `https://www.example.com/images/image.jpg?color=red`
   + The following CloudFront URL is for an image file in a distribution that uses an alternate domain name and the HTTPS protocol:

     `https://www.example.com/images/image.jpg`  
**2. `?`**  
The `?` indicates that query string parameters follow the base URL. Include the `?` even if you don't specify any query parameters.  
You can specify the following query parameters in any order.  
**3. *Your query string parameters, if any*`&`**  
(Optional) You can enter your own query string parameters. To do so, add an ampersand (&) between each one, such as `color=red&size=medium`. You can specify query string parameters in any order within the URL.  
Your query string parameters can't be named `Policy`, `Signature`, `Key-Pair-Id`, or `Hash-Algorithm`.
If you add your own parameters, append an `&` after each one, including the last one.   
**4. `Policy=`*base64 encoded version of policy statement***  
Your policy statement in JSON format, with empty spaces removed, then base64 encoded. For more information, see [Create a policy statement for a signed URL that uses a custom policy](#private-content-custom-policy-statement).  
The policy statement controls the access that a signed URL grants to a user. It includes the URL of the file, an expiration date and time, an optional date and time that the URL becomes valid, and an optional IP address or range of IP addresses that are allowed to access the file.  
**5. `&Signature=`*hashed and signed version of the policy statement***  
A hashed, signed, and base64-encoded version of the JSON policy statement. For more information, see [Create a signature for a signed URL that uses a custom policy](#private-content-custom-policy-creating-signature).  
**6. `&Key-Pair-Id=`*public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature***  
The ID for a CloudFront public key, for example, `K2JCJMDEHXQW5F`. The public key ID tells CloudFront which public key to use to validate the signed URL. CloudFront compares the information in the signature with the information in the policy statement to verify that the URL has not been tampered with.  
This public key must belong to a key group that is a trusted signer in the distribution. For more information, see [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md).  
**7. `&Hash-Algorithm=`*SHA1 or SHA256***  
(Optional) The hash algorithm used to create the signature. Supported values are `SHA1` and `SHA256`. If you don't specify this parameter, CloudFront defaults to `SHA1`.

## Create a policy statement for a signed URL that uses a custom policy
<a name="private-content-custom-policy-statement"></a>

Complete the following steps to create a policy statement for a signed URL that uses a custom policy.

For example policy statements that control access to files in a variety of ways, see [Example policy statements for a signed URL that uses a custom policy](#private-content-custom-policy-statement-examples).<a name="private-content-custom-policy-creating-policy-procedure"></a>

**To create the policy statement for a signed URL that uses a custom policy**

1. Construct the policy statement using the following JSON format. Replace the less than (`<`) and greater than (`>`) symbols, and the descriptions within them, with your own values. For more information, see [Values that you specify in the policy statement for a signed URL that uses a custom policy](#private-content-custom-policy-statement-values).

   ```
   {
       "Statement": [
           {
               "Resource": "<Optional but recommended: URL of the file>",
               "Condition": {
                   "DateLessThan": {
   	                "AWS:EpochTime": <Required: ending date and time in Unix time format and UTC>
                   },
                   "DateGreaterThan": {
   	                "AWS:EpochTime": <Optional: beginning date and time in Unix time format and UTC>
                   },
                   "IpAddress": {
   	                "AWS:SourceIp": "<Optional: IP address>"
                   }
               }
           }
       ]
   }
   ```

   Note the following:
   + You can include only one statement in the policy.
   + Use UTF-8 character encoding.
   + Include all punctuation and parameter names exactly as specified. Abbreviations for parameter names are not accepted.
   + The order of the parameters in the `Condition` section doesn't matter.
   + For information about the values for `Resource`, `DateLessThan`, `DateGreaterThan`, and `IpAddress`, see [Values that you specify in the policy statement for a signed URL that uses a custom policy](#private-content-custom-policy-statement-values).

1. Remove all empty spaces (including tabs and newline characters) from the policy statement. You might have to include escape characters in the string in application code.

1. Base64-encode the policy statement using MIME base64 encoding. For more information, see [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8) in *RFC 2045, MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*.

1. Replace characters that are invalid in a URL query string with characters that are valid. The following table lists invalid and valid characters.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html)

1. Append the resulting value to your signed URL after `Policy=`.

1. Create a signature for the signed URL by hashing, signing, and base64-encoding the policy statement. For more information, see [Create a signature for a signed URL that uses a custom policy](#private-content-custom-policy-creating-signature).

### Values that you specify in the policy statement for a signed URL that uses a custom policy
<a name="private-content-custom-policy-statement-values"></a>

When you create a policy statement for a custom policy, you specify the following values.

**Resource**  
The URL, including any query strings, but excluding the CloudFront `Policy`, `Signature`, `Key-Pair-Id`, and `Hash-Algorithm` parameters. For example:  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg\?size=large&license=yes`  
You can specify only one URL value for `Resource`.  
You can omit the `Resource` parameter in a policy, but doing so means that anyone with the signed URL can access *all* of the files in *any* distribution that is associated with the key pair that you use to create the signed URL.
Note the following:  
+ **Protocol** – The value must begin with `http://`, `https://`, or `*://`.
+ **Query string parameters** – If the URL has query string parameters, don't use a backslash character (`\`) to escape the question mark character (`?`) that begins the query string. For example:

  `https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`
+ **Wildcard characters** – You can use wildcard characters in the URL in the policy. The following wildcard characters are supported:
  + asterisk (`*`), which matches zero or more characters
  + question mark (`?`), which matches exactly one character

  When CloudFront matches the URL in the policy to the URL in the HTTP request, the URL in the policy is divided into four sections—protocol, domain, path, and query string—as follows:

  `[protocol]://[domain]/[path]\?[query string]`

  When you use a wildcard character in the URL in the policy, the wildcard matching applies only within the boundaries of the section that contains the wildcard. For example, consider this URL in a policy:

  `https://www.example.com/hello*world`

  In this example, the asterisk wildcard (`*`) only applies within the path section, so it matches the URLs `https://www.example.com/helloworld` and `https://www.example.com/hello-world`, but it does not match the URL `https://www.example.net/hello?world`.

  The following exceptions apply to the section boundaries for wildcard matching:
  + A trailing asterisk in the path section implies an asterisk in the query string section. For example, `http://example.com/hello*` is equivalent to `http://example.com/hello*\?*`.
  + A trailing asterisk in the domain section implies an asterisk in both the path and query string sections. For example, `http://example.com*` is equivalent to `http://example.com*/*\?*`.
  + A URL in the policy can omit the protocol section and start with an asterisk in the domain section. In that case, the protocol section is implicitly set to an asterisk. For example, the URL `*example.com` in a policy is equivalent to `*://*example.com/`.
  + An asterisk by itself (`"Resource": "*"`) matches any URL.

  For example, the value: `https://d111111abcdef8.cloudfront.net/*game_download.zip*` in a policy matches all of the following URLs:
  + `https://d111111abcdef8.cloudfront.net/game_download.zip`
  + `https://d111111abcdef8.cloudfront.net/example_game_download.zip?license=yes`
  + `https://d111111abcdef8.cloudfront.net/test_game_download.zip?license=temp`
+ **Alternate domain names** – If you specify an alternate domain name (CNAME) in the URL in the policy, the HTTP request must use the alternate domain name in your webpage or application. Do not specify the Amazon S3 URL for the file in a policy.

**DateLessThan**  
The expiration date and time for the URL in Unix time format (in seconds) and Coordinated Universal Time (UTC). In the policy, do not enclose the value in quotation marks. For information about UTC, see [Date and Time on the Internet: Timestamps](https://tools.ietf.org/html/rfc3339).  
For example, January 31, 2023 10:00 AM UTC converts to 1675159200 in Unix time format.  
This is the only required parameter in the `Condition` section. CloudFront requires this value to prevent users from having permanent access to your private content.  
For more information, see [When CloudFront checks expiration date and time in a signed URL](private-content-signed-urls.md#private-content-check-expiration)

**DateGreaterThan (Optional)**  
An optional start date and time for the URL in Unix time format (in seconds) and Coordinated Universal Time (UTC). Users are not allowed to access the file on or before the specified date and time. Do not enclose the value in quotation marks. 

**IpAddress (Optional)**  
The IP address of the client making the HTTP request. Note the following:  
+ To allow any IP address to access the file, omit the `IpAddress` parameter.
+ You can specify either one IP address or one IP address range. You can't use the policy to allow access if the client's IP address is in one of two separate ranges.
+ To allow access from a single IP address, you specify:

  `"`*IPv4 IP address*`/32"`
+ You must specify IP address ranges in standard IPv4 CIDR format (for example, `192.0.2.0/24`). For more information, see [Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan](https://tools.ietf.org/html/rfc4632).
**Important**  
IP addresses in IPv6 format, such as 2001:0db8:85a3::8a2e:0370:7334, are not supported. 

  If you're using a custom policy that includes `IpAddress`, do not enable IPv6 for the distribution. If you want to restrict access to some content by IP address and support IPv6 requests for other content, you can create two distributions. For more information, see [Enable IPv6 (viewer requests)](DownloadDistValuesGeneral.md#DownloadDistValuesEnableIPv6) in the topic [All distribution settings reference](distribution-web-values-specify.md).

## Example policy statements for a signed URL that uses a custom policy
<a name="private-content-custom-policy-statement-examples"></a>

The following example policy statements show how to control access to a specific file, all of the files in a directory, or all of the files associated with a key pair ID. The examples also show how to control access from an individual IP address or a range of IP addresses, and how to prevent users from using the signed URL after a specified date and time.

If you copy and paste any of these examples, remove any empty spaces (including tabs and newline characters), replace the values with your own values, and include a newline character after the closing brace (`}`).

For more information, see [Values that you specify in the policy statement for a signed URL that uses a custom policy](#private-content-custom-policy-statement-values).

**Topics**
+ [Example policy statement: Access one file from a range of IP addresses](#private-content-custom-policy-statement-example-one-object)
+ [Example policy statement: Access all files in a directory from a range of IP addresses](#private-content-custom-policy-statement-example-all-objects)
+ [Example policy statement: Access all files associated with a key pair ID from one IP address](#private-content-custom-policy-statement-example-one-ip)

### Example policy statement: Access one file from a range of IP addresses
<a name="private-content-custom-policy-statement-example-one-object"></a>

The following example custom policy in a signed URL specifies that a user can access the file `https://d111111abcdef8.cloudfront.net/game_download.zip` from IP addresses in the range `192.0.2.0/24` until January 31, 2023 10:00 AM UTC:

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/game_download.zip",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675159200
                }
            }
        }
    ]
}
```

### Example policy statement: Access all files in a directory from a range of IP addresses
<a name="private-content-custom-policy-statement-example-all-objects"></a>

The following example custom policy allows you to create signed URLs for any file in the `training` directory, as indicated by the asterisk wildcard character (`*`) in the `Resource` parameter. Users can access the file from an IP address in the range `192.0.2.0/24` until January 31, 2023 10:00 AM UTC:

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/training/*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675159200
                }
            }
        }
    ]
}
```

Each signed URL with which you use this policy has a URL that identifies a specific file, for example:

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

### Example policy statement: Access all files associated with a key pair ID from one IP address
<a name="private-content-custom-policy-statement-example-one-ip"></a>

The following example custom policy allows you to create signed URLs for any file associated with any distribution, as indicated by the asterisk wildcard character (`*`) in the `Resource` parameter. The signed URL must use the `https://` protocol, not `http://`. The user must use the IP address `192.0.2.10/32`. (The value `192.0.2.10/32` in CIDR notation refers to a single IP address, `192.0.2.10`.) The files are available only from January 31, 2023 10:00 AM UTC until February 2, 2023 10:00 AM UTC:

```
{
    "Statement": [
       {
            "Resource": "https://*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.10/32"
                },
                "DateGreaterThan": {
                    "AWS:EpochTime": 1675159200
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1675332000
                }
            }
        }
    ]
}
```

Each signed URL with which you use this policy has a URL that identifies a specific file in a specific CloudFront distribution, for example:

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

The signed URL also includes a key pair ID, which must be associated with a trusted key group in the distribution (d111111abcdef8.cloudfront.net) that you specify in the URL.

## Create a signature for a signed URL that uses a custom policy
<a name="private-content-custom-policy-creating-signature"></a>

The signature for a signed URL that uses a custom policy is a hashed, signed, and base64-encoded version of the policy statement. To create a signature for a custom policy, complete the following steps.

For additional information and examples of how to hash, sign, and encode the policy statement, see:
+ [Linux commands and OpenSSL for base64 encoding and encryption](private-content-linux-openssl.md)
+ [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md)

**Note**  
The linked examples use SHA-1 by default. To use SHA-256 instead, replace `sha1` with `sha256` in the OpenSSL commands and include the `Hash-Algorithm=SHA256` query parameter in the signed URL.<a name="private-content-custom-policy-creating-signature-download-procedure"></a>

**Option 1: To create a signature by using a custom policy**

1. Use the SHA-1 or SHA-256 hash function and the generated RSA or ECDSA private key to hash and sign the JSON policy statement that you created in the procedure [To create the policy statement for a signed URL that uses a custom policy](#private-content-custom-policy-creating-policy-procedure). Use the version of the policy statement that no longer includes empty spaces but that has not yet been base64-encoded.

   If you use SHA-256, you must include `&Hash-Algorithm=SHA256` in the signed URL.

   For the private key that is required by the hash function, use a private key whose public key is in an active trusted key group for the distribution.
**Note**  
The method that you use to hash and sign the policy statement depends on your programming language and platform. For sample code, see [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md).

1. Remove empty spaces (including tabs and newline characters) from the hashed and signed string.

1. Base64-encode the string using MIME base64 encoding. For more information, see [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8) in *RFC 2045, MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*.

1. Replace characters that are invalid in a URL query string with characters that are valid. The following table lists invalid and valid characters.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-custom-policy.html)

1. Append the resulting value to your signed URL after `&Signature=`, and return to [To create a signed URL using a custom policy](#private-content-creating-signed-url-custom-policy-procedure) to finish concatenating the parts of your signed URL.

# Use signed cookies
<a name="private-content-signed-cookies"></a>

CloudFront signed cookies allow you to control who can access your content when you don't want to change your current URLs or when you want to provide access to multiple restricted files, for example, all of the files in the subscribers' area of a website. This topic explains the considerations when using signed cookies and describes how to set signed cookies using canned and custom policies.

**Topics**
+ [Decide to use canned or custom policies for signed cookies](#private-content-choosing-canned-custom-cookies)
+ [How signed cookies work](#private-content-how-signed-cookies-work)
+ [Prevent misuse of signed cookies](#private-content-signed-cookie-misuse)
+ [When CloudFront checks expiration date and time in a signed cookie](#private-content-check-expiration-cookie)
+ [Sample code and third-party tools](#private-content-overview-sample-code-cookies)
+ [Set signed cookies using a canned policy](private-content-setting-signed-cookie-canned-policy.md)
+ [Set signed cookies using a custom policy](private-content-setting-signed-cookie-custom-policy.md)
+ [Create signed cookies using PHP](signed-cookies-PHP.md)

## Decide to use canned or custom policies for signed cookies
<a name="private-content-choosing-canned-custom-cookies"></a>

When you create a signed cookie, you write a policy statement in JSON format that specifies the restrictions on the signed cookie, for example, how long the cookie is valid. You can use canned policies or custom policies. The following table compares canned and custom policies:


****  

| Description | Canned policy | Custom policy | 
| --- | --- | --- | 
| You can reuse the policy statement for multiple files. To reuse the policy statement, you must use wildcard characters in the `Resource` object. For more information, see [Values that you specify in the policy statement for a custom policy for signed cookies](private-content-setting-signed-cookie-custom-policy.md#private-content-custom-policy-statement-cookies-values).)  | No | Yes | 
| You can specify the date and time that users can begin to access your content | No | Yes (optional) | 
| You can specify the date and time that users can no longer access your content | Yes | Yes | 
| You can specify the IP address or range of IP addresses of the users who can access your content | No | Yes (optional) | 

For information about creating signed cookies using a canned policy, see [Set signed cookies using a canned policy](private-content-setting-signed-cookie-canned-policy.md).

For information about creating signed cookies using a custom policy, see [Set signed cookies using a custom policy](private-content-setting-signed-cookie-custom-policy.md).

## How signed cookies work
<a name="private-content-how-signed-cookies-work"></a>

Here's an overview of how you configure CloudFront for signed cookies and how CloudFront responds when a user submits a request that contains a signed cookie. 

1. In your CloudFront distribution, specify one or more trusted key groups, which contain the public keys that CloudFront can use to verify the URL signature. You use the corresponding private keys to sign the URLs.

   For more information, see [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md).

1. You develop your application to determine whether a user should have access to your content and, if so, to send three `Set-Cookie` headers to the viewer. (Each `Set-Cookie` header can contain only one name-value pair, and a CloudFront signed cookie requires three name-value pairs.) You must send the `Set-Cookie` headers to the viewer before the viewer requests your private content. If you set a short expiration time on the cookie, you might also want to send three more `Set-Cookie` headers in response to subsequent requests, so that the user continues to have access.

   Typically, your CloudFront distribution will have at least two cache behaviors, one that doesn't require authentication and one that does. The error page for the secure portion of the site includes a redirector or a link to a login page.

   If you configure your distribution to cache files based on cookies, CloudFront doesn't cache separate files based on the attributes in signed cookies.

1. A user signs in to your website and either pays for content or meets some other requirement for access.

1. Your application returns the `Set-Cookie` headers in the response, and the viewer stores the name-value pairs.

1. The user requests a file.

   The user's browser or other viewer gets the name-value pairs from step 4 and adds them to the request in a `Cookie` header. This is the signed cookie.

1. CloudFront uses the public key to validate the signature in the signed cookie and to confirm that the cookie hasn't been tampered with. If the signature is invalid, the request is rejected.

   If the signature in the cookie is valid, CloudFront looks at the policy statement in the cookie (or constructs one if you're using a canned policy) to confirm that the request is still valid. For example, if you specified a beginning and ending date and time for the cookie, CloudFront confirms that the user is trying to access your content during the time period that you want to allow access.

   If the request meets the requirements in the policy statement, CloudFront serves your content as it does for content that isn't restricted: it determines whether the file is already in the edge cache, forwards the request to the origin if necessary, and returns the file to the user.

## Prevent misuse of signed cookies
<a name="private-content-signed-cookie-misuse"></a>

If you specify the `Domain` parameter in a `Set-Cookie` header, specify the most precise value possible to reduce the potential for access by someone with the same root domain name. For example, app.example.com is preferable to example.com, especially when you don't control example.com. This helps prevent someone from accessing your content from www.example.com.

To help prevent this type of attack, do the following:
+ Exclude the `Expires` and `Max-Age` cookie attributes, so that the `Set-Cookie` header creates a session cookie. Session cookies are automatically deleted when the user closes the browser, which reduces the possibility of someone getting unauthorized access to your content.
+ Include the `Secure` attribute, so that the cookie is encrypted when a viewer includes it in a request.
+ When possible, use a custom policy and include the IP address of the viewer.
+ In the `CloudFront-Expires` attribute, specify the shortest reasonable expiration time based on how long you want users to have access to your content.

## When CloudFront checks expiration date and time in a signed cookie
<a name="private-content-check-expiration-cookie"></a>

To determine whether a signed cookie is still valid, CloudFront checks the expiration date and time in the cookie at the time of the HTTP request. If a client begins to download a large file immediately before the expiration time, the download should complete even if the expiration time passes during the download. If the TCP connection drops and the client tries to restart the download after the expiration time passes, the download will fail.

If a client uses Range GETs to get a file in smaller pieces, any GET request that occurs after the expiration time passes will fail. For more information about Range GETs, see [How CloudFront processes partial requests for an object (range GETs)](RangeGETs.md).

## Sample code and third-party tools
<a name="private-content-overview-sample-code-cookies"></a>

The sample code for private content shows only how to create the signature for signed URLs. However, the process for creating a signature for a signed cookie is very similar, so much of the sample code is still relevant. For more information, see the following topics: 
+ [Create a URL signature using Perl](CreateURLPerl.md)
+ [Create a URL signature using PHP](CreateURL_PHP.md)
+ [Create a URL signature using C\$1 and the .NET Framework](CreateSignatureInCSharp.md)
+ [Create a URL signature using Java](CFPrivateDistJavaDevelopment.md)

# Set signed cookies using a canned policy
<a name="private-content-setting-signed-cookie-canned-policy"></a>

To set a signed cookie by using a canned policy, complete the following steps. To create the signature, see [Create a signature for a signed cookie that uses a canned policy](#private-content-canned-policy-signature-cookies).<a name="private-content-setting-signed-cookie-canned-policy-procedure"></a>

**To set a signed cookie using a canned policy**

1. If you're using .NET or Java to create signed cookies, and if you haven't reformatted the private key for your key pair from the default .pem format to a format compatible with .NET or with Java, do so now. For more information, see [Reformat the private key (.NET and Java only)](private-content-trusted-signers.md#private-content-reformatting-private-key).

1. Program your application to send three `Set-Cookie` headers to approved viewers (or four, if you want to specify a hash algorithm). You need three `Set-Cookie` headers because each `Set-Cookie` header can contain only one name-value pair, and a CloudFront signed cookie requires three name-value pairs. The name-value pairs are: `CloudFront-Expires`, `CloudFront-Signature`, and `CloudFront-Key-Pair-Id`. You can optionally include a fourth name-value pair, `CloudFront-Hash-Algorithm`, to specify the hash algorithm used for the signature. The values must be present on the viewer before a user makes the first request for a file that you want to control access to. 
**Note**  
In general, we recommend that you exclude `Expires` and `Max-Age` attributes. Excluding the attributes causes the browser to delete the cookie when the user closes the browser, which reduces the possibility of someone getting unauthorized access to your content. For more information, see [Prevent misuse of signed cookies](private-content-signed-cookies.md#private-content-signed-cookie-misuse).

   **The names of cookie attributes are case-sensitive**. 

   Line breaks are included only to make the attributes more readable.

   ```
   Set-Cookie: 
   CloudFront-Expires=date and time in Unix time format (in seconds) and Coordinated Universal Time (UTC); 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Signature=hashed and signed version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Key-Pair-Id=public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Hash-Algorithm=SHA1 or SHA256; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   ```  
**(Optional) `Domain`**  
The domain name for the requested file. If you don't specify a `Domain` attribute, the default value is the domain name in the URL, and it applies only to the specified domain name, not to subdomains. If you specify a `Domain` attribute, it also applies to subdomains. A leading dot in the domain name (for example, `Domain=.example.com`) is optional. In addition, if you specify a `Domain` attribute, the domain name in the URL and the value of the `Domain` attribute must match.  
You can specify the domain name that CloudFront assigned to your distribution, for example, d111111abcdef8.cloudfront.net, but you can't specify \$1.cloudfront.net for the domain name.  
If you want to use an alternate domain name such as example.com in URLs, you must add the alternate domain name to your distribution regardless of whether you specify the `Domain` attribute. For more information, see [Alternate domain names (CNAMEs)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) in the topic [All distribution settings reference](distribution-web-values-specify.md).  
**(Optional) `Path`**  
The path for the requested file. If you don't specify a `Path` attribute, the default value is the path in the URL.  
**`Secure`**  
Requires that the viewer encrypt cookies before sending a request. We recommend that you send the `Set-Cookie` header over an HTTPS connection to ensure that the cookie attributes are protected from man-in-the-middle attacks.  
**`HttpOnly`**  
Defines how the browser (where supported) interacts with the cookie value. With `HttpOnly`, the cookie values are inaccessible to JavaScript. This precaution can help mitigate cross-site scripting (XSS) attacks. For more information, see [Using HTTP cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies).  
**`CloudFront-Expires`**  
Specify the expiration date and time in Unix time format (in seconds) and Coordinated Universal Time (UTC). For example, January 1, 2026 10:00 am UTC converts to 1767290400 in Unix time format.   
To use epoch time, specify a 64-bit integer for a date that's no later than `9223372036854775807` (Friday, April 11, 2262 at 23:47:16.854 UTC).  
For information about UTC, see *RFC 3339, Date and Time on the Internet: Timestamps*, [https://tools.ietf.org/html/rfc3339](https://tools.ietf.org/html/rfc3339).  
**`CloudFront-Signature`**  
A hashed, signed, and base64-encoded version of a JSON policy statement. For more information, see [Create a signature for a signed cookie that uses a canned policy](#private-content-canned-policy-signature-cookies).  
**`CloudFront-Key-Pair-Id`**  
The ID for a CloudFront public key, for example, `K2JCJMDEHXQW5F`. The public key ID tells CloudFront which public key to use to validate the signed URL. CloudFront compares the information in the signature with the information in the policy statement to verify that the URL has not been tampered with.  
This public key must belong to a key group that is a trusted signer in the distribution. For more information, see [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md).  
**`CloudFront-Hash-Algorithm`**  
(Optional) The hash algorithm used to create the signature. Supported values are `SHA1` and `SHA256`. If you don't include this cookie, CloudFront defaults to `SHA1`.

The following example shows `Set-Cookie` headers for one signed cookie when you're using the domain name that is associated with your distribution in the URLs for your files:

```
Set-Cookie: CloudFront-Expires=1426500000; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=yXrSIgyQoeE4FBI4eMKF6ho~CA8_; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=d111111abcdef8.cloudfront.net; Path=/images/*; Secure; HttpOnly
```

The following example shows `Set-Cookie` headers for one signed cookie when you're using the alternate domain name example.org in the URLs for your files:

```
Set-Cookie: CloudFront-Expires=1426500000; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=yXrSIgyQoeE4FBI4eMKF6ho~CA8_; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/images/*; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=example.org; Path=/images/*; Secure; HttpOnly
```

If you want to use an alternate domain name such as example.com in URLs, you must add the alternate domain name to your distribution regardless of whether you specify the `Domain` attribute. For more information, see [Alternate domain names (CNAMEs)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) in the topic [All distribution settings reference](distribution-web-values-specify.md).

## Create a signature for a signed cookie that uses a canned policy
<a name="private-content-canned-policy-signature-cookies"></a>

To create the signature for a signed cookie that uses a canned policy, complete the following procedures.

**Topics**
+ [Create a policy statement for a signed cookie that uses a canned policy](#private-content-canned-policy-statement-cookies)
+ [Sign the policy statement to create a signature for a signed cookie that uses a canned policy](#private-content-canned-policy-cookies-signing-policy-statement)

### Create a policy statement for a signed cookie that uses a canned policy
<a name="private-content-canned-policy-statement-cookies"></a>

When you set a signed cookie that uses a canned policy, the `CloudFront-Signature` attribute is a hashed and signed version of a policy statement. For signed cookies that use a canned policy, you don't include the policy statement in the `Set-Cookie` header, as you do for signed cookies that use a custom policy. To create the policy statement, complete the following steps.<a name="private-content-canned-policy-statement-cookies-procedure"></a>

**To create a policy statement for a signed cookie that uses a canned policy**

1. Construct the policy statement using the following JSON format and using UTF-8 character encoding. Include all punctuation and other literal values exactly as specified. For information about the `Resource` and `DateLessThan` parameters, see [Values that you specify in the policy statement for a canned policy for signed cookies](#private-content-canned-policy-statement-cookies-values).

   ```
   {
       "Statement": [
           {
               "Resource": "base URL or stream name",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime": ending date and time in Unix time format and UTC
                   }
               }
           }
       ]
   }
   ```

1. Remove all empty spaces (including tabs and newline characters) from the policy statement. You might have to include escape characters in the string in application code.

#### Values that you specify in the policy statement for a canned policy for signed cookies
<a name="private-content-canned-policy-statement-cookies-values"></a>

When you create a policy statement for a canned policy, you specify the following values:

**Resource**  
The base URL including your query strings, if any, for example:  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
You can specify only one value for `Resource`.  
Note the following:  
+ **Protocol** – The value must begin with `http://` or `https://`.
+ **Query string parameters** – If you have no query string parameters, omit the question mark.
+ **Alternate domain names** – If you specify an alternate domain name (CNAME) in the URL, you must specify the alternate domain name when referencing the file in your webpage or application. Do not specify the Amazon S3 URL for the file.

**DateLessThan**  
The expiration date and time for the URL in Unix time format (in seconds) and Coordinated Universal Time (UTC). Do not enclose the value in quotation marks.  
For example, March 16, 2015 10:00 am UTC converts to 1426500000 in Unix time format.  
This value must match the value of the `CloudFront-Expires` attribute in the `Set-Cookie` header. Do not enclose the value in quotation marks.  
For more information, see [When CloudFront checks expiration date and time in a signed cookie](private-content-signed-cookies.md#private-content-check-expiration-cookie).

#### Example policy statement for a canned policy
<a name="private-content-canned-policy-cookies-sample-policy-statement"></a>

When you use the following example policy statement in a signed cookie, a user can access the file `https://d111111abcdef8.cloudfront.net/horizon.jpg` until March 16, 2015 10:00 am UTC:

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/horizon.jpg?size=large&license=yes",
            "Condition": {
                "DateLessThan": {
                    "AWS:EpochTime": 1426500000
                }
            }
        }
    ]
}
```

### Sign the policy statement to create a signature for a signed cookie that uses a canned policy
<a name="private-content-canned-policy-cookies-signing-policy-statement"></a>

To create the value for the `CloudFront-Signature` attribute in a `Set-Cookie` header, you hash and sign the policy statement that you created in [To create a policy statement for a signed cookie that uses a canned policy](#private-content-canned-policy-statement-cookies-procedure). 

For additional information and examples of how to hash, sign, and encode the policy statement, see the following topics:
+ [Linux commands and OpenSSL for base64 encoding and encryption](private-content-linux-openssl.md)
+ [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md)

**Note**  
The linked examples use SHA-1 by default. To use SHA-256 instead, replace `sha1` with `sha256` in the OpenSSL commands and include the `CloudFront-Hash-Algorithm` cookie with a value of `SHA256`.<a name="private-content-canned-policy-cookie-creating-signature-procedure"></a>

**To create a signature for a signed cookie using a canned policy**

1. Use the SHA-1 or SHA-256 hash function and RSA to hash and sign the policy statement that you created in the procedure [To create a policy statement for a signed cookie that uses a canned policy](#private-content-canned-policy-statement-cookies-procedure). Use the version of the policy statement that no longer includes empty spaces.

   If you use SHA-256, you must include the `CloudFront-Hash-Algorithm` cookie with a value of `SHA256`.

   For the private key that is required by the hash function, use a private key whose public key is in an active trusted key group for the distribution.
**Note**  
The method that you use to hash and sign the policy statement depends on your programming language and platform. For sample code, see [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md).

1. Remove empty spaces (including tabs and newline characters) from the hashed and signed string.

1. Base64-encode the string using MIME base64 encoding. For more information, see [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8) in *RFC 2045, MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*.

1. Replace characters that are invalid in a URL query string with characters that are valid. The following table lists invalid and valid characters.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-canned-policy.html)

1. Include the resulting value in the `Set-Cookie` header for the `CloudFront-Signature` name-value pair. Then return to [To set a signed cookie using a canned policy](#private-content-setting-signed-cookie-canned-policy-procedure) add the `Set-Cookie` header for `CloudFront-Key-Pair-Id`.

# Set signed cookies using a custom policy
<a name="private-content-setting-signed-cookie-custom-policy"></a>

To set a signed cookie that uses a custom policy, complete the following steps.<a name="private-content-setting-signed-cookie-custom-policy-procedure"></a>

**To set a signed cookie using a custom policy**

1. If you're using .NET or Java to create signed URLs, and if you haven't reformatted the private key for your key pair from the default .pem format to a format compatible with .NET or with Java, do so now. For more information, see [Reformat the private key (.NET and Java only)](private-content-trusted-signers.md#private-content-reformatting-private-key).

1. Program your application to send three `Set-Cookie` headers to approved viewers (or four, if you want to specify a hash algorithm). You need three `Set-Cookie` headers because each `Set-Cookie` header can contain only one name-value pair, and a CloudFront signed cookie requires three name-value pairs. The name-value pairs are: `CloudFront-Policy`, `CloudFront-Signature`, and `CloudFront-Key-Pair-Id`. You can optionally include a fourth name-value pair, `CloudFront-Hash-Algorithm`, to specify the hash algorithm used for the signature. The values must be present on the viewer before a user makes the first request for a file that you want to control access to. 
**Note**  
In general, we recommend that you exclude `Expires` and `Max-Age` attributes. This causes the browser to delete the cookie when the user closes the browser, which reduces the possibility of someone getting unauthorized access to your content. For more information, see [Prevent misuse of signed cookies](private-content-signed-cookies.md#private-content-signed-cookie-misuse).

   **The names of cookie attributes are case-sensitive**. 

   Line breaks are included only to make the attributes more readable.

   ```
   Set-Cookie: 
   CloudFront-Policy=base64 encoded version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   
   Set-Cookie: 
   CloudFront-Signature=hashed and signed version of the policy statement; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Key-Pair-Id=public key ID for the CloudFront public key whose corresponding private key you're using to generate the signature; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   
   Set-Cookie: 
   CloudFront-Hash-Algorithm=SHA1 or SHA256; 
   Domain=optional domain name; 
   Path=/optional directory path; 
   Secure; 
   HttpOnly
   ```  
**(Optional) `Domain`**  
The domain name for the requested file. If you don't specify a `Domain` attribute, the default value is the domain name in the URL, and it applies only to the specified domain name, not to subdomains. If you specify a `Domain` attribute, it also applies to subdomains. A leading dot in the domain name (for example, `Domain=.example.com`) is optional. In addition, if you specify a `Domain` attribute, the domain name in the URL and the value of the `Domain` attribute must match.  
You can specify the domain name that CloudFront assigned to your distribution, for example, d111111abcdef8.cloudfront.net, but you can't specify \$1.cloudfront.net for the domain name.  
If you want to use an alternate domain name such as example.com in URLs, you must add the alternate domain name to your distribution regardless of whether you specify the `Domain` attribute. For more information, see [Alternate domain names (CNAMEs)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) in the topic [All distribution settings reference](distribution-web-values-specify.md).  
**(Optional) `Path`**  
The path for the requested file. If you don't specify a `Path` attribute, the default value is the path in the URL.  
**`Secure`**  
Requires that the viewer encrypt cookies before sending a request. We recommend that you send the `Set-Cookie` header over an HTTPS connection to ensure that the cookie attributes are protected from man-in-the-middle attacks.  
**`HttpOnly`**  
Requires that the viewer send the cookie only in HTTP or HTTPS requests.  
**`CloudFront-Policy`**  
Your policy statement in JSON format, with empty spaces removed, then base64 encoded. For more information, see [Create a signature for a signed cookie that uses a custom policy](#private-content-custom-policy-signature-cookies).  
The policy statement controls the access that a signed cookie grants to a user. It includes the files that the user can access, an expiration date and time, an optional date and time that the URL becomes valid, and an optional IP address or range of IP addresses that are allowed to access the file.  
**`CloudFront-Signature`**  
A hashed, signed, and base64-encoded version of the JSON policy statement. For more information, see [Create a signature for a signed cookie that uses a custom policy](#private-content-custom-policy-signature-cookies).  
**`CloudFront-Key-Pair-Id`**  
The ID for a CloudFront public key, for example, `K2JCJMDEHXQW5F`. The public key ID tells CloudFront which public key to use to validate the signed URL. CloudFront compares the information in the signature with the information in the policy statement to verify that the URL has not been tampered with.  
This public key must belong to a key group that is a trusted signer in the distribution. For more information, see [Specify signers that can create signed URLs and signed cookies](private-content-trusted-signers.md).  
**`CloudFront-Hash-Algorithm`**  
(Optional) The hash algorithm used to create the signature. Supported values are `SHA1` and `SHA256`. If you don't include this cookie, CloudFront defaults to `SHA1`.

## Example `Set-Cookie` headers for custom policies
<a name="example-set-cookie-headers-custom-policy"></a>

See the following examples of `Set-Cookie` header pairs. 

If you want to use an alternate domain name such as example.org in URLs, you must add the alternate domain name to your distribution regardless of whether you specify the `Domain` attribute. For more information, see [Alternate domain names (CNAMEs)](DownloadDistValuesGeneral.md#DownloadDistValuesCNAME) in the topic [All distribution settings reference](distribution-web-values-specify.md).

**Example 1**  
You can use the `Set-Cookie` headers for one signed cookie when you're using the domain name that is associated with your distribution in the URLs for your files.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
```

**Example 2**  
You can use the `Set-Cookie` headers for one signed cookie when you're using an alternate domain name (example.org) in the URLs for your files.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=example.org; Path=/; Secure; HttpOnly
```

**Example 3**  
You can use the `Set-Cookie` header pairs for a signed request when you're using the domain name that is associated with your distribution in the URLs for your files.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=dd111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=d111111abcdef8.cloudfront.net; Path=/; Secure; HttpOnly
```

**Example 4**  
You can use the `Set-Cookie` header pairs for one signed request when you're using an alternate domain name (example.org) that is associated with your distribution in the URLs for your files.  

```
Set-Cookie: CloudFront-Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Signature=dtKhpJ3aUYxqDIwepczPiDb9NXQ_; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Key-Pair-Id=K2JCJMDEHXQW5F; Domain=example.org; Path=/; Secure; HttpOnly
Set-Cookie: CloudFront-Hash-Algorithm=SHA256; Domain=example.org; Path=/; Secure; HttpOnly
```

## Create a policy statement for a signed cookie that uses a custom policy
<a name="private-content-custom-policy-statement-cookies"></a>

To create a policy statement for a custom policy, complete the following steps. For several example policy statements that control access to files in a variety of ways, see [Example policy statements for a signed cookie that uses a custom policy](#private-content-custom-policy-statement-signed-cookies-examples).<a name="private-content-custom-policy-statement-cookies-procedure"></a>

**To create the policy statement for a signed cookie that uses a custom policy**

1. Construct the policy statement using the following JSON format.

   ```
   {
       "Statement": [
           {
               "Resource": "URL of the file",
               "Condition": {
                   "DateLessThan": {
                       "AWS:EpochTime":required ending date and time in Unix time format and UTC
                   },
                   "DateGreaterThan": {
                       "AWS:EpochTime":optional beginning date and time in Unix time format and UTC
                   },
                   "IpAddress": {
                       "AWS:SourceIp": "optional IP address"
                   }
               }
           }
       ]
   }
   ```

   Note the following:
   + You can include only one statement.
   + Use UTF-8 character encoding.
   + Include all punctuation and parameter names exactly as specified. Abbreviations for parameter names are not accepted.
   + The order of the parameters in the `Condition` section doesn't matter.
   + For information about the values for `Resource`, `DateLessThan`, `DateGreaterThan`, and `IpAddress`, see [Values that you specify in the policy statement for a custom policy for signed cookies](#private-content-custom-policy-statement-cookies-values).

1. Remove all empty spaces (including tabs and newline characters) from the policy statement. You might have to include escape characters in the string in application code.

1. Base64-encode the policy statement using MIME base64 encoding. For more information, see [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8) in *RFC 2045, MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*.

1. Replace characters that are invalid in a URL query string with characters that are valid. The following table lists invalid and valid characters.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html)

1. Include the resulting value in your `Set-Cookie` header after `CloudFront-Policy=`.

1. Create a signature for the `Set-Cookie` header for `CloudFront-Signature` by hashing, signing, and base64-encoding the policy statement. For more information, see [Create a signature for a signed cookie that uses a custom policy](#private-content-custom-policy-signature-cookies).

### Values that you specify in the policy statement for a custom policy for signed cookies
<a name="private-content-custom-policy-statement-cookies-values"></a>

When you create a policy statement for a custom policy, you specify the following values.

**Resource**  
The base URL including your query strings, if any:  
`https://d111111abcdef8.cloudfront.net/images/horizon.jpg?size=large&license=yes`  
If you omit the `Resource` parameter, users can access all of the files associated with any distribution that is associated with the key pair that you use to create the signed URL.
You can specify only one value for `Resource`.  
Note the following:  
+ **Protocol** – The value must begin with `http://` or `https://`.
+ **Query string parameters** – If you have no query string parameters, omit the question mark.
+ **Wildcards** – You can use the wildcard character that matches zero or more characters (\$1) or the wild-card character that matches exactly one character (?) anywhere in the string. For example, the value:

  `https://d111111abcdef8.cloudfront.net/*game_download.zip*`

  would include (for example) the following files:
  + `https://d111111abcdef8.cloudfront.net/game_download.zip`
  + `https://d111111abcdef8.cloudfront.net/example_game_download.zip?license=yes`
  + `https://d111111abcdef8.cloudfront.net/test_game_download.zip?license=temp`
+ **Alternate domain names** – If you specify an alternate domain name (CNAME) in the URL, you must specify the alternate domain name when referencing the file in your webpage or application. Do not specify the Amazon S3 URL for the file.

**DateLessThan**  
The expiration date and time for the URL in Unix time format (in seconds) and Coordinated Universal Time (UTC). Do not enclose the value in quotation marks.  
For example, March 16, 2015 10:00 am UTC converts to 1426500000 in Unix time format.  
For more information, see [When CloudFront checks expiration date and time in a signed cookie](private-content-signed-cookies.md#private-content-check-expiration-cookie).

**DateGreaterThan (Optional)**  
An optional start date and time for the URL in Unix time format (in seconds) and Coordinated Universal Time (UTC). Users are not allowed to access the file on or before the specified date and time. Do not enclose the value in quotation marks. 

**IpAddress (Optional)**  
The IP address of the client making the GET request. Note the following:  
+ To allow any IP address to access the file, omit the `IpAddress` parameter.
+ You can specify either one IP address or one IP address range. For example, you can't set the policy to allow access if the client's IP address is in one of two separate ranges.
+ To allow access from a single IP address, you specify:

  `"`*IPv4 IP address*`/32"`
+ You must specify IP address ranges in standard IPv4 CIDR format (for example, `192.0.2.0/24`). For more information, go to *RFC 4632, Classless Inter-domain Routing (CIDR): The Internet Address Assignment and Aggregation Plan*, [https://tools.ietf.org/html/rfc4632](https://tools.ietf.org/html/rfc4632).
**Important**  
IP addresses in IPv6 format, such as 2001:0db8:85a3::8a2e:0370:7334, are not supported. 

  If you're using a custom policy that includes `IpAddress`, do not enable IPv6 for the distribution. If you want to restrict access to some content by IP address and support IPv6 requests for other content, you can create two distributions. For more information, see [Enable IPv6 (viewer requests)](DownloadDistValuesGeneral.md#DownloadDistValuesEnableIPv6) in the topic [All distribution settings reference](distribution-web-values-specify.md).

## Example policy statements for a signed cookie that uses a custom policy
<a name="private-content-custom-policy-statement-signed-cookies-examples"></a>

The following example policy statements show how to control access to a specific file, all of the files in a directory, or all of the files associated with a key pair ID. The examples also show how to control access from an individual IP address or a range of IP addresses, and how to prevent users from using the signed cookie after a specified date and time.

If you copy and paste any of these examples, remove any empty spaces (including tabs and newline characters), replace the values with your own values, and include a newline character after the closing brace ( \$1 ).

For more information, see [Values that you specify in the policy statement for a custom policy for signed cookies](#private-content-custom-policy-statement-cookies-values).

**Topics**
+ [Example policy statement: Access one file from a range of IP addresses](#private-content-custom-policy-statement-signed-cookies-example-one-object)
+ [Example policy statement: Access all files in a directory from a range of IP addresses](#private-content-custom-policy-statement-signed-cookies-example-all-objects)
+ [Example policy statement: Access all files associated with a key pair ID from one IP address](#private-content-custom-policy-statement-signed-cookies-example-one-ip)

### Example policy statement: Access one file from a range of IP addresses
<a name="private-content-custom-policy-statement-signed-cookies-example-one-object"></a>

The following example custom policy in a signed cookie specifies that a user can access the file `https://d111111abcdef8.cloudfront.net/game_download.zip` from IP addresses in the range `192.0.2.0/24` until January 1, 2023 10:00 am UTC:

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/game_download.zip",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

### Example policy statement: Access all files in a directory from a range of IP addresses
<a name="private-content-custom-policy-statement-signed-cookies-example-all-objects"></a>

The following example custom policy allows you to create signed cookies for any file in the `training` directory, as indicated by the \$1 wildcard character in the `Resource` parameter. Users can access the file from an IP address in the range `192.0.2.0/24` until January 1, 2013 10:00 am UTC:

```
{
    "Statement": [
        {
            "Resource": "https://d111111abcdef8.cloudfront.net/training/*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.0/24"
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767290400
                }
            }
        }
    ]
}
```

Each signed cookie in which you use this policy includes a base URL that identifies a specific file, for example:

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

### Example policy statement: Access all files associated with a key pair ID from one IP address
<a name="private-content-custom-policy-statement-signed-cookies-example-one-ip"></a>

The following sample custom policy allows you to set signed cookies for any file associated with any distribution, as indicated by the \$1 wildcard character in the `Resource` parameter. The user must use the IP address `192.0.2.10/32`. (The value `192.0.2.10/32` in CIDR notation refers to a single IP address, `192.0.2.10`.) The files are available only from January 1, 2013 10:00 am UTC until January 2, 2013 10:00 am UTC:

```
{
    "Statement": [
        {
            "Resource": "https://*",
            "Condition": {
                "IpAddress": {
                    "AWS:SourceIp": "192.0.2.10/32"
                },
                "DateGreaterThan": {
                    "AWS:EpochTime": 1767290400
                },
                "DateLessThan": {
                    "AWS:EpochTime": 1767376800
                }
            }
        }
    ]
}
```

Each signed cookie in which you use this policy includes a base URL that identifies a specific file in a specific CloudFront distribution, for example:

`https://d111111abcdef8.cloudfront.net/training/orientation.pdf`

The signed cookie also includes a key pair ID, which must be associated with a trusted key group in the distribution (d111111abcdef8.cloudfront.net) that you specify in the base URL.

## Create a signature for a signed cookie that uses a custom policy
<a name="private-content-custom-policy-signature-cookies"></a>

The signature for a signed cookie that uses a custom policy is a hashed, signed, and base64-encoded version of the policy statement. 

For additional information and examples of how to hash, sign, and encode the policy statement, see:
+ [Linux commands and OpenSSL for base64 encoding and encryption](private-content-linux-openssl.md)
+ [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md)

**Note**  
The linked examples use SHA-1 by default. To use SHA-256 instead, replace `sha1` with `sha256` in the OpenSSL commands and include the `CloudFront-Hash-Algorithm` cookie with a value of `SHA256`.<a name="private-content-custom-policy-signature-cookies-procedure"></a>

**To create a signature for a signed cookie by using a custom policy**

1. Use the SHA-1 or SHA-256 hash function and RSA to hash and sign the JSON policy statement that you created in the procedure [To create the policy statement for a signed URL that uses a custom policy](private-content-creating-signed-url-custom-policy.md#private-content-custom-policy-creating-policy-procedure). Use the version of the policy statement that no longer includes empty spaces but that has not yet been base64-encoded.

   If you use SHA-256, you must include the `CloudFront-Hash-Algorithm` cookie with a value of `SHA256`.

   For the private key that is required by the hash function, use a private key whose public key is in an active trusted key group for the distribution.
**Note**  
The method that you use to hash and sign the policy statement depends on your programming language and platform. For sample code, see [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md).

1. Remove empty spaces (including tabs and newline characters) from the hashed and signed string.

1. Base64-encode the string using MIME base64 encoding. For more information, see [Section 6.8, Base64 Content-Transfer-Encoding](https://tools.ietf.org/html/rfc2045#section-6.8) in *RFC 2045, MIME (Multipurpose Internet Mail Extensions) Part One: Format of Internet Message Bodies*.

1. Replace characters that are invalid in a URL query string with characters that are valid. The following table lists invalid and valid characters.  
****    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-setting-signed-cookie-custom-policy.html)

1. Include the resulting value in the `Set-Cookie` header for the `CloudFront-Signature=` name-value pair, and return to [To set a signed cookie using a custom policy](#private-content-setting-signed-cookie-custom-policy-procedure) to add the `Set-Cookie` header for `CloudFront-Key-Pair-Id`.

# Create signed cookies using PHP
<a name="signed-cookies-PHP"></a>

The following code example is similar to the example in the [Create a URL signature using PHP](CreateURL_PHP.md) in that it creates a link to a video. However, instead of signing the URL in the code, this example signs the cookies with the `create_signed_cookies()` function. The client-side player uses the cookies to authenticate each request to the CloudFront distribution.

This approach is useful to stream content, such as HTTP Live Streaming (HLS) or Dynamic Adaptive Streaming over HTTP (DASH), where the client needs to make multiple requests to retrieve the manifest, segments, and related playback assets. By using signed cookies, the client can authenticate each request without needing to generate a new signed URL for each segment. 

**Note**  
Creating a URL signature is just one part of the process of serving private content using signed cookies. For more information, see [Use signed cookies](private-content-signed-cookies.md).



**Topics**
+ [Create the RSA SHA-1 or SHA-256 signature](#create-rsa-sha-1signature-cookies)
+ [Create the signed cookies](#create-the-signed-cookie)
+ [Full code](#full-code-signed-cookies)

The following sections breaks down the code example into individual parts. You can find the complete [code sample](#full-code-signed-cookies) below.

## Create the RSA SHA-1 or SHA-256 signature
<a name="create-rsa-sha-1signature-cookies"></a>

This code example does the following:

1. The function `rsa_sha1_sign` hashes and signs the policy statement using SHA-1. To use SHA-256 instead, use the rsa\$1sha256\$1sign function shown below. The arguments required are a policy statement and the private key that corresponds with a public key that’s in a trusted key group for your distribution.

1. Next, the `url_safe_base64_encode` function creates a URL-safe version of the signature.

   ```
   function rsa_sha1_sign($policy, $private_key_filename) {
       $signature = "";
       $fp = fopen($private_key_filename, "r");
       $priv_key = fread($fp, 8192);
       fclose($fp);
       $pkeyid = openssl_get_privatekey($priv_key);
       openssl_sign($policy, $signature, $pkeyid);
       openssl_free_key($pkeyid);
       return $signature;
   }
   
   function url_safe_base64_encode($value) {
       $encoded = base64_encode($value);
       return str_replace(
           array('+', '=', '/'),
           array('-', '_', '~'),
           $encoded);
   }
   ```

   The following function uses SHA-256 instead of SHA-1:

   ```
   function rsa_sha256_sign($policy, $private_key_filename) {
       $signature = "";
       $fp = fopen($private_key_filename, "r");
       $priv_key = fread($fp, 8192);
       fclose($fp);
       $pkeyid = openssl_get_privatekey($priv_key);
       openssl_sign($policy, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
       openssl_free_key($pkeyid);
       return $signature;
   }
   ```

   The `rsa_sha256_sign` function is the same as `rsa_sha1_sign`, except that it passes `OPENSSL_ALGO_SHA256` to `openssl_sign`. When you use SHA-256, include the `CloudFront-Hash-Algorithm` cookie with a value of `SHA256`.

## Create the signed cookies
<a name="create-the-signed-cookie"></a>

The following code constructs a creates the signed cookies, using the following cookie attributes: `CloudFront-Expires`, `CloudFront-Signature`, `CloudFront-Key-Pair-Id` and `CloudFront-Hash-Algorithm`. The code uses a custom policy.

```
function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null, $hash_algorithm = 'SHA1') {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    if ($hash_algorithm === 'SHA256') {
        $signature = rsa_sha256_sign($policy, $private_key_filename);
    } else {
        $signature = rsa_sha1_sign($policy, $private_key_filename);
    }
    $encoded_signature = url_safe_base64_encode($signature);

    $cookies = array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );

    if ($hash_algorithm === 'SHA256') {
        $cookies['CloudFront-Hash-Algorithm'] = 'SHA256';
    }

    return $cookies;
}
```

For more information, see [Set signed cookies using a custom policy](private-content-setting-signed-cookie-custom-policy.md).

## Full code
<a name="full-code-signed-cookies"></a>

The following example code provides a complete demonstration of creating CloudFront signed cookies with PHP. You can download the full example from the [demo-php.zip](samples/demo-php.zip) file.

In the following example, you can modify the `$policy Condition` element to allow both IPv4 and IPv6 address ranges. For an example, see [Using IPv6 addresses in IAM policies](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ipv6-access.html#ipv6-access-iam) in the *Amazon Simple Storage Service User Guide*.

```
<?php

function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);
    openssl_sign($policy, $signature, $pkeyid);
    openssl_free_key($pkeyid);
    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}

function rsa_sha256_sign($policy, $private_key_filename) {
    $signature = "";
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);
    openssl_sign($policy, $signature, $pkeyid, OPENSSL_ALGO_SHA256);
    openssl_free_key($pkeyid);
    return $signature;
}

function create_signed_cookies($resource, $private_key_filename, $key_pair_id, $expires, $client_ip = null, $hash_algorithm = 'SHA1') {
    $policy = array(
        'Statement' => array(
            array(
                'Resource' => $resource,
                'Condition' => array(
                    'DateLessThan' => array('AWS:EpochTime' => $expires)
                )
            )
        )
    );

    if ($client_ip) {
        $policy['Statement'][0]['Condition']['IpAddress'] = array('AWS:SourceIp' => $client_ip . '/32');
    }

    $policy = json_encode($policy);
    $encoded_policy = url_safe_base64_encode($policy);
    if ($hash_algorithm === 'SHA256') {
        $signature = rsa_sha256_sign($policy, $private_key_filename);
    } else {
        $signature = rsa_sha1_sign($policy, $private_key_filename);
    }
    $encoded_signature = url_safe_base64_encode($signature);

    $cookies = array(
        'CloudFront-Policy' => $encoded_policy,
        'CloudFront-Signature' => $encoded_signature,
        'CloudFront-Key-Pair-Id' => $key_pair_id
    );

    if ($hash_algorithm === 'SHA256') {
        $cookies['CloudFront-Hash-Algorithm'] = 'SHA256';
    }

    return $cookies;
}



$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';
$base_url = 'https://d1234.cloudfront.net';

$expires = time() + 3600; // 1 hour from now

// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];


// For HLS manifest and segments (using wildcard)
$hls_resource = $base_url . '/sign/*';
$signed_cookies = create_signed_cookies($hls_resource, $private_key_filename, $key_pair_id, $expires, $client_ip, 'SHA256');

// Set the cookies
$cookie_domain = parse_url($base_url, PHP_URL_HOST);
foreach ($signed_cookies as $name => $value) {
    setcookie($name, $value, $expires, '/', $cookie_domain, true, true);
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>CloudFront Signed HLS Stream with Cookies</title>
</head>
<body>
    <h1>Amazon CloudFront Signed HLS Stream with Cookies</h1>
    <h2>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h2>
    
    <div id='hls-video'>
        <video id="video" width="640" height="360" controls></video>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <script>
        var video = document.getElementById('video');
        var manifestUrl = '<?php echo $base_url; ?>/sign/manifest.m3u8';
        
        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(manifestUrl);
            hls.attachMedia(video);
        }
        else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = manifestUrl;
        }
    </script>
</body>
</html>
```

Instead of using signed cookies, you can use signed URLs. For more information, see [Create a URL signature using PHP](CreateURL_PHP.md).

# Linux commands and OpenSSL for base64 encoding and encryption
<a name="private-content-linux-openssl"></a>

You can use the following Linux command-line command and OpenSSL to hash and sign the policy statement, base64-encode the signature, and replace characters that are not valid in URL query string parameters with characters that are valid.

For information about OpenSSL, go to [https://www.openssl.org](https://www.openssl.org).

SHA-1 (default):

```
cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha1 -sign private_key.pem | openssl base64 -A | tr -- '+=/' '-_~'
```

SHA-256:

```
cat policy | tr -d "\n" | tr -d " \t\n\r" | openssl sha256 -sign private_key.pem | openssl base64 -A | tr -- '+=/' '-_~'
```

In the preceding command:
+ `cat` reads the `policy` file.
+ `tr -d "\n" | tr -d " \t\n\r"` removes the empty spaces and newline character that were added by `cat`.
+ OpenSSL hashes the file using SHA-1 (or SHA-256) and signs it using the private key file `private_key.pem`. The private key signature can be either RSA 2048 or ECDSA 256. If you use SHA-256, include the `Hash-Algorithm=SHA256` query parameter in the signed URL, or the `CloudFront-Hash-Algorithm=SHA256` cookie for signed cookies.
+ OpenSSL base64-encodes the hashed and signed policy statement.
+ `tr` replaces characters that are not valid in URL query string parameters with characters that are valid.

For more code examples that demonstrate creating a signature, see [Code examples for creating a signature for a signed URL](PrivateCFSignatureCodeAndExamples.md).

# Code examples for creating a signature for a signed URL
<a name="PrivateCFSignatureCodeAndExamples"></a>

This section includes downloadable application examples that demonstrate how to create signatures for signed URLs. Examples are available in Perl, PHP, C\$1, and Java. You can use any of the examples to create signed URLs. The Perl script runs on Linux and macOS platforms. The PHP example will work on any server that runs PHP. The C\$1 example uses the .NET Framework.

The examples in this section use SHA-1 to hash and sign the policy statement. You can also use SHA-256. To use SHA-256, update the hash algorithm in the signing function (for example, replace `sha1` with `sha256` in OpenSSL calls, or use the equivalent SHA-256 constant in your language's cryptographic library). When you use SHA-256, include the `Hash-Algorithm=SHA256` query parameter in the signed URL.

For example code in JavaScript (Node.js), see [Creating Amazon CloudFront Signed URLs in Node.js](https://aws.amazon.com/blogs/developer/creating-amazon-cloudfront-signed-urls-in-node-js/) on the AWS Developer Blog.

For example code in Python, see [Generate a signed URL for Amazon CloudFront](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#examples) in the *AWS SDK for Python (Boto3) API Reference* and [this example code](https://github.com/boto/boto3/blob/develop/boto3/examples/cloudfront.rst) in the Boto3 GitHub repository.

**Topics**
+ [Create a URL signature using Perl](CreateURLPerl.md)
+ [Create a URL signature using PHP](CreateURL_PHP.md)
+ [Create a URL signature using C\$1 and the .NET Framework](CreateSignatureInCSharp.md)
+ [Create a URL signature using Java](CFPrivateDistJavaDevelopment.md)

# Create a URL signature using Perl
<a name="CreateURLPerl"></a>

This section includes a Perl script for Linux/Mac platforms that you can use to create the signature for private content. To create the signature, run the script with command line arguments that specify the CloudFront URL, the path to the private key of the signer, the key ID, and an expiration date for the URL. The tool can also decode signed URLs. 

**Notes**  
Creating a URL signature is just one part of the process of serving private content using a signed URL. For more information about the end-to-end process, see [Use signed URLs](private-content-signed-urls.md). 
In the signing command, note that `sha1` can be replaced with `sha256` in the `openssl dgst` call.

**Topics**
+ [Source for the Perl script to create a signed URL](#CreateURLPerlScriptSource)

## Source for the Perl script to create a signed URL
<a name="CreateURLPerlScriptSource"></a>

The following Perl source code can be used to create a signed URL for CloudFront. Comments in the code include information about the command line switches and the features of the tool.

```
#!/usr/bin/perl -w

# Copyright 2008 Amazon Technologies, Inc.  Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You may obtain a copy of the License at:
#
# https://aws.amazon.com/apache2.0
#
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and limitations under the License.

=head1 cfsign.pl

cfsign.pl - A tool to generate and verify Amazon CloudFront signed URLs

=head1 SYNOPSIS

This script uses an existing RSA key pair to sign and verify Amazon CloudFront signed URLs

View the script source for details as to which CPAN packages are required beforehand. 

For help, try:

cfsign.pl --help

URL signing examples:

cfsign.pl --action encode --url https://images.my-website.com/gallery1.zip --policy sample_policy.json --private-key privkey.pem --key-pair-id mykey

cfsign.pl --action encode --url https://images.my-website.com/gallery1.zip --expires 1257439868 --private-key privkey.pem --key-pair-id mykey

URL decode example:

cfsign.pl --action decode --url "http//mydist.cloudfront.net/?Signature=AGO-PgxkYo99MkJFHvjfGXjG1QDEXeaDb4Qtzmy85wqyJjK7eKojQWa4BCRcow__&Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovLypicmFkbS5qcGciLCJDb25kaXRpb24iOnsiSXBBZGRyZXNzIjp7IkFXUzpTb3VyY2VJcCI6IjEwLjUyLjE3LjkvMCJ9LCJEYXRlR3JlYXRlclRoYW4iOnsiQVdTOkVwb2NoVGltZSI6MTI1MjUyMDgzMH19fV19Cg__&Key-Pair-Id=mykey"


To generate an RSA key pair, you can use openssl and the following commands:

# Generate a 2048 bit key pair
openssl genrsa -out private-key.pem 2048
openssl rsa -in private-key.pem -pubout -out public-key.pem


=head1 OPTIONS

=over 8

=item B<--help>

Print a help message and exits.

=item B<--action> [action]

The action to execute.  action can be one of:

  encode - Generate a signed URL (using a canned policy or a user policy)
  decode - Decode a signed URL

=item B<--url>

The URL to en/decode

=item B<--stream>

The stream to en/decode

=item B<--private-key>

The path to your private key.

=item B<--key-pair-id>

The key pair identifier.

=item B<--policy>

The CloudFront policy document.

=item B<--expires>

The Unix epoch time when the URL is to expire. If both this option and
the --policy option are specified, --policy will be used. Otherwise, this 
option alone will use a canned policy.

=back

=cut

use strict;
use warnings;

# you might need to use CPAN to get these modules.
# run perl -MCPAN -e "install <module>" to get them.
# The openssl command line will also need to be in your $PATH.
use File::Temp qw/tempfile/;
use File::Slurp;
use Getopt::Long;
use IPC::Open2;
use MIME::Base64 qw(encode_base64 decode_base64);
use Pod::Usage;
use URI;

my $CANNED_POLICY 
    = '{"Statement":[{"Resource":"<RESOURCE>","Condition":{"DateLessThan":{"AWS:EpochTime":<EXPIRES>}}}]}';

my $POLICY_PARAM      = "Policy";
my $EXPIRES_PARAM     = "Expires";
my $SIGNATURE_PARAM   = "Signature";
my $KEY_PAIR_ID_PARAM = "Key-Pair-Id";

my $verbose = 0;
my $policy_filename = "";
my $expires_epoch = 0;
my $action = "";
my $help = 0;
my $key_pair_id = "";
my $url = "";
my $stream = "";
my $private_key_filename = "";

my $result = GetOptions("action=s"      => \$action,
                        "policy=s"      => \$policy_filename,
                        "expires=i"     => \$expires_epoch,
                        "private-key=s" => \$private_key_filename,
                        "key-pair-id=s" => \$key_pair_id,
                        "verbose"       => \$verbose,
                        "help"          => \$help,
                        "url=s"         => \$url,
                        "stream=s"      => \$stream,
                    );

if ($help or !$result) {
    pod2usage(1);
    exit;
}

if ($url eq "" and $stream eq "") {
    print STDERR "Must include a stream or a URL to encode or decode with the --stream or --url option\n";
    exit;
}

if ($url ne "" and $stream ne "") {
    print STDERR "Only one of --url and --stream may be specified\n";
    exit;
}

if ($url ne "" and !is_url_valid($url)) {
    exit;
}

if ($stream ne "") {
    exit unless is_stream_valid($stream);

    # The signing mechanism is identical, so from here on just pretend we're
    # dealing with a URL
    $url = $stream;
} 

if ($action eq "encode") {
    # The encode action will generate a private content URL given a base URL, 
    # a policy file (or an expires timestamp) and a key pair id parameter
    my $private_key;
    my $public_key;
    my $public_key_file;
    
    my $policy;
    if ($policy_filename eq "") {
        if ($expires_epoch == 0) {
            print STDERR "Must include policy filename with --policy argument or an expires" . 
                          "time using --expires\n";            
        }
        
        $policy = $CANNED_POLICY;
        $policy =~ s/<EXPIRES>/$expires_epoch/g;
        $policy =~ s/<RESOURCE>/$url/g;
    } else {
        if (! -e $policy_filename) {
            print STDERR "Policy file $policy_filename does not exist\n";
            exit;
        }
        $expires_epoch = 0; # ignore if set
        $policy = read_file($policy_filename);
    }

    if ($private_key_filename eq "") {
        print STDERR "You must specific the path to your private key file with --private-key\n";
        exit;
    }

    if (! -e $private_key_filename) {
        print STDERR "Private key file $private_key_filename does not exist\n";
        exit;
    }

    if ($key_pair_id eq "") {
        print STDERR "You must specify a key pair id with --key-pair-id\n";
        exit;
    }

    my $encoded_policy = url_safe_base64_encode($policy);
    my $signature = rsa_sha1_sign($policy, $private_key_filename);
    my $encoded_signature = url_safe_base64_encode($signature);

    my $generated_url = create_url($url, $encoded_policy, $encoded_signature, $key_pair_id, $expires_epoch);


    if ($stream ne "") {
        print "Encoded stream (for use within a swf):\n" . $generated_url . "\n";
        print "Encoded and escaped stream (for use on a webpage):\n" .  escape_url_for_webpage($generated_url) . "\n"; 
    } else {
        print "Encoded URL:\n" . $generated_url . "\n";
    }
} elsif ($action eq "decode") {
    my $decoded = decode_url($url);
    if (!$decoded) {
        print STDERR "Improperly formed URL\n";
        exit;
    }

    print_decoded_url($decoded);
} else {
    # No action specified, print help.  But only if this is run as a program (caller will be empty)
    pod2usage(1) unless caller();
}

# Decode a private content URL into its component parts
sub decode_url {
    my $url = shift;

    if ($url =~ /(.*)\?(.*)/) {
        my $base_url = $1;
        my $params = $2;

        my @unparsed_params = split(/&/, $params);
        my %params = ();
        foreach my $param (@unparsed_params) {
            my ($key, $val) = split(/=/, $param);
            $params{$key} = $val;
        }

        my $encoded_signature = "";
        if (exists $params{$SIGNATURE_PARAM}) {
            $encoded_signature = $params{"Signature"};
        } else {
            print STDERR "Missing Signature URL parameter\n";
            return 0;
        }

        my $encoded_policy = "";
        if (exists $params{$POLICY_PARAM}) {
            $encoded_policy = $params{$POLICY_PARAM};
        } else {
            if (!exists $params{$EXPIRES_PARAM}) {
                print STDERR "Either the Policy or Expires URL parameter needs to be specified\n";
                return 0;    
            }
            
            my $expires = $params{$EXPIRES_PARAM};
            
            my $policy = $CANNED_POLICY;
            $policy =~ s/<EXPIRES>/$expires/g;
            
            my $url_without_cf_params = $url;
            $url_without_cf_params =~ s/$SIGNATURE_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$POLICY_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$EXPIRES_PARAM=[^&]*&?//g;
            $url_without_cf_params =~ s/$KEY_PAIR_ID_PARAM=[^&]*&?//g;
            
            if ($url_without_cf_params =~ /(.*)\?$/) {
                $url_without_cf_params = $1;
            }
            
            $policy =~ s/<RESOURCE>/$url_without_cf_params/g;
            
            $encoded_policy = url_safe_base64_encode($policy);
        }

        my $key = "";
        if (exists $params{$KEY_PAIR_ID_PARAM}) {
            $key = $params{$KEY_PAIR_ID_PARAM};
        } else {
            print STDERR "Missing $KEY_PAIR_ID_PARAM parameter\n";
            return 0;
        }

        my $policy = url_safe_base64_decode($encoded_policy);

        my %ret = ();
        $ret{"base_url"} = $base_url;
        $ret{"policy"} = $policy;
        $ret{"key"} = $key;

        return \%ret;
    } else {
        return 0;
    }
}

# Print a decoded URL out
sub print_decoded_url {
    my $decoded = shift;

    print "Base URL: \n" . $decoded->{"base_url"} . "\n";
    print "Policy: \n" . $decoded->{"policy"} . "\n";
    print "Key: \n" . $decoded->{"key"} . "\n";
}

# Encode a string with base 64 encoding and replace some invalid URL characters
sub url_safe_base64_encode {
    my ($value) = @_;

    my $result = encode_base64($value);
    $result =~ tr|+=/|-_~|;

    return $result;
}

# Decode a string with base 64 encoding.  URL-decode the string first
# followed by reversing any special character ("+=/") translation.
sub url_safe_base64_decode {
    my ($value) = @_;

    $value =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
    $value =~ tr|-_~|+=/|;

    my $result = decode_base64($value);

    return $result;
}

# Create a private content URL
sub create_url {
    my ($path, $policy, $signature, $key_pair_id, $expires) = @_;
    
    my $result;
    my $separator = $path =~ /\?/ ? '&' : '?';
    if ($expires) {
        $result = "$path$separator$EXPIRES_PARAM=$expires&$SIGNATURE_PARAM=$signature&$KEY_PAIR_ID_PARAM=$key_pair_id";
    } else {
        $result = "$path$separator$POLICY_PARAM=$policy&$SIGNATURE_PARAM=$signature&$KEY_PAIR_ID_PARAM=$key_pair_id";
    }
    $result =~ s/\n//g;

    return $result;
}

# Sign a document with given private key file.
# The first argument is the document to sign
# The second argument is the name of the private key file
sub rsa_sha1_sign {
    my ($to_sign, $pvkFile) = @_;
    print "openssl sha1 -sign $pvkFile $to_sign\n";

    return write_to_program($pvkFile, $to_sign);
}

# Helper function to write data to a program
sub write_to_program {
my ($keyfile, $data) = @_;
unlink "temp_policy.dat" if (-e "temp_policy.dat");
unlink "temp_sign.dat" if (-e "temp_sign.dat");

write_file("temp_policy.dat", $data);

system("openssl dgst -sha1 -sign \"$keyfile\" -out temp_sign.dat temp_policy.dat");

my $output = read_file("temp_sign.dat");

    return $output;
}

# Read a file into a string and return the string
sub read_file {
    my ($file) = @_;

    open(INFILE, "<$file") or die("Failed to open $file: $!");
    my $str = join('', <INFILE>);
    close INFILE;

    return $str;
}

sub is_url_valid {
    my ($url) = @_;

    # HTTP distributions start with http[s]:// and are the correct thing to sign
    if ($url =~ /^https?:\/\//) {
        return 1;
    } else {
        print STDERR "CloudFront requires absolute URLs for HTTP distributions\n";
        return 0;
    }
}

sub is_stream_valid {
    my ($stream) = @_;

    if ($stream =~ /^rtmp:\/\// or $stream =~ /^\/?cfx\/st/) {
        print STDERR "Streaming distributions require that only the stream name is signed.\n";
        print STDERR "The stream name is everything after, but not including, cfx/st/\n";
        return 0;
    } else {
        return 1;
    }
}

# flash requires that the query parameters in the stream name are url
# encoded when passed in through javascript, etc.  This sub handles the minimal
# required url encoding.
sub escape_url_for_webpage {
    my ($url) = @_;

    $url =~ s/\?/%3F/g;
    $url =~ s/=/%3D/g;
    $url =~ s/&/%26/g;

    return $url;
}

1;
```

# Create a URL signature using PHP
<a name="CreateURL_PHP"></a>

Any web server that runs PHP can use this PHP example code to create policy statements and signatures for private CloudFront distributions. The full example creates a functioning webpage with signed URL links that play a video stream using CloudFront streaming. You can download the full example from the [demo-php.zip](samples/demo-php.zip) file.

**Notes**  
Creating a URL signature is just one part of the process of serving private content using a signed URL. For more information about the entire process, see [Use signed URLs](private-content-signed-urls.md). 
You can also create signed URLs by using the `UrlSigner` class in the AWS SDK for PHP. For more information, see [Class UrlSigner](https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.CloudFront.UrlSigner.html) in the *AWS SDK for PHP API Reference*.
In the `openssl_sign` call, note that passing `OPENSSL_ALGO_SHA256` as the fourth argument switches to SHA-256. (See also the [Create signed cookies using PHP](signed-cookies-PHP.md) for a full example.)

**Topics**
+ [Create the RSA SHA-1 signature](#sample-rsa-sign)
+ [Create a canned policy](#sample-canned-policy)
+ [Create a custom policy](#sample-custom-policy)
+ [Full code example](#full-example)

The following sections breaks down the code example into individual parts. You can find the [Full code example](#full-example) below.

## Create the RSA SHA-1 signature
<a name="sample-rsa-sign"></a>

This code example does the following:
+ The function `rsa_sha1_sign` hashes and signs the policy statement. The arguments required are a policy statement and the private key that corresponds with a public key that’s in a trusted key group for your distribution. 
+ Next, the `url_safe_base64_encode` function creates a URL-safe version of the signature.

```
function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";

    // load the private key
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);

    // compute signature
    openssl_sign($policy, $signature, $pkeyid);

    // free the key from memory
    openssl_free_key($pkeyid);

    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    // replace unsafe characters +, = and / with 
    // the safe characters -, _ and ~
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}
```

The following code snippet uses the functions `get_canned_policy_stream_name()` and `get_custom_policy_stream_name()` to create a canned and custom policy. CloudFront uses the policies to create the URL for streaming the video, including specifying the expiration time. 

You can then used a canned policy or a custom policy to determine how to manage access to your content. For more information about which one to choose, see the [Decide to use canned or custom policies for signed URLs](private-content-signed-urls.md#private-content-choosing-canned-custom-policy) section.

## Create a canned policy
<a name="sample-canned-policy"></a>

The following example code constructs a *canned* policy statement for the signature. 

**Note**  
The `$expires` variable is a date/time stamp that must be an integer, not a string.

```
function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
    // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
    $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($canned_policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($canned_policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
    // URL-encode the query string characters
    return $stream_name;
}
```

For more information about canned policies, see [Create a signed URL using a canned policy](private-content-creating-signed-url-canned-policy.md).

## Create a custom policy
<a name="sample-custom-policy"></a>

The following example code constructs a *custom* policy statement for the signature. 

```
function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
    // URL-encode the query string characters
    return $stream_name;
}
```

For more information about custom policies, see [Create a signed URL using a custom policy](private-content-creating-signed-url-custom-policy.md).

## Full code example
<a name="full-example"></a>

The following example code provides a complete demonstration of creating CloudFront signed URLs with PHP. You can download the full example from the [demo-php.zip](samples/demo-php.zip) file.

In the following example, you can modify the `$policy` `Condition` element to allow both IPv4 and IPv6 address ranges. For an example, see [Using IPv6 addresses in IAM policies](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ipv6-access.html#ipv6-access-iam) in the *Amazon Simple Storage Service User Guide*.

```
<?php

function rsa_sha1_sign($policy, $private_key_filename) {
    $signature = "";

    // load the private key
    $fp = fopen($private_key_filename, "r");
    $priv_key = fread($fp, 8192);
    fclose($fp);
    $pkeyid = openssl_get_privatekey($priv_key);

    // compute signature
    openssl_sign($policy, $signature, $pkeyid);

    // free the key from memory
    openssl_free_key($pkeyid);

    return $signature;
}

function url_safe_base64_encode($value) {
    $encoded = base64_encode($value);
    // replace unsafe characters +, = and / with the safe characters -, _ and ~
    return str_replace(
        array('+', '=', '/'),
        array('-', '_', '~'),
        $encoded);
}

function create_stream_name($stream, $policy, $signature, $key_pair_id, $expires) {
    $result = $stream;
    // if the stream already contains query parameters, attach the new query parameters to the end
    // otherwise, add the query parameters
    $separator = strpos($stream, '?') == FALSE ? '?' : '&';
    // the presence of an expires time means we're using a canned policy
    if($expires) {
        $result .= $separator . "Expires=" . $expires . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
    }
    // not using a canned policy, include the policy itself in the stream name
    else {
        $result .= $separator . "Policy=" . $policy . "&Signature=" . $signature . "&Key-Pair-Id=" . $key_pair_id;
    }

    // new lines would break us, so remove them
    return str_replace('\n', '', $result);
}


function get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires) {
    // this policy is well known by CloudFront, but you still need to sign it, since it contains your parameters
    $canned_policy = '{"Statement":[{"Resource":"' . $video_path . '","Condition":{"DateLessThan":{"AWS:EpochTime":'. $expires . '}}}]}';
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($canned_policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($canned_policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, null, $encoded_signature, $key_pair_id, $expires);
    // URL-encode the query string characters
    return $stream_name;
}

function get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy) {
    // the policy contains characters that cannot be part of a URL, so we base64 encode it
    $encoded_policy = url_safe_base64_encode($policy);
    // sign the original policy, not the encoded version
    $signature = rsa_sha1_sign($policy, $private_key_filename);
    // make the signature safe to be included in a URL
    $encoded_signature = url_safe_base64_encode($signature);

    // combine the above into a stream name
    $stream_name = create_stream_name($video_path, $encoded_policy, $encoded_signature, $key_pair_id, null);
    // URL-encode the query string characters
    return $stream_name;
}


// Path to your private key.  Be very careful that this file is not accessible
// from the web!

$private_key_filename = '/home/test/secure/example-priv-key.pem';
$key_pair_id = 'K2JCJMDEHXQW5F';

// Make sure you have "Restrict viewer access" enabled on this path behaviour and using the above Trusted key groups (recommended).
$video_path = 'https://example.com/secure/example.mp4';

$expires = time() + 300; // 5 min from now
$canned_policy_stream_name = get_canned_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $expires);

// Get the viewer real IP from the x-forward-for header as $_SERVER['REMOTE_ADDR'] will return viewer facing IP. An alternative option is to use CloudFront-Viewer-Address header. Note that this header is a trusted CloudFront immutable header. Example format: IP:PORT ("CloudFront-Viewer-Address": "1.2.3.4:12345")
$client_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$policy =
'{'.
    '"Statement":['.
        '{'.
            '"Resource":"'. $video_path . '",'.
            '"Condition":{'.
                '"IpAddress":{"AWS:SourceIp":"' . $client_ip . '/32"},'.
                '"DateLessThan":{"AWS:EpochTime":' . $expires . '}'.
            '}'.
        '}'.
    ']' .
    '}';
$custom_policy_stream_name = get_custom_policy_stream_name($video_path, $private_key_filename, $key_pair_id, $policy);

?>

<html>

<head>
    <title>CloudFront</title>
</head>

<body>
    <h1>Amazon CloudFront</h1>
    <h2>Canned Policy</h2>
    <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?></h3>
    <br />

    <div id='canned'>The canned policy video will be here: <br>
    
        <video width="640" height="360" autoplay muted controls>
        <source src="<?php echo $canned_policy_stream_name; ?>" type="video/mp4">
        Your browser does not support the video tag.
        </video>
    </div>

    <h2>Custom Policy</h2>
    <h3>Expires at <?php echo gmdate('Y-m-d H:i:s T', $expires); ?> only viewable by IP <?php echo $client_ip; ?></h3>
    <div id='custom'>The custom policy video will be here: <br>

         <video width="640" height="360" autoplay muted controls>
         <source src="<?php echo $custom_policy_stream_name; ?>" type="video/mp4">
         Your browser does not support the video tag.
        </video>
    </div> 

</body>

</html>
```

For additional URL signature examples, see the following topics:
+ [Create a URL signature using Perl](CreateURLPerl.md)
+ [Create a URL signature using C\$1 and the .NET Framework](CreateSignatureInCSharp.md)
+ [Create a URL signature using Java](CFPrivateDistJavaDevelopment.md)

Instead of using signed URLs to create the signature, you can use signed cookies. For more information, see [Create signed cookies using PHP](signed-cookies-PHP.md).

# Create a URL signature using C\$1 and the .NET Framework
<a name="CreateSignatureInCSharp"></a>

The C\$1 examples in this section implement an example application that demonstrates how to create the signatures for CloudFront private distributions using canned and custom policy statements. The examples include utility functions based on the [AWS SDK for .NET](https://aws.amazon.com/sdkfornet) that can be useful in .NET applications.

You can also create signed URLs and signed cookies by using the SDK for .NET. In the *SDK for .NET API Reference*, see the following topics:
+ **Signed URLs** – [AmazonCloudFrontUrlSigner](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFront/TCloudFrontUrlSigner.html) 
+ **Signed cookies** – [AmazonCloudFrontCookieSigner](https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/CloudFront/TCloudFrontCookieSigner.html) 

To download the code, go to [Signature Code in C\$1](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip).

**Notes**  
The `AmazonCloudFrontUrlSigner` and `AmazonCloudFrontCookieSigner` classes have moved to a separate package. For more information about using them, see [CookieSigner and UrlSigner](https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html#net-dg-v4-CookieSigner-UrlSigner) in the *AWS SDK for .NET (V4) Developer Guide*. 
Creating a URL signature is just one part of the process of serving private content using a signed URL. For more information, see [Use signed URLs](private-content-signed-urls.md). For more information about using signed cookies, see [Use signed cookies](private-content-signed-cookies.md).
In the RSA signing call, note that `SHA1` can be replaced with `SHA256` in the hash algorithm parameter.

## Use an RSA key in the .NET Framework
<a name="rsa-key-sdk-net"></a>

To use an RSA key in the .NET Framework, you must convert the AWS supplied .pem file to the XML format that the .NET Framework uses.

After conversion, the RSA private key file is in the following format:

**Example : RSA private key in the XML .NET Framework format**  <a name="RSAPrivateKeyXML.NETFrameworkFormat"></a>

```
<RSAKeyValue>
  <Modulus>
    wO5IvYCP5UcoCKDo1dcspoMehWBZcyfs9QEzGi6Oe5y+ewGr1oW+vB2GPB
    ANBiVPcUHTFWhwaIBd3oglmF0lGQljP/jOfmXHUK2kUUnLnJp+oOBL2NiuFtqcW6h/L5lIpD8Yq+NRHg
    Ty4zDsyr2880MvXv88yEFURCkqEXAMPLE=
  </Modulus>
  <Exponent>AQAB</Exponent>
  <P>
    5bmKDaTz
    npENGVqz4Cea8XPH+sxt+2VaAwYnsarVUoSBeVt8WLloVuZGG9IZYmH5KteXEu7fZveYd9UEXAMPLE==
  </P>
  <Q>
    1v9l/WN1a1N3rOK4VGoCokx7kR2SyTMSbZgF9IWJNOugR/WZw7HTnjipO3c9dy1Ms9pUKwUF4
    6d7049EXAMPLE==
  </Q>
  <DP>
    RgrSKuLWXMyBH+/l1Dx/I4tXuAJIrlPyo+VmiOc7b5NzHptkSHEPfR9s1
    OK0VqjknclqCJ3Ig86OMEtEXAMPLE==
  </DP>
  <DQ>
    pjPjvSFw+RoaTu0pgCA/jwW/FGyfN6iim1RFbkT4
    z49DZb2IM885f3vf35eLTaEYRYUHQgZtChNEV0TEXAMPLE==
  </DQ>
  <InverseQ>
    nkvOJTg5QtGNgWb9i
    cVtzrL/1pFEOHbJXwEJdU99N+7sMK+1066DL/HSBUCD63qD4USpnf0myc24in0EXAMPLE==</InverseQ>
  <D>
      Bc7mp7XYHynuPZxChjWNJZIq+A73gm0ASDv6At7F8Vi9r0xUlQe/v0AQS3ycN8QlyR4XMbzMLYk
      3yjxFDXo4ZKQtOGzLGteCU2srANiLv26/imXA8FVidZftTAtLviWQZBVPTeYIA69ATUYPEq0a5u5wjGy
      UOij9OWyuEXAMPLE=
   </D>
</RSAKeyValue>
```

## Canned policy signing method in C\$1
<a name="canned-policy-signed-url-net"></a>

The following C\$1 code creates a signed URL that uses a canned policy by doing the following:
+ Creates a policy statement.
+ Hashes the policy statement using SHA1, and signs the result using RSA and the private key whose corresponding public key is in a trusted key group.
+ Base64-encodes the hashed and signed policy statement and replaces special characters to make the string safe to use as a URL request parameter.
+ Concatenates the values.

For the complete implementation, see the example at [Signature Code in C\$1](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip). 

**Note**  
The `keyId` is returned when you upload a public key to CloudFront. For more information, see ![\[6\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/images/callouts/6.png)[ &Key-Pair-Id](private-content-creating-signed-url-canned-policy.md).

**Example : Canned policy signing method in C\$1**  <a name="ExampleCannedPolicySigningMethod-CSharp"></a>

```
public static string ToUrlSafeBase64String(byte[] bytes)
{
    return System.Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('=', '_')
        .Replace('/', '~');
}

public static string CreateCannedPrivateURL(string urlString, 
    string durationUnits, string durationNumber, string pathToPolicyStmnt, 
    string pathToPrivateKey, string keyId)
{
    // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days 
    // to expiration, 3-numberOfPreviousUnits, 4-pathToPolicyStmnt, 
    // 5-pathToPrivateKey, 6-keyId

    TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber);

    // Create the policy statement.
    string strPolicy = CreatePolicyStatement(pathToPolicyStmnt,
        urlString, 
        DateTime.Now, 
        DateTime.Now.Add(timeSpanInterval), 
        "0.0.0.0/0");
    if ("Error!" == strPolicy) return "Invalid time frame." + 
        "Start time cannot be greater than end time.";

    // Copy the expiration time defined by policy statement.
    string strExpiration = CopyExpirationTimeFromPolicy(strPolicy);

    // Read the policy into a byte buffer.
    byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy);

    // Initialize the SHA1CryptoServiceProvider object and hash the policy data.
    using (SHA1CryptoServiceProvider 
        cryptoSHA1 = new SHA1CryptoServiceProvider())
    {
        bufferPolicy = cryptoSHA1.ComputeHash(bufferPolicy);

        // Initialize the RSACryptoServiceProvider object.
        RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider();
        XmlDocument xmlPrivateKey = new XmlDocument();

        // Load your private key, which you created by converting your 
        // .pem file to the XML format that the .NET framework uses.  
        // Several tools are available. 
        xmlPrivateKey.Load(pathToPrivateKey);

        // Format the RSACryptoServiceProvider providerRSA and 
        // create the signature.
        providerRSA.FromXmlString(xmlPrivateKey.InnerXml);
        RSAPKCS1SignatureFormatter rsaFormatter = 
            new RSAPKCS1SignatureFormatter(providerRSA);
        rsaFormatter.SetHashAlgorithm("SHA1");
        byte[] signedPolicyHash = rsaFormatter.CreateSignature(bufferPolicy);

        // Convert the signed policy to URL-safe base64 encoding and 
        // replace unsafe characters + = / with the safe characters - _ ~
        string strSignedPolicy = ToUrlSafeBase64String(signedPolicyHash);

        // Concatenate the URL, the timestamp, the signature, 
        // and the key pair ID to form the signed URL.
        return urlString + 
            "?Expires=" + 
            strExpiration + 
            "&Signature=" + 
            strSignedPolicy + 
            "&Key-Pair-Id=" + 
            keyId;
    }
}
```

## Custom policy signing method in C\$1
<a name="custom-policy-signed-url-net"></a>

The following C\$1 code creates a signed URL that uses a custom policy by doing the following:

1. Creates a policy statement.

1. Base64-encodes the policy statement and replaces special characters to make the string safe to use as a URL request parameter.

1. Hashes the policy statement using SHA1, and encrypts the result using RSA and the private key whose corresponding public key is in a trusted key group.

1. Base64-encodes the hashed policy statement and replacing special characters to make the string safe to use as a URL request parameter.

1. Concatenates the values.

For the complete implementation, see the example at [Signature Code in C\$1](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/samples/AWS_PrivateCF_Distributions.zip). 

**Note**  
The `keyId` is returned when you upload a public key to CloudFront. For more information, see ![\[6\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/images/callouts/6.png)[ &Key-Pair-Id](private-content-creating-signed-url-canned-policy.md).

**Example : Custom policy signing method in C\$1**  <a name="ExampleCustomPolicySigningMethod-CSharp"></a>

```
public static string ToUrlSafeBase64String(byte[] bytes)
{
    return System.Convert.ToBase64String(bytes)
        .Replace('+', '-')
        .Replace('=', '_')
        .Replace('/', '~');
}

public static string CreateCustomPrivateURL(string urlString, 
    string durationUnits, string durationNumber, string startIntervalFromNow, 
    string ipaddress, string pathToPolicyStmnt, string pathToPrivateKey, 
    string keyId)
{
    // args[] 0-thisMethod, 1-resourceUrl, 2-seconds-minutes-hours-days 
    // to expiration, 3-numberOfPreviousUnits, 4-starttimeFromNow, 
    // 5-ip_address, 6-pathToPolicyStmt, 7-pathToPrivateKey, 8-keyId

    TimeSpan timeSpanInterval = GetDuration(durationUnits, durationNumber);
    TimeSpan timeSpanToStart = GetDurationByUnits(durationUnits, 
        startIntervalFromNow);
    if (null == timeSpanToStart) 
        return "Invalid duration units." + 
            "Valid options: seconds, minutes, hours, or days";
            
    string strPolicy = CreatePolicyStatement(
        pathToPolicyStmnt, urlString, DateTime.Now.Add(timeSpanToStart), 
        DateTime.Now.Add(timeSpanInterval), ipaddress);

    // Read the policy into a byte buffer.
    byte[] bufferPolicy = Encoding.ASCII.GetBytes(strPolicy);

    // Convert the policy statement to URL-safe base64 encoding and 
    // replace unsafe characters + = / with the safe characters - _ ~

    string urlSafePolicy = ToUrlSafeBase64String(bufferPolicy);

    // Initialize the SHA1CryptoServiceProvider object and hash the policy data.
    byte[] bufferPolicyHash;
    using (SHA1CryptoServiceProvider cryptoSHA1 = 
        new SHA1CryptoServiceProvider())
    {
        bufferPolicyHash = cryptoSHA1.ComputeHash(bufferPolicy);

        // Initialize the RSACryptoServiceProvider object.
        RSACryptoServiceProvider providerRSA = new RSACryptoServiceProvider();
        XmlDocument xmlPrivateKey = new XmlDocument();

        // Load your private key, which you created by converting your 
        // .pem file to the XML format that the .NET framework uses.  
        // Several tools are available. 
        xmlPrivateKey.Load(pathToPrivateKey);

        // Format the RSACryptoServiceProvider providerRSA 
        // and create the signature.
        providerRSA.FromXmlString(xmlPrivateKey.InnerXml);
        RSAPKCS1SignatureFormatter RSAFormatter = 
            new RSAPKCS1SignatureFormatter(providerRSA);
        RSAFormatter.SetHashAlgorithm("SHA1");
        byte[] signedHash = RSAFormatter.CreateSignature(bufferPolicyHash);

        // Convert the signed policy to URL-safe base64 encoding and 
        // replace unsafe characters + = / with the safe characters - _ ~
        string strSignedPolicy = ToUrlSafeBase64String(signedHash);

        return urlString + 
            "?Policy=" + 
            urlSafePolicy + 
            "&Signature=" + 
            strSignedPolicy + 
            "&Key-Pair-Id=" + 
            keyId;
    }
}
```

## Utility methods for signature generation
<a name="utility-methods-signed-url"></a>

The following methods get the policy statement from a file and parse time intervals for signature generation.

**Example : Utility methods for signature generation**  <a name="UtilityMethodsForSignatureGeneration"></a>

```
public static string CreatePolicyStatement(string policyStmnt, 
   string resourceUrl, 
   DateTime startTime, 
   DateTime endTime, 
   string ipAddress)
   
{
   // Create the policy statement.
   FileStream streamPolicy = new FileStream(policyStmnt, FileMode.Open, FileAccess.Read);
   using (StreamReader reader = new StreamReader(streamPolicy))
   {
      string strPolicy = reader.ReadToEnd();

      TimeSpan startTimeSpanFromNow = (startTime - DateTime.Now);
      TimeSpan endTimeSpanFromNow = (endTime - DateTime.Now);
      TimeSpan intervalStart = 
         (DateTime.UtcNow.Add(startTimeSpanFromNow)) - 
         new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
      TimeSpan intervalEnd = 
         (DateTime.UtcNow.Add(endTimeSpanFromNow)) - 
         new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

      int startTimestamp = (int)intervalStart.TotalSeconds; // START_TIME
      int endTimestamp = (int)intervalEnd.TotalSeconds;  // END_TIME

      if (startTimestamp > endTimestamp)
         return "Error!";

      // Replace variables in the policy statement.
      strPolicy = strPolicy.Replace("RESOURCE", resourceUrl);
      strPolicy = strPolicy.Replace("START_TIME", startTimestamp.ToString());
      strPolicy = strPolicy.Replace("END_TIME", endTimestamp.ToString());
      strPolicy = strPolicy.Replace("IP_ADDRESS", ipAddress);
      strPolicy = strPolicy.Replace("EXPIRES", endTimestamp.ToString());
      return strPolicy;
   }   
}

public static TimeSpan GetDuration(string units, string numUnits)
{
   TimeSpan timeSpanInterval = new TimeSpan();
   switch (units)
   {
      case "seconds":
         timeSpanInterval = new TimeSpan(0, 0, 0, int.Parse(numUnits));
         break;
      case "minutes":
         timeSpanInterval = new TimeSpan(0, 0, int.Parse(numUnits), 0);
         break;
      case "hours":
         timeSpanInterval = new TimeSpan(0, int.Parse(numUnits), 0 ,0);
         break;
      case "days":
         timeSpanInterval = new TimeSpan(int.Parse(numUnits),0 ,0 ,0);
         break;
      default:
         Console.WriteLine("Invalid time units;" + 
            "use seconds, minutes, hours, or days");
         break;
   }
   return timeSpanInterval;
}

private static TimeSpan GetDurationByUnits(string durationUnits, 
   string startIntervalFromNow)
{
   switch (durationUnits)
   {
      case "seconds":
         return new TimeSpan(0, 0, int.Parse(startIntervalFromNow));
      case "minutes":
         return new TimeSpan(0, int.Parse(startIntervalFromNow), 0);
      case "hours":
         return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0);
      case "days":
         return new TimeSpan(int.Parse(startIntervalFromNow), 0, 0, 0);
      default:
         return new TimeSpan(0, 0, 0, 0);
   }
}

public static string CopyExpirationTimeFromPolicy(string policyStatement)
{
   int startExpiration = policyStatement.IndexOf("EpochTime");
   string strExpirationRough = policyStatement.Substring(startExpiration + 
      "EpochTime".Length);
   char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
         
   List<char> listDigits = new List<char>(digits);
   StringBuilder buildExpiration = new StringBuilder(20);
         
   foreach (char c in strExpirationRough)
   {
      if (listDigits.Contains(c))
         buildExpiration.Append(c);
   }
   return buildExpiration.ToString();   
}
```

See also
+ [Create a URL signature using Perl](CreateURLPerl.md)
+ [Create a URL signature using PHP](CreateURL_PHP.md)
+ [Create a URL signature using Java](CFPrivateDistJavaDevelopment.md)

# Create a URL signature using Java
<a name="CFPrivateDistJavaDevelopment"></a>

In addition to the following code example, you can use [the `CloudFrontUrlSigner` utility class in the AWS SDK for Java (version 1)](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/cloudfront/CloudFrontUrlSigner.html) to create [CloudFront signed URLs](private-content-signed-urls.md).

For more examples, see [Create signed URLs and cookies using an AWS SDK](https://docs.aws.amazon.com/code-library/latest/ug/cloudfront_example_cloudfront_CloudFrontUtilities_section.html) in the *AWS SDK Code Examples Code Library*. 

**Notes**  
Creating a signed URL is just one part of the process of [serving private content with CloudFront](PrivateContent.md). For more information about the entire process, see [Use signed URLs](private-content-signed-urls.md).
In the `Signature.getInstance` call, note that `SHA1withRSA` can be replaced with `SHA256withRSA`.

**Example Java policy and signature encryption methods**  <a name="ExampleJavaPolicyAndSignatureEncryptionMethods"></a>

```
package org.example;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import software.amazon.awssdk.services.cloudfront.CloudFrontUtilities;
import software.amazon.awssdk.services.cloudfront.model.CannedSignerRequest;
import software.amazon.awssdk.services.cloudfront.url.SignedUrl;

public class Main {

    public static void main(String[] args) throws Exception {
        CloudFrontUtilities cloudFrontUtilities = CloudFrontUtilities.create();
        Instant expirationDate = Instant.now().plus(7, ChronoUnit.DAYS);
        String resourceUrl = "https://a1b2c3d4e5f6g7.cloudfront.net";
        String keyPairId = "K1UA3WV15I7JSD";
        CannedSignerRequest cannedRequest = CannedSignerRequest.builder()
                .resourceUrl(resourceUrl)
                .privateKey(new java.io.File("/path/to/private_key.pem").toPath())
                .keyPairId(keyPairId)
                .expirationDate(expirationDate)
                .build();
        SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCannedPolicy(cannedRequest);
        String url = signedUrl.url();
        System.out.println(url);

    }
}
```

**Example Canned Policy Signing with SHA256 in Java**  <a name="ExampleJavaPolicySHA256AndSignatureEncryptionMethods"></a>

```
package org.example;

import java.io.File;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;

public class Main {

    public static void main(String[] args) throws Exception {
        String resourceUrl = "https://a1b2c3d4e5f6g7.cloudfront.net/myfile.html";
        String keyPairId = "K1UA3WV15I7JSD";
        Instant expiration = Instant.now().plus(7, ChronoUnit.DAYS);
        PrivateKey privateKey = loadPrivateKey("/path/to/private_key.der");

        System.out.println(createSignedUrl(resourceUrl, keyPairId, privateKey, expiration, "SHA1"));
        System.out.println(createSignedUrl(resourceUrl, keyPairId, privateKey, expiration, "SHA256"));
    }

    static String createSignedUrl(String resourceUrl, String keyPairId,
                                  PrivateKey privateKey, Instant expiration,
                                  String hashAlgorithm) throws Exception {
        long epochSeconds = expiration.getEpochSecond();

        String policy = "{\"Statement\":[{\"Resource\":\"" + resourceUrl
                + "\",\"Condition\":{\"DateLessThan\":{\"AWS:EpochTime\":" + epochSeconds + "}}}]}";

        String jcaAlgorithm = hashAlgorithm.equals("SHA256") ? "SHA256withRSA" : "SHA1withRSA";

        Signature sig = Signature.getInstance(jcaAlgorithm);
        sig.initSign(privateKey);
        sig.update(policy.getBytes("UTF-8"));
        String signature = base64UrlEncode(sig.sign());

        String url = resourceUrl
                + (resourceUrl.contains("?") ? "&" : "?")
                + "Expires=" + epochSeconds
                + "&Signature=" + signature
                + "&Key-Pair-Id=" + keyPairId;

        if (hashAlgorithm.equals("SHA256")) {
            url += "&Hash-Algorithm=SHA256";
        }

        return url;
    }

    static String base64UrlEncode(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes)
                .replace('+', '-')
                .replace('=', '_')
                .replace('/', '~');
    }

    static PrivateKey loadPrivateKey(String path) throws Exception {
        byte[] keyBytes = Files.readAllBytes(new File(path).toPath());
        return KeyFactory.getInstance("RSA")
                .generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
    }
}
```

See also:
+ [Create a URL signature using Perl](CreateURLPerl.md)
+ [Create a URL signature using PHP](CreateURL_PHP.md)
+ [Create a URL signature using C\$1 and the .NET Framework](CreateSignatureInCSharp.md)

# Restrict access to an AWS origin
<a name="private-content-restricting-access-to-origin"></a>

You can configure CloudFront and some AWS origins in a way that provides the following benefits:
+ Restricts access to the AWS origin so that it's not publicly accessible.
+ Makes sure that viewers (users) can access the content in the AWS origin only through the specified CloudFront distribution. This prevents viewers from accessing the content directly from the origin, or through an unintended CloudFront distribution.

To do this, configure CloudFront to send authenticated requests to your AWS origin, and configure the AWS origin to only allow access to authenticated requests from CloudFront. For more information, see following topics for compatible types of AWS origins.

**Topics**
+ [Restrict access to an AWS Elemental MediaPackage v2 origin](private-content-restricting-access-to-mediapackage.md)
+ [Restrict access to an AWS Elemental MediaStore origin](private-content-restricting-access-to-mediastore.md)
+ [Restrict access to an AWS Lambda function URL origin](private-content-restricting-access-to-lambda.md)
+ [Restrict access to an Amazon S3 origin](private-content-restricting-access-to-s3.md)
+ [Restrict access with VPC origins](private-content-vpc-origins.md)
+ [Restrict access to an Amazon S3 Multi-Region Access Point origin](private-content-restricting-access-to-s3-mrap.md)

# Restrict access to an AWS Elemental MediaPackage v2 origin
<a name="private-content-restricting-access-to-mediapackage"></a>

CloudFront provides *origin access control* (OAC) for restricting access to a MediaPackage v2 origin.

**Note**  
CloudFront OAC only supports MediaPackage v2. MediaPackage v1 isn't supported.

**Topics**
+ [Creating a new OAC](#create-oac-overview-mediapackage)
+ [Advanced settings for origin access control](#oac-advanced-settings-mediapackage)

## Creating a new OAC
<a name="create-oac-overview-mediapackage"></a>

Complete the steps described in the following topics to set up a new OAC in CloudFront.

**Topics**
+ [Prerequisites](#oac-prerequisites-mediapackage)
+ [Grant CloudFront permission to access the MediaPackage v2 origin](#oac-permission-to-access-mediapackage)
+ [Creating the OAC](#create-oac-mediapackage)

### Prerequisites
<a name="oac-prerequisites-mediapackage"></a>

Before you create and set up OAC, you must have a CloudFront distribution with a MediaPackage v2 origin. For more information, see [Use a MediaStore container or a MediaPackage channel](DownloadDistS3AndCustomOrigins.md#concept_AWS_Media).

### Grant CloudFront permission to access the MediaPackage v2 origin
<a name="oac-permission-to-access-mediapackage"></a>

Before you create an OAC or set it up in a CloudFront distribution, make sure that CloudFront has permission to access the MediaPackage v2 origin. Do this after you create a CloudFront distribution, but before you add the OAC to the MediaPackage v2 origin in the distribution configuration.

Use an IAM policy to allow the CloudFront service principal (`cloudfront.amazonaws.com`) to access the origin. The `Condition` element in the policy allows CloudFront to access the MediaPackage v2 origin *only* when the request is on behalf of the CloudFront distribution that contains the MediaPackage v2 origin. This is the distribution with the MediaPackage v2 origin that you want to add OAC to.

**Example : IAM policy that allows read-only access for a CloudFront distribution with OAC enabled**  
The following policy allows the CloudFront distribution (`E1PDK09ESKHJWT`) access to the MediaPackage v2 origin. The origin is the ARN specified for the `Resource` element.    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {"Service": "cloudfront.amazonaws.com"},
            "Action": "mediapackagev2:GetObject",
            "Resource": "arn:aws:mediapackagev2:us-east-1:123456789012:channelGroup/channel-group-name/channel/channel-name/originEndpoint/origin_endpoint_name",
            "Condition": {
                "StringEquals": {"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT"}
            }
        }
    ]
}
```

**Notes**  
If you enabled the MQAR feature and origin access control (OAC), add the `mediapackagev2:GetHeadObject` action to the IAM policy. MQAR requires this permission to send `HEAD` requests to the MediaPackage v2 origin. For more information about MQAR, see [Media quality-aware resiliency](media-quality-score.md).
If you create a distribution that doesn't have permission to your MediaPackage v2 origin, you can choose **Copy policy** from the CloudFront console and then choose **Update endpoint permissions**. You can then attach the copied permission to the endpoint. For more information, see [Endpoint policy fields](https://docs.aws.amazon.com/mediapackage/latest/userguide/endpoints-policy.html) in the *AWS Elemental MediaPackage User Guide*. 

### Creating the OAC
<a name="create-oac-mediapackage"></a>

To create an OAC, you can use the AWS Management Console, CloudFormation, the AWS CLI, or the CloudFront API.

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

**To create an OAC**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Origin access**.

1. Choose **Create control setting**.

1. On the **Create new OAC** form, do the following:

   1. Enter a **Name** and (optionally) a **Description** for the OAC.

   1. For **Signing behavior**, we recommend that you leave the default setting (**Sign requests (recommended)**). For more information, see [Advanced settings for origin access control](#oac-advanced-settings-mediapackage).

1. For **Origin type**, choose **MediaPackage V2**. 

1. Choose **Create**.
**Tip**  
After you create the OAC, make note of the **Name**. You need this in the following procedure.

**To add an OAC to a MediaPackage v2 origin in a distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose a distribution with a MediaPackage V2 origin that you want to add the OAC to, then choose the **Origins** tab.

1. Select the MediaPackage v2 origin that you want to add the OAC to, then choose **Edit**.

1. Select **HTTPS only** for your origin's **Protocol**.

1. From the **Origin access control** dropdown, choose the OAC name that you want to use.

1. Choose **Save changes**.

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the MediaPackage v2 origin.

------
#### [ CloudFormation ]

To create an OAC with CloudFormation, use the `AWS::CloudFront::OriginAccessControl` resource type. The following example shows the CloudFormation template syntax, in YAML format, for creating an OAC.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: mediapackagev2
      SigningBehavior: always
      SigningProtocol: sigv4
```

For more information, see [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html) in the *AWS CloudFormation User Guide*.

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

To create an origin access control with the AWS Command Line Interface (AWS CLI), use the **aws cloudfront create-origin-access-control** command. You can use an input file to provide the input parameters for the command, rather than specifying each individual parameter as command line input.

**To create an origin access control (CLI with input file)**

1. Use the following command to create a file that's named `origin-access-control.yaml`. This file contains all of the input parameters for the **create-origin-access-control** command.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. Open the `origin-access-control.yaml` file that you just created. Edit the file to add a name for the OAC, a description (optional), and change the `SigningBehavior` to `always`. Then save the file.

   For information about other OAC settings, see [Advanced settings for origin access control](#oac-advanced-settings-mediapackage).

1. Use the following command to create the origin access control using the input parameters from the `origin-access-control.yaml` file.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   Make note of the `Id` value in the command output. You need it to add the OAC to a MediaPackage v2 origin in a CloudFront distribution.

**To attach an OAC to a MediaPackage v2 origin in an existing distribution (CLI with input file)**

1. Use the following command to save the distribution configuration for the CloudFront distribution that you want to add the OAC to. The distribution must have a MediaPackage v2 origin.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. Open the file that's named `dist-config.yaml` that you just created. Edit the file, making the following changes:
   + In the `Origins` object, add the OAC's ID to the field that's named `OriginAccessControlId`.
   + Remove the value from the field that's named `OriginAccessIdentity`, if one exists.
   + Rename the `ETag` field to `IfMatch`, but don't change the field's value.

   Save the file when finished.

1. Use the following command to update the distribution to use the origin access control.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the MediaPackage v2 origin.

------
#### [ API ]

To create an OAC with the CloudFront API, use [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html). For more information about the fields that you specify in this API call, see the API reference documentation for your AWS SDK or other API client.

After you create an OAC you can attach it to a MediaPackage v2 origin in a distribution, using one of the following API calls:
+ To attach it to an existing distribution, use [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html).
+ To attach it to a new distribution, use [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html).

For both of these API calls, provide the OAC ID in the `OriginAccessControlId` field, inside an origin. For more information about the other fields that you specify in these API calls, see [All distribution settings reference](distribution-web-values-specify.md) and the API reference documentation for your AWS SDK or other API client.

------

## Advanced settings for origin access control
<a name="oac-advanced-settings-mediapackage"></a>

The CloudFront OAC feature includes advanced settings that are intended only for specific use cases. Use the recommended settings unless you have a specific need for the advanced settings.

OAC contains a setting named **Signing behavior** (in the console), or `SigningBehavior` (in the API, CLI, and CloudFormation). This setting provides the following options:

**Always sign origin requests (recommended setting)**  
We recommend using this setting, named **Sign requests (recommended)** in the console, or `always` in the API, CLI, and CloudFormation. With this setting, CloudFront always signs all requests that it sends to the MediaPackage v2 origin.

**Never sign origin requests**  
This setting is named **Do not sign requests** in the console, or `never` in the API, CLI, and CloudFormation. Use this setting to turn off OAC for all origins in all distributions that use this OAC. This can save time and effort compared to removing an OAC from all origins and distributions that use it, one by one. With this setting, CloudFront doesn't sign any requests that it sends to the MediaPackage v2 origin.  
To use this setting, the MediaPackage v2 origin must be publicly accessible. If you use this setting with a MediaPackage v2 origin that's not publicly accessible, CloudFront can't access the origin. The MediaPackage v2 origin returns errors to CloudFront and CloudFront passes those errors on to viewers. For more information, see the example MediaPackage v2 policy for [Policies and Permissions in MediaPackage](https://docs.aws.amazon.com/mediapackage/latest/userguide/policies-permissions.html) in the *AWS Elemental MediaPackage User Guide*.

**Don't override the viewer (client) `Authorization` header**  
This setting is named **Do not override authorization header** in the console, or `no-override` in the API, CLI, and CloudFormation. Use this setting when you want CloudFront to sign origin requests only when the corresponding viewer request does not include an `Authorization` header. With this setting, CloudFront passes on the `Authorization` header from the viewer request when one is present, but signs the origin request (adding its own `Authorization` header) when the viewer request doesn't include an `Authorization` header.  
To pass along the `Authorization` header from the viewer request, you *must* add the `Authorization` header to a [cache policy](controlling-the-cache-key.md) for all cache behaviors that use MediaPackage v2 origins associated with this origin access control.

# Restrict access to an AWS Elemental MediaStore origin
<a name="private-content-restricting-access-to-mediastore"></a>

CloudFront provides *origin access control* (OAC) for restricting access to an AWS Elemental MediaStore origin.

**Topics**
+ [Create a new origin access control](#create-oac-overview-mediastore)
+ [Advanced settings for origin access control](#oac-advanced-settings-mediastore)

## Create a new origin access control
<a name="create-oac-overview-mediastore"></a>

Complete the steps described in the following topics to set up a new origin access control in CloudFront.

**Topics**
+ [Prerequisites](#oac-prerequisites-mediastore)
+ [Grant CloudFront permission to access the MediaStore origin](#oac-permission-to-access-mediastore)
+ [Create the origin access control](#create-oac-mediastore)

### Prerequisites
<a name="oac-prerequisites-mediastore"></a>

Before you create and set up origin access control, you must have a CloudFront distribution with a MediaStore origin. 

### Grant CloudFront permission to access the MediaStore origin
<a name="oac-permission-to-access-mediastore"></a>

Before you create an origin access control or set it up in a CloudFront distribution, make sure that CloudFront has permission to access the MediaStore origin. Do this after creating a CloudFront distribution, but before adding the OAC to the MediaStore origin in the distribution configuration. 

Use a MediaStore container policy to allow the CloudFront service principal (`cloudfront.amazonaws.com`) to access the origin. Use a `Condition` element in the policy to allow CloudFront to access the MediaStore container only when the request is on behalf of the CloudFront distribution that contains the MediaStore origin. This is the distribution with the MediaStore origin that you want to add OAC to.

The following are examples of MediaStore container policies that allow a CloudFront distribution to access a MediaStore origin.

**Example MediaStore container policy that allows read-only access for a CloudFront distribution with OAC enabled**    
****  

```
{
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Sid": "AllowCloudFrontServicePrincipalReadOnly",
                "Effect": "Allow",
                "Principal": {
                  "Service": "cloudfront.amazonaws.com"
                },
                "Action": [ 
                  "mediastore:GetObject"
                ],
                "Resource": "arn:aws:mediastore:us-east-1:111122223333:container/<container name>/*",
                "Condition": {
                    "StringEquals": {
                      "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront-distribution-ID"
                    },
                    "Bool": {
                      "aws:SecureTransport": "true"
                    }
                }
            }
        ]
}
```

**Example MediaStore container policy that allows read and write access for a CloudFront distribution with OAC enabled**    
****  

```
{
        "Version":"2012-10-17",		 	 	 
        "Statement": [
            {
                "Sid": "AllowCloudFrontServicePrincipalReadWrite",
                "Effect": "Allow",
                "Principal": {
                  "Service": "cloudfront.amazonaws.com"
                },
                "Action": [ 
                  "mediastore:GetObject",
                  "mediastore:PutObject"
                ],
                "Resource": "arn:aws:mediastore:us-east-1:111122223333:container/container-name/*",
                "Condition": {
                    "StringEquals": {
                      "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront-distribution-ID"
                    },
                    "Bool": {
                      "aws:SecureTransport": "true"
                    }
                }
            }
        ]
}
```

**Note**  
To allow write access, you must configure **Allowed HTTP methods** to include `PUT` in your CloudFront distribution's behavior settings.

### Create the origin access control
<a name="create-oac-mediastore"></a>

To create an OAC, you can use the AWS Management Console, CloudFormation, the AWS CLI, or the CloudFront API.

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

**To create an origin access control**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Origin access**.

1. Choose **Create control setting**.

1. On the **Create control setting** form, do the following:

   1. In the **Details** pane, enter a **Name** and (optionally) a **Description** for the origin access control.

   1. In the **Settings** pane, we recommend that you leave the default setting (**Sign requests (recommended)**). For more information, see [Advanced settings for origin access control](#oac-advanced-settings-mediastore).

1. Choose MediaStore from the **Origin type** dropdown.

1. Choose **Create**.

   After the OAC is created, make note of the **Name**. You need this in the following procedure.

**To add an origin access control to a MediaStore origin in a distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose a distribution with a MediaStore origin that you want to add the OAC to, then choose the **Origins** tab.

1. Select the MediaStore origin that you want to add the OAC to, then choose **Edit**.

1. Select **HTTPS only** for your origin's **Protocol**.

1. From the **Origin access control** dropdown menu, choose the OAC that you want to use.

1. Choose **Save changes**.

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the MediaStore bucket origin.

------
#### [ CloudFormation ]

To create an origin access control (OAC) with CloudFormation, use the `AWS::CloudFront::OriginAccessControl` resource type. The following example shows the CloudFormation template syntax, in YAML format, for creating an origin access control.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: mediastore
      SigningBehavior: always
      SigningProtocol: sigv4
```

For more information, see [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html) in the *AWS CloudFormation User Guide*.

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

To create an origin access control with the AWS Command Line Interface (AWS CLI), use the **aws cloudfront create-origin-access-control** command. You can use an input file to provide the input parameters for the command, rather than specifying each individual parameter as command line input.

**To create an origin access control (CLI with input file)**

1. Use the following command to create a file that's named `origin-access-control.yaml`. This file contains all of the input parameters for the **create-origin-access-control** command.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. Open the `origin-access-control.yaml` file that you just created. Edit the file to add a name for the OAC, a description (optional), and change the `SigningBehavior` to `always`. Then save the file.

   For information about other OAC settings, see [Advanced settings for origin access control](#oac-advanced-settings-mediastore).

1. Use the following command to create the origin access control using the input parameters from the `origin-access-control.yaml` file.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   Make note of the `Id` value in the command output. You need it to add the OAC to a MediaStore origin in a CloudFront distribution.

**To attach an OAC to a MediaStore origin in an existing distribution (CLI with input file)**

1. Use the following command to save the distribution configuration for the CloudFront distribution that you want to add the OAC to. The distribution must have a MediaStore origin.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. Open the file that's named `dist-config.yaml` that you just created. Edit the file, making the following changes:
   + In the `Origins` object, add the OAC's ID to the field that's named `OriginAccessControlId`.
   + Remove the value from the field that's named `OriginAccessIdentity`, if one exists.
   + Rename the `ETag` field to `IfMatch`, but don't change the field's value.

   Save the file when finished.

1. Use the following command to update the distribution to use the origin access control.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the MediaStore origin.

------
#### [ API ]

To create an origin access control with the CloudFront API, use [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html). For more information about the fields that you specify in this API call, see the API reference documentation for your AWS SDK or other API client.

After you create an origin access control you can attach it to a MediaStore origin in a distribution, using one of the following API calls:
+ To attach it to an existing distribution, use [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html).
+ To attach it to a new distribution, use [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html).

For both of these API calls, provide the origin access control ID in the `OriginAccessControlId` field, inside an origin. For more information about the other fields that you specify in these API calls, see [All distribution settings reference](distribution-web-values-specify.md) and the API reference documentation for your AWS SDK or other API client.

------

## Advanced settings for origin access control
<a name="oac-advanced-settings-mediastore"></a>

The CloudFront origin access control feature includes advanced settings that are intended only for specific use cases. Use the recommended settings unless you have a specific need for the advanced settings.

Origin access control contains a setting named **Signing behavior** (in the console), or `SigningBehavior` (in the API, CLI, and CloudFormation). This setting provides the following options:

**Always sign origin requests (recommended setting)**  
We recommend using this setting, named **Sign requests (recommended)** in the console, or `always` in the API, CLI, and CloudFormation. With this setting, CloudFront always signs all requests that it sends to the MediaStore origin.

**Never sign origin requests**  
This setting is named **Do not sign requests** in the console, or `never` in the API, CLI, and CloudFormation. Use this setting to turn off origin access control for all origins in all distributions that use this origin access control. This can save time and effort compared to removing an origin access control from all origins and distributions that use it, one by one. With this setting, CloudFront does not sign any requests that it sends to the MediaStore origin.  
To use this setting, the MediaStore origin must be publicly accessible. If you use this setting with a MediaStore origin that's not publicly accessible, CloudFront cannot access the origin. The MediaStore origin returns errors to CloudFront and CloudFront passes those errors on to viewers. For more information, see the example MediaStore container policy for [Public read access over HTTPS](https://docs.aws.amazon.com/mediastore/latest/ug/policies-examples-public-https.html).

**Don't override the viewer (client) `Authorization` header**  
This setting is named **Do not override authorization header** in the console, or `no-override` in the API, CLI, and CloudFormation. Use this setting when you want CloudFront to sign origin requests only when the corresponding viewer request does not include an `Authorization` header. With this setting, CloudFront passes on the `Authorization` header from the viewer request when one is present, but signs the origin request (adding its own `Authorization` header) when the viewer request doesn't include an `Authorization` header.  
To pass along the `Authorization` header from the viewer request, you *must* add the `Authorization` header to a [cache policy](controlling-the-cache-key.md) for all cache behaviors that use MediaStore origins associated with this origin access control.

# Restrict access to an AWS Lambda function URL origin
<a name="private-content-restricting-access-to-lambda"></a>

CloudFront provides *origin access control* (OAC) for restricting access to a Lambda function URL origin.

**Topics**
+ [Create a new OAC](#create-oac-overview-lambda)
+ [Advanced settings for origin access control](#oac-advanced-settings-lambda)
+ [Example template code](#example-template-code-lambda-oac)

## Create a new OAC
<a name="create-oac-overview-lambda"></a>

Complete the steps described in the following topics to set up a new OAC in CloudFront.

**Important**  
If you use `PUT` or `POST` methods with your Lambda function URL, your users must compute the SHA256 of the body and include the payload hash value of the request body in the `x-amz-content-sha256` header when sending the request to CloudFront. Lambda doesn't support unsigned payloads.

**Topics**
+ [Prerequisites](#oac-prerequisites-lambda)
+ [Grant CloudFront permission to access the Lambda function URL](#oac-permission-to-access-lambda)
+ [Create the OAC](#create-oac-lambda)

### Prerequisites
<a name="oac-prerequisites-lambda"></a>

Before you create and set up OAC, you must have a CloudFront distribution with a Lambda function URL as the origin. To use OAC, you must specify `AWS_IAM` as the value for the `AuthType` parameter. For more information, see [Use a Lambda function URL](DownloadDistS3AndCustomOrigins.md#concept_lambda_function_url).

### Grant CloudFront permission to access the Lambda function URL
<a name="oac-permission-to-access-lambda"></a>

Before you create an OAC or set it up in a CloudFront distribution, make sure that CloudFront has permission to access the Lambda function URL. Do this after you create a CloudFront distribution, but before you add the OAC to the Lambda function URL in the distribution configuration.

**Note**  
To update the IAM policy for the Lambda function URL, you must use the AWS Command Line Interface (AWS CLI). Editing the IAM policy in the Lambda console isn't supported at this time.

The following AWS CLI command grants the CloudFront service principal (`cloudfront.amazonaws.com`) access to your Lambda function URL. The `Condition` element in the policy allows CloudFront to access Lambda *only* when the request is on behalf of the CloudFront distribution that contains the Lambda function URL. This is the distribution with the Lambda function URL origin that you want to add OAC to.

**Example : AWS CLI command to update a policy to allow read-only access for a CloudFront distribution with OAC enabled**  
The following AWS CLI commands allows the CloudFront distribution (`E1PDK09ESKHJWT`) access to your Lambda *`FUNCTION_URL_NAME`*.

```
aws lambda add-permission \
--statement-id "AllowCloudFrontServicePrincipal" \
--action "lambda:InvokeFunctionUrl" \
--principal "cloudfront.amazonaws.com" \
--source-arn "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT" \
--function-name FUNCTION_URL_NAME
```

```
aws lambda add-permission \
--statement-id "AllowCloudFrontServicePrincipalInvokeFunction" \
--action "lambda:InvokeFunction" \
--principal "cloudfront.amazonaws.com" \
--source-arn "arn:aws:cloudfront::123456789012:distribution/E1PDK09ESKHJWT" \
--function-name FUNCTION_URL_NAME
```

**Note**  
If you create a distribution and it doesn't have permission to your Lambda function URL, you can choose **Copy CLI command** from the CloudFront console, and then enter this command from your command line terminal. For more information, see [Granting function access to AWS services](https://docs.aws.amazon.com/lambda/latest/dg/access-control-resource-based.html#permissions-resource-serviceinvoke) in the *AWS Lambda Developer Guide*. 

### Create the OAC
<a name="create-oac-lambda"></a>

To create an OAC, you can use the AWS Management Console, CloudFormation, the AWS CLI, or the CloudFront API.

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

**To create an OAC**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Origin access**.

1. Choose **Create control setting**.

1. On the **Create new OAC** form, do the following:

   1. Enter a **Name** and (optionally) a **Description** for the OAC.

   1. For **Signing behavior**, we recommend that you leave the default setting (**Sign requests (recommended)**). For more information, see [Advanced settings for origin access control](#oac-advanced-settings-lambda).

1. For **Origin type**, choose **Lambda**. 

1. Choose **Create**.
**Tip**  
After you create the OAC, make note of the **Name**. You need this in the following procedure.

**To add an origin access control to a Lambda function URL in a distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose a distribution with a Lambda function URL that you want to add the OAC to, then choose the **Origins** tab.

1. Select the Lambda function URL that you want to add the OAC to, and then choose **Edit**.

1. Select **HTTPS only** for your origin's **Protocol**.

1. From the **Origin access control** dropdown, choose the OAC name that you want to use.

1. Choose **Save changes**.

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the Lambda function URL.

------
#### [ CloudFormation ]

To create an OAC with CloudFormation, use the `AWS::CloudFront::OriginAccessControl` resource type. The following example shows the CloudFormation template syntax, in YAML format, for creating an OAC.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: lambda
      SigningBehavior: always
      SigningProtocol: sigv4
```

For more information, see [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html) in the *AWS CloudFormation User Guide*.

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

To create an origin access control with the AWS Command Line Interface (AWS CLI), use the **aws cloudfront create-origin-access-control** command. You can use an input file to provide the input parameters for the command, rather than specifying each individual parameter as command line input.

**To create an origin access control (CLI with input file)**

1. Use the following command to create a file that's named `origin-access-control.yaml`. This file contains all of the input parameters for the **create-origin-access-control** command.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. Open the `origin-access-control.yaml` file that you just created. Edit the file to add a name for the OAC, a description (optional), and change the `SigningBehavior` to `always`. Then save the file.

   For information about other OAC settings, see [Advanced settings for origin access control](#oac-advanced-settings-lambda).

1. Use the following command to create the origin access control using the input parameters from the `origin-access-control.yaml` file.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   Make note of the `Id` value in the command output. You need it to add the OAC to a Lambda function URL in a CloudFront distribution.

**To attach an OAC to a Lambda function URL in an existing distribution (CLI with input file)**

1. Use the following command to save the distribution configuration for the CloudFront distribution that you want to add the OAC to. The distribution must have a Lambda function URL as the origin.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. Open the file that's named `dist-config.yaml` that you just created. Edit the file, making the following changes:
   + In the `Origins` object, add the OAC's ID to the field that's named `OriginAccessControlId`.
   + Remove the value from the field that's named `OriginAccessIdentity`, if one exists.
   + Rename the `ETag` field to `IfMatch`, but don't change the field's value.

   Save the file when finished.

1. Use the following command to update the distribution to use the origin access control.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the Lambda function URL.

------
#### [ API ]

To create an OAC with the CloudFront API, use [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html). For more information about the fields that you specify in this API call, see the API reference documentation for your AWS SDK or other API client.

After you create an OAC you can attach it to a Lambda function URL in a distribution, using one of the following API calls:
+ To attach it to an existing distribution, use [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html).
+ To attach it to a new distribution, use [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html).

For both of these API calls, provide the OAC ID in the `OriginAccessControlId` field, inside an origin. For more information about the other fields that you specify in these API calls, see and the API reference documentation for your AWS SDK or other API client.

------

## Advanced settings for origin access control
<a name="oac-advanced-settings-lambda"></a>

The CloudFront OAC feature includes advanced settings that are intended only for specific use cases. Use the recommended settings unless you have a specific need for the advanced settings.

OAC contains a setting named **Signing behavior** (in the console), or `SigningBehavior` (in the API, CLI, and CloudFormation). This setting provides the following options:

**Always sign origin requests (recommended setting)**  
We recommend using this setting, named **Sign requests (recommended)** in the console, or `always` in the API, CLI, and CloudFormation. With this setting, CloudFront always signs all requests that it sends to the Lambda function URL.

**Never sign origin requests**  
This setting is named **Do not sign requests** in the console, or `never` in the API, CLI, and CloudFormation. Use this setting to turn off OAC for all origins in all distributions that use this OAC. This can save time and effort compared to removing an OAC from all origins and distributions that use it, one by one. With this setting, CloudFront doesn't sign any requests that it sends to the Lambda function URL.  
To use this setting, the Lambda function URL must be publicly accessible. If you use this setting with a Lambda function URL that's not publicly accessible, CloudFront can't access the origin. The Lambda function URL returns errors to CloudFront and CloudFront passes those errors on to viewers. For more information, see [Security and auth model for Lambda function URLs](https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html) in the *AWS Lambda User Guide*.

**Don't override the viewer (client) `Authorization` header**  
This setting is named **Do not override authorization header** in the console, or `no-override` in the API, CLI, and CloudFormation. Use this setting when you want CloudFront to sign origin requests only when the corresponding viewer request does not include an `Authorization` header. With this setting, CloudFront passes on the `Authorization` header from the viewer request when one is present, but signs the origin request (adding its own `Authorization` header) when the viewer request doesn't include an `Authorization` header.  
+ If you use this setting, you must specify the Signature Version 4 signing for the Lambda function URL instead of your CloudFront distribution's name or CNAME. When CloudFront forwards the `Authorization` header from the viewer request to the Lambda function URL, Lambda will validate the signature against the host of the Lambda URL domain. If the signature isn't based on the Lambda URL domain, the host in the signature won't match the host used by the Lambda URL origin. This means the request will fail, resulting in a signature validation error.
+ To pass along the `Authorization` header from the viewer request, you *must* add the `Authorization` header to a [cache policy](controlling-the-cache-key.md) for all cache behaviors that use Lambda function URLs associated with this origin access control.

## Example template code
<a name="example-template-code-lambda-oac"></a>

If your CloudFront origin is a Lambda function URL that's associated with an OAC, you can use the following Python script to upload files to the Lambda function with the `POST` method. 

This code assumes that you configured the OAC with the default signing behavior set to **Always sign origin requests** and that you didn't select the **Do not override authorization header** setting.

This configuration allows the OAC to manage SigV4 authorization correctly with Lambda by using the Lambda hostname. The payload is signed by using SigV4 from the IAM identity that's authorized for the Lambda function URL, which is designated as the `IAM_AUTH` type. 

The template demonstrates how to handle signed payload hash values in the x-amz-content-sha256 header for `POST` requests from the client side. Specifically, this template is designed to manage form data payloads. The template enables secure file uploads to a Lambda function URL through CloudFront, and uses AWS authentication mechanisms to ensure that only authorized requests can access the Lambda function.

**The code includes the following functionality:**  
Meets the requirement for including the payload hash in the x-amz-content-sha256 header
Uses SigV4 authentication for secure AWS service access
Supports file uploads by using multi-part form data
Includes error handling for request exceptions

```
import boto3
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
import requests
import hashlib
import os


def calculate_body_hash(body):
    return hashlib.sha256(body).hexdigest()


def sign_request(request, credentials, region, service):
    sigv4 = SigV4Auth(credentials, service, region)
    sigv4.add_auth(request)


def upload_file_to_lambda(cloudfront_url, file_path, region):
    # AWS credentials
    session = boto3.Session()
    credentials = session.get_credentials()

    # Prepare the multipart form-data
    boundary = "------------------------boundary"

    # Read file content
    with open(file_path, 'rb') as file:
        file_content = file.read()

    # Get the filename from the path
    filename = os.path.basename(file_path)

    # Prepare the multipart body
    body = (
        f'--{boundary}\r\n'
        f'Content-Disposition: form-data; name="file"; filename="{filename}"\r\n'
        f'Content-Type: application/octet-stream\r\n\r\n'
    ).encode('utf-8')
    body += file_content
    body += f'\r\n--{boundary}--\r\n'.encode('utf-8')

    # Calculate SHA256 hash of the entire body
    body_hash = calculate_body_hash(body)

    # Prepare headers
    headers = {
        'Content-Type': f'multipart/form-data; boundary={boundary}',
        'x-amz-content-sha256': body_hash
    }

    # Create the request
    request = AWSRequest(
        method='POST',
        url=cloudfront_url,
        data=body,
        headers=headers
    )

    # Sign the request
    sign_request(request, credentials, region, 'lambda')

    # Get the signed headers
    signed_headers = dict(request.headers)

    # Print request headers before sending
    print("Request Headers:")
    for header, value in signed_headers.items():
        print(f"{header}: {value}")

    try:
        # Send POST request with signed headers
        response = requests.post(
            cloudfront_url,
            data=body,
            headers=signed_headers
        )

        # Print response status and content
        print(f"\nStatus code: {response.status_code}")
        print("Response:", response.text)

        # Print response headers
        print("\nResponse Headers:")
        for header, value in response.headers.items():
            print(f"{header}: {value}")

    except requests.exceptions.RequestException as e:
        print(f"An error occurred: {e}")


# Usage
cloudfront_url = "https://d111111abcdef8.cloudfront.net"
file_path = r"filepath"
region = "us-east-1"  # example: "us-west-2"

upload_file_to_lambda(cloudfront_url, file_path, region)
```

# Restrict access to an Amazon S3 origin
<a name="private-content-restricting-access-to-s3"></a>

CloudFront provides two ways to send authenticated requests to an Amazon S3 origin: *origin access control* (OAC) and *origin access identity* (OAI). OAC helps you secure your origins, such as Amazon S3. 

We *recommend* that you use OAC instead because it supports the following features:
+ All Amazon S3 buckets in all AWS Regions, including opt-in Regions launched after December 2022
+ Amazon S3 [server-side encryption with AWS KMS](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html) (SSE-KMS)
+ Dynamic requests (`PUT` and `DELETE`) to Amazon S3

OAI doesn't support these features or it requires extra workarounds in those scenarios. If you're already using OAI and want to migrate, see [Migrating from origin access identity (OAI) to origin access control (OAC)](#migrate-from-oai-to-oac).

**Notes**  
When you use CloudFront OAC with Amazon S3 bucket origins, you must set **Amazon S3 Object Ownership** to **Bucket owner enforced**, the default for new Amazon S3 buckets. If you require ACLs, use the **Bucket owner preferred** setting to maintain control over objects uploaded via CloudFront.
If your origin is an Amazon S3 bucket configured as a [website endpoint](https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteEndpoints.html), you must set it up with CloudFront as a custom origin. That means you can't use OAC (or OAI). OAC doesn't support origin redirect by using Lambda@Edge.
If you use an Amazon S3 Multi-Region Access Point as your CloudFront origin, see [Restrict access to an Amazon S3 Multi-Region Access Point origin](private-content-restricting-access-to-s3-mrap.md). S3 Multi-Region Access Points require a different OAC configuration.

The following topics describe how to use OAC with an Amazon S3 origin. 

**Topics**
+ [Create a new origin access control](#create-oac-overview-s3)
+ [Delete a distribution with an OAC attached to an S3 bucket](#delete-oac-distribution-s3)
+ [Migrating from origin access identity (OAI) to origin access control (OAC)](#migrate-from-oai-to-oac)
+ [Advanced settings for origin access control](#oac-advanced-settings-s3)

## Create a new origin access control
<a name="create-oac-overview-s3"></a>

Complete the steps described in the following topics to set up a new origin access control in CloudFront.

**Topics**
+ [Prerequisites](#oac-prerequisites-s3)
+ [Grant CloudFront permission to access the S3 bucket](#oac-permission-to-access-s3)
+ [Create the origin access control](#create-oac-s3)

### Prerequisites
<a name="oac-prerequisites-s3"></a>

Before you create and set up origin access control (OAC), you must have a CloudFront distribution with an Amazon S3 bucket origin. This origin must be a regular S3 bucket, not a bucket configured as a [website endpoint](https://docs.aws.amazon.com/AmazonS3/latest/userguide/WebsiteEndpoints.html). For more information about setting up a CloudFront distribution with an S3 bucket origin, see [Get started with a CloudFront standard distribution](GettingStarted.SimpleDistribution.md).

**Important**  
When you use OAC to secure your Amazon S3 origin, communication between CloudFront and Amazon S3 is *always* through HTTPS, but only when you choose to *always sign requests*. You must choose **Sign requests (recommended)** in the console or specify `always` in the CloudFront API, AWS CLI, or CloudFormation.   
If you choose either the **Do not sign requests** or **Do not override authorization header** option instead, CloudFront uses the connection protocol that you specified in the following policies:  
[Viewer protocol policy](using-https-viewers-to-cloudfront.md) 
[Origin protocol policy](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy) (custom origins only)
For example, if you choose **Do not override authorization header** and want to use HTTPS between CloudFront and your Amazon S3 origin, use **Redirect HTTP to HTTPS** or **HTTPS only** for the [viewer protocol policy](using-https-viewers-to-cloudfront.md).

### Grant CloudFront permission to access the S3 bucket
<a name="oac-permission-to-access-s3"></a>

Before you create an origin access control (OAC) or set it up in a CloudFront distribution, make sure that CloudFront has permission to access the S3 bucket origin. Do this after creating a CloudFront distribution, but before adding the OAC to the S3 origin in the distribution configuration.

Use an S3 [bucket policy](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html) to allow the CloudFront service principal (`cloudfront.amazonaws.com`) to access the bucket. Use a `Condition` element in the policy to allow CloudFront to access the bucket only when the request is on behalf of the CloudFront distribution that contains the S3 origin. This is the distribution with the S3 origin that you want to add OAC to.

For information about adding or modifying a bucket policy, see [Adding a bucket policy using the Amazon S3 console](https://docs.aws.amazon.com/AmazonS3/latest/userguide/add-bucket-policy.html) in the *Amazon S3 User Guide*.

The following are examples of S3 bucket policies that allow a CloudFront distribution with OAC enabled access to an S3 origin.

**Example S3 bucket policy that allows read-only access for a CloudFront distribution with OAC enabled**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipalReadOnly",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
        }
      }
    }
  ]
}
```

**Example S3 bucket policy that allows read and write access for a CloudFront distribution with OAC enabled**    
****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Sid": "AllowCloudFrontServicePrincipalReadWrite",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront-distribution-ID>"
        }
      }
    }
  ]
}
```

#### SSE-KMS
<a name="oac-permissions-sse-kms"></a>

If the objects in the S3 bucket origin are encrypted using [server-side encryption with AWS Key Management Service (SSE-KMS)](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html), you must make sure that the CloudFront distribution has permission to use the AWS KMS key. To give the CloudFront distribution permission to use the KMS key, add a statement to the [KMS key policy](https://docs.aws.amazon.com/kms/latest/developerguide/key-policies.html). For information about how to modify a key policy, see [Changing a key policy](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-modifying.html) in the *AWS Key Management Service Developer Guide*.

**Example KMS key policy statement**  
The following example shows a AWS KMS policy statement that allows the CloudFront distribution with OAC to access a KMS key for SSE-KMS.  

```
{
    "Sid": "AllowCloudFrontServicePrincipalSSE-KMS",
    "Effect": "Allow",
    "Principal": {
        "Service": [
            "cloudfront.amazonaws.com"
        ]
     },
    "Action": [
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:GenerateDataKey*"
    ],
    "Resource": "*",
    "Condition": {
            "StringEquals": {
                "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
            }
        }
}
```

### Create the origin access control
<a name="create-oac-s3"></a>

To create an origin access control (OAC), you can use the AWS Management Console, CloudFormation, the AWS CLI, or the CloudFront API.

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

**To create an origin access control**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Origin access**.

1. Choose **Create control setting**.

1. On the **Create control setting** form, do the following:

   1. In the **Details** pane, enter a **Name** and (optionally) a **Description** for the origin access control.

   1. In the **Settings** pane, we recommend that you leave the default setting (**Sign requests (recommended)**). For more information, see [Advanced settings for origin access control](#oac-advanced-settings-s3).

1. Choose S3 from the **Origin type** dropdown.

1. Choose **Create**.

   After the OAC is created, make note of the **Name**. You need this in the following procedure.

**To add an origin access control to an S3 origin in a distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose a distribution with an S3 origin that you want to add the OAC to, then choose the **Origins** tab.

1. Select the S3 origin that you want to add the OAC to, then choose **Edit**.

1. For **Origin access**, choose **Origin access control settings (recommended)**.

1. From the **Origin access control** dropdown menu, choose the OAC that you want to use.

1. Choose **Save changes**.

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the S3 bucket origin.

------
#### [ CloudFormation ]

To create an origin access control (OAC) with CloudFormation, use the `AWS::CloudFront::OriginAccessControl` resource type. The following example shows the CloudFormation template syntax, in YAML format, for creating an origin access control.

```
Type: AWS::CloudFront::OriginAccessControl
Properties: 
  OriginAccessControlConfig: 
      Description: An optional description for the origin access control
      Name: ExampleOAC
      OriginAccessControlOriginType: s3
      SigningBehavior: always
      SigningProtocol: sigv4
```

For more information, see [AWS::CloudFront::OriginAccessControl](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cloudfront-originaccesscontrol.html) in the *AWS CloudFormation User Guide*.

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

To create an origin access control with the AWS Command Line Interface (AWS CLI), use the **aws cloudfront create-origin-access-control** command. You can use an input file to provide the input parameters for the command, rather than specifying each individual parameter as command line input.

**To create an origin access control (CLI with input file)**

1. Use the following command to create a file that's named `origin-access-control.yaml`. This file contains all of the input parameters for the **create-origin-access-control** command.

   ```
   aws cloudfront create-origin-access-control --generate-cli-skeleton yaml-input > origin-access-control.yaml
   ```

1. Open the `origin-access-control.yaml` file that you just created. Edit the file to add a name for the OAC, a description (optional), and change the `SigningBehavior` to `always`. Then save the file.

   For information about other OAC settings, see [Advanced settings for origin access control](#oac-advanced-settings-s3).

1. Use the following command to create the origin access control using the input parameters from the `origin-access-control.yaml` file.

   ```
   aws cloudfront create-origin-access-control --cli-input-yaml file://origin-access-control.yaml
   ```

   Make note of the `Id` value in the command output. You need it to add the OAC to an S3 bucket origin in a CloudFront distribution.

**To attach an OAC to an S3 bucket origin in an existing distribution (CLI with input file)**

1. Use the following command to save the distribution configuration for the CloudFront distribution that you want to add the OAC to. The distribution must have an S3 bucket origin.

   ```
   aws cloudfront get-distribution-config --id <CloudFront distribution ID> --output yaml > dist-config.yaml
   ```

1. Open the file that's named `dist-config.yaml` that you just created. Edit the file, making the following changes:
   + In the `Origins` object, add the OAC's ID to the field that's named `OriginAccessControlId`.
   + Remove the value from the field that's named `OriginAccessIdentity`, if one exists.
   + Rename the `ETag` field to `IfMatch`, but don't change the field's value.

   Save the file when finished.

1. Use the following command to update the distribution to use the origin access control.

   ```
   aws cloudfront update-distribution --id <CloudFront distribution ID> --cli-input-yaml file://dist-config.yaml
   ```

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the S3 bucket origin.

------
#### [ API ]

To create an origin access control with the CloudFront API, use [CreateOriginAccessControl](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateOriginAccessControl.html). For more information about the fields that you specify in this API call, see the API reference documentation for your AWS SDK or other API client.

After you create an origin access control you can attach it to an S3 bucket origin in a distribution, using one of the following API calls:
+ To attach it to an existing distribution, use [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html).
+ To attach it to a new distribution, use [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html).

For both of these API calls, provide the origin access control ID in the `OriginAccessControlId` field, inside an origin. For more information about the other fields that you specify in these API calls, see [All distribution settings reference](distribution-web-values-specify.md) and the API reference documentation for your AWS SDK or other API client.

------

## Delete a distribution with an OAC attached to an S3 bucket
<a name="delete-oac-distribution-s3"></a>

If you need to delete a distribution with an OAC attached to an S3 bucket, you should delete the distribution before you delete the S3 bucket origin. Alternatively, include the Region in the origin domain name. If this isn't possible, you can remove the OAC from the distribution by switching to public before deletion. For more information, see [Delete a distribution](HowToDeleteDistribution.md).

## Migrating from origin access identity (OAI) to origin access control (OAC)
<a name="migrate-from-oai-to-oac"></a>

To migrate from a legacy origin access identity (OAI) to an origin access control (OAC), first update the S3 bucket origin to allow both the OAI and the distribution with OAC enabled to access the bucket's content. This makes sure that CloudFront never loses access to the bucket during the transition. To allow both OAI and the distribution with OAC enabled to access an S3 bucket, update the [bucket policy](https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-policies.html) to include two statements, one for each kind of principal.

The following example S3 bucket policy allows both an OAI and a distribution with OAC enabled to access an S3 origin.

**Example S3 bucket policy that allows read-only access for an OAI and a CloudFront distribution with OAC enabled**    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipalReadOnly",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::111122223333:distribution/<CloudFront distribution ID>"
                }
            }
        },
        {
            "Sid": "AllowLegacyOAIReadOnly",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*"
        }
    ]
}
```

After you update the S3 origin's bucket policy to allow access to both OAI and OAC, you can update the distribution configuration to use OAC instead of OAI. For more information, see [Create a new origin access control](#create-oac-overview-s3).

After the distribution is fully deployed, you can remove the statement in the bucket policy that allows access to the OAI. For more information, see [Grant CloudFront permission to access the S3 bucket](#oac-permission-to-access-s3).

## Advanced settings for origin access control
<a name="oac-advanced-settings-s3"></a>

The CloudFront origin access control feature includes advanced settings that are intended only for specific use cases. Use the recommended settings unless you have a specific need for the advanced settings.

Origin access control contains a setting named **Signing behavior** (in the console), or `SigningBehavior` (in the API, CLI, and CloudFormation). This setting provides the following options:

**Always sign origin requests (recommended setting)**  
We recommend using this setting, named **Sign requests (recommended)** in the console, or `always` in the API, CLI, and CloudFormation. With this setting, CloudFront always signs all requests that it sends to the S3 bucket origin.

**Never sign origin requests**  
This setting is named **Do not sign requests** in the console, or `never` in the API, CLI, and CloudFormation. Use this setting to turn off origin access control for all origins in all distributions that use this origin access control. This can save time and effort compared to removing an origin access control from all origins and distributions that use it, one by one. With this setting, CloudFront does not sign any requests that it sends to the S3 bucket origin.  
To use this setting, the S3 bucket origin must be publicly accessible. If you use this setting with an S3 bucket origin that's not publicly accessible, CloudFront cannot access the origin. The S3 bucket origin returns errors to CloudFront and CloudFront passes those errors on to viewers.

**Don't override the viewer (client) `Authorization` header**  
This setting is named **Do not override authorization header** in the console, or `no-override` in the API, CLI, and CloudFormation. Use this setting when you want CloudFront to sign origin requests only when the corresponding viewer request does not include an `Authorization` header. With this setting, CloudFront passes on the `Authorization` header from the viewer request when one is present, but signs the origin request (adding its own `Authorization` header) when the viewer request doesn't include an `Authorization` header.  
To pass along the `Authorization` header from the viewer request, you *must* add the `Authorization` header to a [cache policy](controlling-the-cache-key.md) for all cache behaviors that use S3 bucket origins associated with this origin access control.

## Use an origin access identity (legacy, not recommended)
<a name="private-content-restricting-access-to-s3-oai"></a>

### Overview of origin access identity
<a name="private-content-restricting-access-to-s3-overview"></a>

CloudFront *origin access identity* (OAI) provides similar functionality as *origin access control* (OAC), but it doesn't work for all scenarios. Specifically, OAI doesn't support:
+ Amazon S3 buckets in all AWS Regions, including opt-in Regions
+ Amazon S3 [server-side encryption with AWS KMS](https://docs.aws.amazon.com/AmazonS3/latest/userguide/serv-side-encryption.html) (SSE-KMS)
+ Dynamic requests (`PUT`, `POST`, or `DELETE`) to Amazon S3
+ New AWS Regions launched after January 2023

**Tip**  
We recommend that you use OAC instead. To set up OAC, see [Create a new origin access control](#create-oac-overview-s3). For information about how to migrate from OAI to OAC, see [Migrating from origin access identity (OAI) to origin access control (OAC)](#migrate-from-oai-to-oac).

### Give an origin access identity permission to read files in the Amazon S3 bucket
<a name="private-content-granting-permissions-to-oai"></a>

When you create an OAI or add one to a distribution with the CloudFront console, you can automatically update the Amazon S3 bucket policy to give the OAI permission to access your bucket. Alternatively, you can choose to manually create or update the bucket policy. Whichever method you use, you should still review the permissions to make sure that:
+ Your CloudFront OAI can access files in the bucket on behalf of viewers who are requesting them through CloudFront.
+ Viewers can't use Amazon S3 URLs to access your files outside of CloudFront.

**Important**  
If you configure CloudFront to accept and forward all of the HTTP methods that CloudFront supports, make sure you give your CloudFront OAI the desired permissions. For example, if you configure CloudFront to accept and forward requests that use the `DELETE` method, configure your bucket policy to handle `DELETE` requests appropriately so viewers can delete only files that you want them to.

#### Use Amazon S3 bucket policies
<a name="private-content-updating-s3-bucket-policies"></a>

You can give a CloudFront OAI access to files in an Amazon S3 bucket by creating or updating the bucket policy in the following ways:
+ Using the Amazon S3 bucket's **Permissions** tab in the [Amazon S3 console](https://console.aws.amazon.com/s3/home).
+ Using [PutBucketPolicy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketPolicy.html) in the Amazon S3 API.
+ Using the [CloudFront console](https://console.aws.amazon.com/cloudfront/v4/home). When you add an OAI to your origin settings in the CloudFront console, you can choose **Yes, update the bucket policy** to tell CloudFront to update the bucket policy on your behalf.

If you update the bucket policy manually, make sure that you:
+ Specify the correct OAI as the `Principal` in the policy.
+ Give the OAI the permissions it needs to access objects on behalf of viewers.

For more information, see the following sections.

##### Specify an OAI as the `Principal` in a bucket policy
<a name="private-content-updating-s3-bucket-policies-principal"></a>

To specify an OAI as the `Principal` in an Amazon S3 bucket policy, use the OAI's Amazon Resource Name (ARN), which includes the OAI's ID. For example:

```
"Principal": {
    "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
}
```

Find the OAI ID in the CloudFront console under **Security**, **Origin access**, **Identities (legacy)**. Alternatively, use [ListCloudFrontOriginAccessIdentities](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListCloudFrontOriginAccessIdentities.html) in the CloudFront API.

##### Give permissions to an OAI
<a name="private-content-updating-s3-bucket-policies-permissions"></a>

To give the OAI the permissions to access objects in your Amazon S3 bucket, use actions in the policy that relate to specific Amazon S3 API operations. For example, the `s3:GetObject` action allows the OAI to read objects in the bucket. For more information, see the examples in the following section, or see [Amazon S3 actions](https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html) in the *Amazon Simple Storage Service User Guide*.

##### Amazon S3 bucket policy examples
<a name="private-content-updating-s3-bucket-policies-examples"></a>

The following examples show Amazon S3 bucket policies that allow CloudFront OAI to access an S3 bucket.

Find the OAI ID in the CloudFront console under **Security**, **Origin access**, **Identities (legacy)**. Alternatively, use [ListCloudFrontOriginAccessIdentities](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListCloudFrontOriginAccessIdentities.html) in the CloudFront API.

**Example Amazon S3 bucket policy that gives the OAI read access**  
The following example allows the OAI to read objects in the specified bucket (`s3:GetObject`).    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<S3 bucket name>/*"
        }
    ]
}
```

**Example Amazon S3 bucket policy that gives the OAI read and write access**  
The following example allows the OAI to read and write objects in the specified bucket (`s3:GetObject` and `s3:PutObject`). This allows viewers to upload files to your Amazon S3 bucket through CloudFront.    
****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <origin access identity ID>"
            },
            "Action": [
                "s3:GetObject",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::<S3 bucket name>/*"
        }
    ]
}
```

#### Use Amazon S3 object ACLs (not recommended)
<a name="private-content-updating-s3-acls"></a>

**Important**  
We recommend [using Amazon S3 bucket policies](#private-content-updating-s3-bucket-policies) to give an OAI access to an S3 bucket. You can use access control lists (ACLs) as described in this section, but we don't recommend it.  
Amazon S3 recommends setting [S3 Object Ownership](https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html) to **bucket owner enforced**, which means that ACLs are disabled for the bucket and the objects in it. When you apply this setting for Object Ownership, you must use bucket policies to give access to the OAI (see the previous section).  
This following section is only for legacy use cases that require ACLs.

You can give a CloudFront OAI access to files in an Amazon S3 bucket by creating or updating the file's ACL in the following ways:
+ Using the Amazon S3 object's **Permissions** tab in the [Amazon S3 console](https://console.aws.amazon.com/s3/home).
+ Using [PutObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html) in the Amazon S3 API.

When you grant access to an OAI using an ACL, you must specify the OAI using its Amazon S3 canonical user ID. In the CloudFront console, you can find this ID under **Security**, **Origin access**, **Identities (legacy)**. If you're using the CloudFront API, use the value of the `S3CanonicalUserId` element that was returned when you created the OAI, or call [ListCloudFrontOriginAccessIdentities](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ListCloudFrontOriginAccessIdentities.html) in the CloudFront API.

### Use an origin access identity in Amazon S3 regions that support only signature version 4 authentication
<a name="private-content-origin-access-identity-signature-version-4"></a>

Newer Amazon S3 Regions require that you use Signature Version 4 for authenticated requests. (For the signature versions supported in each Amazon S3 Region, see [Amazon Simple Storage Service endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/s3.html) in the *AWS General Reference*.) If you're using an origin access identity and if your bucket is in one of the Regions that requires Signature Version 4, note the following:
+ `DELETE`, `GET`, `HEAD`, `OPTIONS`, and `PATCH` requests are supported without qualifications.
+ `POST` requests are not supported.

# Restrict access with VPC origins
<a name="private-content-vpc-origins"></a>

You can use CloudFront to deliver content from applications that are hosted in your virtual private cloud (VPC) private subnets. You can use Application Load Balancers (ALBs), Network Load Balancers (NLBs), and EC2 instances in private subnets as VPC origins.

Here are some reasons why you might want to use VPC origins:
+ **Security** – VPC origins is designed to enhance the security posture of your application by placing your load balancers and EC2 instances in private subnets, making CloudFront the single point of entry. User requests go from CloudFront to the VPC origins over a private, secure connection, providing additional security for your applications.
+ **Management** – VPC origins reduces the operational overhead required for secure connectivity between CloudFront and origins. You can move your origins to private subnets with no public access, and you don’t have to implement access control lists (ACLs) or other mechanisms to restrict access to your origins. This way, you don't have to invest in undifferentiated development work to secure your web applications with CloudFront. 
+ **Scalability and performance** – VPC origins helps you to secure your web applications, freeing up time to focus on growing your critical business applications while improving security and maintaining high performance and global scalability with CloudFront. VPC origins streamlines security management and reduces operational complexity so that you can use CloudFront as the single point of entry for your applications.

**Tip**  
CloudFront supports sharing VPC origins across AWS accounts, whether they're in your organization or not. You can share VPC origins from the CloudFront console or use AWS Resource Access Manager (AWS RAM). For more information, see [Working with shared resources in CloudFront](sharing-resources.md).

## Prerequisites
<a name="vpc-origin-prerequisites"></a>

Before you create a VPC origin for your CloudFront distribution, you must complete the following:

### VPC Configuration
<a name="vpc-configuration"></a>

**Create a virtual private cloud (VPC) on Amazon VPC** in one of the AWS Regions that are supported for VPC origins. For information about creating a VPC, see [Create a VPC plus other VPC resources](https://docs.aws.amazon.com/vpc/latest/userguide/create-vpc.html#create-vpc-and-other-resources) in the *Amazon VPC User Guide*. For a list of supported Regions, see [Supported AWS Regions for VPC origins](#vpc-origins-supported-regions).

Your VPC must include the following:
+ **Internet gateway** – You need to add an internet gateway to the VPC that has your VPC origin resources. The internet gateway is required to denote that the VPC can receive traffic from the internet. The internet gateway is not used for routing traffic to origins inside the subnet, and you don't need to update the routing policies.
+ **Private subnet with at least one available IPv4 address** – CloudFront routes to your subnet by using a service-managed elastic network interface (ENI) that CloudFront creates after you define your VPC origin resource with CloudFront. You must have at least one available IPv4 address in your private subnet so that the ENI creation process can succeed. The IPv4 address can be private, and there is no additional cost for it. IPv6-only subnets are not supported.

### Origin Resources
<a name="origin-resources"></a>

In the private subnet, launch an Application Load Balancer, a Network Load Balancer, or an EC2 instance to use as your origin. The resource you launch must be fully deployed and in Active status before you can use it for a VPC origin.

**Origin restrictions:**
+ Gateway Load Balancers cannot be added as origins
+ Dual-stack Network Load Balancers cannot be added as origins
+ Network Load Balancers with TLS listeners cannot be added as origins
+ To be used as a VPC origin, a Network Load Balancer must have a security group attached to it

### Security Group Configuration
<a name="security-group-configuration"></a>

Your VPC origin resources (Application Load Balancer, Network Load Balancer, or EC2 instance) must have a security group attached. When you create a VPC origin, CloudFront automatically creates a service-managed security group with the naming pattern `CloudFront-VPCOrigins-Service-SG`. This security group is fully managed by AWS, and should not be edited.

To allow traffic from CloudFront to reach your VPC origin, update the security group attached to your origin resource (ALB, NLB, or EC2 instance) to allow inbound traffic using one of the following methods:
+ **Option 1:** Allow traffic from the CloudFront managed prefix list. For more information, see [Use the CloudFront managed prefix list](LocationsOfEdgeServers.md#managed-prefix-list). This can be done before VPC origin created as well.
+ **Option 2:** Allow traffic from the CloudFront service-managed security group (`CloudFront-VPCOrigins-Service-SG`). This can be done only after the VPC origin is created and the service-managed security group is created. This configuration is further restrictive as it restricts the traffic only to your CloudFront distributions.

**Important**  
Do not create your own security group with a name starting with `CloudFront-VPCOrigins-Service-SG`. This is an AWS reserved naming pattern for service-managed security groups. For more information, see [Creating a security group](https://docs.aws.amazon.com/vpc/latest/userguide/creating-security-groups.html).

### Protocol and Feature Restrictions
<a name="protocol-feature-restrictions"></a>

VPC origins do not support the following:
+ WebSockets
+ gRPC traffic
+ Origin request and origin response triggers with Lambda@Edge

## Create a VPC origin (new distribution)
<a name="new-vpc-origin"></a>

The following procedure shows you how to create a VPC origin for your new CloudFront distribution in the CloudFront console. Alternatively, you can use the [CreateVpcOrigin](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateVpcOrigin.html) and [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html) API operations with the AWS CLI or an AWS SDK.

**To create a VPC origin for a new CloudFront distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose **VPC origins**, **Create VPC origin**.

1. Fill out the required fields. For **Origin ARN**, select the ARN of your Application Load Balancer, Network Load Balancer, or EC2 instance. If you don’t see the ARN, you can copy your specific resource ARN and paste it here instead.

1. Choose **Create VPC origin**.

1. Wait for your VPC origin status to change to **Deployed**. This can take up to 15 minutes.

1. Choose **Distributions**, **Create distribution**.

1. For **Origin domain**, select your VPC origins resource from the dropdown list.

   If your VPC origin is an EC2 instance, copy and paste the **Private IP DNS name** of the instance into the **Origin domain** field.

1. Finish creating your distribution. For more information, see [Create a CloudFront distribution in the console](distribution-web-creating-console.md#create-console-distribution).

## Create a VPC origin (existing distribution)
<a name="existing-vpc-origin"></a>

The following procedure shows you how to create a VPC origin for your existing CloudFront distribution in the CloudFront console, which helps to ensure continuous availability of your applications. Alternatively, you can use the [CreateVpcOrigin](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateVpcOrigin.html) and [UpdateDistributionWithStagingConfig](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistributionWithStagingConfig.html) API operations with the AWS CLI or an AWS SDK.

Optionally, you could choose to add your VPC origin to your existing distribution without creating a staging distribution.

**To create a VPC origin for your existing CloudFront distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose **VPC origins**, **Create VPC origin**.

1. Fill out the required fields. For **Origin ARN**, select the ARN of your Application Load Balancer, Network Load Balancer, or EC2 instance. If you don’t see the ARN, you can copy your specific resource ARN and paste it here instead.

1. Choose **Create VPC origin**.

1. Wait for your VPC origin status to change to **Deployed**. This can take up to 15 minutes.

1. In the navigation pane, choose **Distributions**.

1. Choose the ID of your distribution.

1. On the **General** tab, under **Continuous deployment**, choose **Create staging distribution**. For more information, see [Use CloudFront continuous deployment to safely test CDN configuration changes](continuous-deployment.md).

1. Follow the steps in the **Create staging distribution** wizard to create a staging distribution. Include the following steps:
   + For **Origins**, choose **Create origin**.
   + For **Origin domain**, select your VPC origins resource from the dropdown menu.

     If your VPC origin is an EC2 instance, copy and paste the **Private IP DNS name** of the instance into the **Origin domain** field.
   + Choose **Create origin**.

1. In your staging distribution, test the VPC origin.

1. Promote the staging distribution configuration to your primary distribution. For more information, see [Promote a staging distribution configuration](working-with-staging-distribution-continuous-deployment-policy.md#promote-staging-distribution-configuration).

1. Remove public access to your VPC origin by making the subnet private. After you do this, the VPC origin won't be discoverable over the internet, but CloudFront will still have private access to it. For more information, see [Associate or disassociate a subnet with a route table](https://docs.aws.amazon.com/vpc/latest/userguide/WorkWithRouteTables.html#AssociateSubnet) in the *Amazon VPC User Guide*.

## Update a VPC origin
<a name="update-vpc-origin"></a>

The following procedure shows you how to update a VPC origin for your CloudFront distribution in the CloudFront console. Alternatively, you can use the [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html) and [UpdateVpcOrigin](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateVpcOrigin.html) API operations with the AWS CLI or an AWS SDK.

**To update an existing VPC origin for your CloudFront distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Distributions**.

1. Choose the ID of your distribution.

1. Choose the **Behaviors** tab.

1. Make sure that the VPC origin is not the default origin for your cache behavior. 

1. Choose the **Origins** tab.

1. Select the VPC origin that you're going to update and choose **Delete**. This disassociates the VPC origin from your distribution. Repeat steps 2-7 to disassociate the VPC origin from any other distributions.

1. Choose **VPC origins**.

1. Select the VPC origin and choose **Edit**.

1. Make your updates and choose **Update VPC origin**.

1. Wait for your VPC origin status to change to **Deployed**. This can take up to 15 minutes.

1. In the navigation pane, choose **Distributions**.

1. Choose the ID of your distribution.

1. Choose the **Origins** tab.

1. Choose **Create origin**.

1. For **Origin domain**, select your VPC origins resource from the dropdown menu.

   If your VPC origin is an EC2 instance, copy and paste the **Private IP DNS name** of the instance into the **Origin domain** field.

1. Choose **Create origin**. This associates the VPC origin with your distribution again. Repeat steps 12-17 to associate the updated VPC origin with any other distributions.

## Supported AWS Regions for VPC origins
<a name="vpc-origins-supported-regions"></a>

VPC origins are currently supported in the following commercial AWS Regions. Availability Zone (AZ) exceptions are noted.

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-vpc-origins.html)

# Restrict access to an Amazon S3 Multi-Region Access Point origin
<a name="private-content-restricting-access-to-s3-mrap"></a>

You can use origin access control (OAC) to restrict access to an Amazon S3 Multi-Region Access Point origin. S3 Multi-Region Access Points provide a global endpoint that routes requests to the closest S3 bucket based on network latency.

For information about using OAC with a standard Amazon S3 bucket origin, see [Restrict access to an Amazon S3 origin](private-content-restricting-access-to-s3.md).

## Prerequisites
<a name="oac-prerequisites-s3-mrap"></a>

Before you create and set up OAC, you must have a CloudFront distribution with an Amazon S3 Multi-Region Access Point origin. The origin domain name must use the S3 Multi-Region Access Point hostname format:

`multi-region-access-point-alias.accesspoint.s3-global.amazonaws.com`

For more information about creating an S3 Multi-Region Access Point, see [Creating Multi-Region Access Points](https://docs.aws.amazon.com/AmazonS3/latest/userguide/CreatingMultiRegionAccessPoints.html) in the *Amazon Simple Storage Service User Guide*.

## Grant CloudFront permission to access the S3 Multi-Region Access Point
<a name="oac-permission-to-access-s3-mrap"></a>

Update the Multi-Region Access Point policy to allow the CloudFront service principal (`cloudfront.amazonaws.com`) to access the Multi-Region Access Point. Use a `Condition` element in the policy to allow CloudFront to access the Multi-Region Access Point only when the request is on behalf of the CloudFront distribution that contains the origin.

For information about adding or modifying a Multi-Region Access Point policy, see [Multi-Region Access Point policy examples](https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiRegionAccessPointPermissions.html) in the *Amazon Simple Storage Service User Guide*.

**Example Multi-Region Access Point policy for CloudFront OAC**  

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowCloudFrontOACAccess",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3::111122223333:accesspoint/Multi-Region-Access-Point-Alias.mrap/object/*",
            "Condition": {
                "StringEquals": {
                    "aws:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront distribution ID"
                }
            }
        }
    ]
}
```

## Grant CloudFront permission to access the underlying S3 buckets
<a name="oac-permission-to-access-s3-mrap-buckets"></a>

In addition to the Multi-Region Access Point policy, you must also grant CloudFront permission to access each of the underlying S3 buckets that are associated with the Multi-Region Access Point. You can do this in one of two ways:

### Option 1: Grant access only to CloudFront
<a name="oac-s3-mrap-bucket-option1"></a>

Add a bucket policy to each S3 bucket that allows the CloudFront service principal to access the bucket. Use this option when you also need to allow direct access to the bucket from other sources.

**Example S3 bucket policy for an underlying bucket**  

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowCloudFrontOACAccessViaMRAP",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::amzn-s3-demo-bucket-us-east-1/*",
            "Condition": {
                "StringEquals": {
                    "aws:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront distribution ID"
                }
            }
        }
    ]
}
```

### Option 2: Delegate full bucket access to the Multi-Region Access Point
<a name="oac-s3-mrap-bucket-option2"></a>

Grant the Multi-Region Access Point full access to each underlying bucket. With this approach, all access to the bucket is controlled by the Multi-Region Access Point policy, which simplifies access management. We recommend this option for use cases that don't require direct access to the bucket.

**Example S3 bucket policy that delegates access to the Multi-Region Access Point**  

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "DelegateAccessToMRAP",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::amzn-s3-demo-bucket-us-east-1",
                "arn:aws:s3:::amzn-s3-demo-bucket-us-east-1/*"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:DataAccessPointArn": "arn:aws:s3::111122223333:accesspoint/Multi-Region-Access-Point-Alias.mrap"
                }
            }
        }
    ]
}
```

For more information, see [Multi-Region Access Point policy example](https://docs.aws.amazon.com/AmazonS3/latest/userguide/MultiRegionAccessPointPermissions.html#MultiRegionAccessPointPolicyExamples) in the *Amazon Simple Storage Service User Guide*.

**Important**  
You must add this bucket policy to every S3 bucket that is associated with the Multi-Region Access Point. If any bucket is missing the policy, CloudFront requests routed to that bucket will be denied.

### SSE-KMS
<a name="oac-s3-mrap-sse-kms"></a>

If the objects in the underlying S3 buckets are encrypted using server-side encryption with AWS KMS (SSE-KMS), you must make sure that the CloudFront distribution has permission to use the AWS KMS key. Because S3 Multi-Region Access Points can route requests to buckets in multiple Regions, you must add a statement to the KMS key policy in each Region where an underlying bucket uses SSE-KMS. For information about how to modify a key policy, see [Changing a key policy](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-modifying.html) in the *AWS Key Management Service Developer Guide*.

**Example KMS key policy statement**  
The following example shows a KMS key policy statement that allows the CloudFront distribution with OAC to access a KMS key for SSE-KMS.  

```
{
    "Sid": "AllowCloudFrontServicePrincipalSSE-KMS",
    "Effect": "Allow",
    "Principal": {
        "Service": "cloudfront.amazonaws.com"
    },
    "Action": [
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:GenerateDataKey*"
    ],
    "Resource": "*",
    "Condition": {
        "StringEquals": {
            "aws:SourceArn": "arn:aws:cloudfront::111122223333:distribution/CloudFront distribution ID"
        }
    }
}
```

**Important**  
You must add this key policy statement to the KMS key in every Region where an underlying S3 bucket uses SSE-KMS encryption.

## Create the origin access control
<a name="create-oac-s3-mrap"></a>

To create an origin access control (OAC), you can use the AWS Management Console, CloudFormation, the AWS CLI, or the CloudFront API.

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

**To create an origin access control**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Origin access**.

1. Choose **Create control setting**.

1. On the **Create control setting** form, do the following:

   1. In the **Details** pane, enter a **Name** and (optionally) a **Description** for the origin access control.

   1. In the **Settings** pane, we recommend that you leave the default setting (**Sign requests (recommended)**). For more information, see [Advanced settings for origin access control](private-content-restricting-access-to-s3.md#oac-advanced-settings-s3).

1. Choose **S3 Multi-Region Access Point** from the **Origin type** dropdown.

1. Choose **Create**.

   After the OAC is created, make note of the **Name**. You need this in the following procedure.

**To add an origin access control to an S3 Multi-Region Access Point origin in a distribution**

1. Open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. Choose a distribution with an S3 Multi-Region Access Point origin that you want to add the OAC to, then choose the **Origins** tab.

1. Select the S3 Multi-Region Access Point origin that you want to add the OAC to, then choose **Edit**.

1. For **Origin access**, choose **Origin access control settings (recommended)**.

1. From the **Origin access control** dropdown menu, choose the OAC that you want to use.

1. Choose **Save changes**.

The distribution starts deploying to all of the CloudFront edge locations. When an edge location receives the new configuration, it signs all requests that it sends to the S3 Multi-Region Access Point origin.

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

Use the **create-origin-access-control** command:

```
aws cloudfront create-origin-access-control \
    --origin-access-control-config '{
        "Name": "my-s3-mrap-oac",
        "Description": "OAC for S3 Multi-Region Access Point",
        "SigningProtocol": "sigv4a",
        "SigningBehavior": "always",
        "OriginAccessControlOriginType": "s3mrap"
    }'
```

------
#### [ CloudFormation ]

Specify the following values in the `OriginAccessControlConfig`:
+ `SigningProtocol`: `sigv4a`
+ `SigningBehavior`: `always`, `never`, or `no-override`
+ `OriginAccessControlOriginType`: `s3mrap`

**Example CloudFormation template**  

```
Type: AWS::CloudFront::OriginAccessControl
Properties:
  OriginAccessControlConfig:
    Description: An optional description for the origin access control
    Name: my-s3-mrap-oac
    OriginAccessControlOriginType: s3mrap
    SigningBehavior: always
    SigningProtocol: sigv4a
```

------

## Signing behavior
<a name="oac-signing-behavior-s3-mrap"></a>

The signing behavior options for S3 Multi-Region Access Point origins are the same as those for regular Amazon S3 bucket origins. For more information, see [Advanced settings for origin access control](private-content-restricting-access-to-s3.md#oac-advanced-settings-s3) in *Restrict access to an Amazon S3 origin*.

# Restrict access to Application Load Balancers
<a name="restrict-access-to-load-balancer"></a>

You can use both internal and internet-facing Application Load Balancers with Amazon CloudFront. You can use internal Application Load Balancers inside private subnets with CloudFront by using VPC origins. CloudFront VPC origins allow you to serve content from applications hosted in private VPC subnets without exposing them to the public internet. For more information, see [Restrict access with VPC origins](private-content-vpc-origins.md).

If you are using an internet-facing Application Load Balancer with CloudFront, you can use the following security mitigations to prevent users from directly accessing an Application Load Balancer, and allow access only through CloudFront.

1. Configure CloudFront to add a custom HTTP header to requests that it sends to the Application Load Balancer.

1. Configure the Application Load Balancer to only forward requests that contain the custom HTTP header.

1. Require HTTPS to improve the security of this solution.

CloudFront can also help to reduce latency and even absorb some distributed denial of service (DDoS) attacks.

If your use case requires dual access to web applications from both CloudFront and Application Load Balancer directly over the internet, consider splitting your web application APIs as follows:
+ APIs that must go through CloudFront. In this case, consider using a separate private Application Load Balancer as an origin.
+ APIs that require access through Application Load Balancer. In this case, you bypass CloudFront.

Alternatively, for a web application or other content that’s served by an internet-facing Application Load Balancer in Elastic Load Balancing, CloudFront can cache objects and serve them directly to users (viewers), reducing the load on your Application Load Balancer. An internet-facing load balancer has a publicly resolvable DNS name and routes requests from clients to targets over the internet.

For more information, see the following topics. After you complete these steps, users can only access your Application Load Balancer through CloudFront.

**Topics**
+ [Configure CloudFront to add a custom HTTP header to requests](#restrict-alb-add-custom-header)
+ [Configure an Application Load Balancer to only forward requests that contain a specific header](#restrict-alb-route-based-on-header)
+ [(Optional) Improve the security of this solution](#restrict-alb-improve-security)
+ [(Optional) Limit access to origin by using the AWS-managed prefix list for CloudFront](#limit-access-to-origin-using-aws-managed-prefixes)

## Configure CloudFront to add a custom HTTP header to requests
<a name="restrict-alb-add-custom-header"></a>

You can configure CloudFront to add a custom HTTP header to the requests that it sends to your origin (in this case, an Application Load Balancer).

**Important**  
This use case relies on keeping the custom header name and value secret. If the header name and value are not secret, other HTTP clients could potentially include them in requests that they send directly to the Application Load Balancer. This can cause the Application Load Balancer to behave as though the requests came from CloudFront when they did not. To prevent this, keep the custom header name and value secret.

You can configure CloudFront to add a custom HTTP header to origin requests with the CloudFront console, CloudFormation, or the CloudFront API.

**To add a custom HTTP header (CloudFront console)**  
In the CloudFront console, use the **Origin Custom Headers** setting in **Origin Settings**. Enter the **Header Name** and its **Value**.  
In production, use randomly generated header names and values. Treat header names and values as secure credentials, like usernames and passwords.
You can edit the **Origin Custom Headers** setting when you create or edit an origin for an existing CloudFront distribution, and when you create a new distribution. For more information, see [Update a distribution](HowToUpdateDistribution.md) and [Create a distribution](distribution-web-creating-console.md).

**To add a custom HTTP header (CloudFormation)**  
In an CloudFormation template, use the `OriginCustomHeaders` property, as shown in the following example.  
The header name and value in this example are just for demonstration. In production, use randomly generated values. Treat the header name and value as a secure credential, like a user name and password.

```
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  TestDistribution:
    Type: 'AWS::CloudFront::Distribution'
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: app-load-balancer.example.com
            Id: Example-ALB
            CustomOriginConfig:
              OriginProtocolPolicy: https-only
              OriginSSLProtocols:
                - TLSv1.2
            OriginCustomHeaders:
               - HeaderName: X-Custom-Header
                 HeaderValue: random-value-1234567890
        Enabled: 'true'
        DefaultCacheBehavior:
          TargetOriginId: Example-ALB
          ViewerProtocolPolicy: allow-all
          CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
        PriceClass: PriceClass_All
        ViewerCertificate:
          CloudFrontDefaultCertificate: 'true'
```
For more information, see the [Origin](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origin.html) and [OriginCustomHeader](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cloudfront-distribution-origincustomheader.html) properties in the *AWS CloudFormation User Guide*.

**To add a custom HTTP header (CloudFront API)**  
In the CloudFront API, use the `CustomHeaders` object inside `Origin`. For more information, see [CreateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_CreateDistribution.html) and [UpdateDistribution](https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_UpdateDistribution.html) in the *Amazon CloudFront API Reference*, and the documentation for your SDK or other API client.

There are some header names that you can’t specify as origin custom headers. For more information, see [Custom headers that CloudFront can’t add to origin requests](add-origin-custom-headers.md#add-origin-custom-headers-denylist).

## Configure an Application Load Balancer to only forward requests that contain a specific header
<a name="restrict-alb-route-based-on-header"></a>

After you configure CloudFront to add a custom HTTP header to the requests that it sends to your Application Load Balancer (see [the previous section](#restrict-alb-add-custom-header)), you can configure the load balancer to only forward requests that contain this custom header. You do this by adding a new rule and modifying the default rule in your load balancer’s listener.

**Prerequisites**  
To use the following procedures, you need an Application Load Balancer with at least one listener. If you haven’t created one yet, see [Create an Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-application-load-balancer.html) in the *User Guide for Application Load Balancers*.

The following procedures modify an HTTPS listener. You can use the same process to modify an HTTP listener.

**To update the rules in an Application Load Balancer listener**

1. Add a new rule. Use the instructions from [Add a rule](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-update-rules.html#add-rule), with the following modifications:
   + Add the rule to the load balancer that is the origin for your CloudFront distribution.
   + For **Add condition**, choose **Http header**. Specify the HTTP header name and value that you added as an origin custom header in CloudFront.
   + For **Add action**, choose **Forward to**. Choose the target group where you want to forward requests.

1. Edit the default rule in your load balancer's listener. Use the instructions from [Edit a rule](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/listener-update-rules.html#edit-rule), with the following modifications:
   + Edit the default rule of the load balancer that is the origin for your CloudFront distribution.
   + Delete the default action, and then for **Add action**, choose **Return fixed response**. 
   + For **Response code**, enter **403**.
   + For **Response body**, enter **Access denied**.

After you complete these steps, your load balancer listener has two rules. One rule forwards requests that contain the HTTP header (requests that come from CloudFront). The other rule sends a fixed response to all other requests (requests that don’t come from CloudFront).

You can verify that the solution works by sending a request to your CloudFront distribution and one to your Application Load Balancer. The request to CloudFront returns your web application or content, and the one sent directly to your Application Load Balancer returns a `403` response with the plain text message `Access denied`.

## (Optional) Improve the security of this solution
<a name="restrict-alb-improve-security"></a>

To improve the security of this solution, you can configure your CloudFront distribution to always use HTTPS when sending requests to your Application Load Balancer. Remember, this solution only works if you keep the custom header name and value secret. Using HTTPS can help prevent an eavesdropper from discovering the header name and value. We also recommend rotating the header name and value periodically.

**Use HTTPS for origin requests**  
To configure CloudFront to use HTTPS for origin requests, set the **Origin Protocol Policy** setting to **HTTPS Only**. This setting is available in the CloudFront console, CloudFormation, and the CloudFront API. For more information, see [Protocol (custom origins only)](DownloadDistValuesOrigin.md#DownloadDistValuesOriginProtocolPolicy).

The following also applies when you configure CloudFront to use HTTPS for origin requests:
+ You must configure CloudFront to forward the `Host` header to the origin with the origin request policy. You can use the [AllViewer managed origin request policy](using-managed-origin-request-policies.md#managed-origin-request-policy-all-viewer).
+ Make sure that your Application Load Balancer has an HTTPS listener (as shown in [the preceding section](#restrict-alb-route-based-on-header)). For more information, see [Create an HTTPS listener](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html) in the *User Guide for Application Load Balancers*. Using an HTTPS listener requires you to have an SSL/TLS certificate that matches the domain name that's routed to your Application Load Balancer.
+ SSL/TLS certificates for CloudFront can only be requested (or imported) in the `us-east-1` AWS Region in AWS Certificate Manager (ACM). Because CloudFront is a global service, it automatically distributes the certificate from the `us-east-1` Region to all Regions associated with your CloudFront distribution.
  + For example, if you have an Application Load Balancer (ALB) in the `ap-southeast-2` Region, you must configure SSL/TLS certificates in both the `ap-southeast-2` Region (for using HTTPS between CloudFront and the ALB origin) and the `us-east-1` Region (for using HTTPS between viewers and CloudFront). Both certificates should match the domain name that is routed to your Application Load Balancer. For more information, see [AWS Region for AWS Certificate Manager](cnames-and-https-requirements.md#https-requirements-aws-region).
+ If the end users (also known as *viewers*, or *clients*) of your web application can use HTTPS, you can also configure CloudFront to prefer (or even require) HTTPS connections from the end users. To do this, use the **Viewer Protocol Policy** setting. You can set it to redirect end users from HTTP to HTTPS, or to reject requests that use HTTP. This setting is available in the CloudFront console, CloudFormation, and the CloudFront API. For more information, see [Viewer protocol policy](DownloadDistValuesCacheBehavior.md#DownloadDistValuesViewerProtocolPolicy).

**Rotate the header name and value**  
In addition to using HTTPS, we also recommend rotating the header name and value periodically. The high-level steps for doing this are as follows:

1. Configure CloudFront to add an additional custom HTTP header to requests that it sends to the Application Load Balancer.

1. Update the Application Load Balancer listener rule to forward requests that contain this additional custom HTTP header.

1. Configure CloudFront to stop adding the original custom HTTP header to requests that it sends to the Application Load Balancer.

1. Update the Application Load Balancer listener rule to stop forwarding requests that contain the original custom HTTP header.

For more information about accomplishing these steps, see the preceding sections.

## (Optional) Limit access to origin by using the AWS-managed prefix list for CloudFront
<a name="limit-access-to-origin-using-aws-managed-prefixes"></a>

To further restrict access to your Application Load Balancer, you can configure the security group associated with the Application Load Balancer so that it only accept traffic from CloudFront when the service is using an AWS-managed prefix list. This prevents traffic that doesn't originate from CloudFront from reaching your Application Load Balancer at the network layer (layer 3) or transport layer (layer 4).

For more information, see the [Limit access to your origins using the AWS-managed prefix list for Amazon CloudFront](https://aws.amazon.com//blogs/networking-and-content-delivery/limit-access-to-your-origins-using-the-aws-managed-prefix-list-for-amazon-cloudfront/) blog post.

# Restrict the geographic distribution of your content
<a name="georestrictions"></a>

You can use *geographic restrictions*, sometimes known as *geo blocking*, to prevent users in specific geographic locations from accessing content that you're distributing through an Amazon CloudFront distribution. To use geographic restrictions, you have two options:
+ Use the CloudFront geographic restrictions feature. Use this option to restrict access to all of the files that are associated with a distribution and to restrict access at the country level.
+ Use a third-party geolocation service. Use this option to restrict access to a subset of the files that are associated with a distribution or to restrict access at a finer granularity than the country level.

**Topics**
+ [Use CloudFront geographic restrictions](#georestrictions-cloudfront)
+ [Use a third-party geolocation service](#georestrictions-geolocation-service)

## Use CloudFront geographic restrictions
<a name="georestrictions-cloudfront"></a>

When a user requests your content, CloudFront typically serves the requested content regardless of where the user is located. If you need to prevent users in specific countries from accessing your content, you can use the CloudFront geographic restrictions feature to do one of the following:
+ Grant permission to your users to access your content only if they’re in one of the approved countries on your allowlist.
+ Prevent your users from accessing your content if they’re in one of the banned countries on your denylist.

For example, if a request comes from a country where you are not authorized to distribute your content, you can use CloudFront geographic restrictions to block the request.

**Note**  
CloudFront determines the location of your users by using a third-party database. The accuracy of the mapping between IP addresses and countries varies by Region. Based on recent tests, the overall accuracy is 99.8%. If CloudFront can’t determine a user’s location, CloudFront serves the content that the user has requested.

Here’s how geographic restrictions work:

1. Suppose you have rights to distribute your content only in Liechtenstein. You update your CloudFront distribution to add an allowlist that contains only Liechtenstein. (Alternatively, you could add a denylist that contains every country except Liechtenstein.)

1. A user in Monaco requests your content, and DNS routes the request to a CloudFront edge location in Milan, Italy.

1. The edge location in Milan looks up your distribution and determines that the user in Monaco does not have permission to download your content.

1. CloudFront returns an HTTP status code `403 (Forbidden)` to the user.

You can optionally configure CloudFront to return a custom error message to the user, and you can specify how long you want CloudFront to cache the error response for the requested file. The default value is 10 seconds. For more information, see [Create a custom error page for specific HTTP status codes](creating-custom-error-pages.md).

Geographic restrictions apply to an entire distribution. If you need to apply one restriction to part of your content and a different restriction (or no restriction) to another part of your content, you must create separate CloudFront distributions or [use a third-party geolocation service](#georestrictions-geolocation-service).

If you enable CloudFront [standard logs](AccessLogs.md) (access logs), you can identify the requests that CloudFront rejected by searching for the log entries in which the value of `sc-status` (the HTTP status code) is `403`. However, using only the standard logs, you can’t distinguish a request that CloudFront rejected based on the location of the user from a request that CloudFront rejected because the user didn’t have permission to access the file for another reason. If you have a third-party geolocation service such as Digital Element or MaxMind, you can identify the location of requests based on the IP address in the `c-ip` (client IP) column in the access logs. For more information about CloudFront standard logs, see [Access logs (standard logs)](AccessLogs.md).

The following procedure explains how to use the CloudFront console to add geographic restrictions to an existing distribution. For information about how to use the console to create a distribution, see [Create a distribution](distribution-web-creating-console.md).<a name="restrictions-geo-procedure"></a>

**To add geographic restrictions to your CloudFront web distribution (console)**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Distributions**, then choose the distribution that you want to update.

1. Choose the **Security** tab, then choose **Geographic restrictions**.

1. Choose **Edit**.

1. Select **Allow list** to create a list of allowed countries, or **Block list** to create a list of blocked countries.

1. Add the desired countries to the list, then choose **Save changes**.

## Use a third-party geolocation service
<a name="georestrictions-geolocation-service"></a>

With the CloudFront geographic restrictions feature, you control distribution of your content at the country level for all files that you're distributing with a given web distribution. If you have a use case for geographic restrictions where the restrictions don't follow country boundaries, or if you want to restrict access to only some of the files that you're serving by a given distribution, you can combine CloudFront with a third-party geolocation service. This provides you with control over your content based not only on country but also based on city, ZIP, or postal code, or even latitude and longitude.

When you're using a third-party geolocation service, we recommend that you use CloudFront signed URLs, with which you can specify an expiration date and time after which the URL is no longer valid. In addition, we recommend that you use an Amazon S3 bucket as your origin because you can then use a CloudFront [origin access control](private-content-restricting-access-to-s3.md) to prevent users from accessing your content directly from the origin. For more information about signed URLs and origin access control, see [Serve private content with signed URLs and signed cookies](PrivateContent.md).

The following steps explain how to control access to your files by using a third-party geolocation service.

**To use a third-party geolocation service to restrict access to files in a CloudFront distribution**

1. Get an account with a geolocation service.

1. Upload your content to an Amazon S3 bucket.

1. Configure Amazon CloudFront and Amazon S3 to serve private content. For more information, see [Serve private content with signed URLs and signed cookies](PrivateContent.md).

1. Write your web application to do the following:
   + Send the IP address for each user request to the geolocation service.
   + Evaluate the return value from the geolocation service to determine whether the user is in a location where you want CloudFront to distribute your content.
   + If you want to distribute your content to the user’s location, generate a signed URL for your CloudFront content. If you don’t want to distribute content to that location, return HTTP status code `403 (Forbidden)` to the user. Alternatively, you can configure CloudFront to return a custom error message. For more information, see [Create a custom error page for specific HTTP status codes](creating-custom-error-pages.md).

   For more information, refer to the documentation for the geolocation service that you’re using.

You can use a web server variable to get the IP addresses of the users who are visiting your website. Note the following caveats:
+ If your web server is not connected to the internet through a load balancer, you can use a web server variable to get the remote IP address. However, this IP address isn’t always the user’s IP address. It can also be the IP address of a proxy server, depending on how the user is connected to the internet.
+ If your web server is connected to the internet through a load balancer, a web server variable might contain the IP address of the load balancer, not the IP address of the user. In this configuration, we recommend that you use the last IP address in the `X-Forwarded-For` HTTP header. This header typically contains more than one IP address, most of which are for proxies or load balancers. The last IP address in the list is the one most likely to be associated with the user’s geographic location.

If your web server is not connected to a load balancer, we recommend that you use web server variables instead of the `X-Forwarded-For` header to avoid IP address spoofing.

# Use field-level encryption to help protect sensitive data
<a name="field-level-encryption"></a>

With Amazon CloudFront, you can enforce secure end-to-end connections to origin servers by using HTTPS. Field-level encryption adds an additional layer of security that lets you protect specific data throughout system processing so that only certain applications can see it.

Field-level encryption allows you to enable your users to securely upload sensitive information to your web servers. The sensitive information provided by your users is encrypted at the edge, close to the user, and remains encrypted throughout your entire application stack. This encryption ensures that only applications that need the data—and have the credentials to decrypt it—are able to do so.

To use field-level encryption, when you configure your CloudFront distribution, specify the set of fields in POST requests that you want to be encrypted, and the public key to use to encrypt them. You can encrypt up to 10 data fields in a request. (You can’t encrypt all of the data in a request with field-level encryption; you must specify individual fields to encrypt.)

When the HTTPS request with field-level encryption is forwarded to the origin, and the request is routed throughout your origin application or subsystem, the sensitive data is still encrypted, reducing the risk of a data breach or accidental data loss of the sensitive data. Components that need access to the sensitive data for business reasons, such as a payment processing system needing access to a credit number, can use the appropriate private key to decrypt and access the data.

**Note**  
To use field-level encryption, your origin must support chunked encoding.

![\[Field-level encryption in CloudFront\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/images/fleoverview.png)


CloudFront field-level encryption uses asymmetric encryption, also known as public key encryption. You provide a public key to CloudFront, and all sensitive data that you specify is encrypted automatically. The key you provide to CloudFront cannot be used to decrypt the encrypted values; only your private key can do that.

![\[Encrypt only sensitive data\]](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/images/encryptedfields.png)


**Topics**
+ [Overview of field-level encryption](#field-level-encryption-overview)
+ [Set up field-level encryption](#field-level-encryption-setting-up)
+ [Decrypt data fields at your origin](#field-level-encryption-decrypt)

## Overview of field-level encryption
<a name="field-level-encryption-overview"></a>

The following steps provide an overview of setting up field-level encryption. For specific steps, see [Set up field-level encryption](#field-level-encryption-setting-up).

1. **Get a public key-private key pair.** You must obtain and add the public key before you start setting up field-level encryption in CloudFront.

1. **Create a field-level encryption profile.** Field-level encryption profiles, which you create in CloudFront, define the fields that you want to be encrypted.

1. **Create a field-level encryption configuration.** A configuration specifies the profiles to use, based on the content type of the request or a query argument, for encrypting specific data fields. You can also choose the request-forwarding behavior options that you want for different scenarios. For example, you can set the behavior for when the profile name specified by the query argument in a request URL doesn’t exist in CloudFront.

1. **Link to a cache behavior.** Link the configuration to a cache behavior for a distribution, to specify when CloudFront should encrypt data.

## Set up field-level encryption
<a name="field-level-encryption-setting-up"></a>

Follow these steps to get started using field-level encryption. To learn about quotas (formerly known as limits) on field-level encryption, see [Quotas](cloudfront-limits.md).
+ [Step 1: Create an RSA key pair](#field-level-encryption-setting-up-step1)
+ [Step 2: Add your public key to CloudFront](#field-level-encryption-setting-up-step2)
+ [Step 3: Create a profile for field-level encryption](#field-level-encryption-setting-up-step3)
+ [Step 4: Create a configuration](#field-level-encryption-setting-up-step4)
+ [Step 5: Add a configuration to a cache behavior](#field-level-encryption-setting-up-step5)

### Step 1: Create an RSA key pair
<a name="field-level-encryption-setting-up-step1"></a>

To get started, you must create an RSA key pair that includes a public key and a private key. The public key enables CloudFront to encrypt data, and the private key enables components at your origin to decrypt the fields that have been encrypted. You can use OpenSSL or another tool to create a key pair. The key size must be 2048 bits.

For example, if you’re using OpenSSL, you can use the following command to generate a key pair with a length of 2048 bits and save it in the file `private_key.pem`:

```
openssl genrsa -out private_key.pem 2048
```

The resulting file contains both the public and the private key. To extract the public key from that file, run the following command:

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

The public key file (`public_key.pem`) contains the encoded key value that you paste in the following step.

### Step 2: Add your public key to CloudFront
<a name="field-level-encryption-setting-up-step2"></a>

After you get your RSA key pair, add your public key to CloudFront.<a name="field-level-encryption-setting-up-step2-procedure"></a>

**To add your public key to CloudFront (console)**

1. Sign in to the AWS Management Console and open the CloudFront console at [https://console.aws.amazon.com/cloudfront/v4/home](https://console.aws.amazon.com/cloudfront/v4/home).

1. In the navigation pane, choose **Public key**.

1. Choose **Add public key**.

1. For **Key name**, type a unique name for the key. The name can't have spaces and can include only alphanumeric characters, underscores (\$1), and hyphens (-). The maximum number of characters is 128.

1. For **Key value**, paste the encoded key value for your public key, including the `-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----` lines.

1. For **Comment**, add an optional comment. For example, you could include the expiration date for the public key.

1. Choose **Add**.

You can add more keys to use with CloudFront by repeating the steps in the procedure.

### Step 3: Create a profile for field-level encryption
<a name="field-level-encryption-setting-up-step3"></a>

After you add at least one public key to CloudFront, create a profile that tells CloudFront which fields to encrypt.<a name="field-level-encryption-setting-up-step3-procedure"></a>

**To create a profile for field-level encryption (console)**

1. In the navigation pane, choose **Field-level encryption**.

1. Choose **Create profile**.

1. Fill in the following fields:  
**Profile name**  
Type a unique name for the profile. The name can't have spaces and can include only alphanumeric characters, underscores (\$1), and hyphens (-). The maximum number of characters is 128.  
**Public key name**  
In the drop-down list, choose the name of a public key that you added to CloudFront in step 2. CloudFront uses the key to encrypt the fields that you specify in this profile.  
**Provider name**  
Type a phrase to help identify the key, such as the provider where you got the key pair. This information, along with the private key, is needed when applications decrypt data fields. The provider name can't have spaces and can include only alphanumeric characters, colons (:), underscores (\$1), and hyphens (-). The maximum number of characters is 128.  
**Field name pattern to match**  
Type the names of the data fields, or patterns that identify data field names in the request, that you want CloudFront to encrypt. Choose the \$1 option to add all the fields that you want to encrypt with this key.  
For the field name pattern, you can type the entire name of the data field, like DateOfBirth, or just the first part of the name with a wildcard character (\$1), like CreditCard\$1. The field name pattern must include only alphanumeric characters, square brackets ([ and ]), periods (.), underscores (\$1), and hyphens (-), in addition to the optional wildcard character (\$1).  
Make sure that you don’t use overlapping characters for different field name patterns. For example, if you have a field name pattern of ABC\$1, you can’t add another field name pattern that is AB\$1. In addition, field names are case-sensitive and the maximum number of characters that you can use is 128.  
**Comment**  
(Optional) Type a comment about this profile. The maximum number of characters that you can use is 128.

1. After you fill in the fields, choose **Create profile**.

1. If you want to add more profiles, choose **Add profile**.

### Step 4: Create a configuration
<a name="field-level-encryption-setting-up-step4"></a>

After you create one or more field-level encryption profiles, create a configuration that specifies the content type of the request that includes the data to be encrypted, the profile to use for encryption, and other options that specify how you want CloudFront to handle encryption.

For example, when CloudFront can’t encrypt the data, you can specify whether CloudFront should block or forward a request to your origin in the following scenarios:
+ **When a request’s content type isn’t in a configuration** – If you haven’t added a content type to a configuration, you can specify whether CloudFront should forward the request with that content type to the origin without encrypting data fields, or block the request and return an error.
**Note**  
If you add a content type to a configuration but haven’t specified a profile to use with that type, CloudFront always forwards requests with that content type to the origin.
+ **When the profile name provided in a query argument is unknown** – When you specify the `fle-profile` query argument with a profile name that doesn’t exist for your distribution, you can specify whether CloudFront should send the request to the origin without encrypting data fields, or block the request and return an error.

In a configuration, you can also specify whether providing a profile as a query argument in a URL overrides a profile that you’ve mapped to the content type for that query. By default, CloudFront uses the profile that you’ve mapped to a content type, if you specify one. This lets you have a profile that’s used by default but decide for certain requests that you want to enforce a different profile.

So, for example, you might specify (in your configuration) **SampleProfile** as the query argument profile to use. Then you could use the URL `https://d1234.cloudfront.net?fle-profile=SampleProfile` instead of `https://d1234.cloudfront.net`, to have CloudFront use **SampleProfile** for this request, instead of the profile you’d set up for the content type of the request.

You can create up to 10 configurations for a single account, and then associate one of the configurations to the cache behavior of any distribution for the account.<a name="field-level-encryption-setting-up-step4-procedure"></a>

**To create a configuration for field-level encryption (console)**

1. On the **Field-level encryption** page, choose **Create configuration**.

   Note: If you haven’t created at least one profile, you won’t see the option to create a configuration.

1. Fill in the following fields to specify the profile to use. (Some fields can’t be changed.)  
**Content type (can’t be changed)**  
The content type is set to `application/x-www-form-urlencoded` and can’t be changed.  
**Default profile ID (optional)**  
In the drop-down list, choose the profile that you want to map to the content type in the **Content type** field.  
**Content format (can’t be changed)**  
The content format is set to `URLencoded` and can’t be changed.

1. If you want to change the CloudFront default behavior for the following options, select the appropriate check box.  
**Forward request to origin when request’s content type is not configured**  
Select the check box if you want to allow the request to go to your origin *if you have not specified a profile to use for the content type of the request*.  
**Override the profile for a content type with a provided query argument**  
Select the check box if you want to allow a profile provided in a query argument to *override the profile that you’ve specified for a content type*.

1. If you select the check box to allow a query argument to override the default profile, you must complete the following additional fields for the configuration. You can create up to five of these query argument mappings to use with queries.  
**Query argument**  
Type the value that you want to include in URLs for the `fle-profile` query argument. This value tells CloudFront to use the profile ID (that you specify in the next field) associated with this query argument for field-level encryption for this query.  
The maximum number of characters that you can use is 128. The value can’t include spaces, and must use only alphanumeric or the following characters: dash (-), period (.), underscore (\$1), asterisk (\$1), plus-sign (\$1), percent (%).  
**Profile ID**  
In the drop-down list, choose the profile that you want to associate with the value that you typed for **Query argument**.  
**Forward request to origin when the profile specified in a query argument does not exist**  
Select the check box if you want to allow the request to go to your origin *if the profile specified in a query argument isn't defined in CloudFront*.

### Step 5: Add a configuration to a cache behavior
<a name="field-level-encryption-setting-up-step5"></a>

To use field-level encryption, link a configuration to a cache behavior for a distribution by adding the configuration ID as a value for your distribution.

**Important**  
To link a field-level encryption configuration to a cache behavior, the distribution must be configured to always use HTTPS, and to accept HTTP `POST` and `PUT` requests from viewers. That is, the following must be true:  
The cache behavior’s **Viewer Protocol Policy** must be set to **Redirect HTTP to HTTPS** or **HTTPS Only**. (In CloudFormation or the CloudFront API, `ViewerProtocolPolicy` must be set to `redirect-to-https` or `https-only`.)
The cache behavior’s **Allowed HTTP Methods** must be set to **GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE**. (In CloudFormation or the CloudFront API, `AllowedMethods` must be set to `GET`, `HEAD`, `OPTIONS`, `PUT`, `POST`, `PATCH`, `DELETE`. These can be specified in any order.)
The origin setting’s **Origin Protocol Policy** must be set to **Match Viewer** or **HTTPS Only**. (In CloudFormation or the CloudFront API, `OriginProtocolPolicy` must be set to `match-viewer` or `https-only`.)

For more information, see [All distribution settings reference](distribution-web-values-specify.md).

## Decrypt data fields at your origin
<a name="field-level-encryption-decrypt"></a>

CloudFront encrypts data fields by using the [AWS Encryption SDK](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html). The data remains encrypted throughout your application stack and can be accessed only by applications that have the credentials to decrypt it.

After encryption, the ciphertext is base64 encoded. When your applications decrypt the text at the origin, they must first decode the ciphertext, and then use the AWS Encryption SDK to decrypt the data.

The following code example illustrates how applications can decrypt data at your origin. Note the following: 
+ To simplify the example, this sample loads public and private keys (in DER format) from files in the working directory. In practice, you would store the private key in a secure offline location, such as an offline hardware security module, and distribute the public key to your development team.
+ CloudFront uses specific information while encrypting the data, and the same set of parameters should be used at the origin to decrypt it. Parameters CloudFront uses while initializing the MasterKey include the following:
  + PROVIDER\$1NAME: You specified this value when you created a field-level encryption profile. Use the same value here.
  + KEY\$1NAME: You created a name for your public key when you uploaded it to CloudFront, and then specified the key name in the profile. Use the same value here.
  + ALGORITHM: CloudFront uses `RSA/ECB/OAEPWithSHA-256AndMGF1Padding` as the algorithm for encrypting, so you must use the same algorithm to decrypt the data.
+ If you run the following sample program with ciphertext as input, the decrypted data is output to your console. For more information, see the [Java Example Code](https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/java-example-code.html) in the AWS Encryption SDK.

### Sample code
<a name="field-level-encryption-decrypt-sample"></a>

```
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import org.apache.commons.codec.binary.Base64;

import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.jce.JceMasterKey;

/**
 * Sample example of decrypting data that has been encrypted by CloudFront field-level encryption.
 */
public class DecryptExample {

    private static final String PRIVATE_KEY_FILENAME = "private_key.der";
    private static final String PUBLIC_KEY_FILENAME = "public_key.der";
    private static PublicKey publicKey;
    private static PrivateKey privateKey;

    // CloudFront uses the following values to encrypt data, and your origin must use same values to decrypt it.
    // In your own code, for PROVIDER_NAME, use the provider name that you specified when you created your field-level
    // encryption profile. This sample uses 'DEMO' for the value.
    private static final String PROVIDER_NAME = "DEMO";
    // In your own code, use the key name that you specified when you added your public key to CloudFront. This sample
    // uses 'DEMOKEY' for the key name.
    private static final String KEY_NAME = "DEMOKEY";
    // CloudFront uses this algorithm when encrypting data.
    private static final String ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";

    public static void main(final String[] args) throws Exception {

        final String dataToDecrypt = args[0];

        // This sample uses files to get public and private keys.
        // In practice, you should distribute the public key and save the private key in secure storage.
        populateKeyPair();

        System.out.println(decrypt(debase64(dataToDecrypt)));
    }

    private static String decrypt(final byte[] bytesToDecrypt) throws Exception {
        // You can decrypt the stream only by using the private key.

        // 1. Instantiate the SDK
        final AwsCrypto crypto = new AwsCrypto();

        // 2. Instantiate a JCE master key
        final JceMasterKey masterKey = JceMasterKey.getInstance(
                publicKey,
                privateKey,
                PROVIDER_NAME,
                KEY_NAME,
                ALGORITHM);

        // 3. Decrypt the data
        final CryptoResult <byte[], ? > result = crypto.decryptData(masterKey, bytesToDecrypt);
        return new String(result.getResult());
    }

    // Function to decode base64 cipher text.
    private static byte[] debase64(final String value) {
        return Base64.decodeBase64(value.getBytes());
    }

    private static void populateKeyPair() throws Exception {
        final byte[] PublicKeyBytes = Files.readAllBytes(Paths.get(PUBLIC_KEY_FILENAME));
        final byte[] privateKeyBytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILENAME));
        publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(PublicKeyBytes));
        privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
    }
}
```