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

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

问题描述

我在 CloudFront 中创建了一个 S3 存储桶,上传了一个视频,创建了一个流分配.使用静态 HTML 播放器对其进行了测试,并且可以正常工作.我通过帐户设置创建了一个密钥对.目前我的桌面上有私钥文件.这就是我所在的地方.

我的目标是让我的 Django/Python 站点创建安全 URL,并且人们无法访问视频,除非他们来自我的一个页面.问题是我对亚马逊的布局方式过敏,而且我越来越困惑.

我意识到这不会是 StackOverflow 上最好的问题,但我确信我不会是这里唯一一个无法对如何设置安全的 CloudFront 做出正面或反面的傻瓜/S3情况.我非常感谢您的帮助,并愿意(两天后)对最佳答案给予 500pt 奖励.

我有几个问题,一旦得到回答,就应该符合如何完成我所追求的一个解释:

  • 在文档中(下一点有一个例子)有很多 XML 告诉我我需要将内容POST 到不同的地方.是否有用于执行此操作的在线控制台?还是我真的必须通过 cURL(等)强制执行此操作?

  • 如何为 CloudFront 创建源访问身份并将其绑定到我的分配?我已阅读本文档,但是,根据第一点,不要不知道该怎么办.我的密钥对如何适应这个?

  • 完成后,我如何限制 S3 存储桶以仅允许人们通过该身份下载内容?如果这是另一个 XML 作业,而不是在 Web UI 上点击,请告诉我应该在哪里以及如何将其放入我的帐户.

  • 在 Python 中,为文件生成过期 URL 的最简单方法是什么.我安装了 boto,但我不知道如何从流分发中获取文件.

  • 是否有任何应用程序或脚本可以解决设置此问题的难度?我使用 Ubuntu (Linux),但如果它仅适用于 Windows,我在 VM 中有 XP.我已经看过 CloudBerry S3 Explorer Pro - 但它和在线用户界面一样有意义.

解决方案

你说得对,需要大量的 API 工作才能完成这个设置.我希望他们尽快在 AWS 控制台中获得它!

更新:我已将此代码提交给 boto - 从 boto v2.1(2011 年 10 月 27 日发布)开始,这变得容易多了.对于 boto <2.1、使用说明这里.对于 boto 2.1 或更高版本,请在我的博客上获取更新说明:http://www.secretmike.com/2011/10/aws-cloudfront-secure-streaming.html 一旦 boto v2.1 被更多发行版打包,我将在此处更新答案.

要完成您想要的操作,您需要执行以下步骤,我将在下面详细说明:

  1. 创建您的 s3 存储桶并上传一些对象(您已完成此操作)
  2. 创建 Cloudfront源访问身份"(基本上是一个 AWS 帐户,允许 cloudfront 访问您的 s3 存储桶)
  3. 修改对象上的 ACL,以便仅允许您的 Cloudfront Origin Access Identity 读取它们(这可以防止人们绕过 Cloudfront 并直接进入 s3)
  4. 创建一个包含基本 URL 和需要签名 URL 的 Cloudfront 分发
  5. 测试您是否可以从基本的 Cloudfront 发行版下载对象,但不能从 s3 或签名的 Cloudfront 发行版下载对象
  6. 创建用于签署 URL 的密钥对
  7. 使用 Python 生成一些 URL
  8. 测试签名网址是否有效

<小时>

1 - 创建 Bucket 并上传对象

最简单的方法是通过 AWS 控制台,但为了完整起见,我将展示如何使用 boto.Boto 代码显示在此处:

导入boto#credentials 存储在环境 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY 中s3 = boto.connect_s3()#bucket 名称必须遵循 dns 指南new_bucket_name = "stream.example.com"存储桶 = s3.create_bucket(new_bucket_name)object_name = "video.mp4"key = bucket.new_key(object_name)key.set_contents_from_filename(object_name)

2 - 创建 Cloudfront源访问身份"

目前,此步骤只能使用 API 执行.Boto 代码在这里:

导入boto#credentials 存储在环境 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY 中cf = boto.connect_cloudfront()oai = cf.create_origin_access_identity(comment='安全视频的新身份')#我们需要以下两个值用于后面的步骤:打印(源访问身份ID:%s"% oai.id)打印(原始访问身份 S3CanonicalUserId:%s"% oai.s3_user_id)

3 - 修改对象上的 ACL

现在我们已经有了我们的特殊 S3 用户帐户(我们在上面创建的 S3CanonicalUserId),我们需要让它访问我们的 s3 对象.我们可以使用 AWS 控制台轻松完成此操作,方法是打开对象的(不是存储桶的!)权限选项卡,单击添加更多权限"按钮,然后将我们在上面获得的很长的 S3CanonicalUserId 粘贴到新的被授予者"字段中.确保您授予新权限打开/下载"权限.

您也可以使用以下 boto 脚本在代码中执行此操作:

