Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6105435
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 23, 20262026-05-23T13:58:23+00:00 2026-05-23T13:58:23+00:00

I have created a S3 bucket, uploaded a video, created a streaming distribution in

  • 0

I have created a S3 bucket, uploaded a video, created a streaming distribution in CloudFront. Tested it with a static HTML player and it works. I have created a keypair through the account settings. I have the private key file sitting on my desktop at the moment. That’s where I am.

My aim is to get to a point where my Django/Python site creates secure URLs and people can’t access the videos unless they’ve come from one of my pages. The problem is I’m allergic to the way Amazon have laid things out and I’m just getting more and more confused.

I realise this isn’t going to be the best question on StackOverflow but I’m certain I can’t be the only fool out here that can’t make heads or tails out of how to set up a secure CloudFront/S3 situation. I would really appreciate your help and am willing (once two days has passed) give a 500pt bounty to the best answer.

I have several questions that, once answered, should fit into one explanation of how to accomplish what I’m after:

  • In the documentation (there’s an example in the next point) there’s lots of XML lying around telling me I need to POST things to various places. Is there an online console for doing this? Or do I literally have to force this up via cURL (et al)?

  • How do I create a Origin Access Identity for CloudFront and bind it to my distribution? I’ve read this document but, per the first point, don’t know what to do with it. How does my keypair fit into this?

  • Once that’s done, how do I limit the S3 bucket to only allow people to download things through that identity? If this is another XML jobby rather than clicking around the web UI, please tell me where and how I’m supposed to get this into my account.

  • In Python, what’s the easiest way of generating an expiring URL for a file. I have boto installed but I don’t see how to get a file from a streaming distribution.

  • Are there are any applications or scripts that can take the difficulty of setting this garb up? I use Ubuntu (Linux) but I have XP in a VM if it’s Windows-only. I’ve already looked at CloudBerry S3 Explorer Pro – but it makes about as much sense as the online UI.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-23T13:58:23+00:00Added an answer on May 23, 2026 at 1:58 pm

    You’re right, it takes a lot of API work to get this set up. I hope they get it in the AWS Console soon!

    UPDATE: I have submitted this code to boto – as of boto v2.1 (released 2011-10-27) this gets much easier. For boto < 2.1, use the instructions here. For boto 2.1 or greater, get the updated instructions on my blog: http://www.secretmike.com/2011/10/aws-cloudfront-secure-streaming.html Once boto v2.1 gets packaged by more distros I’ll update the answer here.

    To accomplish what you want you need to perform the following steps which I will detail below:

    1. Create your s3 bucket and upload some objects (you’ve already done this)
    2. Create a Cloudfront “Origin Access Identity” (basically an AWS account to allow cloudfront to access your s3 bucket)
    3. Modify the ACLs on your objects so that only your Cloudfront Origin Access Identity is allowed to read them (this prevents people from bypassing Cloudfront and going direct to s3)
    4. Create a cloudfront distribution with basic URLs and one which requires signed URLs
    5. Test that you can download objects from basic cloudfront distribution but not from s3 or the signed cloudfront distribution
    6. Create a key pair for signing URLs
    7. Generate some URLs using Python
    8. Test that the signed URLs work

    1 – Create Bucket and upload object

    The easiest way to do this is through the AWS Console but for completeness I’ll show how using boto. Boto code is shown here:

    import boto
    
    #credentials stored in environment AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
    s3 = boto.connect_s3()
    
    #bucket name MUST follow dns guidelines
    new_bucket_name = "stream.example.com"
    bucket = s3.create_bucket(new_bucket_name)
    
    object_name = "video.mp4"
    key = bucket.new_key(object_name)
    key.set_contents_from_filename(object_name)
    

    2 – Create a Cloudfront “Origin Access Identity”

    For now, this step can only be performed using the API. Boto code is here:

    import boto
    
    #credentials stored in environment AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
    cf = boto.connect_cloudfront()
    
    oai = cf.create_origin_access_identity(comment='New identity for secure videos')
    
    #We need the following two values for later steps:
    print("Origin Access Identity ID: %s" % oai.id)
    print("Origin Access Identity S3CanonicalUserId: %s" % oai.s3_user_id)
    

    3 – Modify the ACLs on your objects

    Now that we’ve got our special S3 user account (the S3CanonicalUserId we created above) we need to give it access to our s3 objects. We can do this easily using the AWS Console by opening the object’s (not the bucket’s!) Permissions tab, click the “Add more permissions” button, and pasting the very long S3CanonicalUserId we got above into the “Grantee” field of a new. Make sure you give the new permission “Open/Download” rights.

    You can also do this in code using the following boto script:

    import boto
    
    #credentials stored in environment AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
    s3 = boto.connect_s3()
    
    bucket_name = "stream.example.com"
    bucket = s3.get_bucket(bucket_name)
    
    object_name = "video.mp4"
    key = bucket.get_key(object_name)
    
    #Now add read permission to our new s3 account
    s3_canonical_user_id = "<your S3CanonicalUserID from above>"
    key.add_user_grant("READ", s3_canonical_user_id)
    

    4 – Create a cloudfront distribution

    Note that custom origins and private distributions are not fully supported in boto until version 2.0 which has not been formally released at time of writing. The code below pulls out some code from the boto 2.0 branch and hacks it together to get it going but it’s not pretty. The 2.0 branch handles this much more elegantly – definitely use that if possible!

    import boto
    from boto.cloudfront.distribution import DistributionConfig
    from boto.cloudfront.exception import CloudFrontServerError
    
    import re
    
    def get_domain_from_xml(xml):
        results = re.findall("<DomainName>([^<]+)</DomainName>", xml)
        return results[0]
    
    #custom class to hack this until boto v2.0 is released
    class HackedStreamingDistributionConfig(DistributionConfig):
    
        def __init__(self, connection=None, origin='', enabled=False,
                     caller_reference='', cnames=None, comment='',
                     trusted_signers=None):
            DistributionConfig.__init__(self, connection=connection,
                                        origin=origin, enabled=enabled,
                                        caller_reference=caller_reference,
                                        cnames=cnames, comment=comment,
                                        trusted_signers=trusted_signers)
    
        #override the to_xml() function
        def to_xml(self):
            s = '<?xml version="1.0" encoding="UTF-8"?>\n'
            s += '<StreamingDistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-07-15/">\n'
    
            s += '  <S3Origin>\n'
            s += '    <DNSName>%s</DNSName>\n' % self.origin
            if self.origin_access_identity:
                val = self.origin_access_identity
                s += '    <OriginAccessIdentity>origin-access-identity/cloudfront/%s</OriginAccessIdentity>\n' % val
            s += '  </S3Origin>\n'
    
    
            s += '  <CallerReference>%s</CallerReference>\n' % self.caller_reference
            for cname in self.cnames:
                s += '  <CNAME>%s</CNAME>\n' % cname
            if self.comment:
                s += '  <Comment>%s</Comment>\n' % self.comment
            s += '  <Enabled>'
            if self.enabled:
                s += 'true'
            else:
                s += 'false'
            s += '</Enabled>\n'
            if self.trusted_signers:
                s += '<TrustedSigners>\n'
                for signer in self.trusted_signers:
                    if signer == 'Self':
                        s += '  <Self/>\n'
                    else:
                        s += '  <AwsAccountNumber>%s</AwsAccountNumber>\n' % signer
                s += '</TrustedSigners>\n'
            if self.logging:
                s += '<Logging>\n'
                s += '  <Bucket>%s</Bucket>\n' % self.logging.bucket
                s += '  <Prefix>%s</Prefix>\n' % self.logging.prefix
                s += '</Logging>\n'
            s += '</StreamingDistributionConfig>\n'
    
            return s
    
        def create(self):
            response = self.connection.make_request('POST',
                '/%s/%s' % ("2010-11-01", "streaming-distribution"),
                {'Content-Type' : 'text/xml'},
                data=self.to_xml())
    
            body = response.read()
            if response.status == 201:
                return body
            else:
                raise CloudFrontServerError(response.status, response.reason, body)
    
    
    cf = boto.connect_cloudfront()
    
    s3_dns_name = "stream.example.com.s3.amazonaws.com"
    comment = "example streaming distribution"
    oai = "<OAI ID from step 2 above like E23KRHS6GDUF5L>"
    
    #Create a distribution that does NOT need signed URLS
    hsd = HackedStreamingDistributionConfig(connection=cf, origin=s3_dns_name, comment=comment, enabled=True)
    hsd.origin_access_identity = oai
    basic_dist = hsd.create()
    print("Distribution with basic URLs: %s" % get_domain_from_xml(basic_dist))
    
    #Create a distribution that DOES need signed URLS
    hsd = HackedStreamingDistributionConfig(connection=cf, origin=s3_dns_name, comment=comment, enabled=True)
    hsd.origin_access_identity = oai
    #Add some required signers (Self means your own account)
    hsd.trusted_signers = ['Self']
    signed_dist = hsd.create()
    print("Distribution with signed URLs: %s" % get_domain_from_xml(signed_dist))
    

    5 – Test that you can download objects from cloudfront but not from s3

    You should now be able to verify:

    • stream.example.com.s3.amazonaws.com/video.mp4 – should give AccessDenied
    • signed_distribution.cloudfront.net/video.mp4 – should give MissingKey (because the URL is not signed)
    • basic_distribution.cloudfront.net/video.mp4 – should work fine

    The tests will have to be adjusted to work with your stream player, but the basic idea is that only the basic cloudfront url should work.

    6 – Create a keypair for CloudFront

    I think the only way to do this is through Amazon’s web site. Go into your AWS “Account” page and click on the “Security Credentials” link. Click on the “Key Pairs” tab then click “Create a New Key Pair”. This will generate a new key pair for you and automatically download a private key file (pk-xxxxxxxxx.pem). Keep the key file safe and private. Also note down the “Key Pair ID” from amazon as we will need it in the next step.

    7 – Generate some URLs in Python

    As of boto version 2.0 there does not seem to be any support for generating signed CloudFront URLs. Python does not include RSA encryption routines in the standard library so we will have to use an additional library. I’ve used M2Crypto in this example.

    For a non-streaming distribution, you must use the full cloudfront URL as the resource, however for streaming we only use the object name of the video file. See the code below for a full example of generating a URL which only lasts for 5 minutes.

    This code is based loosely on the PHP example code provided by Amazon in the CloudFront documentation.

    from M2Crypto import EVP
    import base64
    import time
    
    def aws_url_base64_encode(msg):
        msg_base64 = base64.b64encode(msg)
        msg_base64 = msg_base64.replace('+', '-')
        msg_base64 = msg_base64.replace('=', '_')
        msg_base64 = msg_base64.replace('/', '~')
        return msg_base64
    
    def sign_string(message, priv_key_string):
        key = EVP.load_key_string(priv_key_string)
        key.reset_context(md='sha1')
        key.sign_init()
        key.sign_update(str(message))
        signature = key.sign_final()
        return signature
    
    def create_url(url, encoded_signature, key_pair_id, expires):
        signed_url = "%(url)s?Expires=%(expires)s&Signature=%(encoded_signature)s&Key-Pair-Id=%(key_pair_id)s" % {
                'url':url,
                'expires':expires,
                'encoded_signature':encoded_signature,
                'key_pair_id':key_pair_id,
                }
        return signed_url
    
    def get_canned_policy_url(url, priv_key_string, key_pair_id, expires):
        #we manually construct this policy string to ensure formatting matches signature
        canned_policy = '{"Statement":[{"Resource":"%(url)s","Condition":{"DateLessThan":{"AWS:EpochTime":%(expires)s}}}]}' % {'url':url, 'expires':expires}
    
        #now base64 encode it (must be URL safe)
        encoded_policy = aws_url_base64_encode(canned_policy)
        #sign the non-encoded policy
        signature = sign_string(canned_policy, priv_key_string)
        #now base64 encode the signature (URL safe as well)
        encoded_signature = aws_url_base64_encode(signature)
    
        #combine these into a full url
        signed_url = create_url(url, encoded_signature, key_pair_id, expires);
    
        return signed_url
    
    def encode_query_param(resource):
        enc = resource
        enc = enc.replace('?', '%3F')
        enc = enc.replace('=', '%3D')
        enc = enc.replace('&', '%26')
        return enc
    
    
    #Set parameters for URL
    key_pair_id = "APKAIAZCZRKVIO4BQ" #from the AWS accounts page
    priv_key_file = "cloudfront-pk.pem" #your private keypair file
    resource = 'video.mp4' #your resource (just object name for streaming videos)
    expires = int(time.time()) + 300 #5 min
    
    #Create the signed URL
    priv_key_string = open(priv_key_file).read()
    signed_url = get_canned_policy_url(resource, priv_key_string, key_pair_id, expires)
    
    #Flash player doesn't like query params so encode them
    enc_url = encode_query_param(signed_url)
    print(enc_url)
    

    8 – Try out the URLs

    Hopefully you should now have a working URL which looks something like this:

    video.mp4%3FExpires%3D1309979985%26Signature%3DMUNF7pw1689FhMeSN6JzQmWNVxcaIE9mk1x~KOudJky7anTuX0oAgL~1GW-ON6Zh5NFLBoocX3fUhmC9FusAHtJUzWyJVZLzYT9iLyoyfWMsm2ylCDBqpy5IynFbi8CUajd~CjYdxZBWpxTsPO3yIFNJI~R2AFpWx8qp3fs38Yw_%26Key-Pair-Id%3DAPKAIAZRKVIO4BQ
    

    Put this into your js and you should have something which looks like this (from the PHP example in Amazon’s CloudFront documentation):

    var so_canned = new SWFObject('http://location.domname.com/~jvngkhow/player.swf','mpl','640','360','9');
        so_canned.addParam('allowfullscreen','true');
        so_canned.addParam('allowscriptaccess','always');
        so_canned.addParam('wmode','opaque');
        so_canned.addVariable('file','video.mp4%3FExpires%3D1309979985%26Signature%3DMUNF7pw1689FhMeSN6JzQmWNVxcaIE9mk1x~KOudJky7anTuX0oAgL~1GW-ON6Zh5NFLBoocX3fUhmC9FusAHtJUzWyJVZLzYT9iLyoyfWMsm2ylCDBqpy5IynFbi8CUajd~CjYdxZBWpxTsPO3yIFNJI~R2AFpWx8qp3fs38Yw_%26Key-Pair-Id%3DAPKAIAZRKVIO4BQ');
        so_canned.addVariable('streamer','rtmp://s3nzpoyjpct.cloudfront.net/cfx/st');
        so_canned.write('canned');
    

    Summary

    As you can see, not very easy! boto v2 will help a lot setting up the distribution. I will find out if it’s possible to get some URL generation code in there as well to improve this great library!

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have an S3 bucket setup as a streaming distribution with a CloudFront service
I have created a public repository on bit bucket website. I can run the
I have an S3 Bucket that holds static content for all my clients in
I am looking into serving my static site with Amazon S3. I have created
I have created a bucket on Amazon S3 and I kept some images in
I have created an Amazon Web Services S3 bucket in the past, without specifying
So I have created an AMI bundle, and have uploaded it to a S3
I have a bucket created since mid 2010. The bucket exists but is empty.
I am trying to setup secure streaming with amazon s3 and cloudfront. I have
I have created a bucket in Amazon S3 and pointed a cname to its

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.