-
-
Save mekza/b7cdc0858aa1dd22b016 to your computer and use it in GitHub Desktop.
| from boto.cloudfront.distribution import Distribution | |
| from cryptography.hazmat.primitives.asymmetric import padding | |
| from cryptography.hazmat.primitives import serialization | |
| from cryptography.hazmat.backends import default_backend | |
| from cryptography.hazmat.primitives import hashes | |
| import base64 | |
| class BetterThanBoto(Distribution): | |
| def sign_rsa(self, message): | |
| private_key = serialization.load_pem_private_key(self.keyfile, password=None, | |
| backend=default_backend()) | |
| signer = private_key.signer(padding.PKCS1v15(), hashes.SHA1()) | |
| message = message.encode('utf-8') | |
| signer.update(message) | |
| return signer.finalize() | |
| def _sign_string(self, message, private_key_file=None, private_key_string=None): | |
| if private_key_file: | |
| self.keyfile = open(private_key_file, 'rb').read() | |
| elif private_key_string: | |
| self.keyfile = private_key_string.encode('utf-8') | |
| return self.sign_rsa(message) | |
| @staticmethod | |
| def _url_base64_encode(msg): | |
| """ | |
| Base64 encodes a string using the URL-safe characters specified by | |
| Amazon. | |
| """ | |
| msg_base64 = base64.b64encode(msg).decode('utf-8') | |
| msg_base64 = msg_base64.replace('+', '-') | |
| msg_base64 = msg_base64.replace('=', '_') | |
| msg_base64 = msg_base64.replace('/', '~') | |
| return msg_base64 | |
| def generate_signature(self, policy, private_key_file=None): | |
| """ | |
| :param policy: no-whitespace json str (NOT encoded yet) | |
| :param private_key_file: your .pem file with which to sign the policy | |
| :return: encoded signature for use in cookie | |
| """ | |
| # Distribution._create_signing_params() | |
| signature = self._sign_string(policy, private_key_file) | |
| # now base64 encode the signature & make URL safe | |
| encoded_signature = self._url_base64_encode(signature) | |
| return encoded_signature | |
| def create_signed_cookies(self, url, private_key_file=None, keypair_id=None, | |
| expires_at=20, secure=True): | |
| """ | |
| generate the Cloudfront download distirbution signed cookies | |
| :param resource: The object or path of resource. | |
| Examples: 'dir/object.mp4', 'dir/*', '*' | |
| :param private_key_file: Path to the private key file (pem encoded) | |
| :param key_pair_id: ID of the keypair used to sign the cookie | |
| :param expire_minutes: The number of minutes until expiration | |
| :param secure: use https or http protocol for Cloudfront URL - update | |
| to match your distribution settings. | |
| :return: Cookies to be set | |
| """ | |
| # generate no-whitespace json policy, | |
| # then base64 encode & make url safe | |
| policy = self._custom_policy( | |
| url, | |
| expires_at | |
| ) | |
| encoded_policy = self._url_base64_encode(policy.encode('utf-8')) | |
| # assemble the 3 Cloudfront cookies | |
| signature = self.generate_signature( | |
| policy, private_key_file=private_key_file | |
| ) | |
| cookies = { | |
| "CloudFront-Policy": encoded_policy, | |
| "CloudFront-Signature": signature, | |
| "CloudFront-Key-Pair-Id": keypair_id | |
| } | |
| return cookies | |
| def sign_to_cloudfront(object_url, expires_at): | |
| """ Sign URL to distribute file""" | |
| cf = BetterThanBoto() | |
| url = cf.create_signed_url(url=object_url, | |
| keypair_id="XXXXXXXXXXX", | |
| expire_time=expires_at, | |
| private_key_file="ssl/key.pem") | |
| return url | |
| def create_signed_cookies(object_url, expires_at): | |
| """ | |
| Create a signed cookie | |
| """ | |
| cf = BetterThanBoto() | |
| cookies = cf.create_signed_cookies(url=object_url, | |
| keypair_id=keypair_id="XXXXXXXXXXX", | |
| expires_at=expires_at, | |
| private_key_file="ssl/key.pem") | |
| return cookies |
got this working https://stackoverflow.com/a/49972685/1118576
How do I generate the pem file for this?
@DataGreed note that my snippet might be very outdated since it uses boto and not botocore nor boto3. Better way to do it: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudfront.html#generate-a-signed-url-for-amazon-cloudfront
@mekza thank you very much!
That was helpful! Thanks
more simple and clean code: https://gist.github.com/ox0spy/f532475f394c1b14f0e33ef047f78e05#python-code
Hi there, I was searching for a python version for signing cloudfront cookies and found yours.
@ox0spy I gave it a try with your implementation but I keep getting:
Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>.
I followed the steps you mentioned:
- created the keys, and upload the public to cloudfront
- configured a key group associated to the public key, which then is the one used for restricting access to the s3 bucket.
-the bucket policy is correctly configured to only accept access from the cloudfront distribution (if I disable the restricted access based on the cookies/urls it works fine.)
Do have any idea that might help? Maybe if you could share the values of the variables you are using could give an insight on what I might be doing wrong.
private_key_path=''; key_id = ''; base_url =''; obj_key ='';
Thanks
Hi abaptista, please check my latest code and make sure you choose the correct Trusted Key Group.
# example of variables
private_key_path = 'the-path-of-your-private-key' # e.g.: './private_key.pem'
key_id = 'KXXXXXXXXXXXQ'
base_url = 'https://xxxx.cloudfront.net'
obj_key = 'the-object-path-of-your-s3' # e.g.: 'images/avatar.png'
new code remove `base_url`, just using the file's cdn url, e.g.: `url = 'https://xxxx.cloudfront.net/images/avatar.png'`
@zhangwm404
Do you still have your updated code? I'm getting a 404 on the link you sent earlier. Any help would be much appreciated.
Latest link appears to be https://gist.github.com/zh4n7wm/f532475f394c1b14f0e33ef047f78e05#python-code. Seems to be a username change.
I tried using this script for generating signed cookies but im getting access denied in response. Is there any thing im missing.
below is the issue i posted in stack overflow
http://stackoverflow.com/questions/43540243/unable-to-use-signed-cookies-for-cloudfront