Mitigazione degli incidenti di sicurezza


Questo documento descrive mitigazioni e risposte a potenziali incidenti di sicurezza per i cluster e i container Google Kubernetes Engine (GKE).

I suggerimenti riportati in Rafforzare la sicurezza del cluster possono migliorare la sicurezza dei carichi di lavoro GKE. Gli incidenti relativi alla sicurezza, tuttavia, possono verificarsi anche quando sono attive misure per proteggere i carichi di lavoro.

Rilevamento incidenti

Per rilevare potenziali incidenti, ti consigliamo di configurare un processo che raccolga e monitori i log del carico di lavoro. Poi, configura avvisi basati sugli eventi anomali rilevati dai log. Gli avvisi avvisano il team addetto alla sicurezza quando viene rilevato qualcosa di insolito. Il team di sicurezza potrà quindi esaminare il potenziale incidente.

Generazione di avvisi dai log

Puoi personalizzare gli avvisi in base a metriche o azioni specifiche. Ad esempio, gli avvisi relativi a un utilizzo elevato della CPU sui nodi GKE potrebbero indicare che sono compromessi per il cryptomining.

Dovresti generare avvisi nel punto in cui aggreghi i log e le metriche. Ad esempio, puoi utilizzare l'audit logging di GKE in combinazione con gli avvisi basati su log in Cloud Logging.

Per ulteriori informazioni sulle query relative alla sicurezza, consulta la documentazione sull'audit logging.

Risposta a un incidente di sicurezza

Intervieni dopo aver ricevuto un avviso relativo a un incidente. Se possibile, correggi la vulnerabilità. Se non conosci la causa principale della vulnerabilità o se non è pronta una correzione, applica le mitigazioni.

Le mitigazioni che potresti adottare dipendono dalla gravità dell'incidente e dalla certezza di aver identificato il problema.

Questa guida descrive le azioni che puoi intraprendere dopo aver rilevato un incidente su un carico di lavoro in esecuzione su GKE. Potresti, in ordine crescente di gravità:

Queste mitigazioni sono descritte nelle sezioni seguenti.

Prima di iniziare

I metodi utilizzati in questo argomento utilizzano le seguenti informazioni:

  • Il nome dei pod che pensi siano stati compromessi o POD_NAME.
  • Il nome della VM host che esegue il container o i pod oppure NODE_NAME.

Inoltre, prima di intraprendere qualsiasi azione, valuta se l'utente malintenzionato viene scoperto in una reazione negativa. L'utente malintenzionato potrebbe decidere di eliminare i dati o i carichi di lavoro. Se il rischio è troppo elevato, prima di eseguire ulteriori indagini valuta la possibilità di mitigazioni più drastiche, come l'eliminazione di un carico di lavoro.

Crea snapshot del disco della VM

La creazione di uno snapshot del disco della VM consente un'indagine forense dopo che è stato eseguito nuovamente il deployment o eliminato il carico di lavoro. Puoi creare snapshot mentre i dischi sono collegati a istanze in esecuzione.

  1. Per creare uno snapshot del disco permanente, devi prima trovare i dischi collegati alla VM. Esegui questo comando e osserva il campo source:

    gcloud compute instances describe NODE_NAME --zone COMPUTE_ZONE \
        --format="flattened([disks])"
    
  2. Cerca le righe che contengono disks[NUMBER].source. L'output è simile al seguente:

    disks[0].source: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/zones/COMPUTE_ZONE/disks/DISK_NAME
    

    Il nome del disco è la parte del nome di origine che segue la barra finale. Ad esempio, il nome del disco è gke-cluster-pool-1-abcdeffff-zgt8.

  3. Per completare lo snapshot, esegui questo comando:

    gcloud compute disks snapshot DISK_NAME
    

Per ulteriori informazioni, consulta la sezione sulla creazione di disco permanente permanenti nella documentazione di Compute Engine.

Ispeziona la VM durante l'esecuzione del carico di lavoro

Prima di intervenire, valuta anche di quale accesso può disporre un utente malintenzionato. Se sospetti che un container sia stato compromesso e temi di informare l'utente malintenzionato, puoi collegarti al container ed ispezionarlo. L'ispezione è utile per indagini rapide prima di intraprendere azioni più fastidiose. L'ispezione è anche l'approccio meno invasivo per il carico di lavoro, ma non arresta l'incidente.

