Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloudfront vs S3 signed URL and Boto3

Trying to setup a cloudfront URL that is fully signed and protected. E.g. I want an application code to be required to access the resource.

With S3 direct distribution I can do this simply with:

s3 = boto3.client('s3')    
s3.generate_presigned_url('get_object', Params={'Bucket': bucket, 'Key': unique_key}, ExpiresIn=186400)

But I can't seem to figure out how to create the equivalent signed URL when requesting a cloudfront URL.

like image 313
JAR.JAR.beans Avatar asked Oct 26 '25 10:10

JAR.JAR.beans


2 Answers

The boto3 documentation has a section showing Generate a signed URL for Amazon CloudFront:

The following example shows how to generate a signed URL for Amazon CloudFront. Note that you will need the cryptography library to follow this example:

import datetime

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from botocore.signers import CloudFrontSigner
def rsa_signer(message):
    with open('path/to/key.pem', 'rb') as key_file:
        private_key = serialization.load_pem_private_key(
            key_file.read(),
            password=None,
            backend=default_backend()
        )
    return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())

key_id = 'AKIAIOSFODNN7EXAMPLE'
url = 'http://d2949o5mkkp72v.cloudfront.net/hello.txt'
expire_date = datetime.datetime(2017, 1, 1)

cloudfront_signer = CloudFrontSigner(key_id, rsa_signer)

# Create a signed url that will be valid until the specfic expiry date
# provided using a canned policy.
signed_url = cloudfront_signer.generate_presigned_url(
    url, date_less_than=expire_date)
print(signed_url)

Cloudfront vs S3

You'll notice that the above code uses a Public/Private keypair to create the CloudFront signed URL. This means that any application can generate a signed URL as long as it knows the keypair.

This is different to creating Signed URLs in Amazon S3, which uses the Secret Key belonging to the user who generated the request to authenticate the request.

Why are they different? I don't know, but the keypair option allows the use of CloudFront without needing any IAM Users, which might be useful for customers who only use CloudFront. But that's just a guess.

like image 119
John Rotenstein Avatar answered Oct 28 '25 23:10

John Rotenstein


Updating this wonderful answer by John, for those that find this and see warning messages coming from the cryptography module in Python.. signer has been deprecated in favor of the sign function on the serialization object according to the documentation.

import datetime

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from botocore.signers import CloudFrontSigner
def rsa_signer(message):
   with open('path/to/key.pem', 'rb') as key_file:
       private_key = serialization.load_pem_private_key(
           key_file.read(),
           password=None,
           backend=default_backend()
       )
   return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())

key_id = 'AKIAIOSFODNN7EXAMPLE'
url = 'http://d2949o5mkkp72v.cloudfront.net/hello.txt'
expire_date = datetime.datetime(2017, 1, 1)

cloudfront_signer = CloudFrontSigner(key_id, rsa_signer)

# Create a signed url that will be valid until the specfic expiry date
# provided using a canned policy.
signed_url = cloudfront_signer.generate_presigned_url(
     url, date_less_than=expire_date)
print(signed_url)

This just updates the answer so it doesn't throw the deprecation warning, and doesn't look at security aspects of pieces in use.

like image 32
David Bodine Avatar answered Oct 28 '25 23:10

David Bodine



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!