AWS can have annoyingly few details about errors and I've found myself stuck without a clear path forward.
I have code in my Node.js app that seems to be generating both signed URLs and signed cookies, but neither are allowing me to access resources on my private CloudFront distribution. This is the 403 response I get, instead:
<Error>
<Code>InvalidKey</Code>
<Message>Unknown Key</Message>
</Error>
My solution is spread across two AWS accounts.
The key pair ID and private key are configured as environment variables using the Elastic Beanstalk console. Here's my code (it's executing without errors):
const cloudFront =
sails.config.custom.cloudfront.keyPairId &&
sails.config.custom.cloudfront.privateKey &&
new AWS.CloudFront.Signer(
sails.config.custom.cloudfront.keyPairId,
sails.config.custom.cloudfront.privateKey.replace(/\\n/g, '\n') // environment variables passed through Elastic Beanstalk get altered
);
// Set Cookies after successful verification
const policy = JSON.stringify({
Statement: [
{
Resource: 'https://privatedistro.mydomain.com/*',
Condition: {
DateLessThan: {
'AWS:EpochTime':
Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24 // Current Time in UTC + time in seconds, (1 day)
}
}
}
]
});
cookie = cloudFront.getSignedCookie({ policy });
this.res.cookie(
'CloudFront-Key-Pair-Id',
cookie['CloudFront-Key-Pair-Id'],
{
domain: '.mydomain.com',
path: '/',
httpOnly: true
}
);
this.res.cookie(
'CloudFront-Expires',
Math.floor(new Date().getTime() / 1000) + 60 * 60 * 24, // Current Time in UTC + time in seconds, (60 * 60 * 24 = 1 day)
{
domain: '.mydomain.com',
path: '/',
httpOnly: true
}
);
this.res.cookie(
'CloudFront-Signature',
cookie['CloudFront-Signature'],
{
domain: '.mydomain.com',
path: '/',
httpOnly: true
}
);
The cookies that are returned look like this:
In the Default Cache Behavior Settings of my private distribution, I've selected Yes for Restrict Viewer Access, selected both self and selected accounts as Trusted Signers and entered the 13-digit number of the member account in the AWS Account Numbers field. Before I turned on Restrict Viewer Access, everything was being served nicely, so I don't think there's an issue with other parts of the CloudFront setup.
Any ideas where I went wrong?
The key you're using looks incorrect, to work with CloudFront signed URL, you need to use CloudFront key pair, not the EC2 one, mentioned in below doc:
Generate Signed URL CloudFront
The CloudFront key-ID looks more like a Access key of IAM.