Saltar al contenido

Creación de URL firmadas para Amazon CloudFront

Solución:

Las URL firmadas de Amazon CloudFront funcionan de manera diferente a las URL firmadas de Amazon S3. CloudFront utiliza firmas RSA basadas en un par de claves de CloudFront separado que debe configurar en la página Credenciales de su cuenta de Amazon. Aquí hay un código para generar una URL de tiempo limitado en Python usando la biblioteca M2Crypto:

Cree un par de claves para CloudFront

Creo que la única forma de hacerlo es a través del sitio web de Amazon. Vaya a la página “Cuenta” de AWS y haga clic en el enlace “Credenciales de seguridad”. Haga clic en la pestaña “Pares de claves” y luego haga clic en “Crear un nuevo par de claves”. Esto generará un nuevo par de claves y descargará automáticamente un archivo de clave privada (pk-xxxxxxxxx.pem). Mantenga el archivo de claves seguro y privado. También anote el “ID del par de claves” de amazon, ya que lo necesitaremos en el siguiente paso.

Genera algunas URL en Python

A partir de la versión 2.0 de boto, no parece haber ningún soporte para generar URL de CloudFront firmadas. Python no incluye rutinas de cifrado RSA en la biblioteca estándar, por lo que tendremos que usar una biblioteca adicional. He usado M2Crypto en este ejemplo.

Para una distribución sin transmisión, debe usar la URL completa de la nube como recurso; sin embargo, para la transmisión solo usamos el nombre de objeto del archivo de video. Consulte el código a continuación para ver un ejemplo completo de cómo generar una URL que solo dura 5 minutos.

Este código se basa libremente en el código de ejemplo PHP proporcionado por Amazon en la documentación de 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("https://foroayuda.es/", '~')
    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)

Asegúrese de configurar su distribución con un parámetro TrustedSigners establecido en la cuenta que tiene su par de claves (o “Self” si es su propia cuenta)

Consulte Introducción a la transmisión segura de AWS CloudFront con Python para obtener un ejemplo completamente elaborado sobre cómo configurar esto para la transmisión con Python.

Esta función ya es compatible con Botocore, que es la biblioteca subyacente de Boto3, el último AWS SDK oficial para Python. (El siguiente ejemplo requiere la instalación del paquete rsa, pero también puede usar otro paquete RSA, simplemente defina su propio “firmante RSA normalizado”).

El uso se ve así:

    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)

Descargo de responsabilidad: soy el autor de ese PR.

Como muchos ya han comentado, la respuesta inicialmente aceptada no se aplica a Amazon CloudFront, de hecho, en la medida en que el servicio de contenido privado a través de CloudFront requiere el uso de URL firmadas de CloudFront dedicadas; en consecuencia, la respuesta de secretmike ha sido correcta, pero mientras tanto está desactualizada después de que él mismo se tomó el tiempo y se agregó soporte para generar URL firmadas para CloudFront (¡muchas gracias por esto!).

boto ahora admite un método create_signed_url dedicado y la antigua dependencia binaria M2Crypto también ha sido reemplazada recientemente por una implementación pura de Python RSA, consulte No use M2Crypto para la firma de URL frente a la nube.

Como es cada vez más común, se pueden encontrar uno o más ejemplos de buen uso dentro de las pruebas unitarias relacionadas (ver test_signed_urls.py), por ejemplo test_canned_policy (self) – ver setUp (self) para las variables referenciadas self.pk_idy self.pk_str (obviamente necesitarás tus propias llaves):

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)
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *