Frage

Kurzversion:. Wie kann ich signierte URLs "on-demand" zu imitieren Nginx X-Accel-Redirect-Verhalten (das heißt Downloads Schutz) mit Amazon Cloudfront / S3 Python mit

Ich habe eine Django-Server aufgestanden und läuft mit einem Nginx Front-End. Ich habe mit Anfragen es immer gehämmert und vor kurzem hatte es als Tornado WSGI Anwendung zu installieren, um es zu verhindern, in FastCGI-Modus abstürzt.

Jetzt bin ich ein Problem mit meinem Server mit verzetteln (dh den größten Teil seiner Bandbreite verbraucht wird) aufgrund zu viele Anfragen für Medien, um es gemacht wird, ich habe in CDNs suchen und ich glaube, Amazon Cloudfront / S3 wäre die richtige Lösung für mich sein.

Ich habe mit Nginx X-Accel-Redirect-Header, die Dateien vor unbefugtem Herunterladen zu schützen, aber ich habe nicht die Fähigkeit, mit Cloudfront / S3 - aber sie bieten signierte URLs tun. Ich bin keinen Python-Experte bei weitem und definitiv nicht wissen, wie eine Unterzeichnung URL richtig zu erstellen, so dass ich hoffte, dass jemand einen Link, wie hätte diese URLs „on-demand“ zu machen oder wäre bereit, zu erklären, wie man hier wäre es sehr zu schätzen.

Auch ist dies die richtige Lösung, auch? Ich bin nicht allzu vertraut mit CDNs, gibt es einen CDN, die besser dafür geeignet wären?

War es hilfreich?

Lösung

Amazon Cloudfront Signed URLs Arbeit anders als Amazon S3 signierte URLs. Cloudfront verwendet RSA-Signaturen basierend auf einer separaten Cloudfront Keypair, die Sie in Ihrem Amazon-Konto Seite Anmeldeinformationen einzurichten haben. Hier ist ein Code, um tatsächlich eine zeitlich begrenzte URL in Python zu generieren mit der m2crypto Bibliothek:

Erstellen Sie ein Schlüsselpaar für Cloudfront

ich glaube, der einzige Weg, dies zu tun, durch Website von Amazon ist. Gehen Sie in Ihrem AWS „Konto“ und klicken Sie auf den „Sicherheits Credentials“ -Link. Klicken Sie auf die „Schlüsselpaare“ Registerkarte klicken Sie dann auf „Erstellen eines neuen Schlüsselpaars“. Dies wird ein neues Schlüsselpaar für Sie generiert und automatisch eine private Schlüsseldatei (pk-xxxxxxxxx.pem) herunterladen. Halten Sie die Schlüsseldatei sicher und privat. notieren Sie auch die „Key-Pair-ID“ von amazon, wie wir es im nächsten Schritt benötigen.

generieren einige URLs in Python

Ab Boto Version 2.0 scheint es keine Unterstützung zu sein für signierte URLs Cloudfront zu erzeugen. Python enthält keine RSA-Verschlüsselungsroutinen in der Standard-Bibliothek, so dass wir eine weitere Bibliothek verwenden müssen. Ich habe m2crypto in diesem Beispiel verwendet.

Für eine Nicht-Streaming-Verteilung, müssen Sie die vollständige URL Cloudfront als die Ressource verwenden, aber für das Streaming nur wir die Objektname der Videodatei verwenden. Sehen Sie den Code unten für ein vollständiges Beispiel für eine URL zu erzeugen, die nur 5 Minuten dauern.

Dieser Code basiert lose auf dem PHP-Beispielcode zur Verfügung gestellt von Amazon in der Cloudfront-Dokumentation.

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)

Stellen Sie sicher, dass Sie Ihre Verteilung mit einem TrustedSigners Parametersatz auf das Konto hält Ihr Schlüsselpaar einrichten (oder „Selbst“ wenn es Ihr eigenes Konto ist)

Siehe Erste mit sicherer AWS Cloudfront gestartet Streaming mit Python für ein voll gearbeitet Beispiel auf diese Einstellung für das Streaming mit Python bis

Andere Tipps

Diese Funktion ist jetzt bereits in Botocore unterstützt, die die zugrunde liegende Bibliothek von Boto3, die neuesten offiziellen AWS SDK für Python. (Das folgende Beispiel erfordert die Installation des rsa Pakets, aber Sie können anderes RSA-Paket verwenden, nur Ihren eigenen „normalisiert RSA signer“ definieren.)

Die Nutzung sieht wie folgt aus:

    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)

Disclaimer: Ich bin der Autor dieser PR

.

Wie viele bereits bemerkt haben, die zunächst Antwort akzeptiert nicht auf eine href gilt <= "http: / /aws.amazon.com/cloudfront/ "rel = "nofollow noreferrer"> Amazon Cloudfront in der Tat, sofern Serving Privat Inhalte über Cloudfront die Verwendung von dedizierten Cloudfront URLs Signed - entsprechend secretmike Antwort war richtig, aber es ist inzwischen überholt, nachdem er sich die Zeit genommen hat und Zusätzliche Unterstützung für die Erzeugung signierten URLs für Cloudfront (dank viel für diese!).

Boto unterstützt jetzt eine gewidmet als auch pure-Python RSA Implementierung , a href finden Sie unter <= "https://github.com/boto/boto / Zug / 1214" rel = "nofollow noreferrer"> Do m2crypto nicht für Cloudfront URL-Signierung verwenden.

Wie immer häufiger kann man einen oder mehrere gute Beispiele für die Verwendung innerhalb der zugehörigen Unit-Tests finden (siehe test_signed_urls.py ), zum Beispiel test_canned_policy (Selbst-) - siehe setUp (Selbst-) für die referenzierten Variablen self.pk_idand self.pk_str (natürlich werden Sie Ihre eigenen Schlüssel benötigen):

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)

secretmike Antwort funktioniert, aber es ist besser, verwenden rsa statt M2Crypto.

Ich benutzte boto die rsa verwendet.

import boto
from boto.cloudfront import CloudFrontConnection
from boto.cloudfront.distribution import Distribution

expire_time = int(time.time() +3000)
conn = CloudFrontConnection('ACCESS_KEY_ID', 'SECRET_ACCESS_KEY')

##enter the id or domain name to select a distribution
distribution = Distribution(connection=conn, config=None, domain_name='', id='', last_modified_time=None, status='')
signed_url = distribution.create_signed_url(url='YOUR_URL', keypair_id='YOUR_KEYPAIR_ID_example-APKAIAZVIO4BQ',expire_time=expire_time,private_key_file="YOUR_PRIVATE_KEY_FILE_LOCATION")

Mit dem boto documentation

Dies ist, was ich für eine Richtlinie erstellen, so dass ich den Zugriff auf mehrere Dateien mit der gleichen „Signatur“ geben kann:

import json 
import rsa
import time                                                                                                                                                                           

from base64 import b64encode 

url = "http://your_domain/*"                                                                                                                                                                      
expires = int(time.time() + 3600)

pem = """-----BEGIN RSA PRIVATE KEY-----  
...
-----END RSA PRIVATE KEY-----"""

key_pair_id = 'ABX....'

policy = {}                                                                                                                                                                           
policy['Statement'] = [{}]                                                                                                                                                            
policy['Statement'][0]['Resource'] = url                                                                                                                                              
policy['Statement'][0]['Condition'] = {}                                                                                                                                              
policy['Statement'][0]['Condition']['DateLessThan'] = {}                                                                                                                              
policy['Statement'][0]['Condition']['DateLessThan']['AWS:EpochTime'] = expires                                                                                                        

policy = json.dumps(policy)

private_key = rsa.PrivateKey.load_pkcs1(pem)                                                                                                                                          
signature = b64encode(rsa.sign(str(policy), private_key, 'SHA-1'))

print '?Policy=%s&Signature=%s&Key-Pair-Id=%s' % (b64encode(policy),                                                                                                                             
                                                  signature,                                                                                                                          
                                                  key_pair_id)

ich es für alle Dateien unter http://your_domain/* zum Beispiel verwenden kann:

 http://your_domain/image2.png?Policy...
 http://your_domain/image2.png?Policy...
 http://your_domain/file1.json?Policy...
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top