通过AWS SDK创build签名的S3和Cloudfront URL

是否有人成功使用AWS开发工具包生成签名的URL到S3存储桶中的对象,这些存储也可以通过CloudFront? 我正在使用JavaScript AWS SDK ,通过S3链接生成签名的URL非常简单。 我刚刚创build了一个私人存储分区,并使用以下代码来生成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) }) 

这很好,但我也想暴露一个CloudFront的URL给我的用户,所以他们可以得到使用CDN增加的下载速度。 我设置了一个修改存储桶策略以允许访问的CloudFront分配。 但是,这样做后,任何文件可以通过CloudFront URL访问,亚马逊似乎忽略了我的链接签名。 在阅读了更多关于这个之后,我已经看到人们生成一个.pem文件来获得使用CloudFront的签名URL,但是为什么S3不需要? 似乎getSignedUrl方法只是使用AWS Secret Key和AWS Access Key进行签名。 有没有人得到了这样的工作之前?

更新:经过进一步研究,CloudFront似乎处理与S3完全不同的URL签名[link] 。 不过,我还不清楚如何使用Javascript创build签名的CloudFront URL。

更新:我将以下示例代码中的签名function移到了NPM上的aws-cloudfront-sign软件包中。 这样,你可以只需要这个包,并调用getSignedUrl()


经过一番进一步的调查,我发现了一个解决scheme,这是一个在这个答案和我在博托图书馆find的方法之间的组合。 确实,S3 URL签名的处理方式与CloudFront URL签名的处理方式不同。 如果你只需要签署一个S3链接,那么我的第一个问题中的示例代码将适合你。 但是,如果要生成使用CloudFront分发的签名URL,则会变得更复杂一些。 这是因为AWS SDK目前不支持CloudFront URL签名,因此您必须自行创build签名。 如果你还需要这样做,这里是基本的步骤。 我假设你已经有一个S3桶设置:

configurationCloudFront

  1. 创build一个CloudFront分配
  2. 使用以下设置configuration原点
    • 来源域名:{your-s3-bucket}
    • 限制桶访问:是的
    • 在桶上授予读取权限:是,更新桶策略
  3. 创buildCloudFront密钥对。 应该可以在这里做到这一点 。

创build已签名的CloudFront URL

要获得签名的CloudFront URL,只需使用RSA-SHA1签署策略,并将其作为查询参数包含在内。 您可以在这里find更多关于自定义策略的信息,但是我已经在下面的示例代码中包含了一个基本的代码,可以让您启动并运行。 示例代码是针对Node.js的,但是该过程可以应用于任何语言。

 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 

为了让我的代码和Jason Sims的代码一起工作,我还必须将策略转换为base64并将其添加到最终的signedUrl中,如下所示:

 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 }