Un bucket S3 lasciato aperto non richiede exploit sofisticati. Basta una policy copiata male, un’ACL ereditata da un progetto di test o una casella dimenticata su “pubblico” durante una demo. Nel 2026 questo tipo di errore continua a costare caro, e per le aziende italiane ed europee porta con sé anche l’obbligo di notifica al Garante entro 72 ore quando sono coinvolti dati personali.

Un’indagine sulle infrastrutture cloud pubbliche ha individuato 535.480 bucket di storage accessibili da chiunque tra AWS, Google Cloud, Azure, DigitalOcean e Alibaba Cloud, per un totale vicino a 20 miliardi di file esposti. Tra questi file comparivano 685.047 documenti con credenziali, chiavi API o segreti applicativi, oltre a quasi un milione di dump di database completi di record .sql e .bak. Numeri che spiegano perché la misconfigurazione cloud resta tra le cause più frequenti di violazione dei dati, molto più della semplice vulnerabilità software.

Cloud Security Alliance ha pubblicato un caso concreto che mostra quanto velocemente le cose degenerino: chiavi AWS trovate in un bucket S3 pubblico hanno permesso a un attaccante di ottenere il controllo amministrativo completo dell’account in meno di dieci minuti. Non serviva un bug in AWS. Serviva solo una chiave lasciata nel posto sbagliato e nessun controllo che se ne accorgesse.

La parte più scomoda di questi numeri è che riguardano quasi sempre configurazioni scelte da qualcuno, non falle nel software di AWS. Una policy troppo permissiva, un’ACL ereditata da un vecchio progetto o una chiave hardcoded in un repository pubblico bastano a trasformare un bucket qualunque in un bersaglio facile. Per un team che lavora su più progetti in parallelo, senza un processo di controllo ricorrente, questo tipo di errore tende a ripetersi ogni pochi mesi, anche dopo la prima correzione.

Questa guida percorre 12 passi pratici per bloccare un bucket S3 pubblico, applicare il privilegio minimo con IAM, cifrare i dati e automatizzare il controllo con AWS Config. Alla fine costruiamo anche uno script Python che verifica in autonomia lo stato di sicurezza dei tuoi bucket, così il lavoro non resta un’operazione una tantum ma diventa un controllo ricorrente.

Il pubblico di riferimento sono team DevOps, amministratori di sistema e ingegneri di sicurezza che gestiscono infrastrutture AWS per aziende con sede o clienti in Italia e in Europa. Se il tuo account ospita anche un solo bucket con dati personali di cittadini UE, ogni passo di questa guida ha una ricaduta diretta sulla tua esposizione GDPR, non solo su un ipotetico rischio tecnico astratto.

Perché le misconfigurazioni S3 restano un’emergenza nel 2026

AWS ha reso il comportamento predefinito più sicuro negli anni: i bucket S3 creati oggi nascono con Block Public Access attivo, ACL disattivate e cifratura automatica sui nuovi oggetti. Il problema non è quasi mai un bucket nuovo. Il problema è l’infrastruttura esistente, i bucket creati anni fa, le pipeline Terraform che riaprono permessi a ogni deploy e le policy copiate da un tutorial online senza essere adattate.

Ad aprile 2026 AWS ha anche cambiato il comportamento sulla cifratura lato client (SSE-C): i nuovi bucket general purpose non accettano più scritture cifrate con SSE-C, e la modifica riguarda pure alcuni bucket esistenti privi di oggetti SSE-C. Chi gestisce pipeline di backup basate su questo schema deve rivedere la configurazione prima che qualcosa smetta di funzionare in produzione. Ne parliamo nel Passo 8.

Il 23 settembre 2026 AWS ha inoltre promosso due nuove regole gestite di AWS Config pensate apposta per questo scenario: s3-bucket-public-read-prohibited e s3-bucket-public-write-prohibited, attivabili con un clic per bloccare rispettivamente lettura e scrittura pubblica sui bucket. Si aggiungono alle 191 regole gestite introdotte a luglio 2026 per servizi come S3, CloudTrail, RDS, ECS, EKS, SageMaker e Bedrock. Questa guida usa entrambe.

Vale la pena capire anche da dove arriva il problema, non solo come chiuderlo. La maggior parte dei bucket esposti che finiscono nei report di ricerca non nasce pubblica per scelta. Nasce privata, poi qualcuno applica una policy temporanea per un test, la segna come “da rimuovere dopo il rilascio” e se ne dimentica. Con account che contano centinaia di bucket, senza un controllo automatico questi residui si accumulano silenziosamente per mesi o anni.

Prerequisiti e versioni per seguire la guida

Prima di eseguire un solo comando, prepara l’ambiente di lavoro. Nessuno dei passi seguenti richiede strumenti a pagamento oltre ai normali costi AWS di S3, Config e CloudTrail, ma alcuni comandi modificano permessi in modo irreversibile se applicati al bucket sbagliato.

  • Un account AWS di test, non di produzione, con permessi IAM sufficienti su S3, IAM, AWS Config, CloudTrail e Access Analyzer. Non eseguire i comandi di blocco per la prima volta su un account con carichi reali.
  • AWS CLI versione 2.31 o superiore. Verifica con aws --version e aggiorna se necessario.
  • Python 3.12 o superiore con la libreria boto3 1.35 o successiva, per lo script del Passo 10.
  • Un bucket S3 dedicato agli esperimenti, con dati fittizi, mai con informazioni reali durante i test.
  • MFA attivo sull’utente root e su tutti gli utenti IAM con permessi amministrativi.
  • Familiarità di base con la sintassi JSON, necessaria per leggere e modificare bucket policy e policy IAM.

Passo 1: audit iniziale, mappare tutti i bucket

Prima di bloccare qualcosa devi sapere cosa esiste. Molte aziende scoprono bucket dimenticati creati da progetti chiusi da tempo. Il primo comando elenca tutti i bucket dell’account e verifica lo stato di Block Public Access (BPA) per ciascuno.

aws s3api list-buckets --query 'Buckets[].Name' --output text | tr '\t' '\n' | while read -r bucket; do
  echo "== $bucket =="
  aws s3api get-public-access-block --bucket "$bucket" 2>&1
done

Un bucket protetto restituisce i quattro flag tutti a true. Se invece ricevi l’errore NoSuchPublicAccessBlockConfiguration, quel bucket non ha alcuna configurazione di blocco attiva: è il segnale più chiaro che serve intervenire subito, prima di passare a qualunque altro controllo.

Passo 2: attivare S3 Block Public Access a livello di account

Il modo più rapido per ridurre il rischio su tutto l’account è attivare Block Public Access a livello globale, così qualunque nuovo bucket eredita la protezione anche se qualcuno dimentica di configurarla manualmente.

aws s3control put-public-access-block \
  --account-id 123456789012 \
  --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

Sostituisci l’ID account con il tuo. Se gestisci più account tramite AWS Organizations, questa impostazione può essere applicata centralmente a livello organizzativo, evitando di doverla ripetere account per account.

ControlloCosa bloccaQuando usarlo
BlockPublicAclsImpedisce di aggiungere nuove ACL pubblicheSempre, salvo siti statici legacy senza CDN
IgnorePublicAclsIgnora le ACL pubbliche già esistentiQuando vuoi neutralizzare ACL storiche senza rimuoverle
BlockPublicPolicyRifiuta bucket policy che concedono accesso pubblicoSempre, tranne bucket di hosting statico pubblico intenzionale
RestrictPublicBucketsLimita l’accesso pubblico anche se la policy lo consentirebbeAmbienti multi-account con accessi cross-account da rivedere

Passo 3: bloccare l’accesso pubblico bucket per bucket

Se hai bucket che devono restare parzialmente pubblici (un sito statico, ad esempio), applica il blocco a livello di singolo bucket invece che sull’intero account.

aws s3api put-public-access-block \
  --bucket nome-bucket \
  --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

Chi preferisce la console può ottenere lo stesso risultato con un clic: IAM Access Analyzer for S3 include un pulsante “Block all public access” direttamente nella pagina del bucket, utile per chi gestisce pochi bucket manualmente senza script.

Passo 4: eliminare le ACL pubbliche e attivare Object Ownership

Le ACL a livello di oggetto sono un residuo delle versioni più vecchie di S3 e restano una fonte comune di esposizioni accidentali. La soluzione più solida è disattivarle del tutto con Object Ownership impostato su BucketOwnerEnforced.

aws s3api put-bucket-ownership-controls \
  --bucket nome-bucket \
  --ownership-controls Rules=[{ObjectOwnership=BucketOwnerEnforced}]

Con questa impostazione, il proprietario del bucket possiede automaticamente ogni oggetto caricato e le ACL smettono di avere effetto. Da tempo AWS crea i nuovi bucket già con questa configurazione di default, ma i bucket più vecchi vanno migrati manualmente. Prima di applicare questa modifica su un bucket condiviso tra più account AWS, verifica che nessun processo dipenda ancora da ACL personalizzate per concedere accesso cross-account: in quel caso, sostituisci le ACL con una bucket policy esplicita prima di forzare BucketOwnerEnforced, altrimenti rischi di interrompere un flusso di lavoro legittimo insieme a quello indesiderato.

Passo 5: correggere le bucket policy pericolose

La bucket policy è spesso il punto in cui finisce un accesso pubblico non voluto, di solito perché qualcuno ha copiato un esempio online senza restringerne il campo di applicazione. Ecco una policy da evitare.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PericolosaAccessoPubblico",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::nome-bucket/*"
    }
  ]
}

Il campo "Principal": "*" concede l’accesso a chiunque su internet, non solo alla tua organizzazione. Una versione corretta aggiunge una condizione esplicita e nega il traffico non cifrato.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "NegaTrafficoNonSicuro",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::nome-bucket",
        "arn:aws:s3:::nome-bucket/*"
      ],
      "Condition": { "Bool": { "aws:SecureTransport": "false" } }
    }
  ]
}

Se il bucket serve più applicazioni con esigenze diverse, valuta anche gli access point S3, che permettono di definire policy separate per ogni caso d’uso invece di accumulare eccezioni sempre più complesse in un’unica bucket policy. Ogni access point ha il proprio nome DNS e la propria policy, così un’applicazione compromessa che usa un access point specifico non espone automaticamente l’accesso concesso agli altri.

Passo 6: individuare gli accessi esterni con IAM Access Analyzer

IAM Access Analyzer per S3 controlla ACL, bucket policy e access-point policy e segnala quando un bucket concede accesso pubblico o accesso ad altri account AWS che non ti aspetti. Crea un analyzer a livello di account.

aws accessanalyzer create-analyzer \
  --analyzer-name s3-accessi-esterni \
  --type ACCOUNT

aws accessanalyzer list-findings \
  --analyzer-arn arn:aws:access-analyzer:eu-west-1:123456789012:analyzer/s3-accessi-esterni \
  --filter '{"resourceType":{"eq":["AWS::S3::Bucket"]}}'

La prima scansione può richiedere fino a mezz’ora prima di popolare i risultati. Ogni finding indica la risorsa, il principal esterno coinvolto e il tipo di accesso concesso, così puoi decidere se è intenzionale o va corretto.

Passo 7: applicare il privilegio minimo con IAM

Bloccare l’accesso pubblico non basta se poi un ruolo applicativo interno ha permessi troppo ampi su tutto il bucket. Definisci policy IAM che concedono solo le azioni necessarie, su un prefisso specifico.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "LetturaLimitataAlPrefisso",
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": "arn:aws:s3:::dati-clienti/report-mensili/*",
      "Condition": {
        "StringEquals": { "aws:SourceVpce": "vpce-0abc123def456" }
      }
    }
  ]
}

Evita ruoli con s3:* su Resource: "*", anche per applicazioni interne. Se un’applicazione legge soltanto oggetti, non concederle mai PutObject o DeleteObject: limita ogni permesso all’azione realmente usata dal codice. Un buon punto di partenza è generare la policy minima analizzando i log di CloudTrail delle ultime settimane con IAM Access Analyzer, che propone automaticamente un set di permessi basato sull’utilizzo reale osservato invece che su una stima approssimativa fatta a tavolino.

Passo 8: attivare la cifratura lato server e gestire l’addio a SSE-C

Un bucket cifrato non impedisce un accesso pubblico indesiderato, ma riduce il danno se qualcuno riesce comunque a scaricare i file, ad esempio tramite credenziali rubate invece che tramite una policy sbagliata. Configura la cifratura di default con SSE-KMS.

aws s3api put-bucket-encryption \
  --bucket nome-bucket \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "alias/s3-default"
      },
      "BucketKeyEnabled": true
    }]
  }'

Se la tua pipeline usa ancora SSE-C (cifratura con chiave fornita dal cliente), sappi che da aprile 2026 i nuovi bucket general purpose rifiutano di default le nuove scritture cifrate con questo schema, e la stessa restrizione si applica anche ad alcuni bucket esistenti privi di oggetti SSE-C. Se dipendi da SSE-C per motivi di conformità, verifica la configurazione del bucket prima di un deploy, oppure migra a SSE-KMS.

Metodo di cifraturaChi gestisce la chiaveStato nel 2026
SSE-S3Gestita interamente da AWSDefault su tutti i nuovi bucket, nessuna azione richiesta
SSE-KMSAWS KMS, con policy e audit dedicatiConsigliata per dati sensibili, supporta rotazione e log di utilizzo chiave
SSE-CFornita dal cliente a ogni richiestaNuove scritture disabilitate di default sui nuovi bucket general purpose da aprile 2026

Passo 9: automatizzare i controlli con AWS Config

Controllare manualmente centinaia di bucket non è sostenibile, soprattutto in un’organizzazione con più team che creano ed eliminano bucket ogni settimana. AWS Config valuta continuamente la conformità e segnala le violazioni appena si verificano, invece di aspettare il prossimo audit trimestrale. Attiva le due regole gestite pensate apposta per S3.

aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "s3-bucket-public-read-prohibited",
  "Source": {
    "Owner": "AWS",
    "SourceIdentifier": "S3_BUCKET_PUBLIC_READ_PROHIBITED"
  }
}'

aws configservice put-config-rule --config-rule '{
  "ConfigRuleName": "s3-bucket-public-write-prohibited",
  "Source": {
    "Owner": "AWS",
    "SourceIdentifier": "S3_BUCKET_PUBLIC_WRITE_PROHIBITED"
  }
}'

AWS Config supporta ormai 191 regole gestite aggiuntive introdotte a luglio 2026, che coprono anche CloudTrail, RDS, ECS, EKS, SageMaker e Bedrock: se il tuo stack usa questi servizi, vale la pena attivare le regole equivalenti nello stesso passaggio.

Passo 10: costruire il progetto completo, uno script di audit continuo in Python

Ecco il progetto funzionante della guida: uno script Python che scorre tutti i bucket dell’account, controlla Block Public Access, ACL, bucket policy e cifratura, poi stampa un report leggibile. Puoi pianificarlo con cron o con una Lambda schedulata.

Struttura consigliata del progetto

Per un uso reale, non tenere lo script in un unico file. Organizzalo così: una cartella audit_s3/ con main.py (il codice mostrato sotto), un file requirements.txt con boto3>=1.35, e un file report.py separato che si occupa solo di formattare l’output, così puoi cambiare formato (testo, CSV, JSON per un dashboard) senza toccare la logica di controllo. Aggiungi anche un file test_main.py con qualche test unitario che usa la libreria moto per simulare le risposte di S3, così puoi verificare la logica di controllo senza toccare un account AWS reale a ogni modifica del codice.

import boto3
import json

s3 = boto3.client("s3")
s3control = boto3.client("s3control")
sts = boto3.client("sts")

account_id = sts.get_caller_identity()["Account"]

def bucket_ha_bpa_attivo(nome_bucket):
    try:
        risposta = s3.get_public_access_block(Bucket=nome_bucket)
        cfg = risposta["PublicAccessBlockConfiguration"]
        return all(cfg.values())
    except s3.exceptions.ClientError:
        return False

def policy_ha_principal_pubblico(nome_bucket):
    try:
        risposta = s3.get_bucket_policy(Bucket=nome_bucket)
        policy = json.loads(risposta["Policy"])
        for statement in policy.get("Statement", []):
            if statement.get("Effect") == "Allow" and statement.get("Principal") == "*":
                return True
        return False
    except s3.exceptions.ClientError:
        return False

def bucket_ha_cifratura(nome_bucket):
    try:
        s3.get_bucket_encryption(Bucket=nome_bucket)
        return True
    except s3.exceptions.ClientError:
        return False

def main():
    bucket_list = s3.list_buckets()["Buckets"]
    problemi_trovati = []

    print(f"Audit account {account_id}: {len(bucket_list)} bucket trovati\n")

    for bucket in bucket_list:
        nome = bucket["Name"]
        bpa_attivo = bucket_ha_bpa_attivo(nome)
        policy_rischiosa = policy_ha_principal_pubblico(nome)
        cifrato = bucket_ha_cifratura(nome)

        stato = "OK" if bpa_attivo and not policy_rischiosa and cifrato else "DA CORREGGERE"
        print(f"{nome:40s} BPA={bpa_attivo!s:5s} PolicyPubblica={policy_rischiosa!s:5s} Cifrato={cifrato!s:5s} -> {stato}")

        if stato == "DA CORREGGERE":
            problemi_trovati.append(nome)

    print(f"\nBucket da correggere: {len(problemi_trovati)}")
    return problemi_trovati

if __name__ == "__main__":
    main()

Su un account con migliaia di bucket, aggiungi un paginator alle chiamate API e un backoff esponenziale per evitare throttling, come indicato nella sezione di risoluzione dei problemi più avanti.

Come eseguirlo in produzione senza intervento manuale

Impacchetta lo script come funzione Lambda con un trigger EventBridge schedulato ogni ora, invece di lanciarlo a mano dal laptop di qualcuno. Concedi alla Lambda un ruolo IAM con permessi in sola lettura (s3:GetBucketPolicy, s3:GetPublicAccessBlock, s3:GetEncryptionConfiguration) e nulla in scrittura: uno script di audit non deve mai avere il potere di modificare ciò che controlla, altrimenti un bug diventa un incidente invece di un semplice falso allarme.

Passo 11: notifiche in tempo reale con EventBridge e SNS

Un audit periodico è utile, ma un avviso immediato quando qualcuno modifica una policy è meglio. Collega AWS Config a SNS tramite EventBridge, così ogni cambiamento di conformità genera una notifica.

aws sns create-topic --name allarmi-s3-pubblici

aws sns subscribe \
  --topic-arn arn:aws:sns:eu-west-1:123456789012:allarmi-s3-pubblici \
  --protocol email \
  --notification-endpoint [email protected]

aws events put-rule \
  --name regola-config-non-conforme \
  --event-pattern '{
    "source": ["aws.config"],
    "detail-type": ["Config Rules Compliance Change"],
    "detail": {
      "messageType": ["ComplianceChangeNotification"],
      "newEvaluationResult": { "complianceType": ["NON_COMPLIANT"] }
    }
  }'

Ricorda di confermare l’iscrizione via email dopo la subscribe: finché non lo fai, SNS non recapita alcun messaggio, anche se la regola di EventBridge si attiva correttamente.

Per un team che gestisce guardie di sicurezza su più fronti, vale la pena collegare lo stesso topic SNS anche ad altri canali oltre all’email, per esempio uno Slack webhook o uno strumento di gestione incidenti. Una notifica che arriva solo su una casella di posta condivisa e poco monitorata rischia di restare inosservata per giorni, vanificando il vantaggio di avere un allarme in tempo reale.

Passo 12: tracciare tutto con CloudTrail e Security Hub

Sapere chi ha cambiato cosa e quando è essenziale per un’indagine post-incidente. Abilita i data event selector di CloudTrail per il bucket e usa i controlli CSPM di Security Hub per aggregare lo stato di conformità di tutti i bucket in un’unica dashboard.

aws cloudtrail put-event-selectors \
  --trail-name trail-principale \
  --event-selectors '[{
    "ReadWriteType": "All",
    "IncludeManagementEvents": true,
    "DataResources": [{
      "Type": "AWS::S3::Object",
      "Values": ["arn:aws:s3:::nome-bucket/"]
    }]
  }]'

Con Security Hub attivo, i controlli come s3-bucket-public-write-prohibited e s3-bucket-level-public-access-prohibited compaiono automaticamente nel punteggio di sicurezza complessivo dell’account, utile per riportare lo stato a un responsabile non tecnico. Tieni presente che abilitare i data event su ogni bucket dell’account genera un volume di log significativo e un costo CloudTrail proporzionale: per bucket a basso rischio con solo asset statici pubblici intenzionali, può bastare il livello di management event, riservando i data event completi ai bucket che contengono dati sensibili o soggetti a obblighi di audit.

Prevenire la deriva della configurazione con Infrastructure as Code

I 12 passi precedenti risolvono lo stato attuale dei tuoi bucket. Non impediscono che qualcuno riapra un accesso pubblico la settimana prossima con un terraform apply distratto. La soluzione più stabile è codificare la configurazione sicura in un modulo riutilizzabile, così ogni nuovo bucket nasce già conforme, senza dipendere dalla memoria di chi lo crea.

Un modulo Terraform per bucket sicuri per default

resource "aws_s3_bucket" "sicuro" {
  bucket = var.nome_bucket
}

resource "aws_s3_bucket_public_access_block" "sicuro" {
  bucket                  = aws_s3_bucket.sicuro.id
  block_public_acls       = true
  ignore_public_acls      = true
  block_public_policy     = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_server_side_encryption_configuration" "sicuro" {
  bucket = aws_s3_bucket.sicuro.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = var.kms_key_arn
    }
  }
}

resource "aws_s3_bucket_ownership_controls" "sicuro" {
  bucket = aws_s3_bucket.sicuro.id
  rule {
    object_ownership = "BucketOwnerEnforced"
  }
}

Ogni team che deve creare un bucket richiama questo modulo invece di scrivere risorse S3 da zero. Se in futuro serve aggiornare lo standard di sicurezza, lo cambi in un solo posto e si propaga a ogni nuovo deploy. Per verificare che nessuno bypassi il modulo con risorse scritte a mano, integra uno scanner statico come Checkov nella pipeline, così un bucket pubblico viene bloccato prima del merge, non scoperto mesi dopo da un finding di Access Analyzer.

Errori comuni da evitare

Anche seguendo tutti i 12 passi, ci sono trappole ricorrenti che riportano un bucket allo stato vulnerabile senza che nessuno se ne accorga subito.

  • Considerare “privato per default” una garanzia permanente. Un redeploy Terraform mal scritto può riaprire un bucket in pochi secondi, senza che nessuno se ne accorga finché non arriva un finding di Access Analyzer.
  • Disattivare Block Public Access per far funzionare un sito statico. La soluzione corretta è servire il contenuto tramite CloudFront con Origin Access Control, mantenendo il bucket completamente privato.
  • Dimenticare gli accessi cross-account. Una policy che concede accesso a un altro account AWS non è “pubblica” in senso stretto, ma va comunque rivista periodicamente con Access Analyzer, non solo alla creazione.
  • Usare credenziali IAM statiche invece di ruoli temporanei. Una chiave access key salvata in un file di configurazione è esattamente il tipo di errore che ha portato al takeover in dieci minuti descritto da Cloud Security Alliance.
  • Ignorare gli avvisi di AWS Config perché “generano troppo rumore”. Meglio silenziare temporaneamente una regola specifica con una motivazione documentata che disattivare tutto il monitoraggio.
  • Copiare bucket policy da forum online senza adattarle. Un Principal: "*" trovato in un tutorial generico raramente è pensato per un bucket con dati reali.
  • Non testare le regole di privilegio minimo prima del rollout. Una policy IAM troppo restrittiva applicata direttamente in produzione può bloccare un’applicazione critica: testa sempre prima in un ambiente di staging con traffico simulato.

Esempi di output e come leggerli

Quando esegui lo script Python del Passo 10 su un account con configurazioni miste, l’output assomiglia a questo.

Audit account 123456789012: 14 bucket trovati

backup-produzione-eu             BPA=True  PolicyPubblica=False Cifrato=True  -> OK
sito-statico-marketing           BPA=False PolicyPubblica=True  Cifrato=False -> DA CORREGGERE
log-applicativi-2025             BPA=True  PolicyPubblica=False Cifrato=False -> DA CORREGGERE
dati-clienti-fatturazione        BPA=True  PolicyPubblica=False Cifrato=True  -> OK

Bucket da correggere: 2

Il bucket sito-statico-marketing con PolicyPubblica=True è il caso più urgente: significa che una policy attiva concede accesso pubblico in lettura o scrittura, non solo che manca un livello di protezione difensiva. Il bucket log-applicativi-2025 ha Block Public Access corretto, ma manca la cifratura di default, un rischio minore ma comunque da correggere prima di un audit di conformità.

Tratta l’output come una lista di priorità, non come un elenco piatto da correggere in ordine alfabetico. Un bucket con policy pubblica attiva va sistemato entro ore, non entro lo sprint successivo. Un bucket privo solo di cifratura può aspettare la prossima finestra di manutenzione pianificata, a patto che resti tracciato e non finisca dimenticato di nuovo.

Risoluzione dei problemi più comuni

Anche seguendo la guida passo per passo, capita di incontrare errori legati a permessi mancanti, tempistiche di propagazione o interazioni inaspettate tra regole diverse. Ecco i problemi più segnalati e come risolverli senza dover riaprire un ticket di supporto AWS.

ProblemaCausa probabileSoluzione
get-public-access-block restituisce NoSuchPublicAccessBlockConfigurationNessuna configurazione BPA impostata sul bucketApplica il Passo 2 o il Passo 3
AccessDenied su put-public-access-blockL’utente IAM non ha il permesso s3:PutAccountPublicAccessBlockAggiungi il permesso mancante o usa un ruolo con privilegi amministrativi
Un’applicazione smette di funzionare dopo BlockPublicPolicyLa policy legittima usava un Principal ampio per servire una CDNSostituisci con Origin Access Control su CloudFront
IAM Access Analyzer non mostra risultatiL’analyzer è stato creato da pocoAttendi fino a 30 minuti dopo create-analyzer
Le scritture SSE-C falliscono dopo aprile 2026Nuovi bucket disabilitano di default le scritture SSE-CPassa a SSE-KMS o SSE-S3
AWS Config segnala non conformità ma il bucket sembra privatoLa regola valuta anche le ACL, non solo le bucket policyControlla anche gli ACL con get-bucket-acl
Le notifiche SNS non arrivanoLa subscription email non è stata confermataConferma il link ricevuto via email dopo la subscribe
Lo script Python restituisce errori di throttlingTroppe chiamate API su un account con migliaia di bucketAggiungi un paginator e un backoff esponenziale
Una regola Deny blocca anche il team internoManca una condizione di eccezione per i ruoli fidatiAggiungi una condizione NotPrincipal per i ruoli interni
CloudTrail non registra gli eventi dati S3I data event selector non sono configurati per quel bucketApplica il Passo 12

Se un problema non compare in questa tabella, il primo passo di debug resta sempre lo stesso: rilancia il comando con --debug aggiunto alla CLI AWS e controlla la risposta HTTP completa dell’API, non solo il messaggio di errore riassunto. Molti errori apparentemente oscuri di IAM nascondono semplicemente un permesso mancante che il messaggio breve non nomina esplicitamente.

Consigli avanzati per team di sicurezza

Una volta chiusi i punti base, un team di sicurezza maturo passa dalla correzione reattiva alla prevenzione strutturale. Ecco le pratiche che fanno davvero la differenza su larga scala.

  • Usa Amazon Macie per scansionare automaticamente i bucket alla ricerca di dati personali, molto utile per dimostrare conformità GDPR durante un audit e per scoprire dati sensibili finiti per errore in bucket non pensati per contenerli.
  • Restringi l’accesso a S3 tramite un VPC Gateway Endpoint, così il traffico applicativo non attraversa mai la rete pubblica di internet e resta interno alla tua VPC anche quando l’applicazione gira su EC2 o EKS.
  • Integra uno scanner di configurazione Terraform nella pipeline CI/CD prima del deploy: la nostra guida su Checkov per Terraform copre esattamente questo passaggio, bloccando un merge non conforme prima che diventi un bucket reale.
  • Per i workload containerizzati che leggono da S3, uno scanner come Trivy per cloud e Kubernetes individua misconfigurazioni simili anche a livello di cluster, comprese le credenziali incorporate nelle immagini container.
  • Rivedi periodicamente gli strumenti di CSPM disponibili: il confronto tra Prowler e ScoutSuite aiuta a scegliere quello più adatto al tuo team in base a manutenzione attiva e copertura dei controlli.
  • Centralizza Block Public Access su tutta la landing zone con AWS Organizations, invece di ripetere la configurazione account per account ogni volta che un nuovo team richiede un ambiente AWS separato.
  • Programma revisioni trimestrali dei permessi IAM per ruoli e utenti con accesso a bucket sensibili: i permessi accumulati nel tempo, il cosiddetto permission creep, sono difficili da individuare con un solo controllo puntuale.

Implicazioni GDPR e NIS2 per le aziende italiane ed europee

Se un bucket S3 esposto contiene dati personali di cittadini UE, l’esposizione può configurare una violazione ai sensi dell’articolo 33 del GDPR, con l’obbligo di notificare il Garante per la Protezione dei Dati Personali entro 72 ore dalla scoperta. Il tempo conta: uno script di audit continuo come quello del Passo 10 riduce il rischio di scoprire l’esposizione mesi dopo, quando i dati sono già stati indicizzati da motori di ricerca specializzati in cloud storage aperto.

Prima ancora di arrivare a un incidente, un bucket che ospita dati personali dovrebbe passare da una valutazione d’impatto sulla protezione dei dati (DPIA), specialmente se contiene categorie particolari come dati sanitari o finanziari. Documenta nel registro dei trattamenti quali bucket contengono dati personali, chi vi accede e con quali permessi IAM: in caso di ispezione, questa mappatura vale quanto la configurazione tecnica corretta, perché dimostra un approccio strutturato alla protezione dei dati fin dalla progettazione.

Per le aziende che rientrano nel perimetro della direttiva NIS2, che copre anche fornitori di servizi digitali e cloud, le sanzioni per carenze nella gestione del rischio possono arrivare fino a 10 milioni di euro. Chi ha già affrontato il tema della conformità può approfondire nella nostra guida su NIS2 in Italia, che spiega obblighi e scadenze per le imprese soggette a ispezione ACN. Le stesse misure tecniche descritte in questa guida, dal privilegio minimo alla cifratura, rientrano tra i controlli di base che un’ispezione ACN si aspetta di trovare documentati.

Come la misconfigurazione S3 si collega alla OWASP Top 10

Un bucket pubblico non è tecnicamente una vulnerabilità nel codice, ma rientra a pieno titolo nella categoria “Security Misconfiguration” della OWASP Top 10, e spesso si sovrappone anche a “Broken Access Control” quando la policy concede permessi più ampi di quelli previsti dal disegno dell’applicazione. Se stai già lavorando su un piano di remediation più ampio, la nostra guida OWASP Top 10:2025 copre gli altri passaggi da affrontare oltre alla parte cloud.

La lezione pratica è che la sicurezza del bucket non si esaurisce con Block Public Access. Serve un livello di controllo continuo, perché una configurazione corretta oggi può essere sovrascritta domani da un deploy automatico o da un collega che non conosce lo storico delle scelte fatte sul progetto.

Vale anche la pena distinguere tra i due scenari che spesso si confondono. Un bucket pubblico per una policy scritta male è quasi sempre un errore di configurazione. Un bucket compromesso perché un’applicazione con permessi eccessivi è stata sfruttata tramite un’altra vulnerabilità, per esempio una SQL injection o un token JWT contraffatto, è invece un problema di accesso applicativo che la sola configurazione S3 non risolve. Se il tuo stack espone API che leggono da S3, vale la pena rivedere anche la sicurezza di quello strato, dai controlli sulle richieste in ingresso fino alla gestione dei token di autenticazione.

Domande frequenti su sicurezza e misconfigurazione dei bucket S3

Un bucket S3 privato per default è sempre sicuro?
No. È sicuro finché nessuno modifica policy, ACL o impostazioni di Object Ownership. Un audit periodico resta necessario anche su bucket configurati correttamente al momento della creazione.

Come faccio a sapere se un mio bucket è già stato indicizzato pubblicamente?
Esegui prima il Passo 1 di questa guida per verificare lo stato attuale, poi controlla i log di accesso del bucket per individuare richieste da IP non riconducibili alla tua infrastruttura. Un volume anomalo di richieste GET provenienti da IP sparsi in tutto il mondo, soprattutto se concentrato in un breve lasso di tempo, è un segnale tipico di scansione automatica da parte di motori specializzati in cloud storage aperto.

IAM Access Analyzer ha un costo aggiuntivo?
L’analyzer per la ricerca di accessi esterni non ha un costo diretto separato per l’uso base. Verifica comunque il listino AWS aggiornato per la tua regione prima di attivarlo su larga scala.

Cosa cambia con la fine del supporto SSE-C su alcuni bucket da aprile 2026?
I nuovi bucket general purpose e alcuni bucket esistenti senza oggetti SSE-C non accettano più nuove scritture cifrate con questo schema. Chi lo usa per conformità deve migrare a SSE-KMS o SSE-S3.

Posso applicare queste regole a tutti gli account con AWS Organizations?
Sì. Block Public Access e molte regole di AWS Config possono essere applicate centralmente tramite policy organizzative, senza doverle configurare account per account.

Cosa devo fare se scopro che un bucket è stato pubblico per mesi?
Applica subito Block Public Access, poi verifica i log di accesso per capire l’estensione dell’esposizione. Se sono coinvolti dati personali di cittadini UE, valuta con il tuo DPO l’obbligo di notifica entro 72 ore previsto dal GDPR. Documenta ogni passaggio della risposta, dalla scoperta alla correzione: quella cronologia è ciò che un’autorità di controllo chiederà per prima in caso di ispezione.

Le stesse regole valgono anche per Google Cloud Storage e Azure Blob Storage?
I principi sono simili: privilegio minimo, blocco dell’accesso pubblico di default, cifratura e monitoraggio continuo, ma i nomi dei servizi e i comandi CLI cambiano da provider a provider.

Quanto tempo serve per completare tutti e 12 i passi su un account già esistente?
Su un account con poche decine di bucket, tra 45 e 60 minuti bastano per applicare Block Public Access, IAM Access Analyzer e AWS Config. Su account più grandi conviene prima automatizzare con lo script del Passo 10 e poi correggere i bucket segnalati in ordine di priorità.