当前位置:  开发笔记 > 编程语言 > 正文

为Amazon CloudFront创建签名URL

如何解决《为AmazonCloudFront创建签名URL》经验,为你挑选了3个好方法。

简短版本:如何"按需"制作签名URL,以使用Python模拟Nginx的X-Accel-Redirect行为(即保护下载)与Amazon CloudFront/S3.

我有一个Django服务器,并运行Nginx前端.我一直受到了对它的请求的打击,最近不得不将其安装为Tornado WSGI应用程序,以防止它在FastCGI模式下崩溃.

现在我遇到了一个问题,我的服务器陷入困境(因为它的大部分带宽正在用完),因为有太多的媒体请求,我一直在寻找CDN,我相信Amazon CloudFront/S3对我来说是合适的解决方案.

我一直在使用Nginx的X-Accel-Redirect标头来保护文件免受未经授权的下载,但我没有使用CloudFront/S3的能力 - 但是它们确实提供了签名的URL.到目前为止,我不是Python专家,并且肯定不知道如何正确创建签名URL,所以我希望有人可以获得如何"按需"制作这些URL的链接,或者愿意解释如何在这里,我们将不胜感激.

而且,这是正确的解决方案吗?我不太熟悉CDN,是否有更适合这种情况的CDN?



1> secretmike..:

Amazon CloudFront签名URL与Amazon S3 签名URL的工作方式不同.CloudFront使用基于单独CloudFront密钥对的RSA签名,您必须在Amazon帐户凭据页面中设置该密钥对.以下是使用M2Crypto库在Python中实际生成限时URL的一些代码:

为CloudFront创建密钥对

我认为唯一的方法是通过亚马逊的网站.进入您的AWS"帐户"页面,然后单击"安全凭据"链接.单击"密钥对"选项卡,然后单击"创建新密钥对".这将为您生成一个新的密钥对,并自动下载私钥文件(pk-xxxxxxxxx.pem).保持密钥文件安全和私密.另请注意亚马逊的"密钥对ID",因为我们将在下一步中使用它.

在Python中生成一些URL

从boto版本2.0开始,似乎没有任何支持来生成签名的CloudFront URL.Python在标准库中不包含RSA加密例程,因此我们必须使用其他库.我在这个例子中使用过M2Crypto.

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

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

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(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}

    #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 = "APKAIAZVIO4BQ" #from the AWS accounts CloudFront tab
priv_key_file = "cloudfront-pk.pem" #your private keypair file
# Use the FULL URL for non-streaming:
resource = "http://34254534.cloudfront.net/video.mp4"
#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)

print(signed_url)

#Flash player doesn't like query params so encode them if you're using a streaming distribution
#enc_url = encode_query_param(signed_url)
#print(enc_url)

确保使用设置为持有密钥对的帐户的TrustedSigners参数设置您的分配(如果是您自己的帐户,则设置为"Self")

请参阅使用Python开始使用安全的AWS CloudFront流式传输,以获得有关使用Python进行流式传输的完整工作示例


嗨MattoTodd,你是对的,不需要在那里.此外,boto v2.1现在支持本机.有关如何使用新的boto代码,请参见http://www.secretmike.com/2011/10/aws-cloudfront-secure-streaming.html.一旦boto版本出来一段时间我就会更新这些答案.

2> RayLuo..:

Botocore现已支持此功能,Botocore是最新的官方适用于Python的AWS SDK Boto3的底层库.(以下示例需要安装rsa软件包,但您也可以使用其他RSA软件包,只需定义自己的"规范化RSA签名者".)

用法如下:

    from botocore.signers import CloudFrontSigner
    # First you create a cloudfront signer based on a normalized RSA signer::
    import rsa
    def rsa_signer(message):
        private_key = open('private_key.pem', 'r').read()
        return rsa.sign(
            message,
            rsa.PrivateKey.load_pkcs1(private_key.encode('utf8')),
            'SHA-1')  # CloudFront requires SHA-1 hash
    cf_signer = CloudFrontSigner(key_id, rsa_signer)

    # To sign with a canned policy::
    signed_url = cf_signer.generate_presigned_url(
        url, date_less_than=datetime(2015, 12, 1))

    # To sign with a custom policy::
    signed_url = cf_signer.generate_presigned_url(url, policy=my_policy)

免责声明:我是该公关的作者.



3> Steffen Opel..:

正如许多人已经评论过的那样,最初接受的答案实际上并不适用于Amazon CloudFront,因为通过CloudFront服务私有内容需要使用专用的CloudFront签名URL - 因此secretmike的答案是正确的,但同时他自己已经过时了花了很多时间并添加了为CloudFront生成签名URL的支持(非常感谢!).

boto现在支持专用的create_signed_url方法,前一个二进制依赖项M2Crypto最近也被纯Python RSA实现取代,请参阅不要使用M2Crypto进行云端URL签名.

随着越来越普遍,人们可以找到(请参阅相关的单元测试中的一个或更多的好用法示例test_signed_urls.py),例如test_canned_policy(个体经营) -见设置(个体经营)为引用的变量self.pk_idself.pk_str(很明显,你需要自己键):

def test_canned_policy(self):
    """
    Generate signed url from the Example Canned Policy in Amazon's
    documentation.
    """
    url = "http://d604721fxaaqy9.cloudfront.net/horizon.jpg?large=yes&license=yes"
    expire_time = 1258237200
    expected_url = "http://example.com/" # replaced for brevity
    signed_url = self.dist.create_signed_url(
        url, self.pk_id, expire_time, private_key_string=self.pk_str)
    # self.assertEqual(expected_url, signed_url)

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有