首页 文章

使用Amazon CloudFront专用分发拒绝访问

提问于
浏览
2

我正在尝试为私人内容分发设置CloudFront,但是当我按照生成的URL时,我不断收到“拒绝访问”错误 . 为了清楚起见,我已经创建了CloudFront发行版,将其标记为私有,创建了一个Origin Access ID,该ID已被授予对所有相关文件的读取权限 .

我编写了一个简单的Python脚本,使用亚马逊网页上提供的示例生成URL,用于签名URL,包括以下文本:

import os, time

def GetCloudFrontURL(file, expires=86400):
  resource = "http://mydistribution.cloudfront.net/" + file
  exptime = int(time.time()) + expires
  epochtime = str(exptime)
  policy = '{"Statement":[{"Resource":"' + resource + '","Condition":{"DateLessThan":{"AWS:EpochTime":' + epochtime + '}}}]}'
  pk = "MY-PK-GOES-HERE"
  signature = os.popen("echo '" + policy + "' | openssl sha1 -sign /path/to/file/pk-" + pk + ".pem | openssl base64 | tr '+=/' '-_~'").read()
  signature = signature.replace('\n','')
  url = resource + "&Expires=" + epochtime + "&Signature=" + signature + "&Key-Pair-Id=" + pk
  return url

任何人都可以看到我正在做的事情明显错误吗?我已经验证当我使用私钥对摘要进行签名时,我可以使用公钥对其进行验证(前提是我在通过base64和转换步骤进行验证之前进行了验证) .

谢谢 .

3 回答

  • 0

    运行你的方法我在第一个关键字Expires之前得到一个&符号 .

    >>> GetCloudFrontURL('test123')
    http://mydistribution.cloudfront.net/test123&Expires=1297954193&Signature=&Key-Pair-Id=MY-PK-GOES-HERE
    

    不知道它是否解决了你的整个问题,但我怀疑你在URL中需要问号以使params正确解析 . 尝试这样的事情:

    url = resource + "?Expires=" + epochtime + "&Signature=" + signature + "&Key-Pair-Id=" + pk
    

    除此之外,urllib.urlencode方法会将params字典转换为URL . http://docs.python.org/library/urllib.html#urllib.urlencode

  • 1

    基于此,我能够通过一些调整来实现它 .

    另外,请参阅boto的set_all_permissions函数,该函数将自动为您设置S3 ACL .

    from OpenSSL.crypto import *
    import base64
    import time
    from django.conf import settings
    
    ALT_CHARS = '-~' 
    
    def get_cloudfront_url(file, expires=86400):
        resource = "https://" + settings.AWS_CLOUDFRONT_URL + "/" + file
        exptime = int(time.time()) + expires
    
        epochtime = str(exptime)
        policy = '{"Statement":[{"Resource":"' + resource + '","Condition":{"DateLessThan":{"AWS:EpochTime":' + epochtime + '}}}]}'
    
        f = open(settings.AWS_PRIVATE_KEY, 'r')
        private_key = load_privatekey(FILETYPE_PEM, f.read())
        f.close()
    
        signature = base64.b64encode(sign(private_key, policy, 'sha1'), ALT_CHARS)
        signature = signature.replace('=', '_')
    
        url = resource + "?Expires=" + epochtime + "&Signature=" + signature + "&Key-Pair-Id=" + settings.AWS_CLOUDFRONT_KEY_PAIR_ID
        return url
    
  • 1

    以下是如何生成签名URL而无需os.popen到openssl . 这使用了优秀的M2Crypto python库

    此代码基于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}
    
        #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 = "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进行流式传输的完整工作示例,请参阅Getting started with secure AWS CloudFront streaming with Python

相关问题