Signing CloudFront URLs with aws:kms encryption

0

We're using CloudFront to securely distribute audio to authenticated users. Historically we've used AES256 encryption on our S3 objects and dynamically served the requested objects by using signed CloudFront URLs.

We've since switched to aws:kms for encryption of these objects, but that has since broken our method for signing URLs. Using our internal method and using the SDK Link: http://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.CloudFront.CloudFrontClient.html#_getSignedUrl , we can generate urls but they result in:

<Code>KMS.UnrecognizedClientException</Code>
<Message>No account found for the given parameters</Message>

I realize something needs to be updated to use the aws:kms encryption, but I cannot figure out what. Any input is greatly appreciated.

Edit: I should also mention that the IAM user that is trying to sign this url is approved for the kms encryption key we're trying to use.

Edited by: StevenMills on Nov 30, 2017 7:28 AM

asked 6 years ago5174 views
9 Answers
0

Hello,

A request was forwarded to our CloudFront team so they can look into the issue you have mentioned in your forum post. Below is their update with regards to this issue that you are having.

"This is an expected behavior as CloudFront currently does not support KMS server-side encryption for S3. The reason this does not work is that viewer requests through CloudFront does not have access to the KMS credentials used to encrypt the s3 objects. We would recommend using signed URLs and Origin Access Identities without KMS. We are aware of this limitation and a feature request is submitted to the CloudFront team."

Hope this is able to answer your question.

AWS
answered 6 years ago
0

I should also mention that the IAM user that is trying to sign this url is approved for the kms encryption key we're trying to use.

Note that IAM users do not sign CloudFront requests. CloudFront signed URLs are signed using CloudFront Key Pairs, which are not IAM credentials.

sqlb0t
answered 6 years ago
0

We also have the same issue. Do you have an update on when this will be resolved?

answered 6 years ago
0

Any movement on this since the last response almost a year ago? We are trying to use an SSE-KMS encrypted bucket as a CloudFront origin and are getting the same error.

tbell83
answered 6 years ago
0

I would also like to know when this feature will be supported. We are trying to use an SSE-KMS encrypted S3 objects via signed CloudFront URL.

answered 5 years ago
0

+1 We are facing the same issue and would love to see this implemented in CloudFront.

answered 5 years ago
0

Any update on this feature request?

answered 3 years ago
0

Hello,

I would like to share our findings since we too tried to orchestrate a solution. Note: this is still not technically a supported feature as of Oct 2021, and native signed URLs through the SDK, as far as I am aware are not supported. I would also like to add, that though I have spent significant time on this, I have seen a couple of examples online of others claiming to have had success using s3 signed URLs and swapping the domain, without a need for the CF ID (I have not been able to do so). However, you can access a private bucket that is encrypted through KMS through cloudfront, but there are caveats. Essentially you would have to overcome the obstacles and handle the auth in a different way. This info is not intended to solve the signed URL problem, only to provide answers to some of the lingering questions behind the problem itself. Last we heard the cloudfront team was aiming to support v4 signed URLs and increase IAM support in their next release, which will hopefully solve these problems. Fingers crossed for re invent.

  1. Most SDKs were using v2 signatures in the signer classes (most examples of cloudfront signed URLs are shown with the Signer Class.) However you need v4. These signer classes we not part of the s3 SDK so s3 signatures on a put or get object specifically for example aren't integrated. Honestly haven't picked apart the s3 SDK to know whether it truly matters.
  2. S3 signed URLs use v4, however as far as I have been able to tell from testing, in order to use a v4 signature through cloudfront / kms the signature MUST INCLUDE the Cloudfront Request Id. In order for that to happen, you must Sign the request using a Lambda Edge function when you intercept it on the way to the origin. This is why v4 support matters, they will need a solution for this.
  3. You MUST use S3 as CUSTOM ORIGIN. As far as I know, you cannot create an s3 CUSTOM origin through the console, so you must deploy the cloudformation template/stack you are using and configure it as such. There is an article which has a good example of this https://aws.amazon.com/blogs/networking-and-content-delivery/serving-sse-kms-encrypted-content-from-s3-using-cloudfront/ . It will not work unless you use s3 as custom origin. The v4 signing process is fairly well documented online and in the Aws guides. That article also has an example if you are using node.js.
  4. If you want to UPLOAD data through this same approach, you have to first allow the distribution to accept Put and Post requests in the configuration. You also need to ensure your cloudfront trigger INCLUDES THE BODY. Otherwise it will not be accessible event.Records[0].cf.request.body.data. You then need to parse the request body and hash it using hex encoding and make sure it's included in the signature if you are signing the body. If you are not signing the body there is a string literal you can use in its place. In either case, you have to use the amz-content-sha256 header and set the hash of the body to it. Another limitation as far as I am aware with this approach is the 1mb limit. So you cannot pass more than 1mb to the function and as a result it will not be uploaded and accepted by s3 if the payload is larger.
  5. (Should be a given you need the permissions set on the role). Obviously need corresponding S3 Access. I also have
    "cloudfront:GetFunction",
    "cloudfront:DescribeFunction"
    "s3:PutObject",
    "s3:GetObject",
    "logs:CreateLogStream",
    "secretsmanager:GetSecretValue",
    "secretsmanager:DescribeSecret",
    "lambda:GetFunction",
    "logs:CreateLogGroup",
    "logs:PutLogEvents",
    "lambda:EnableReplication*"
    "Action": "s3:ListBucket",

I have set this up and proven it works as expected with uploads and downloads. Obviously, if you are taking any random request and giving it permissions and signing it on the fly on the way to the origin, it is a far cry from a secure signed URL (tear this down when you are done). Only without KMS can you use an OAI and signed URLs just as you would expect to use them. This is where you have to implement your own auth strategy, whatever that may be. Again, I decided against all of this and moved my team away from it and implemented an alternative strategy through API Gateway, and will continue to do so until the support is there. Just leaving this here in case it helps anyone.

You could in theory go the extra mile and implement a more sophisticated auth strategy before and during the intercept to achieve a similar result, just remember to manage the cache.

ALSO: FEATURE REQUEST!!! Our particular use case could have been solved much more easily is S3 and Transfer acceleration would allow CNAMES on our buckets without virtual hosting. If I could map files.mycompany.com to our transfer acceleration endpoint with a signed URL , that would be magic.

nmattei
answered 3 years ago
0

We also need this feature. We need to store data encrypted at rest and have it cached in CDN with pre-signed CDN URLs. We are aware of pre-signing S3 URLs and replacing the hostname. However, this disables caching at CDN. Any updates on this feature request?

borfig
answered 2 years 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