In alternativa, per evitare di accedere a una macchina con credenziali privilegiate, puoi analizzare i tuoi carichi di lavoro configurando l'analisi forense in tempo reale (come GRR Rapid Response), agenti on-node o filtri di rete.

Riduci l'accesso prima di ispezionare la VM attiva

Se nascondi, svuota e limiti l'accesso della rete alla VM che ospita un container compromesso, puoi isolare parzialmente il container compromesso dal resto del cluster. Limitare l'accesso alla VM riduce i rischi, ma non impedisce a un utente malintenzionato di spostarsi lateralmente nel tuo ambiente se si avvale di una vulnerabilità critica.

Non pianifica il nodo ed svuota gli altri carichi di lavoro al suo interno

L'eliminazione o lo svuotamento di un nodo sposta i carichi di lavoro che si trovano insieme al container compromesso ad altre VM nel tuo cluster. Lo svuotamento e lo svuotamento riducono la capacità degli utenti malintenzionati di influire su altri carichi di lavoro sullo stesso nodo. Non gli impedisce in alcun modo di ispezionare lo stato permanente di un carico di lavoro (ad esempio, esaminando i contenuti delle immagini container).

  1. Utilizza kubectl per contrassegnare il nodo come non pianificabile e assicurarti che non vi siano pianificati altri pod:

    kubectl cordon NODE_NAME
    

    Dopo aver contrassegnato il nodo come non pianificabile, svuota quello degli altri pod.

  2. Etichetta il pod che metti in quarantena:

    kubectl label pods POD_NAME quarantine=true
    

    Sostituisci POD_NAME con il nome del pod che vuoi mettere in quarantena.

  3. Svuota i nodi dei pod non etichettati con quarantine:

    kubectl drain NODE_NAME --pod-selector='!quarantine'
    

Limitare l'accesso di rete al nodo

Consigliamo di bloccare l'accesso alla VM host sia al traffico interno che esterno. Quindi, consenti alle connessioni in entrata da una VM specifica sulla tua rete o VPC di connettersi alla VM in quarantena.

Il primo passaggio consiste nell'abbandonare la VM dal gruppo di istanze gestite a cui appartiene. Se abbandoni la VM, il nodo non verrà contrassegnato come non integro e riparato automaticamente (ricreato) prima del completamento dell'indagine.

Per abbandonare la VM, esegui questo comando:

gcloud compute instance-groups managed abandon-instances INSTANCE_GROUP_NAME \
    --instances=NODE_NAME

Esegui il firewall sulla VM

Creare un firewall tra il container interessato e altri carichi di lavoro nella stessa rete aiuta a impedire a un utente malintenzionato di spostarsi in altre parti dell'ambiente mentre conduci ulteriori analisi. Poiché hai già svuotato la VM di altri container, l'operazione ha effetto solo sul container in quarantena.

Le seguenti istruzioni sul firewall per la VM impediscono:

  • Nuove connessioni in uscita verso altre VM nel tuo cluster utilizzando una regola in uscita.
  • Connessioni in entrata alla VM compromessa tramite una regola in entrata.

Per limitare la VM alle altre istanze, segui questi passaggi per il nodo che ospita il pod che vuoi mettere in quarantena:

  1. Applica un tag all'istanza per poter applicare una nuova regola firewall.

    gcloud compute instances add-tags NODE_NAME \
        --zone COMPUTE_ZONE \
        --tags quarantine
    
  2. Crea una regola firewall per negare tutto il traffico TCP in uscita dalle istanze con il tag quarantine:

    gcloud compute firewall-rules create quarantine-egress-deny \
        --network NETWORK_NAME \
        --action deny \
        --direction egress \
        --rules tcp \
        --destination-ranges 0.0.0.0/0 \
        --priority 0 \
        --target-tags quarantine
    
  3. Crea una regola firewall per negare tutto il traffico TCP in entrata verso le istanze con il tag quarantine. Assegna a questa regola in entrata un valore priority pari a 1, per sostituirla con un'altra regola che consente SSH da una VM specificata.

    gcloud compute firewall-rules create quarantine-ingress-deny \
        --network NETWORK_NAME \
        --action deny \
        --direction ingress \
        --rules tcp \
        --source-ranges 0.0.0.0/0 \
        --priority 1 \
        --target-tags quarantine
    

