Secret Manager: mai credenziali hardcoded
Il principio di partenza del codice sicuro su Google Cloud è che una credenziale non deve mai vivere nel codice sorgente, in un file .env committato, in un layer di un’immagine container o in una variabile d’ambiente in chiaro. Il posto giusto è Secret Manager: le API key, le password di database, i token di terze parti e i certificati vengono archiviati cifrati e recuperati a runtime dall’applicazione. Ogni secret è versionato: puoi puntare a una versione specifica per rollout deterministici, oppure all’alias latest accettando che la rotazione cambi il valore sotto i piedi dell’app. In esame ragiona sul trade-off: pinnare una versione dà riproducibilità ma richiede un redeploy per aggiornare; latest semplifica la rotazione ma impone all’app di gestire i cambi. Il pattern raccomandato è recuperare il secret all’avvio (o con una cache a scadenza breve), non ad ogni richiesta, per non pagare latenza e quota inutili. L’accesso si controlla con IAM sul singolo secret, non a livello di progetto: così un service account legge solo i secret che gli servono.
Service account e least privilege
Ogni carico di lavoro deve girare con un service account dedicato, non con il default service account del progetto (che ha ruoli troppo ampi) e mai con credenziali utente. Il principio del least privilege significa assegnare ruoli predefiniti stretti (o custom role) allo scope più granulare possibile: un solo bucket, un solo secret, un solo topic. Su Cloud Run e Cloud Functions si “attacca” il service account al servizio in fase di deploy; il codice poi ottiene i token automaticamente tramite il metadata server, senza gestire chiavi. Se un servizio deve agire come un altro, si usa la service account impersonation (ruolo Service Account Token Creator) per farsi rilasciare token a breve durata, evitando di distribuire credenziali statiche.
Workload Identity e federation
La regola d’oro è: niente service account key JSON scaricate su disco, perché sono credenziali statiche a lunga vita che, se trapelano, restano valide. Su GKE si usa la Workload Identity, che mappa un Kubernetes service account a un Google service account: i pod ottengono token effimeri senza chiavi montate. Per carichi che girano fuori da Google Cloud (CI/CD esterni come GitHub Actions, altri cloud, on-prem) si usa la Workload Identity Federation: un identity provider esterno (OIDC/SAML) viene fidato tramite un workload identity pool, e l’identità esterna scambia il proprio token con credenziali Google short-lived. In entrambi i casi elimini le chiavi da ruotare e da custodire.
Auth service-to-service e signed URL
Quando un servizio invoca un Cloud Run privato, l’autenticazione corretta è tramite ID token OIDC: il chiamante ottiene dal metadata server un ID token con l’audience impostato all’URL del servizio target e lo invia nell’header Authorization: Bearer. Il target, configurato per richiedere autenticazione, verifica il token; l’autorizzazione si concede con il ruolo Cloud Run Invoker sul service account chiamante. Non usare API key per auth service-to-service. Per dare a un client esterno accesso temporaneo a un oggetto di Cloud Storage senza renderlo pubblico né distribuire credenziali, si generano signed URL: URL firmati con validità limitata che concedono un permesso specifico (es. lettura o upload) su un singolo oggetto, per una finestra di tempo definita. Infine, tratta sempre l’input esterno come non fidato: valida e normalizza i dati in ingresso lato server per prevenire injection e abusi.
Trappole tipiche d’esame
- Serve rotazione automatica delle credenziali senza redeploy → soluzione: metti il secret in Secret Manager e leggi la versione
latestcon cache breve, invece di pinnare una versione o iniettare env in chiaro. - Pipeline CI/CD esterna deve accedere a GCP → soluzione: Workload Identity Federation, non una service account key JSON archiviata come segreto della CI.
- Pod GKE deve chiamare API Google → soluzione: Workload Identity (KSA↔GSA), non chiavi montate come Secret Kubernetes.
- Un microservizio invoca un Cloud Run privato → soluzione: ID token OIDC con
audience= URL del target e ruolo Invoker, non API key né rendere il servizio pubblico. - Un client deve scaricare/caricare un file temporaneamente → soluzione: signed URL a scadenza sul singolo oggetto, non bucket pubblico né condivisione di credenziali.
- Il servizio gira con permessi troppo ampi → soluzione: service account dedicato con ruoli minimi sullo scope granulare, non il default service account del progetto.