Cloudfront Malformed Policy Error with AWS Cloudfront-Signer V3

1

I'm having an issue with the AWS Cookie-Signer V3 and Custom Policies. I'm currently using @aws-sdk/cloudfront-signer v3.254.0. I have followed the official docs of how to create and handle signed cookies - it works as long as I don't use custom policies.

Setup

I use a custom lambda via an API Gateway to obtain the Set-Cookie header with my signed cookies. These cookies will be attached to a further file-request via my AWS Cloudfront instance. In order to avoid CORS errors, I have set up custom domains for the API Gateway as well as for the Cloudfront instance.

A minified example of the signing and the return value looks as follows:

// Expiration time
const getExpTime = new Date(Date.now() + 5 * (60 * 60 * 1000)).toISOString();

// Cookie-Signer
const signedCookie = getSignedCookies({
  keyPairId: "MY-KEYPAIR-ID",
  privateKey: "MY-PRIVATE-KEY",
  url: "https://cloudfront.example.com/path-to-file/file.m3u8",
  dateLessThan: getExpTime,
});

// Response
const response = {
  statusCode: 200,
  isBase64Encoded: false,
  body: JSON.stringify({ url: url, bucket: bucket, key: key }),
  headers: {
    "Content-Type": "application/json",
    "Access-Control-Allow-Origin": "https://example.com",
    "Access-Control-Allow-Credentials": true,
    "Access-Control-Allow-Methods": "OPTIONS,POST,GET",
  },
  multiValueHeaders: {
    "Set-Cookie": [
      `CloudFront-Expires=${signedCookie["CloudFront-Expires"]}; Domain=example.com; Path=/${path}/`,
      `CloudFront-Signature=${signedCookie["CloudFront-Signature"]}; Domain=example.com; Path=/${path}/`,
      `CloudFront-Key-Pair-Id=${signedCookie["CloudFront-Key-Pair-Id"]}; Domain=example.com; Path=/${path}/`,
    ],
  },
};

This works well if I request a single file from my S3 bucket. However, since I want to stream video files from my S3 via Cloudfront and according to the AWS docs, wildcard characters are only allowed with Custom Policies. I need this wildcard to give access to the entire video folder with my video chunks. Again following the official docs, I have updated my lambda with:

// Expiration time
const getExpTime = new Date(Date.now() + 5 * (60 * 60 * 1000)).getTime();

// Custom Policy
const policyString = JSON.stringify({
  Statement: [
    {
      Resource: "https://cloudfront.example.com/path-to-file/*",
      Condition: {
        DateLessThan: { "AWS:EpochTime": getExpTime },
      },
    },
  ],
});

// Cookie signing
const signedCookie = getSignedCookies({
  keyPairId: "MY-KEYPAIR-ID",
  privateKey: "MY-PRIVATE-KEY",
  policy: policyString,
  url: "https://cloudfront.example.com/path-to-file/*",
});

which results in a Malformed Policy error.

What confuses me is that the getSignedCookies() method requires the url property even though I'm using a custom policy with the Ressource parameter. Since the Resource parameter is optional, I've also tried without which led to the same error.

To rule out that something is wrong with the wildcard character, I've also run a test where I've pointed to the exact file but using the custom policy. Although this works without custom policy, it does fail with the Malformed Policy error when using the custom policy.

Since there is also no example of how to use the Cloudfront Cookie-Signer V3 with custom policies, I'd be very grateful if someone can tell me how I'm supposed to type this out!

Cheers! 🙌

3 Answers
0
Accepted Answer

I found the solution and it's pretty embarrassing...

My above example signs cookies via a Custom Policy but uses the Set-Cookie header keys from a Canned Policy. The difference in the docs is not really obvious but its clearly there...

However, instead of

Set-Cookie: CloudFront-Expires= ...

you use

Set-Cookie: CloudFront-Policy=<your policy string>

The keys

Set-Cookie: CloudFront-Expires= ...
Set-Cookie: CloudFront-Signature= ...

are identical.

Hope this helps!

FloRag
answered 7 months ago
0

Try changing the "DateLessThan" line to:

DateLessThan: { "AWS:EpochTime": Math.floor(getExpTime / 1000) },

AWS:EpochTime expects a value in seconds, not milliseconds.

answered a year ago
0

Did you find any solution to this ? I am facing the same issue.

answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions