Pytanie Tworzenie podpisanych adresów URL S3 i Cloudfront za pomocą pakietu SDK AWS


Czy ktokolwiek pomyślnie użył pakietu SDK AWS do wygenerowania podpisanych adresów URL do obiektów w wiadrze S3, które działają również w CloudFront? Używam JavaScript AWS SDK Generowanie URL-i za pomocą linków S3 jest naprawdę proste. Właśnie utworzyłem prywatny segment i używam następującego kodu do wygenerowania adresu 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)
})

Działa to świetnie, ale chcę również udostępnić użytkownikom CloudFront adres URL, aby mogli zwiększyć szybkość pobierania przy użyciu CDN. Skonfigurowałem dystrybucję CloudFront, która zmodyfikowała zasady bucket, aby umożliwić dostęp. Jednak po wykonaniu tego dowolnego pliku można uzyskać dostęp za pośrednictwem adresu URL CloudFront i Amazon wydawało się zignorować podpis w moim linku. Po przeczytaniu trochę więcej na ten temat widziałem, że ludzie generują plik .pem, aby uzyskać podpisane adresy URL współpracujące z CloudFront, ale dlaczego nie jest to konieczne dla S3? Wygląda na to, że metoda getSignedUrl po prostu podpisuje się za pomocą klucza tajnego AWS i klucza dostępu AWS. Czy ktoś wcześniej miał taką konfigurację?

Aktualizacja: Po dalszych badaniach wydaje się, że CloudFront obsługuje sygnatury URL zupełnie różne od S3 [połączyć]. Jednak wciąż nie jestem pewien, jak utworzyć podpisany adres CloudFront przy użyciu Javascript.


18
2018-02-03 06:51


pochodzenie


Nie dostaję twojej implementacji. Czy możesz wyjaśnić to szczegółowo. Muszę zrobić to samo dla mojej aplikacji na Androida. To, o czym myślałem, to: Mój klient wyśle ​​żądanie do mojego serwera -> mój serwer poprosi AWS S3 o podpisany URL -> Mój serwer wyśle ​​ten URL z powrotem do klient, aby ukończyć ładowanie. Czy to w porządku podejście. Mój serwer jest zapisany w pliku node.js. Czy pomożesz mi to zrobić. ? - Abhishek Kaushik
Jeśli jest napisane w węźle, powinieneś być w stanie użyć aws-cloudfront-sign narzędzie, które napisałem. Plik README.md powinien wyjaśnić, co należy zrobić. - Jason Sims


Odpowiedzi:


Aktualizacja: Przesunąłem funkcję podpisywania z przykładowego kodu poniżej do pliku aws-cloudfront-sign pakiet na NPM. W ten sposób możesz po prostu wymagać tego pakietu i zadzwonić getSignedUrl().


Po dalszych badaniach znalazłem rozwiązanie, które jest swego rodzaju kombinacją ta odpowiedź i metodę, którą znalazłem w Biblioteka Boto. To prawda, że ​​podpisy URL S3 są obsługiwane inaczej niż podpisy CloudFront URL. Jeśli chcesz tylko podpisać link S3, przykładowy kod z mojego pierwszego pytania zadziała dla Ciebie. Jednak staje się nieco bardziej skomplikowana, jeśli chcesz generować podpisane adresy URL, które wykorzystują twoją dystrybucję CloudFront. Wynika to z faktu, że podpisy URL CloudFront nie są obecnie obsługiwane w pakiecie AWS SDK, więc musisz samodzielnie utworzyć podpis. Jeśli musisz to zrobić, poniżej znajdziesz podstawowe kroki. Zakładam, że masz już konfigurację kubełkową S3:

Skonfiguruj CloudFront

  1. Utwórz dystrybucję CloudFront
  2. Skonfiguruj swoje pochodzenie za pomocą następujących ustawień
    • Nazwa domeny źródłowej: {your-s3-bucket}
    • Ogranicz dostęp do zasobnika: Tak
    • Przydziel uprawnienia odczytu do zasobnika: Tak, zaktualizuj zasady zasobu
  3. Utwórz parę kluczy CloudFront. Powinien być w stanie to zrobić tutaj.

Utwórz podpisany adres CloudFront

Aby uzyskać wielki podpisany adres CloudFront, wystarczy podpisać polisę za pomocą RSA-SHA1 i uwzględnić ją jako parametr zapytania. Więcej informacji na temat niestandardowych zasad tutaj ale w poniższym przykładowym kodzie zawarłem podstawowy kod, który powinien zacząć działać. Przykładowy kod dotyczy Node.js, ale proces można zastosować do dowolnego języka.

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

22
2018-02-03 20:20



cześć muszę utworzyć podpisany adres URL przeglądarki. Nie używam node.js. Używam sdk dla javascript w przeglądarce. Czy wiesz, jakie libra muszę dołączyć do tego? var crypto = require ('crypto') w tym, co jest "wymagane"? - Priya Sunanthan
Crypto to wbudowany moduł nodejs do podpisywania, a instrukcja require jest informacją o sposobie importowania. Jeśli robisz to w czystym Javascriptu, możesz zajrzeć do czegoś podobnego crypto-js. Chociaż uważam, że najlepiej jest podpisywać się po stronie serwera, aby chronić prywatność swojej pary kluczy. - Jason Sims
na wypadek, gdyby ktoś chciał mieć skrypt powłoki bash, napisałem jeden, aby podpisać URL S3 w bashu: github.com/gdbtek/aws-tools - Nam Nguyen
Czy to działa z niestandardową polityką S3 POST jako Policy parametr zapytania? Należy przesłać za pośrednictwem żądania POST do dystrybucji CloudFront, która wymaga wcześniej podpisanych adresów URL. - aleclarson


Aby mój kod działał z kodem Jason Sims, musiałem również przekonwertować zasady na base64 i dodać je do ostatecznego signedUrl, jak poniżej:

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 
}

2
2018-01-28 18:06



Zostało to rozwiązane na podstawie v2.1.0 znaku aws-cloudfront - Jason Sims