导入boto#credentials 存储在环境 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY 中s3 = boto.connect_s3()bucket_name = "stream.example.com"桶 = s3.get_bucket(bucket_name)object_name = "video.mp4"key = bucket.get_key(object_name)#现在为我们的新 s3 帐户添加读取权限s3_canonical_user_id = "<你上面的 S3CanonicalUserID>"key.add_user_grant("READ", s3_canonical_user_id)

4 - 创建云前端分发

请注意,在撰写本文时尚未正式发布的 2.0 版之前,boto 并不完全支持自定义来源和私有分发.下面的代码从 boto 2.0 分支中提取了一些代码并将其组合在一起以使其运行,但它并不漂亮.2.0 分支更优雅地处理了这一点 - 如果可能,一定要使用它!

导入boto从 boto.cloudfront.distribution 导入 DistributionConfig从 boto.cloudfront.exception 导入 CloudFrontServerError进口重新def get_domain_from_xml(xml):结果 = re.findall("<域名>([^<]+)", xml)返回结果[0]#custom 类来破解这个直到 boto v2.0 发布类 HackedStreamingDistributionConfig(DistributionConfig):def __init__(self, connection=None, origin='', enabled=False,caller_reference='', cnames=None, comment='',可信签名者=无):DistributionConfig.__init__(self, connection=connection,原点=原点,启用=启用,caller_reference=caller_reference,cnames=cnames,comment=comment,受信任的签名者=受信任的签名者)#覆盖 to_xml() 函数def to_xml(self):s = '<?xml version="1.0" encoding="UTF-8"?>
's += '<StreamingDistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-07-15/">
's += ' 
's += ' <DNSName>%s</DNSName>
' % self.origin如果 self.origin_access_identity:val = self.origin_access_identitys += ' origin-access-identity/cloudfront/%s
' % vals += ' </S3Origin>
's += ' <CallerReference>%s</CallerReference>
' % self.caller_reference对于 self.cnames 中的 cname:s += ' %s
' % cname如果 self.comment:s += ' <Comment>%s</Comment>
' % self.comments += ' <已启用>'如果 self.enabled:s += '真'别的:s += '假's += '
'如果 self.trusted_signers:s += '
'对于 self.trusted_signers 中的签名者:如果签名者 == '自我':s += ' <自己/>
'别的:s += ' %s
' % 签名者s += '</TrustedSigners>
'如果 self.logging:s += '<日志>
's += ' <Bucket>%s</Bucket>
' % self.logging.buckets += ' <Prefix>%s</Prefix>
' % self.logging.prefixs += '</日志记录>
's += '
'返回定义创建(自我):response = self.connection.make_request('POST','/%s/%s' % ("2010-11-01", "streaming-distribution"),{'内容类型':'文本/xml'},数据=self.to_xml())正文 = response.read()如果 response.status == 201:返回身体别的:引发 CloudFrontServerError(response.status, response.reason, body)cf = boto.connect_cloudfront()s3_dns_name = "stream.example.com.s3.amazonaws.com"评论 =示例流分发"oai = "<来自上面第 2 步的 OAI ID,如 E23KRHS6GDUF5L>"#创建一个不需要签名 URL 的发行版hsd = HackedStreamingDistributionConfig(connection=cf, origin=s3_dns_name, comment=comment, enabled=True)hsd.origin_access_identity = oaibasic_dist = hsd.create()打印(带有基本 URL 的分布:%s" % get_domain_from_xml(basic_dist))#创建一个不需要签名 URL 的发行版hsd = HackedStreamingDistributionConfig(connection=cf, origin=s3_dns_name, comment=comment, enabled=True)hsd.origin_access_identity = oai#添加一些需要的签名者(Self是指自己的账号)hsd.trusted_signers = ['Self']signed_dist = hsd.create()print("带有签名 URL 的分发:%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 中生成一些 URL

从 boto 2.0 版开始,似乎不支持生成签名的 CloudFront URL.Python 的标准库中不包含 RSA 加密例程,因此我们将不得不使用额外的库.我在这个例子中使用了 M2Crypto.

对于非流媒体分发,您必须使用完整的 cloudfront URL 作为资源,但是对于流媒体,我们仅使用视频文件的对象名称.有关生成仅持续 5 分钟的 URL 的完整示例,请参阅下面的代码.

此代码松散地基于 Amazon 在 CloudFront 文档中提供的 PHP 示例代码.

from M2Crypto import EVP导入 base64导入时间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('/', '~')返回 msg_base64def sign_string(消息,priv_key_string):key = EVP.load_key_string(priv_key_string)key.reset_context(md='sha1')key.sign_init()key.sign_update(str(message))签名 = key.sign_final()返回签名def create_url(url, encoding_signature, key_pair_id, expires):signed_url = "%(url)s?Expires=%(expires)s&Signature=%(encoded_signature)s&Key-Pair-Id=%(key_pair_id)s" % {网址":网址,'过期':过期,'encoded_signature':encoded_signature,'key_pair_id':key_pair_id,}返回signed_urldef get_canned_policy_url(url, priv_key_string, key_pair_id, expires):#我们手动构建此策略字符串以确保格式匹配签名canned_policy = '{"Statement":[{"Resource":"%(url)s","Condition":{"DateLessThan":{"AWS:EpochTime":%(expires)s}}}]}' %{'url':url, 'expires':expires}#now base64 对其进行编码(必须是 URL 安全的)编码策略 = aws_url_base64_encode(canned_policy)#签署非编码策略签名 = sign_string(canned_policy, priv_key_string)#now base64 对签名进行编码(URL 也是安全的)编码签名 = aws_url_base64_encode(签名)#将这些组合成一个完整的网址signed_url = create_url(url,encoded_signature,key_pair_id, expires);返回signed_urldef encode_query_param(资源):enc = 资源enc = enc.replace('?', '%3F')enc = enc.replace('=', '%3D')enc = enc.replace('&', '%26')返回编码#设置URL参数key_pair_id = "APKAIAZCZRKVIO4BQ" #来自 AWS 账户页面priv_key_file = "cloudfront-pk.pem" #你的私钥对文件resource = 'video.mp4' #你的资源(只是流视频的对象名称)expires = int(time.time()) + 300 #5 分钟#创建签名的URLpriv_key_string = 打开(priv_key_file).read()signed_url = get_canned_policy_url(资源,priv_key_string,key_pair_id,过期)#Flash 播放器不喜欢查询参数,因此对其进行编码enc_url = encode_query_param(signed_url)打印(enc_url)

8 - 试用网址

希望您现在应该有一个如下所示的有效网址:

<预> <代码> video.mp4%3FExpires%3D1309979985%26Signature%3DMUNF7pw1689FhMeSN6JzQmWNVxcaIE9mk1x〜KOudJky7anTuX0oAgL〜1GW-ON6Zh5NFLBoocX3fUhmC9FusAHtJUzWyJVZLzYT9iLyoyfWMsm2ylCDBqpy5IynFbi8CUajd〜CjYdxZBWpxTsPO3yIFNJI〜R2AFpWx8qp3fs38Yw_%26Key线对-ID%3DAPKAIAZRKVIO4BQ

将其放入您的 js 中,您应该会得到如下所示的内容(来自 Amazon CloudFront 文档中的 PHP 示例):

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( '文件', 'video.mp4%3FExpires%3D1309979985%26Signature%3DMUNF7pw1689FhMeSN6JzQmWNVxcaIE9mk1x〜KOudJky7anTuX0oAgL〜1GW-ON6Zh5NFLBoocX3fUhmC9FusAHtJUzWyJVZLzYT9iLyoyfWMsm2ylCDBqpy5IynFbi8CUajd〜CjYdxZBWpxTsPO3yIFNJI〜R2AFpWx8qp3fs38Yw_%26Key线对-ID%3DAPKAIAZRKVIO4BQ');so_canned.addVariable('streamer','rtmp://s3nzpoyjpct.cloudfront.net/cfx/st');so_canned.write('canned');

<小时>

总结

如您所见,这并不容易!boto v2 对设置发行版有很大帮助.我会找出是否有可能在那里获得一些 URL 生成代码来改进这个伟大的库!

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"?>
'
        s += '<StreamingDistributionConfig xmlns="http://cloudfront.amazonaws.com/doc/2010-07-15/">
'

        s += '  <S3Origin>
'
        s += '    <DNSName>%s</DNSName>
' % self.origin
        if self.origin_access_identity:
            val = self.origin_access_identity
            s += '    <OriginAccessIdentity>origin-access-identity/cloudfront/%s</OriginAccessIdentity>
' % val
        s += '  </S3Origin>
'


        s += '  <CallerReference>%s</CallerReference>
' % self.caller_reference
        for cname in self.cnames:
            s += '  <CNAME>%s</CNAME>
' % cname
        if self.comment:
            s += '  <Comment>%s</Comment>
' % self.comment
        s += '  <Enabled>'
        if self.enabled:
            s += 'true'
        else:
            s += 'false'
        s += '</Enabled>
'
        if self.trusted_signers:
            s += '<TrustedSigners>
'
            for signer in self.trusted_signers:
                if signer == 'Self':
                    s += '  <Self/>
'
                else:
                    s += '  <AwsAccountNumber>%s</AwsAccountNumber>
' % signer
            s += '</TrustedSigners>
'
        if self.logging:
            s += '<Logging>
'
            s += '  <Bucket>%s</Bucket>
' % self.logging.bucket
            s += '  <Prefix>%s</Prefix>
' % self.logging.prefix
            s += '</Logging>
'
        s += '</StreamingDistributionConfig>
'

        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!

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

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