putobject nodejs node getsignedurl getobject example aws javascript node.js amazon-web-services amazon-s3 pre-signed-url

javascript - nodejs - s3 getsignedurl



Creación de URL firmadas de S3 y Cloudfront a través del SDK de AWS (2)

Para que mi código funcione con el código de Jason Sims, también tuve que convertir la política a base64 y agregarla a la firma finalUrl, así:

sign.update(JSON.stringify(policy)) var signature = sign.sign(key, ''base64'') var policy_64 = new Buffer(JSON.stringify(policy)).toString(''base64''); // ADDED // Finally, you build the URL with all of the required query params: var url = { host: ''<your-cloudfront-domain-name>'', protocol: ''http'', pathname: ''<path-to-s3-object>'' } var params = { ''Key-Pair-Id='' + cloudfrontAccessKey, ''Expires='' + expiration, ''Signature='' + signature, ''Policy='' + policy_64 // ADDED }

¿Alguien ha utilizado con éxito el SDK de AWS para generar URL firmadas para objetos en un grupo de S3 que también funciona en CloudFront? Estoy usando el AWS SDK de JavaScript y es realmente sencillo generar URL firmadas a través de los enlaces S3. Acabo de crear un grupo privado y uso el siguiente código para generar la URL:

var AWS = require(''aws-sdk'') , s3 = new AWS.S3() , params = {Bucket: ''my-bucket'', Key: ''path/to/key'', Expiration: 20} s3.getSignedUrl(''getObject'', params, function (err, url) { console.log(''Signed URL: '' + url) })

Esto funciona muy bien, pero también quiero exponer una URL de CloudFront a mis usuarios para que puedan obtener la mayor velocidad de descarga al usar la CDN. Configuré una distribución de CloudFront que modificó la política de depósito para permitir el acceso. Sin embargo, después de hacer esto, se pudo acceder a cualquier archivo a través de la URL de CloudFront y Amazon pareció ignorar la firma en mi enlace. Después de leer un poco más sobre esto, he visto que las personas generan un archivo .pem para obtener las URL firmadas que trabajan con CloudFront, pero ¿por qué esto no es necesario para S3? Parece que el método getSignedUrl simplemente firma con la clave secreta de AWS y la clave de acceso de AWS. ¿Alguien ha conseguido una configuración como esta trabajando antes?

Actualización: Después de más investigaciones, parece que CloudFront maneja las firmas de URL completamente diferentes de S3 [link] . Sin embargo, todavía no estoy seguro de cómo crear una URL firmada de CloudFront con Javascript.


Actualización: moví la funcionalidad de firma del código de ejemplo a continuación al paquete aws-cloudfront-sign en NPM. De esa manera, solo puede requerir este paquete y llamar a getSignedUrl() .

Después de una investigación adicional, encontré una solución que es una especie de combinación entre esta respuesta y un método que encontré en la biblioteca de Boto . Es cierto que las firmas de URL de S3 se manejan de manera diferente a las firmas de URL de CloudFront. Si solo necesita firmar un enlace S3, el código de ejemplo en mi pregunta inicial funcionará bien para usted. Sin embargo, se vuelve un poco más complicado si desea generar URL firmadas que utilizan su distribución de CloudFront. Esto se debe a que las firmas de URL de CloudFront no son compatibles actualmente en el SDK de AWS, por lo que debe crear la firma por su cuenta. En caso de que también necesite hacer esto, aquí hay pasos básicos. Asumiré que ya tienes una configuración de cubeta S3:

Configurar CloudFront

  1. Crear una distribución de CloudFront
  2. Configure su origen con las siguientes configuraciones
    • Nombre de dominio de origen: {your-s3-bucket}
    • Restringir el acceso de cubo: Sí
    • Otorgar permisos de lectura en Bucket: Sí, actualizar política de Bucket
  3. Crear un par de claves de CloudFront. Debería poder hacer esto here .

Crear una URL firmada de CloudFront

Para obtener una URL de CloudFront firmada, solo necesita firmar su política mediante RSA-SHA1 e incluirla como parámetro de consulta. Puede encontrar más información sobre políticas personalizadas here pero he incluido una básica en el código de ejemplo a continuación que debería ponerlo en funcionamiento. El código de ejemplo es para Node.js pero el proceso podría aplicarse a cualquier idioma.

var crypto = require(''crypto'') , fs = require(''fs'') , util = require(''util'') , moment = require(''moment'') , urlParse = require(''url'') , cloudfrontAccessKey = ''<your-cloudfront-public-key>'' , expiration = moment().add(''seconds'', 30) // epoch-expiration-time // Define your policy. var policy = { ''Statement'': [{ ''Resource'': ''http://<your-cloudfront-domain-name>/path/to/object'', ''Condition'': { ''DateLessThan'': {''AWS:EpochTime'': ''<epoch-expiration-time>''}, } }] } // Now that you have your policy defined you can sign it like this: var sign = crypto.createSign(''RSA-SHA1'') , pem = fs.readFileSync(''<path-to-cloudfront-private-key>'') , key = pem.toString(''ascii'') sign.update(JSON.stringify(policy)) var signature = sign.sign(key, ''base64'') // Finally, you build the URL with all of the required query params: var url = { host: ''<your-cloudfront-domain-name>'', protocol: ''http'', pathname: ''<path-to-s3-object>'' } var params = { ''Key-Pair-Id='' + cloudfrontAccessKey, ''Expires='' + expiration, ''Signature='' + signature } var signedUrl = util.format(''%s?%s'', urlParse.format(url), params.join(''&'')) return signedUrl