2011-01-26 27 views
2

我正在嘗試爲私人內容分發設置CloudFront,但是當我按照生成的URL進行操作時,我不斷收到拒絕訪問錯誤。爲了清楚起見,我已經創建了CloudFront分配,並將其標記爲私有,並創建了一個Origin Access ID,該ID已被授予所有相關文件的讀取權限。使用Amazon CloudFront私人分發拒絕訪問

心中已經寫了一個簡單的Python腳本,以使用亞馬遜網頁呈現簽署的網址和我,包括下面的文本的例子網址:

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和翻譯步驟進行驗證之前進行驗證)。

感謝。

回答

1

運行你的方法我在第一個關鍵函數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方法會將一個參數字典轉換爲您的URL。 http://docs.python.org/library/urllib.html#urllib.urlencode

+0

這絕對看起來可能是一個問題,但不幸的是,我仍然得到訪問被拒絕的錯誤。 – 2011-02-16 20:06:46

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 
0

下面是如何生成簽名的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參數的分佈(或「自我」如果這是你自己的帳號)

一個完全工作在設置示例見Getting started with secure AWS CloudFront streaming with Python這與Python流式傳輸