This was previously not possible because CloudFront didn't support it and because (as I mentioned in comments on John's answer -- which was on the right track) there was no way to roll-your-own solution with Lambda@Edge because the X-Amz-Cf-Id
request header --generated on the back side of CloudFront and visible only to S3, not to the trigger invocation -- would invalidate any signature you tried to add to the request inside a Lambda@Edge trigger, because signing of all X-Amz-*
headers is mandatory.
But the X-Amz-Cf-Id
header value is now exposed to a Lambda@Edge trigger function in the event structure -- not with the other request headers, but as a simple string attribute -- at event.Records[0].cf.config.requestId
.
With that value in hand, you can use the execution role credentials and the built-in SDK in the Lambda@Edge environment to generate a signature and and add the necessary headers (including an Authorization
header with the derived credential identifier and freshly-generated signature) to the request.
This setup does not use an Origin Access Identifier (OAI) because the Lambda@Edge trigger's IAM Execution Role is used instead of an OAI to persuade S3 that the request is authorized.
Achraf Souk has published an official AWS blog post explaining the solution from start to finish.
https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/