开始使用安全AWS CloudFront的流媒体与Python [英] Getting started with secure AWS CloudFront streaming with Python

查看:214
本文介绍了开始使用安全AWS CloudFront的流媒体与Python的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了一个S3存储,上传视频,创建于CloudFront的流媒体分发。使用静态的HTML玩家测试,它的工作原理。我创建通过帐户设置一个密钥。我有私钥文件坐在我桌面上的那一刻。这就是我。

我的目标是去哪里我的Django / Python的网站创建安全网址和人民不能访问的视频,除非他们是来自我的网页一个点。问题是我过敏的方式亚马逊奠定东西出来,我只是越来越糊涂了。

我知道这是不是要上StackOverflow上最好的问题,但我敢肯定,我不能是唯一的傻瓜在这里不能做出正面或反面出如何建立一个安全的CloudFront的/ S3的情况。我真的AP preciate你们的帮助,我愿意(做两项几天一直通过)给予500pt赏金的最佳答案。

我有几个问题,一旦回答了,应该适应如何完成我后一种解释:

  • 在文件(有在未来的点为例)有大量的XML躺在身边,告诉我,我需要 POST 的东西到各个地方。是否有这样做的一个在线的控制台?还是我从字面上通过卷曲(等)?

  • 要迫使这件事
  • 如何创建一个地访问标识为CloudFront的,并将其绑定到我的分配?我读过<一个href="http://docs.amazonwebservices.com/AmazonCloudFront/latest/DeveloperGuide/index.html?SecuringContent_S3.html#CreateOriginAccessIdentity">this文档但是,按照第一点,不知道该怎么办。如何我的密钥对融入这个?

  • 一旦这样做了,我怎么限制的S3存储桶,只允许人们通过身份下载的东西?如果这是另一个XML jobby,而不是一下周围的网络用户界面,请告诉我在哪里以及如何我应该得到这个到我的帐户。

  • 在Python中,什么是生成一个文件的URL到期的最简单的方法。我有博托安装,但我不知道怎么去从流式分发的文件。

  • 是否有一些可以采取设置此装束起来的难度的任何应用程序或脚本?我使用Ubuntu(Linux的),但我有XP的虚拟机,如果是仅Windows。我已经看了云莓S3 Pro的资源管理器 - 但它使大约多大意义的网上用户界面

解决方案

您是对的,它需要大量的API的工作得到这个成立。我希望他们得到它在AWS控制台很快!

更新:我已经提交了这个code到博托 - 作为博托V2.1的(发布2011-10-27)这变得容易得多。对于博托&LT; 2.1,在这里使用的说明。对于博托2.1或更高版本,让我的博客的更新说明:<一href="http://www.secretmike.com/2011/10/aws-cloudfront-secure-streaming.html">http://www.secretmike.com/2011/10/aws-cloudfront-secure-streaming.html一旦博托V2.1得到由多个发行版打包我会更新这里的答案。

要完成你想要什么,你需要执行以下步骤,我将详细介绍如下:

  1. 创建您的S3存储和上传一些物体(你已经做到了这一点)
  2. 建立的Cloudfront原产地访问标识(基本上是一个AWS账号,让CloudFront的访问您的S3存储)
  3. 修改的ACL对你的对象,这样只有你的Cloudfront地访问标识被允许阅读
  4. (绕过的Cloudfront和去直接到S3这prevents人)
  5. 创建一个CloudFront的分布基本URL和一个需要签署的网址
  6. 测试您是否可以从S3或签署CloudFront的分布
  7. 下载从基本CloudFront的分配对象,但不
  8. 创建一个密钥对签名网址
  9. 生成使用Python一些网址
  10. 测试已签名的网址工作

1 - 创建桶并上传对象

要做到这一点,最简单的方法是通过AWS控制台,但出于完整性我将介绍如何使用博托。宝途code如下所示:

 进口博托

存储环境AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY #credentials
S3 = boto.connect_s3()

#bucket名称必须遵循DNS指引
new_bucket_name =stream.example.com
斗= s3.create_bucket(new_bucket_name)

OBJECT_NAME =video.mp4
键= bucket.new_key(对象)
key.set_contents_from_filename(对象)
 

2 - 创建的Cloudfront原产地访问标识

目前,这一步只能使用API​​执行。宝途code是在这里:

 进口博托

存储环境AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY #credentials
CF = boto.connect_cloudfront()

OAI = cf.create_origin_access_identity(注释='为安全视频新身份)

#We需要以下两个值后面的步骤:
打印(原产地访问标识ID:%s的%oai.id)
打印(原产地访问标识S3CanonicalUserId:%s的%oai.s3_user_id)
 

3 - 修改访问控制列表上的对象

现在,我们已经得到了我们的特别S3的用户帐户(S3CanonicalUserId我们上面创建的),我们需要给它进入我们的S3对象。我们可以使用AWS控制台通过打开对象的(而不是桶的!)权限选项卡做到这一点很容易,请单击添加更多的权限按钮,并粘贴我们得到了上述进入了一个新的受让人字段中的很长S3CanonicalUserId。请确保你给了新的权限打开/下载的权利。

您也可以在code。使用以下博托脚本做到这一点:

 进口博托

存储环境AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY #credentials
S3 = boto.connect_s3()

bucket_name =stream.example.com
斗= s3.get_bucket(bucket_name)

OBJECT_NAME =video.mp4
键= bucket.get_key(对象)

#Now添加读取权限到我们的新S3帐户
s3_canonical_user_id =&lt;您S3CanonicalUserID从上面&gt;中
key.add_user_grant(READ,s3_canonical_user_id)
 

4 - 创建CloudFront的分布

需要注意的是自定义的起源和私人分布不完全支持在博托直到2.0版本还没有被正式发布,在写本新闻时下面的code翻出从博托2.0分支约code和黑客一起得到它去,但它不是pretty的。 2.0分支处理这个更优雅 - !肯定可以使用,如果可能的

 进口博托
从boto.cloudfront.distribution进口DistributionConfig
从boto.cloudfront.exception进口CloudFrontServerError

进口重

高清get_domain_from_xml(XML):
    结果=通过re.findall(&其中;域名&GT;([^&所述;] +)所述; /域名&gt;中,XML)
    返回结果[0]

#custom类破解,直到博托V2.0发布
类HackedStreamingDistributionConfig(DistributionConfig):

    高清__init __(个体经营,连接=无,产地='',启用=假,
                 caller_reference ='',的CNAME =无,评论='',
                 trusted_signers =无):
        DistributionConfig .__的init __(个体经营,连接=连接,
                                    起源=原产地,使=启用,
                                    caller_reference = caller_reference,
                                    的CNAME =的CNAME,评论=评论,
                                    trusted_signers = trusted_signers)

    #override所述to_xml()函数
    高清to_xml(个体经营):
        S ='&LT; XML版本=1.0编码=UTF-8&GT;吗?\ n
        S + ='&LT; StreamingDistributionConfig的xmlns =htt​​p://cloudfront.amazonaws.com/doc/2010-07-15/&GT; \ N'

        S + ='&LT; S3Origin&GT; \ N'
        S + ='&LT; D​​NSNAME&GT;%S&LT; / DNSNAME&GT; \ N'%self.origin
        如果self.origin_access_identity:
            VAL = self.origin_access_identity
            S + ='&LT; OriginAccessIdentity&GT;原产地访问身份/ CloudFront的/%S&LT; / OriginAccessIdentity&GT; \ N'%VAL
        S + ='&LT; / S3Origin&GT; \ N'


        S + ='&LT; CallerReference&GT;%S&LT; / CallerReference&GT; \ N'%self.caller_reference
        对于CNAME在self.cnames:
            S + ='&LT; CNAME&GT;%S&LT; / CNAME&GT; \ N'%CNAME
        如果self.comment:
            S + ='&LT;注释&GT;%S&LT; /评论&GT; \ N'%self.comment
        S + ='&LT;启用&GT;
        如果self.enabled:
            S + ='真实'
        其他:
            S + ='假'
        S + ='&LT; /启用&GT; \ N'
        如果self.trusted_signers:
            S + ='&LT; TrustedSigners&GT; \ N'
            签名者在self.trusted_signers:
                如果签名者=='自我':
                    S + ='&LT;自/&GT; \ N'
                其他:
                    S + ='&LT; AwsAccountNumber&GT;%S&LT; / AwsAccountNumber&GT; \ N'%签名
            S + ='&LT; / TrustedSigners&GT; \ N'
        如果self.logging:
            S + ='&LT;记录&GT; \ N'
            S + ='&LT;斗&GT;%S&LT; /桶&GT; \ N'%self.logging.bucket
            S + ='&LT; preFIX&GT;%S&LT; / preFIX&GT; \ N'。%self.logging preFIX
            S + ='&LT; /日志&GT; \ N'
        S + ='&LT; / StreamingDistributionConfig&GT; \ N'

        返回小号

    高清创建(个体经营):
        响应= self.connection.make_request('POST',
            /%S /%s的%(2010-11-01,流分配),
            {内容类型:为text / xml},
            数据= self.to_xml())

        身体= response.read()
        如果response.status == 201:
            回体
        其他:
            提高CloudFrontServerError(response.status,response.reason,体)


CF = boto.connect_cloudfront()

s3_dns_name =stream.example.com.s3.amazonaws.com
注释=例如流媒体分发
OAI =&LT; OAI ID从第2步上述像E23KRHS6GDUF5L&gt;中

#Create分布,这并不需要签署的URLS
HSD = HackedStreamingDistributionConfig(连接= CF,产地= s3_dns_name,评论=评论,启用=真)
hsd.origin_access_identity = OAI
basic_dist = hsd.create()
打印(分布的基本网址:%s的%get_domain_from_xml(basic_dist))

#Create分布,它需要签署的URLS
HSD = HackedStreamingDistributionConfig(连接= CF,产地= s3_dns_name,评论=评论,启用=真)
hsd.origin_access_identity = OAI
#Add一些必要的签名者(自意味着你自己的帐号)
hsd.trusted_signers = ['自我']
signed_dist = hsd.create()
打印(分销与签约的网址:%s的%get_domain_from_xml(signed_dist))
 

5 - 测试,你可以从CloudFront的对象,而不是从S3

现在你应该可以验证:

  • stream.example.com.s3.amazonaws.com/video.mp4 - 应该给AccessDenied
  • signed_distribution.cloudfront.net/video.mp4 - 应该给MissingKey(因为URL没有签名)
  • basic_distribution.cloudfront.net/video.mp4 - 应该可以正常工作

该测试将必须调整你的流播放器的工作,但其基本思想是,只有基本的CloudFront的URL应该工作。

6 - 为CloudFront的创建一个密钥对

我觉得要做到这一点的唯一方法是通过亚马逊的网站。进入您的AWS帐户页面,点击安全证书链接。点击密钥对选项卡,然后点击创建一个新的密钥对。这将产生一个新的密钥对你并自动下载一个私钥文件(PK-xxxxxxxxx.pem)。保持密钥文件的安全和隐私。同时记下密钥对ID从亚马逊,因为我们需要它的下一个步骤。

7 - 生成Python中的一些网址

由于博托2.0版似乎没有被用于生成签名的CloudFront的URL的任何支持。 Python没有包括在标准库中的RSA加密例程,所以我们将不得不使用一个额外的库。我用M2Crypto在这个例子。

有关非流分发,则必须使用完整的CloudFront的URL作为资源,但是,对于流媒体,我们只用了视频文件的对象名称。请参见下面的code生成一个URL只持续5分钟的完整例子。

这code是松散的CloudFront的文档中提供亚马逊的PHP例如code为主。

 从M2Crypto进口EVP
进口的base64
进口时间

高清aws_url_base64_en code(MSG):
    msg_base64 = base64.b64en code(MSG)
    msg_base64 = msg_base64.replace(+, - )
    msg_base64 = msg_base64.replace('=','_')
    msg_base64 = msg_base64.replace('/','〜')
    回报msg_base64

高清sign_string(消息,priv_key_string):
    键= EVP.load_k​​ey_string(priv_key_string)
    key.reset_context(MD =SHA1)
    key.sign_init()
    key.sign_update(STR(消息))
    签名= key.sign_final()
    返回签名

高清create_url(URL,连接coded_signature,key_pair_id,过期):
    signed_url =?%(URL)■过期=%(到期),S&安培;签字=%(EN coded_signature)S&安培;密钥对-ID =%(key_pair_id)的%{
            URL:URL,
            过期:到期,
            恩coded_signature':恩coded_signature,
            key_pair_id:key_pair_id,
            }
    回报signed_url

高清get_canned_policy_url(URL,priv_key_string,key_pair_id,过期):
    #we手动构建这一政策的字符串,以保证格式相匹配的签名
    canned_policy ='{声明:[{资源:%(URL)的,条件:{DateLessThan:{AWS:EpochTime:%(到期)■}}}]}'% {URL:URL,过期:到期}

    #now的base64 EN $ C C是$(必须是URL安全的)
    EN coded_policy = aws_url_base64_en code(canned_policy)
    #sign非恩codeD政策
    签名= sign_string(canned_policy,priv_key_string)
    #now的base64 EN code中的签名(URL安全以及)
    EN coded_signature = aws_url_base64_en code(签名)

    #combine这些成一个完整的URL
    signed_url = create_url(URL,连接coded_signature,key_pair_id,到期);

    回报signed_url

DEF EN code_query_param(资源):
    ENC =资源
    ENC = enc.replace('?','%3F)
    ENC = enc.replace(=,%3D')
    ENC = enc.replace('&安培;','%26')
    回报ENC


#设置参数的URL
key_pair_id =APKAIAZCZRKVIO4BQ#from的AWS账户页面
priv_key_file =CloudFront的-pk.pem#your私有密钥文件
资源='video.mp4'#your资源(只是对象名称的流媒体视频)
期满= INT(time.time())+ 300#5分钟

#Create签署的网址
priv_key_string =开(priv_key_file).read()
signed_url = get_canned_policy_url(资源,priv_key_string,key_pair_id,到期)

#Flash球员不喜欢查询参数,以便连接$ C C他们$
enc_url = EN code_query_param(signed_url)
打印(enc_url)
 

8 - 尝试一下网址

希望你现在应该有它看起来像这样一个工作URL:

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

将这个到您的JS和前人的精力,你有东西,看起来像这样(从PHP例如亚马逊的CloudFront的文件):

  VAR so_canned =新的SWFObject(http://location.domname.com/~jvngkhow/player.swf','mpl','640','360',' 9');
    so_canned.addParam('的allowFullScreen','真');
    so_canned.addParam(allowScriptAccess的','永远');
    so_canned.addParam('WMODE','不透明');
    so_canned.addVariable('file','video.mp4%3FExpires%3D1309979985%26Signature%3DMUNF7pw1689FhMeSN6JzQmWNVxcaIE9mk1x~KOudJky7anTuX0oAgL~1GW-ON6Zh5NFLBoocX3fUhmC9FusAHtJUzWyJVZLzYT9iLyoyfWMsm2ylCDBqpy5IynFbi8CUajd~CjYdxZBWpxTsPO3yIFNJI~R2AFpWx8qp3fs38Yw_%26Key-Pair-Id%3DAPKAIAZRKVIO4BQ');
    so_canned.addVariable('流光','设rtmp://s3nzpoyjpct.cloudfront.net/cfx/st');
    so_canned.write('罐装');
 


摘要

正如你所看到的,也不是很容易的!博托V2将有很大的帮助建立的分布。我会找出是否有可能得到一些URL生成code。在那里,以及改善这个伟大的图书馆!

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.

解决方案

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 sould 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!

这篇关于开始使用安全AWS CloudFront的流媒体与Python的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