How do I troubleshoot issues related to a signed URL or signed cookies in CloudFront?

Last updated: 2022-06-02

I'm securing private content by using Amazon CloudFront and a signed URL or signed cookies. I'm receiving a 403 Access Denied error. How can I troubleshoot this error?

Short description

Amazon CloudFront might return a 403 Access Denied error if there's an issue with a signed URL or signed cookies. See the following resolution sections for causes of this error and troubleshooting steps.

Resolution

When you turn on Restrict Viewer Access in a behavior, you must determine 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. The following 403 error messages indicate that the signer information is missing or incorrect:

403 Access Denied error with the message "Missing Key-Pair-Id query parameter or cookie value."

This message indicates that the query string parameter Key-Pair-ID is missing or empty in a signed URL.

403 Access Denied error with the message "Missing Key-Pair-Id query parameter or cookie value."

This message indicates that the query string parameter CloudFront-Key-Pair-ID is missing or empty in the signed cookie.

403 Access Denied error with message "Unknown Key."

This message indicates that CloudFront can't verify signer information through Key-Pair-ID (for signed URLs) or CloudFront-Key-Pair-ID (for signed cookies).To resolve this issue, confirm that the correct value of Key-Pair-ID is used for a signed URL or CloudFront-Key-Pair-ID for signed cookies. First:

If you're using a signed URL, find and note the value of Key-Pair-ID.
-or-
If you're using signed cookies, find and note the value of CloudFront-Key-Pair-ID.

Then, find the Key ID and confirm that it matches the Key-Pair-IDor CloudFront-Key-Pair-ID:

  1. Open the CloudFront console. In the left navigation menu, choose Distributions.
  2. Choose your distribution. Then, choose the Behaviors tab.
  3. Select the behavior name, and then choose Edit.
  4. Find the Restrict viewer access setting.
    Note: If it's set to Yes, then requests for files that match the path pattern of this cache behavior must use the signed URL or signed cookie.
  5. After confirming the Restrict view access field is set to Yes, check the Trusted authorization type field.
  6. If the value of Trusted authorization type setting is Trusted key groups, note the name of trust key group.
    Then, find the public key IDs for a trust key group: return to the CloudFront console. Choose Key Groups. In the list of key groups, choose the name of the trusted key group that you noted.
    Confirm that the value of Key-Pair-Id or CloudFront-Key-Pair-Id you noted in step 1 matches one of the public key IDs in the trusted key group.
  7. If the value of Trusted authorization type is Trusted Signer, CloudFront credentials generated by AWS are used. In this case, the value of Key-Pair-Id or CloudFront-Key-Pair-Id that you noted in step 1 must match the Access Key ID of CloudFront credentials.
    To find the Access Key ID of CloudFront credentials, see Creating key pairs for your signers.

When you create a signed URL or signed cookie, a policy statement in JSON format specifies the restrictions on the signed URL. This statement determines how long the URL is valid. CloudFront will return 403 Access Denied error if:

  • A signed URL is sent at time greater than value of Expires in a signed URL using canned policy.
  • A signed cookie is sent at a time greater than the value of CloudFront-Expires in a signed cookie using canned policy.
  • A signed URL or a signed cookie is sent at time greater than value of DateLessThan or less than value of DateGreaterThan in custom policy.

Note: The values in Expires, CloudFront-Expires, DateLessThan, and DateGreaterThan are in Unix time format (in seconds) and Coordinated Universal Time (UTC). For example, January 1, 2013 10:00 AM UTC converts to 1357034400 in Unix time format. If using epoch time, use a 32-bit integer for a date that's no later than 2147483647 (January 19, 2038 at 03:14:07 UTC).

The Policy parameter in a signed URL or the CloudFront-Policy attribute in a signed cookie indicates that a custom policy is used. The policy statement is in JSON format and base64 encoded. To find out the value of DateLessThan or DateGreaterThan, use a 64base decode command.

An example of base64 encode custom policy looks like:

eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__

Use the following Linux command to decode custom policy in base64 encoded format into JSON format. This example uses the value from the previous example. Replace with your own custom policy.

$ echo -n eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__ | base64 -di

The output of the command looks similar to the following:

{ "Statement": [{ "Resource": "http://d111111abcdef8.cloudfront.net/game_download.zip", "Condition": { "IpAddress": { "AWS:SourceIp": "192.0.2.0/24" }, "DateLessThan": { "AWS:EpochTime": 1426500000 } } }] }

CloudFront will return a 403 Access denied error if more than one statement is included in canned policy or custom policy.

To troubleshoot, use the Linux command in the previous section to check the statement of custom policy. Verify your code details and confirm that only one statement is included in canned policy or custom policy.

CloudFront will return a 403 Access denied error if:

  • The base URL in the key Resource in the policy statement has an abbreviated URL (www.example.com). Use a full URL (http://www.example.com).
  • The base URL doesn't have UTF-8 character encoding.
  • The base URL doesn't include all punctuation and parameter names.
  • The HTTP or HTTPS protocol in the base URL doesn't match the protocol that's used in a request that's sending a signed URL or signed cookies.
  • The domain name in the base URL doesn't match the value of the Host header used by the user agent that's sending a signed URL or signed cookies.
  • The base URL query string includes characters that aren't valid.

CloudFront will return a 403 Access Denied error if:

  • The policy statement includes white spaces (including tabs and newline characters).
  • The canned policy or custom policy isn't formatted as string before it was hashed. This can happen if you create a signed URL or signed cookie without using an AWS SDK.
  • The policy wasn't hashed before generating the signature. This can happen if you are creating signed URL or signed cookie without using an AWS SDK.

For signature best practices when using a signed URL or signed cookies, see Code examples for creating a signature for a signed URL.

CloudFront will return a 403 Access denied error if:

  • A signed URL or signed cookies were sent from an IPv6 IP address.
  • A signed URL or signed cookies weren't sent from an IPv4 address or IPv4 IP range specified in custom policy.

The key IpAddress is only available in custom policy in a signed URL or a signed cookie. IP addresses in IPv6 format are not supported. If you're using a custom policy that includes IpAddress, then don't enable IPv6 for the distribution.

CloudFront returns a 403 Access Denied error if cookies are returned from CloudFront but weren't included in following requests to the same domain. In this case, check the cookie attributes Domain and Path in the Set-Cookie response header.

The Domain value is the domain name for the requested file. If you don't specify a Domain attribute, then the default value is the domain name in the URL. This applies only to the specified domain name, not to subdomains. If you specify a Domain attribute, then it also applies to subdomains.

If you specify a Domain attribute, then the domain name in the URL and the value of the Domain attribute must match. You can specify the domain name that CloudFront assigns to your distribution (for example, d111111abcdef8.cloudfront.net), but you can't specify *.cloudfront.net for the domain name. To use an alternate domain name (such as example.com) in URLs, add an alternate domain name to your distribution.

The Path value is the path for the requested file. If you don't specify a Path attribute, then the default value is the path in the URL.


Did this article help?


Do you need billing or technical support?