2011-01-26 4 views
2

Je suis en train de configurer CloudFront pour la distribution de contenu privé, mais je continue à avoir des erreurs d'accès refusé lorsque je suis l'URL générée. Pour être clair, j'ai déjà créé la distribution CloudFront, l'ai marquée privée, créé un identifiant d'accès à l'origine qui a reçu une autorisation de lecture pour tous les fichiers pertinents.Accès refusé avec la distribution privée Amazon CloudFront

I'v écrit un simple script Python pour générer des URL en utilisant les exemples présentés sur la page Web Amazon pour la signature des URL et je suis y compris le texte ci-dessous:

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 

Quelqu'un peut-il voir quoi que ce soit évidemment faux avec ce que je fais? J'ai vérifié que lorsque je signe le résumé en utilisant la clé privée que je peux le vérifier avec la clé publique (à condition que je fais la vérification avant de le faire passer par base64 et l'étape de traduction).

Merci.

Répondre

1

Exécution de votre méthode que j'obtenir une esperluette avant la première keywork, Expires.

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

Je ne sais pas si cela résout votre problème dans son ensemble, mais je vous suspectez besoin point d'interrogation dans l'URL pour obtenir les params pour analyser correctement. Essayez quelque chose comme ceci:

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

En plus, la méthode de urllib.urlencode convertira un dictionnaire de params dans une URL pour vous. http://docs.python.org/library/urllib.html#urllib.urlencode

+0

cela ressemble vraiment à cela pourrait être un problème, mais malheureusement, je reçois toujours l'erreur d'accès refusé. –

1

Sur cette base, j'ai pu le faire fonctionner avec quelques modifications.

Voir aussi la fonction set_all_permissions de Boto qui vous coûtera S3 ACL automatiquement pour vous.

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

Voici comment générer des URL signées sans os.popen to openssl. Celui-ci utilise l'excellente bibliothèque Python M2Crypto

Ce code est vaguement basé sur l'exemple de code PHP fourni par Amazon CloudFront dans la 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(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) 

Assurez-vous que vous configurez votre distribution avec un paramètre TrustedSigners réglé sur le compte tenue de votre paire de clés (ou « Auto » si elle est votre propre compte)

Voir Getting started with secure AWS CloudFront streaming with Python pour un exemple entièrement travaillé à la mise cela pour le streaming avec Python