Last active
October 19, 2025 11:58
-
-
Save cheeyeo/3b1c08cb288e2ffc8ab246257e13cd8d to your computer and use it in GitHub Desktop.
Example of using boto3 CloudFrontSigner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import datetime | |
| import json | |
| import base64 | |
| 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: bytes) -> bytes: | |
| with open('private_key.pem', 'rb') as f: | |
| private_key = serialization.load_pem_private_key(f.read(), password=None, backend=default_backend()) | |
| return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1()) | |
| def cookie_policy(resource: str, expires_in: int) -> str: | |
| """Signed cookies require a cookie policy attached""" | |
| return json.dumps({"Statement": [{"Resource": resource, "Condition": {"DateLessThan": {"AWS:EpochTime": expires_in}}}]}, separators=(",", ":")) | |
| def replace_chars(orig: str) -> str: | |
| return orig.replace("+", "-").replace("=", "_").replace("/", "~") | |
| def cloudfront_signed_url(key_id: str, url: str, expires_in: int = 3600) -> str: | |
| expire_date = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=expires_in) | |
| cloudfront_signer = CloudFrontSigner(key_id, rsa_signer) | |
| return cloudfront_signer.generate_presigned_url(url, date_less_than=expire_date) | |
| def cloudfront_signed_cookies(key_id: str, url: str, expires_in: int = 3600) -> dict[str, str]: | |
| expiration = (datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(seconds=expires_in)).timestamp() | |
| policy = cookie_policy(resource=url, expires_in=int(expiration)) | |
| signature = rsa_signer(policy.encode("utf-8")) | |
| return { | |
| "CloudFront-Policy": replace_chars(str(base64.b64encode(policy.encode("utf-8")), "utf-8")), | |
| "CloudFront-Signature": replace_chars(str(base64.b64encode(signature), "utf-8")), | |
| "CloudFront-Key-Pair-Id": key_id | |
| } | |
| if __name__ == "__main__": | |
| # Public key ID uploaded to Cloudfront > Public Key | |
| key_id = 'XXXXXXXX' | |
| url = 'https://YYYY.cloudfront.net/cat.jpeg' | |
| signed_url = cloudfront_signed_url(key_id=key_id, url=url) | |
| print(signed_url) | |
| # For signed cookies, we can specify either specific file or * for all files. Note that the url must match else we get access denied error | |
| url = 'https://YYYY.cloudfront.net/*' | |
| signed_cookies = cloudfront_signed_cookies(key_id, url) | |
| # print(signed_cookies) | |
| output = f"Cookie: CloudFront-Policy={signed_cookies["CloudFront-Policy"]};CloudFront-Signature={signed_cookies["CloudFront-Signature"]};CloudFront-Key-Pair-Id={signed_cookies["CloudFront-Key-Pair-Id"]}" | |
| print(output) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment