Search code examples
pythonamazon-web-servicesamazon-s3amazon-cloudfrontboto3

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.


Solution

  • 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.