IAM: policy, ruoli e least privilege

AWS IAM governa chi può fare cosa su quali risorse. Le policy sono documenti JSON con Effect (Allow/Deny), Action, Resource e condizioni opzionali. Distingui due famiglie: le identity-based policy, allegate a user, group o role, e le resource-based policy, allegate direttamente alla risorsa (bucket policy S3, resource policy di una coda SQS o di una funzione Lambda), che dichiarano anche il Principal autorizzato.

Per il codice cloud-native la best practice è assegnare un IAM role al servizio (Lambda execution role, task role ECS, instance profile EC2) invece di incorporare access key statiche: il servizio assume il role e ottiene credenziali temporanee a rotazione automatica.

Ricorda la logica di valutazione: un explicit deny vince sempre su qualsiasi allow; in assenza di allow vige il deny implicito. Applica il principio del least privilege, concedendo solo i permessi effettivamente necessari e restringendo l’ambito con Resource puntuali e condizioni.

Amazon Cognito: user pool e identity pool

Cognito risolve due problemi distinti, e confonderli è l’errore più frequente.

Lo user pool è la directory utenti: gestisce sign-up, sign-in, MFA, verifica email, password policy e integrazione con social o enterprise identity provider. Dopo l’autenticazione restituisce token JWT (ID token, access token, refresh token): l’ID token descrive l’utente, l’access token autorizza le chiamate. API Gateway può validare questi token con un Cognito authorizer per proteggere le API.

L’identity pool (Federated Identities) fa un’altra cosa: scambia un’identità (token di uno user pool, di Google/Facebook, un provider SAML, o un utente guest) con credenziali AWS temporanee tramite STS, mappate a un IAM role. Serve quando l’app deve chiamare direttamente servizi AWS (upload su S3, query su DynamoDB) dal client.

Regola pratica: user pool per autenticare e ottenere JWT; identity pool per autorizzare l’accesso alle risorse AWS con credenziali temporanee.

AWS STS, assume-role e federazione

AWS STS (Security Token Service) emette credenziali temporanee a scadenza limitata. L’operazione centrale è AssumeRole: un principal assume un role e riceve access key, secret key e session token. È il meccanismo dietro l’accesso cross-account, dove il role nell’account target ha una trust policy che indica come Principal l’account chiamante.

Per la federazione con un identity provider SAML aziendale si usa AssumeRoleWithSAML; per provider OIDC/web (social login e identity pool Cognito) esiste il pattern web-identity. In tutti i casi il risultato sono credenziali temporanee, mai chiavi permanenti.

Quando concedi accesso a una terza parte (un SaaS che deve operare nel tuo account) usa un role con ExternalId: il vendor deve fornire l’ExternalId concordato per assumere il role, mitigando il confused deputy problem.

Trappole tipiche d’esame

  • App client che deve caricare file su S3 direttamente → identity pool: lo user pool da solo dà JWT ma non credenziali AWS; servono le temporary credentials di un identity pool.
  • Solo login e validazione token in API Gateway → user pool: qui basta autenticare e verificare i JWT, senza identity pool né credenziali AWS.
  • SaaS di terze parti che accede al tuo account → AssumeRole con ExternalId: non creare un IAM user con access key da consegnare al vendor; usa un role cross-account con trust policy ed ExternalId.
  • Allow ampio ma la chiamata fallisce → cerca l’explicit deny: una SCP o una policy con Deny esplicito prevale su qualsiasi Allow, e l’ordine delle policy non conta.
  • Lambda che deve leggere DynamoDB → execution role, non access key: mai hardcodare credenziali; assegna i permessi al role della funzione seguendo il least privilege.
  • SSO con Active Directory / IdP SAML aziendale → AssumeRoleWithSAML: non si crea un IAM user per persona, si federa l’identità e si assume un role con credenziali temporanee.