简体   繁体   中英

Cloudfront vs S3 signed URL and Boto3

Trying to setup a cloudfront URL that is fully signed and protected. Eg 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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM