INTRODUZIONE
Se hai mai creato un’applicazione che comporta la memorizzazione di un’immagine, hai riscontrato il problema di decidere dove salvare le immagini.
È probabile che per mancanza di tempo hai risolto nella maniera più’ semplice: nel tuo database o sul tuo filesystem locale. Questa soluzione ha dei grossi limiti riguardo a scalabilità’ e HA. Tutti i cloud provider offrono come soluzione a questo problema l utilizzo di un object storage; Oggi parleremo di Google Cloud Storage mostrando i concetti principali attorno a questo utilissimo servizio.
bucket e objects
I concetti chiave dietro a Cloud storage sono bucket e object. Puoi immaginare un bucket come un container per memorizzare i tuoi dati. Gli Object sono invece i files che salvi all’interno di un bucket. Gli object hanno un nome univoco che li identifica all’ interno del bucket e possono essere organizzati all interno del bucket in folder.
bucket
Andiamo ad analizzare le caratteristiche fondamentali di un bucket analizzando il form di creazione bucket.
- Name: l identificativo univoco globale del bucket.
- Location: Come le VM di Compute Engine, anche i bucket possono avere location.
Anziché definire sempre una zona specifica (ad esempio, us-central1-a), e’ possibile specificare una regione (ad esempio, us-central1) o addirittura multi regionale (ad esempio, “Stati Uniti” o “Asia”). Se si sceglie una regione o multi regional i costi aumenteranno ma di conseguenza anche l HA e l utente potrà scaricare dal bucket geograficamente più’ vicino. - Storage Class: Proprio come esistono diversi tipi di dischi (ad esempio, SSD o magnetico) Cloud Storage offre diversi tipi di bucket. Queste storage class presentano caratteristiche prestazionali diverse (entrambe latenza e disponibilità), nonché prezzi diversi.
- Encryption: Se vogliamo gestire l encryption con nostre chiavi.
- ACL Settings: E’ Specificare l’accesso a singoli oggetti utilizzando le autorizzazioni a livello di oggetto (ACL) oltre alle autorizzazioni a livello di bucket (IAM). Approfondiremo le ACL in una sezione successiva.
upload
A questo punto procediamo a creare il bucket e usando la cli iniziamo a salvare object all interno del bucket.
PS C:\Users\Dario\test> echo Ciao Mondo > test.txt PS C:\Users\Dario\test> cat test.txt Ciao Mondo PS C:\Users\Dario\test> gsutil ls gs://demo-123-4/ gs://italiancoderstest/ gs://my-public-bucket-df/ gs://profile_pictures_itc/ PS C:\Users\Dario\test> gsutil cp .\test.txt gs://italiancoderstest Copying file://.\test.txt [Content-Type=text/plain]... - [1 files][ 28.0 B/ 28.0 B] Operation completed over 1 objects/28.0 B. PS C:\Users\Dario\test>
download
Andiamo a scaricare il file precedentemente caricato sul bucket.
PS C:\Users\Dario\test> gsutil ls gs://italiancoderstest/ gs://italiancoderstest/test.txt PS C:\Users\Dario\test> gsutil cp gs://italiancoderstest/test.txt download.txt Copying gs://italiancoderstest/test.txt... / [1 files][ 28.0 B/ 28.0 B] Operation completed over 1 objects/28.0 B. PS C:\Users\Dario\test> cat .\download.txt Ciao Mondo PS C:\Users\Dario\test>
limitare l aCCESSO CON LE ACL
Prima di entrare nel dettaglio, potrebbe essere utile dire che di default tutto quello che crei e’ accessibile solo da quelle persone che hanno accesso al tuo progetto. Quando aggiungi qualcun altro nel tuo progetto, anche loro avranno accesso ai tuoi dati nel Cloud Storage. Ad esempio, se aggiungi qualcuno come un altro proprietario del progetto, automaticamente sara’ in grado di controllare i dati del proprio Cloud Storage (bucket e oggetti).
Cloud Storage consente un controllo di accesso piu’ di dettaglio attraverso un meccanismo di sicurezza chiamato Access Control Lists (ACLs). Queste liste fanno
esattamente quello che ti aspetti lasciandoti dire quali account possono fare quali operazioni
(ad esempio, leggi o scrivi). Queste operazioni sono trasmesse da tre ruoli, che hanno un significato diverso per bucket e oggetti.
READERS:
- Bucket: I bucket reader possono vedere la lista di oggetti in un bucket
- Object: object reader possono scaricare l oggetto
WRITERS:
- Bucket: i Bucket Writers possono vedere la lista di oggetti, crearne nuovi e cancellare oggetti dal bucket.
- Object: –
OWNERS:
- Bucket: i Bucket Owners possono fare tutto quello che possono fare gli writers con l aggiunta di aggiornare il bucket e quindi anche le ACL.
- Object: I Object owners possono fare tutto quello che fa un reader con l aggiunta di modificare le ACL di un object
La domanda adesso sorge spontanea: cosa accade se sono Owner del bucket ma Reader di un oggetto ? La risposta è abbastanza semplice: ciascuna delle autorizzazioni trasmette attività specifiche che sono consentite, quindi non esiste una gerarchia di autorizzazioni che scendono verso il basso. Basandosi sulle specifiche dei ruoli appena riportate, in questo scenario potrò’ manipolare gli object del bucket ma non potrò modificare i metadata di quell object e quindi non potrò definire dei permessi custom ad hoc per quel object.
BUCKET ACL
Come prevedibile, puoi controllare l’accesso ai tuoi oggetti assegnando questi ruoli a diversi
attori (ad esempio un particolare utente). Cominciamo guardando l’ACL per
il bucket appena creato nella Cloud Console.
Da quello che si evince, l accesso di default al bucket e’ basato sul project con i project editors e owners che hanno l owner access al bucket e i project viewers che hanno il Reader Access. E’possibile aggiungere altri utenti con specifici ruoli per il singolo bucket o usare degli user speciali come: allUsers, allAuthenticatedUsers o specificare un gruppo o dominio.
default object ACL
In aggiunta a definire permessi a Bucket e Object e’ possibile definire per un bucket una default ACL che farà’ si che ogni object che viene creato erediti quest ultima. Nota bene: la modifica di una una default object ACL non e’ retroattiva.
acl predefinite
E’ possibile utilizzare delle ACL predefinite che mette a disposizione Google per impostare velocemente il permesso di un object. Tornando al nostro esempio
PS C:\Users\Dario\test> gsutil acl get gs://italiancoderstest/test.txt [ { "entity": "project-owners-677206649094", "projectTeam": { "projectNumber": "677206649094", "team": "owners" }, "role": "OWNER" }, { "entity": "project-editors-677206649094", "projectTeam": { "projectNumber": "677206649094", "team": "editors" }, "role": "OWNER" }, { "entity": "project-viewers-677206649094", "projectTeam": { "projectNumber": "677206649094", "team": "viewers" }, "role": "READER" } ]
Proviamo con una curl a scaricare il file
PS C:\Users\Dario\test> curl https://italiancoderstest.storage.googleapis.com/test.txt curl : AccessDeniedAccess denied.Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object. At line:1 char:1 + curl https://italiancoderstest.storage.googleapis.com/test.txt + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebExc eption + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand PS C:\Users\Dario\test>
Come era prevedibile non riusciamo a scaricare il file non essendo pubblico il bucket. A questo punto utilizzando una ACL predefinita: public potremmo settare velocemente i permessi pubblici in sola lettura per tale object e scaricare il file con una curl.
PS C:\Users\Dario\test> gsutil acl set public-read gs://italiancoderstest/test.txt Setting ACL on gs://italiancoderstest/test.txt... / [1 objects] Operation completed over 1 objects. PS C:\Users\Dario\test> gsutil acl get gs://italiancoderstest/test.txt [ { "email": "dario.frongillo@gmail.com", "entity": "user-dario.frongillo@gmail.com", "role": "OWNER" }, { "entity": "allUsers", "role": "READER" } ] PS C:\Users\Dario\test> curl https://italiancoderstest.storage.googleapis.com/test.txt StatusCode : 200 StatusDescription : OK Content : ÿþC i a o M o n d o RawContent : HTTP/1.1 200 OK X-GUploader-UploadID: AAANsUkv7_5DzZMtKTc6gbcT3xc-cSMY-WeUCAvLZjL4knV6AUWBy52esGc5viEL678bjJFNu2_TdQWzItWsafU3ow x-goog-generation: 1591690976898840 x-goog-metageneration: 3 x-goog... Forms : {} Headers : {[X-GUploader-UploadID, AAANsUkv7_5DzZMtKTc6gbcT3xc-cSMY-WeUCAvLZjL4knV6AUWBy52esGc5viEL678bjJFNu2_TdQWzItWsafU3ow], [x-goog-generation, 1591690976898840], [x-goog-metageneration, 3], [x-goog-stored-content-encoding, identity]...} Images : {} InputFields : {} Links : {} ParsedHtml : mshtml.HTMLDocumentClass RawContentLength : 28
acl best practices
Ora che sappiamo in grosso modo cosa sono le ACL voglio suggerirvi alcune best practices per evitare brutte sorprese:
- Quando sei in dubbio dai sempre il minimo accesso possibile ad un nuovo utente
- Il permesso Owner e’ molto potente quindi fai attenzione a chi lo assegni
- Fai attenzione alla tua ACL di default in quanto i nuovi object erediteranno tali permessi.
signed url
A volte siamo nelle situazioni in cui non si desidera aggiungere qualcuno alla ACL per sempre, ma piuttosto si vuole dare accesso per un determinato periodo di tempo ad un object. Situazione tipica in cui non ci preoccupiamo che l utente sia autenticato con i servizi google, in quanto magari abbiamo fatto autenticare l utente con la nostra piattaforma e vorremmo banalmente dire al sistema di controllo del Bucket:
“Questa persona ha accesso per visualizzare questi dati.”
Fortunatamente, Cloud Storage offre un modo semplice per farlo con i signed URL. Un signed URL è un URL che fornisce autorizzazioni e tempo limitati per effettuare una richiesta. Gli URL firmati contengono informazioni di autenticazione nella loro stringa di query, consentendo agli utenti senza credenziali di eseguire azioni specifiche su una risorsa. Quando si genera un URL firmato, si specifica un account utente o di servizio che deve disporre dell’autorizzazione sufficiente per effettuare la richiesta che verrà effettuata dall’URL firmato. Dopo aver generato un URL firmato, chiunque lo possiede può utilizzare l’URL firmato per eseguire azioni specifiche, come la lettura di un oggetto, entro un determinato periodo di tempo.
Andiamo a creare una signed URL per scaricare un file non pubblico del mio bucket
upload file
Andiamo a creare un object nel mio bucket che di default sara manipolabile solo dagli owner del progetto.
PS C:\Users\Dario\test> echo privatoooooooo > private.txt PS C:\Users\Dario\test> cat .\private.txt privatoooooooo PS C:\Users\Dario\test> gsutil cp .\private.txt gs://italiancoderstest Copying file://.\private.txt [Content-Type=text/plain]... - [1 files][ 34.0 B/ 34.0 B] Operation completed over 1 objects/34.0 B. PS C:\Users\Dario\test> curl https://italiancoderstest.storage.googleapis.com/private.txt curl : AccessDeniedAccess denied.Anonymous caller does not have storage.objects.get access to the Google Cloud Storage object. At line:1 char:1 + curl https://italiancoderstest.storage.googleapis.com/private.txt + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
creiamo service account
Andiamo a creare un service Account che vogliamo impersonare nel signed url. Creo quindi dalla consolle un service account Bucket Reader con il ruolo Storage Object Viewer in quanto nella signed Url vorro’ permettere di scaricare l object. Ricordatevi di generare la key Json del service account.
creiamo signed url
Una volta creato il service account e scaricata localmente la key procediamo alla creazione del signed url. Gli step che seguiremo sono:
- modificare l ACL del mio object per permettere la lettura usando il service account
- creazione di un signed URL utilizzando la key del nostro service account.
>> gsutil acl ch -u bucket-reader@italiancoders-demo.iam.gserviceaccount.com:R gs://italiancoderstest/private.txt Updated ACL on gs://italiancoderstest/private.txt >> gsutil signurl -m GET -d 10m .\KEY.json gs://italiancoderstest/private.txt URL HTTP Method Expiration Signed URL gs://italiancoderstest/private.txt GET 2020-06-09 13:00:39 https://storage.googleapis.com/italiancoderstest/private.txt?x-goog-signature=cbd4bac5c8ca6e769d1a8b54438b5dd2cacfa1454d48683001f611cf16f825929a9a10bcebe2808dda1cd1ce2e06be560b360e2bdabde199c05f4f2e2de8d65680164f466812a89bba79a9a784db921b6eb62cd0df2f94c58e9fe210a137534210005a7e6020e4675fa2463459b4614600cb6ee464479317b739c47b8c77e4c5db8e9e2f2d90d1031a03681e97f4a23d6e6476c868ddee6ab8ef8081f2a2fa5661426c8a3ac36ccc01233797a34870c648776fff5947adf7ac9ba6f4d1f3cba9295d1d0de7f5ecc0d896c31cc8cdd5f446f6beecbaa7e5fc28b0b94eff63739b1b448c06f15c5a5278cd1f9b0cee9efef3c3619b79c433935b94f4c14bba7d03&x-goog-algorithm=GOOG4-RSA-SHA256&x-goog-credential=bucket-reader%40italiancoders-demo.iam.gserviceaccount.com%2F20200609%2Feurope-west2%2Fstorage%2Fgoog4_request&x-goog-date=20200609T105039Z&x-goog-expires=600&x-goog-signedheaders=host
Se proviamo ad accedere all URL creato riusciremo adesso a scaricare il file per 10 min.