Rimuovi l'indirizzo IP esterno della VM

La rimozione dell'indirizzo IP esterno della VM comporta l'interruzione di tutte le connessioni di rete esistenti all'esterno del VPC.

Per rimuovere l'indirizzo esterno di una VM, segui questi passaggi:

  1. Trova ed elimina la configurazione di accesso che associa l'IP esterno alla VM. Innanzitutto trova la configurazione dell'accesso descrivendo la VM:

    gcloud compute instances describe NODE_NAME \
        --zone COMPUTE_ZONE --format="flattened([networkInterfaces])"
    

    Cerca le righe che contengono name e natIP. Hanno il seguente aspetto:

    networkInterfaces[0].accessConfigs[0].name:              ACCESS_CONFIG_NAME
    networkInterfaces[0].accessConfigs[0].natIP:             EXTERNAL_IP_ADDRESS
    
  2. Trova il valore di natIP che corrisponda all'IP esterno che vuoi rimuovere. Prendi nota del nome della configurazione dell'accesso.

  3. Per rimuovere l'IP esterno, esegui questo comando:

    gcloud compute instances delete-access-config NODE_NAME \
        --access-config-name "ACCESS_CONFIG_NAME"
    

SSH alla VM host tramite una VM intermedia

Dopo aver rimosso l'IP esterno della VM host, non puoi accedere tramite SSH dall'esterno del VPC. Puoi accedervi da un'altra VM nella stessa rete. Nel resto di questa sezione, facciamo riferimento a VM intermedia.

Prerequisiti

  • Una VM intermedia con accesso alla subnet della VM host. Se non ne hai già una, crea una VM per questo scopo.
  • L'indirizzo IP interno della VM intermedia.
  • Una chiave pubblica SSH dalla VM intermedia. Per scoprire di più, consulta Gestione delle chiavi SSH

Connessione alla VM host

  1. Aggiungi la chiave pubblica della VM intermedia alla VM host. Per ulteriori informazioni, consulta Aggiunta e rimozione di chiavi SSH nella documentazione di Compute Engine.
  2. Aggiungi un tag alla VM intermedia.

    gcloud compute instances add-tags INTERMEDIATE_NODE_NAME \
      --zone COMPUTE_ZONE \
      --tags intermediate
    
  3. Aggiungi una regola di autorizzazione in entrata per eseguire l'override della regola di negazione aggiunta in precedenza. Per aggiungere la regola, esegui questo comando.

    gcloud compute firewall-rules create quarantine-ingress-allow \
        --network NETWORK_NAME \
        --action allow \
        --direction ingress \
        --rules tcp:22 \
        --source-tags intermediate \
        --priority 0 \
        --target-tags quarantine
    

    Questa regola consente il traffico in entrata sulla porta 22 (SSH) dalle VM nella tua rete con il tag intermediate. Sostituisce la regola di negazione con un valore priority pari a 0.

  4. Connettiti alla VM in quarantena utilizzando l'IP interno:

    ssh -i KEY_PATH USER@QUARANTINED_VM_INTERNAL_IP
    

    Sostituisci quanto segue:

    • KEY_PATH: il percorso della chiave privata SSH.
    • USER: l'indirizzo email del tuo account Google Cloud.
    • QUARANTINED_VM_INTERNAL_IP: l'indirizzo IP interno.

Esegui di nuovo il deployment di un container

Se esegui nuovamente il deployment del container, avvii una nuova copia del container ed elimini il container compromesso.

Esegui nuovamente il deployment di un container eliminando il pod che lo ospita. Se il pod è gestito da un costrutto Kubernetes di livello superiore (ad esempio un oggetto Deployment o DaemonSet), l'eliminazione del pod pianifica un nuovo pod. Questo pod esegue nuovi container.

