В частном распространении Amazon CloudFront отказано в доступе - PullRequest
2 голосов
/ 27 января 2011

Я пытаюсь настроить CloudFront для распространения частного контента, но у меня продолжают появляться ошибки «Отказано в доступе» при переходе по сгенерированному URL. Чтобы было ясно, я уже создал дистрибутив CloudFront, пометил его как частный, создал Origin Access ID, которому было предоставлено разрешение на чтение всех соответствующих файлов.

Я написал простой скрипт на Python для генерации URL-адресов, используя примеры, представленные на веб-странице Amazon для подписи 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 ]

1 голос
/ 24 июня 2011

Исходя из этого, я смог заставить его работать с несколькими настройками.

Также см. Функцию set_all_permissions от boto, которая автоматически установит вам списки ACL S3.

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 голос
/ 16 февраля 2011

Запустив твой метод, я получаю амперсанд перед первой клавиатурой, Истекает.

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

Не знаю, решит ли это всю вашу проблему, но я подозреваю, что вам нужен вопросительный знак в URL, чтобы параметры анализировались правильно. Попробуйте что-то вроде этого:

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

Кроме того, метод urllib.urlencode преобразует словарь параметров в URL для вас. http://docs.python.org/library/urllib.html#urllib.urlencode

0 голосов
/ 14 июля 2011

Вот как вы можете создавать подписанные URL-адреса без необходимости открывать файл openssl. Это использует превосходную библиотеку M2Crypto Python

Этот код основан на примере PHP-кода, предоставленного Amazon в документации CloudFront.

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", если это ваша собственная учетная запись)

См. Начало работы с безопасной потоковой передачей AWS CloudFront с Python , чтобы получить полностью проработанный пример настройки этой функции для потоковой передачи с Python

...