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

7 minute read
1

I'm using Amazon CloudFront and a signed URL or signed cookies to secure private content. I receive a 403 Access Denied error.

Resolution

If Amazon CloudFront encounters an issue with a signed URL or signed cookies, then you might receive a 403 Access Denied error.

A signed URL or signed cookie doesn't include the correct signer

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:

The error includes the message "Missing Key-Pair-Id query parameter or cookie value."

This message indicates a missing or empty Key-Pair-Id query parameter with a signed URL. Or, it indicates a missing CloudFront-Key-Pair-ID query string parameter in a signed cookie.

The error includes the 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 Key-Pair-ID value is used for a signed URL or CloudFront-Key-Pair-ID for signed cookies:

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

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

  1. Open the CloudFront console. In the navigation menu, choose Distributions.
  2. Select 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 cache behavior's path pattern must use the signed URL or signed cookie.
  5. Check the Trusted authorization type field.
  6. If the Trusted authorization type value setting is Trusted key groups, then note the name of the trust key group. Find the public key IDs for the trust key group:
    Open the CloudFront console.
    Choose Key Groups. Choose the name of the trusted key group that you noted.
    Confirm that the Key-Pair-Id or CloudFront-Key-Pair-Id value matches one of the public key IDs in the trusted key group.
  7. If the value of Trusted authorization type is Trusted Signer, then CloudFront uses the credentials that AWS generates. In this case, the Key-Pair-Id or CloudFront-Key-Pair-Id value must match the Access Key ID of the CloudFront credentials.
    Note: To find the Access Key ID of CloudFront credentials, see Creating key pairs for your signers.

A signed URL or signed cookie isn't sent at a valid time

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 returns a 403 Access Denied error in the following scenarios:

  • A signed URL is sent at a time that's greater than the Expires value in a signed URL that uses a canned policy.
  • A signed cookie is sent at a time that's greater than the CloudFront-Expires value in a signed cookie that uses a canned policy.
  • A signed URL or a signed cookie is sent at time that's greater than the DateLessThan value in a custom policy. Or, it's sent at a time that's less than the DateGreaterThan value.

Note: The Expires, CloudFront-Expires, DateLessThan, and DateGreaterThan values 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 you use epoch time, then 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 you use a custom policy. The policy statement is in JSON format and is base64 encoded. To find out the DateLessThan or DateGreaterThan value, use a 64base decode command.

Example of a base64-encoded custom policy:

eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__

To decode a custom policy that's in base64-encoded format into JSON format, run the following Linux command. Replace the policy value with your custom policy value:

echo "eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__" | tr -- '-_~' '+=/' | base64 -d

You receive an output that looks similar to the following one:

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

A signed URL or signed cookie has more than one statement in the policy

If more than one statement is included in a canned policy or custom policy, then CloudFront returns a 403 Access Denied error.

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

A signed URL or signed cookie has an incorrect base URL in the policy

CloudFront returns a 403 Access Denied error when the base URL in the policy is incorrect:

  • It's abbreviated (www.example.com) in the Resource key. Use a full URL (http://www.example.com).
  • There's no UTF-8 character encoding.
  • It doesn't include all punctuation and parameter names.
  • The HTTP or HTTPS protocol doesn't match the protocol that's used in a request that's sending a signed URL or signed cookies.
  • The domain name doesn't match the host header that the user agent uses to send a signed URL or signed cookies.
  • The query string includes characters that aren't valid.

A signed URL or signed cookie has an incorrect signature in the policy

CloudFront returns a 403 Access Denied error in the following scenarios:

  • The policy statement includes white spaces, including tabs and newline characters.
  • The canned policy or custom policy isn't formatted as string before it's hashed. This happens when you create a signed URL or signed cookie without an AWS SDK.
  • The policy isn't hashed before it generates the signature. This happens when you create the signed URL or signed cookie without an AWS SDK.

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

A signed URL or signed cookie was sent from an unsupported IP address or IP range

CloudFront returns a 403 Access Denied error when a signed URL or signed cookie is sent from an IPv6 address. Or, it's sent from an IPv4 address or IPv4 range that's not permitted in the custom policy.

The IpAddress key is available only in the custom policy that's in a signed URL or a signed cookie. IP addresses in IPv6 format aren't supported. If you use a custom policy that includes IpAddress, then don't turn on IPv6 for the distribution.

A signed cookie doesn't include the Domain and Path attributes in Set-cookie response headers

CloudFront returns a 403 Access Denied error when cookies return from CloudFront but aren't included in later requests to the same domain. In this case, check the Domain and Path cookie attributes 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, add an alternate domain name to your distribution in your URLs.

The Path attribute 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.

AWS OFFICIAL
AWS OFFICIALUpdated 2 months ago
2 Comments

Using the example encoded string (inside the post) with the given linux command returns the json but with the base64: invalid input at the end of the json output.

echo -n eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ__ | base64 -di

returns (see at the end of the json)

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

UNLESS if you replace the last two underscore "_" at the end of the encoded string with two "=" characters.

Change "....B9fX1dfQ__" to "....B9fX1dfQ=="

Then try again

echo -n eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cDovL2QxMTExMTFhYmNkZWY4LmNsb3VkZnJvbnQubmV0L2dhbWVfZG93bmxvYWQuemlwIiwiQ29uZGl0aW9uIjp7IklwQWRkcmVzcyI6eyJBV1M6U291cmNlSXAiOiIxOTIuMC4yLjAvMjQifSwiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE0MjY1MDAwMDB9fX1dfQ== | base64 -di

returns (no base64: invalid input anymore!)

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

Is there any explanation about that?

TG
replied 3 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 3 months ago