Eseguire nuovamente il deployment ha senso quando:

  • Conosci già la causa della vulnerabilità.
  • Ritieni che sia necessario uno sforzo significativo o molto tempo da parte di un utente malintenzionato per compromettere nuovamente il tuo container.
  • Pensi che il container possa essere compromesso di nuovo rapidamente e non vuoi metterlo offline, quindi ti consigliamo di inserirlo in una sandbox per limitarne l'impatto.

Quando riesegui il deployment del carico di lavoro, se la possibilità di un altro problema è elevato, valuta la possibilità di posizionare il carico di lavoro in un ambiente sandbox come GKE Sandbox. La limitazione tramite sandbox limita l'accesso al kernel del nodo host se un utente malintenzionato compromette nuovamente il container.

Per eseguire nuovamente il deployment di un container in Kubernetes, elimina il pod che lo contiene:

kubectl delete pods POD_NAME --grace-period=10

Se i container nel pod eliminato continuano a essere eseguiti, puoi eliminare il carico di lavoro.

Per eseguire nuovamente il deployment del container all'interno di una sandbox, segui le istruzioni in Rafforzare l'isolamento dei carichi di lavoro con GKE Sandbox.

Elimina un carico di lavoro

L'eliminazione di un carico di lavoro, ad esempio un oggetto Deployment o DaemonSet, determina l'eliminazione di tutti i relativi pod di membri. L'esecuzione di tutti i container all'interno di questi pod viene interrotta. L'eliminazione di un carico di lavoro può avere senso quando:

  • Vuoi fermare un attacco in corso.
  • Hai intenzione di portare il carico di lavoro offline.
  • L'arresto immediato dell'attacco è più importante dell'uptime delle applicazioni o dell'analisi forense.

Per eliminare un carico di lavoro, utilizza kubectl delete CONTROLLER_TYPE. Ad esempio, per eliminare un deployment, esegui questo comando:

kubectl delete deployments DEPLOYMENT

Se l'eliminazione del carico di lavoro non comporta l'eliminazione di tutti i pod o i container associati, puoi eliminare manualmente i container utilizzando lo strumento dell'interfaccia a riga di comando del runtime dei container, in genere docker. Se i nodi vengono eseguiti containerd, utilizza crictl.

Docker

Per arrestare un container utilizzando il runtime del container Docker, puoi usare docker stop o docker kill.

docker stop arresta il container inviando un segnale SIGTERM al processo principale e attende 10 secondi l'uscita del processo per impostazione predefinita. Se il processo non è uscito nel periodo di tempo specificato, viene inviato un indicatore SIGKILL. Puoi specificare questo periodo di tolleranza tramite l'opzione --time.

docker stop --time TIME_IN_SECONDS CONTAINER

docker kill è il metodo più veloce per arrestare un container. Invia immediatamente il segnale SIGKILL.

docker kill CONTAINER

Puoi anche arrestare e rimuovere un container in un comando con docker rm -f:

docker rm -f CONTAINER

containerd

Se utilizzi il runtime containerd in GKE, interrompi o rimuovi i container con crictl.

Per arrestare un container in containerd, esegui questo comando:

crictl stop CONTAINER

Per rimuovere un container in containerd, esegui questo comando:

crictl rm -f CONTAINER

Eliminazione della VM host

Se non riesci a eliminare o rimuovere il container, puoi eliminare la macchina virtuale che ospita il container interessato.

Se il pod è ancora visibile, puoi trovare il nome della VM host con il comando seguente:

kubectl get pods --all-namespaces \
  -o=custom-columns=POD_NAME:.metadata.name,INSTANCE_NAME:.spec.nodeName \
  --field-selector=metadata.name=POD_NAME

Per eliminare la VM host, esegui questo comando gcloud:

gcloud compute instance-groups managed delete-instances INSTANCE_GROUP_NAME \
    --instances=NODE_NAME

Se abbandoni l'istanza dal gruppo di istanze gestite, le dimensioni del gruppo vengono ridotte di una VM. Puoi aggiungere di nuovo manualmente un'istanza al gruppo con il seguente comando:

gcloud compute instance-groups managed resize INSTANCE_GROUP_NAME \
    --size=SIZE

Passaggi successivi