Install AWS CLI v2
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.0.30.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
Generate Signed URLs with Linux Tools
e.g. for accessing a website behind a CloudFront distribution using a canned policy.
Write the policy file
policy
{
"Statement": [
{
"Resource": "https://xxxxxxxxxxxx.cloudfront.net/",
"Condition": {
"DateLessThan": {
"AWS:EpochTime": 1648293147
}
}
}
]
}
Then apply the following commands[1] - you need to have OpenSSL installed.
cat policy |
tr -d "\n" | (1)
tr -d " \t\n\r" | (2)
openssl sha1 -sign private_key.pem | (3)
openssl base64 -A | (4)
tr -- '+=/' '-_~' (5)
1 | replace newlines |
2 | replace whitespaces |
3 | sign using the private key |
4 | base64 encode |
5 | replace invalid query-string parameters |
Then our final signed-URL looks like this:
Resources:
CloudFront
Invalidate CloudFront Cache with a Lambda Function
'use strict';
const aws = require('aws-sdk');
exports.handler = async event => {
try {
const params = {
DistributionId: 'XXXXXXXXXX', (1)
InvalidationBatch: {
CallerReference: `web-app-${new Date().getTime()}`,
Paths: {
Quantity: 1,
Items: ["/*"], (2)
}
},
}
const cloudfront = new aws.CloudFront()
const data = await cloudfront.createInvalidation(params)
console.log('success create invalidation', JSON.stringify(params))
return data.promise()
} catch (err) {
if (err) console.error('error invalidating cache', err, err.stack)
return new Error(err)
}
}
1 | The CloudFront Distribution’s ID |
2 | The list of origin paths .. here we simply invalidate all .. |
It’s important to await the response from createInvalidation or else the lambda function might terminate and no invalidation is done
|
Resources:
Rewrite Requests for Paths without Index File
async function handler(event) {
const request = event.request;
const uri = request.uri;
// Check whether the URI is missing a file name.
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// Check whether the URI is missing a file extension.
else if (!uri.includes('.')) {
request.uri += '/index.html';
}
return request;
}
Add Security Response Headers
async function handler(event) {
const response = event.response;
const headers = response.headers;
headers['strict-transport-security'] = { value: 'max-age=63072000; includeSubdomains; preload'};
headers['content-security-policy'] = { value: "default-src 'self'; base-uri 'self'; script-src 'self' 'nonce-31zwrvSsZOskdTpu' 'unsafe-inline'; style-src 'self' 'nonce-1234567890'; require-trusted-types-for 'script';trusted-types default;"};
headers['x-content-type-options'] = { value: 'nosniff'};
headers['x-frame-options'] = {value: 'DENY'};
headers['x-xss-protection'] = {value: '1; mode=block'};
headers['referrer-policy'] = {value: 'same-origin'};
return response;
}