
Nota di traduzione.: L'autore dell'articolo, Reuven Harrison, ha oltre 20 anni di esperienza nello sviluppo di software ed è attualmente il direttore tecnico e cofondatore di Tufin, che crea soluzioni per la gestione delle politiche di sicurezza. Considerando le politiche di rete di Kubernetes come uno strumento piuttosto potente per la segmentazione della rete nel cluster, crede anche che non siano così facili da implementare nella pratica. Questo materiale (piuttosto voluminoso) è progettato per migliorare la consapevolezza dei professionisti su questo tema e aiutarli nella creazione delle configurazioni necessarie.
Oggi molte aziende scelgono sempre più spesso Kubernetes per l'esecuzione delle proprie applicazioni. L'interesse per questo software è così alto che alcuni lo definiscono "il nuovo sistema operativo per i data center". Gradualmente, Kubernetes (o k8s) inizia a essere percepito come una parte critica del business, che richiede l'organizzazione di processi aziendali maturi, incluso il mantenimento della sicurezza di rete.
Per i professionisti della sicurezza, che sono stati messi in difficoltà dal lavoro con Kubernetes, potrebbe essere una vera e propria scoperta la politica predefinita di questa piattaforma: consentire tutto.
Questa guida aiuterà a comprendere il funzionamento interno delle politiche di rete e a capire come si differenziano dalle regole per i normali firewall. Saranno anche menzionate alcune insidie e fornite raccomandazioni che aiuteranno a proteggere le applicazioni su Kubernetes.
Politiche di rete di Kubernetes
Il meccanismo delle politiche di rete di Kubernetes consente di gestire l'interazione delle applicazioni distribuite sulla piattaforma a livello di rete (il terzo nella modellazione OSI). Le politiche di rete mancano di alcune funzionalità avanzate dei firewall moderni, come il controllo di livello 7 OSI e la rilevazione delle minacce, tuttavia forniscono un livello base di sicurezza di rete che rappresenta un buon punto di partenza.
Le politiche di rete controllano le comunicazioni tra pod.
I carichi di lavoro in Kubernetes sono distribuiti tra i pod, che consistono in uno o più contenitori implementati insieme. Kubernetes assegna a ciascun pod un indirizzo IP accessibile da altri pod. Le politiche di rete di Kubernetes definiscono i diritti di accesso per gruppi di pod nello stesso modo in cui i gruppi di sicurezza nel cloud vengono utilizzati per gestire l'accesso alle istanze delle macchine virtuali.
Definizione delle politiche di rete
Come tutte le altre risorse di Kubernetes, le politiche di rete sono definite in YAML. Nel seguente esempio, all'applicazione balance viene concesso l'accesso a postgres:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: balance
policyTypes:
- Ingress 
(Nota di traduzione.: questo screenshot, come tutti i successivi simili, è stato creato non con gli strumenti nativi di Kubernetes, ma attraverso lo strumento Tufin Orca, il cui sviluppo è sostenuto dalla società dell'autore dell'articolo originale e che viene menzionato alla fine del materiale.)
Per definire una propria politica di rete saranno richieste conoscenze di base di YAML. Questo linguaggio si basa su indentazioni (definite da spazi, non tabulazioni). Un elemento con indentazione appartiene all'elemento con indentazione più vicino sopra di esso. Un nuovo elemento di lista inizia con un trattino, mentre gli altri elementi appaiono come chiave-valore.
Dopo aver descritto la politica in YAML, utilizza , per crearla nel cluster:
kubectl create -f policy.yamlSpecifiche della politica di rete
Le specifiche della politica di rete di Kubernetes comprendono quattro elementi:
-
podSelector: definisce i pod interessati da questa politica (obiettivi) — obbligatorio; -
policyTypes: specifica quali tipi di politiche sono incluse: ingress e/o egress — non obbligatorio, ma consiglio di definirlo esplicitamente in tutti i casi; -
ingress: definisce il traffico ingress consentito nei pod di destinazione — non obbligatorio; -
egress: definisce il traffico traffico in uscita dai pod di destinazione — non obbligatorio. Un esempio, preso dal sito di Kubernetes (ho sostituito
role ), mostra come vengono utilizzati tutti e quattro gli elementi: in app), mostra come vengono utilizzati tutti e quattro gli elementi:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector: # <<<
matchLabels:
app: db
policyTypes: # <<<
- Ingress
- Egress
ingress: # <<<
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress: # <<<
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978 

Si prega di notare che tutti e quattro gli elementi non sono obbligatori. Solo podSelectorl'elemento obbligatorio può essere utilizzato come desiderato.
Se si omette policyTypes, la politica sarà interpretata nel seguente modo:
- Per impostazione predefinita, si presume che definisca il lato ingress. Se non ci sono indicazioni esplicite al riguardo nella politica, il sistema considererà che tutto il traffico è vietato.
- Il comportamento sul lato egress sarà determinato dalla presenza o dall'assenza del corrispondente parametro egress.
Per evitare errori, consiglio di specificare sempre in modo esplicito policyTypes.
In base alla logica sopra esposta, nel caso in cui i parametri ingress e/o egress siano omessi, la politica vieta tutto il traffico (vedere "Regola di pulizia" qui sotto).
La politica predefinita è consentita
Se non sono definite politiche, Kubernetes per impostazione predefinita consente tutto il traffico. Tutti i pod possono scambiare informazioni liberamente tra loro. Da un punto di vista della sicurezza, ciò potrebbe sembrare illogico, ma ricorda che Kubernetes è stato originariamente creato dagli sviluppatori per garantire l'interazione delle applicazioni. Le politiche di rete sono state aggiunte in un secondo momento.
Spazi dei nomi
Gli spazi dei nomi (Namespaces) sono un meccanismo di collaborazione in Kubernetes. Sono progettati per isolare gli ambienti logici l'uno dall'altro, mentre lo scambio di dati tra gli spazi è consentito per impostazione predefinita.
Come la maggior parte dei componenti di Kubernetes, le politiche di rete esistono in uno spazio dei nomi specifico. Nel blocco metadati puoi specificare a quale spazio appartiene la politica:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: my-namespace # <<<
spec:
... Se lo spazio dei nomi nei metadati non è specificato esplicitamente, il sistema utilizzerà lo spazio dei nomi specificato in kubectl (per impostazione predefinita namespace=default):
kubectl apply -n my-namespace -f namespace.yamlConsiglio di specificare esplicitamente lo spazio dei nomi, a meno che tu non stia scrivendo una politica destinata a più namespace simultaneamente.
Principale elemento podSelector nella politica selezionerà i pod dal namespace a cui appartiene la politica (non avrà accesso ai pod di un altro namespace).
Analogamente, i podSelector nei blocchi ingress ed egress possono selezionare pod solo dal proprio namespace, a meno che non vengano uniti tramite namespaceSelector (di questo si parlerà nella sezione 'Filtra per namespace e pod').
Regole di denominazione delle politiche
I nomi delle politiche sono unici all'interno di un singolo namespace. Non possono esserci due politiche con lo stesso nome nello stesso namespace, ma possono esserci politiche con nomi identici in namespace diversi. Questo è utile quando si desidera riapplicare la stessa politica su più namespace.
Mi piace particolarmente un modo di denominazione. Consiste nel collegare il nome del namespace ai pod target. Ad esempio:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres # <<<
namespace: default
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: admin
policyTypes:
- Ingress 
Etichette
Si possono assegnare etichette personalizzate a oggetti Kubernetes, come pod e namespace. Le etichette (labels — sono etichette) sono l'equivalente dei tag nel cloud. Le politiche di rete Kubernetes utilizzano le etichette per selezionare pod, a cui si applicano:
podSelector:
matchLabels:
role: db… o namespace, a cui si applicano. In questo esempio, vengono selezionati tutti i pod nei namespace con etichette corrispondenti:
namespaceSelector:
matchLabels:
project: myproject Una avvertenza: quando si usa namespaceSelector assicurati che i namespace selezionati contengano l'etichetta necessaria. Tieni presente che i namespace predefiniti, come default e kube-system, di default non contengono etichette.
Per aggiungere un'etichetta a un namespace, puoi procedere nel seguente modo:
kubectl label namespace default namespace=default In questo caso, il namespace nella sezione metadati deve fare riferimento al nome reale del namespace, non all'etichetta:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default # <<<
spec:
...Fonte e destinatario
Le politiche per i firewall consistono in regole con fonti e destinatari. Le politiche di rete di Kubernetes sono definite per un obiettivo — un insieme di pod a cui si applicano, e poi stabiliscono regole per il traffico in entrata (ingress) e/o in uscita (egress). Nel nostro esempio, l'obiettivo della politica saranno tutti i pod nello spazio dei nomi default con un'etichetta con chiave app e il valore db:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: db # <<<
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978 

Sottosezione ingress in questa politica apre il traffico in ingresso ai pod di destinazione. In altre parole, ingress funge da fonte, mentre l'obiettivo è il destinatario corrispondente. Analogamente, egress è il destinatario, e l'obiettivo è la sua fonte.

Questo è equivalente a due regole per il firewall: Ingress → Obiettivo; Obiettivo → Egress.
Egress e DNS (importante!)
Limitando il traffico in uscita, prestare particolare attenzione a DNS — Kubernetes utilizza questo servizio per mappare i servizi agli indirizzi IP. Ad esempio, la seguente politica non funzionerà poiché non hai consentito all'applicazione balance di accedere a DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
policyTypes:
- Egress 
Può essere risolta aprendo l'accesso al servizio DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to: # <<<
ports: # <<<
- protocol: UDP # <<<
port: 53 # <<<
policyTypes:
- Egress 
Elemento finale to — vuoto, e quindi seleziona indirettamente tutti i pod in tutti gli spazi dei nomi, consentendo balance di inviare richieste DNS al servizio Kubernetes corrispondente (di solito opera nello spazio kube-system).
Questo approccio funziona, tuttavia è eccessivamente permissivo e non sicuro, poiché consente di inoltrare richieste DNS al di fuori del cluster.
Può essere migliorato in tre passi consecutivi.
1. Consentire le richieste DNS solo all'interno al cluster, aggiungendo namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to:
- namespaceSelector: {} # <<<
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress 
2. Consentire le query DNS solo nello spazio dei nomi kube-system.
Per fare ciò, è necessario aggiungere un'etichetta allo spazio dei nomi kube-system: kubectl label namespace kube-system namespace=kube-system — e definirla nella politica utilizzando namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to:
- namespaceSelector: # <<<
matchLabels: # <<<
namespace: kube-system # <<<
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress 
3. I paranoici possono spingersi ulteriormente e limitare le query DNS a un determinato servizio DNS in kube-system. Nella sezione "Filtra per spazi dei nomi e pod" verrà spiegato come farlo.
Un'altra opzione è consentire DNS a livello dello spazio dei nomi. In questo caso, non sarà necessario aprirlo per ogni servizio:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.dns
namespace: default
spec:
podSelector: {} # <<<
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress Vuoto podSelector seleziona tutti i pod nello spazio dei nomi.

La prima corrispondenza e l'ordine delle regole
Nei normali firewall, l'azione ("Consenti" o "Negare") per un pacchetto è determinata dalla prima regola che soddisfa. In Kubernetes, l'ordine delle politiche non ha importanza.
Per impostazione predefinita, quando non sono impostate politiche, le comunicazioni tra i pod sono permesse e possono scambiarsi liberamente informazioni. Non appena inizi a formulare politiche, ogni pod colpito da almeno una di esse diventa isolato in base alla disgiunzione (OR logico) di tutte le politiche che lo hanno selezionato. I pod non colpiti da alcuna politica rimangono aperti.
Puoi modificare questo comportamento con una regola di pulizia.
Regola di pulizia ("Negare")
Le politiche firewall di solito negano qualsiasi traffico non esplicitamente autorizzato.
In Kubernetes non esiste un'azione "negare" (deny), tuttavia un effetto simile può essere ottenuto con una politica ordinaria (consentente) selezionando un gruppo vuoto di pod sorgente (ingress):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress 
Questa politica seleziona tutti i pod nello spazio dei nomi e lascia l'ingresso indefinito, vietando tutto il traffico in entrata.
Analogamente, è possibile limitare tutto il traffico in uscita dallo spazio dei nomi:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress 
Si prega di notare che qualsiasi politica aggiuntiva che consenta il traffico verso i pod nello spazio dei nomi avrà la precedenza su questa regola (analogamente all'aggiunta di una regola permissiva prima di una proibitiva nella configurazione del firewall).
Consentire tutto (Any-Any-Any-Allow)
Per creare una politica "Consentire tutto", è necessario completare la suddetta politica proibitiva con un elemento vuoto ingress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
namespace: default
spec:
podSelector: {}
ingress: # <<<<
- {} # <<<<
policyTypes:
- Ingress 
Essa consente l'accesso da tutti i pod in tutti gli spazi dei nomi (e tutti gli IP) a qualsiasi pod nello spazio dei nomi default. Un comportamento simile è abilitato per impostazione predefinita, quindi di solito non è necessario definirlo ulteriormente. Tuttavia, può essere necessario disattivare temporaneamente alcune autorizzazioni specifiche per diagnosticare un problema.
La regola può essere ristretta e consentire l'accesso solo a un determinato insieme di pod (app:balance) nello spazio dei nomi default:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-to-balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
ingress:
- {}
policyTypes:
- Ingress 
La seguente politica consente tutto il traffico in entrata (ingress) e in uscita (egress), compreso l'accesso a qualsiasi IP al di fuori del cluster:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress:
- {}
egress:
- {}
policyTypes:
- Ingress
- Egress 

Unire più politiche
Le politiche si uniscono tramite l'operatore logico OR a tre livelli; le autorizzazioni di ogni pod sono determinate dalla disgiunzione di tutte le politiche che lo riguardano:
1. Nei campi da e to è possibile definire tre tipi di elementi (tutti combinati tramite OR):
-
namespaceSelector— seleziona l'intero spazio dei nomi; -
podSelector— seleziona i pod; -
ipBlock— seleziona una sottorete.
In questo caso, il numero di elementi (anche identici) nelle sottosezioni da/to non è limitato. Tutti saranno uniti tramite l'operatore logico OR.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- podSelector:
matchLabels:
app: admin
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
2. All'interno della policy, ingress può contenere molti elementi da (combinati con un logico O). Analogamente, la sezione egress può includere molti elementi to (anch'essi combinati tramite disgiunzione):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- from:
- podSelector:
matchLabels:
app: admin
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
3. Diverse policy vengono anch'esse aggregate con un logico O
Ma durante la loro aggregazione esiste una limitazione, alla quale : Kubernetes può combinare policy solo con diverse policyTypes (Ingress o Egress). Le policy che definiscono ingress (o egress) si sovrascriveranno a vicenda.
Collegamento tra spazi dei nomi
Per impostazione predefinita, lo scambio di informazioni tra spazi dei nomi è consentito. È possibile modificare ciò tramite una policy restrittiva che limiterà il traffico in uscita e/o in entrata in uno spazio dei nomi (vedi "Regola di pulizia" sopra).
Bloccando l'accesso a uno spazio dei nomi (vedi "Regola di pulizia" sopra), è possibile fare delle eccezioni nella policy restrittiva, consentendo connessioni da uno spazio dei nomi specifico con namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector: # <<<
matchLabels:
namespace: default
policyTypes:
- Ingress 
Di conseguenza, tutti i pod nello spazio dei nomi default potranno accedere ai pod postgres nello spazio dei nomi database. Ma cosa succede se si desidera aprire l'accesso a postgres solo a specifici pod nello spazio dei nomi default?
Filtrare per spazi dei nomi e pod
Kubernetes versione 1.11 e successivi permette di combinare operatori namespaceSelector e podSelector utilizzando un logico E. Si presenta come segue:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector:
matchLabels:
namespace: default
podSelector: # <<<
matchLabels:
app: admin
policyTypes:
- Ingress 
Perché questo viene interpretato come E invece del consueto O?
Si prega di notare che podSelector non inizia con un trattino. In YAML, ciò significa che podSelector e quello davanti ad esso namespaceSelector appartengono allo stesso elemento della lista. Pertanto, sono combinati con un logico E.
Aggiungere un trattino davanti podSelector porterà alla creazione di un nuovo elemento della lista, che sarà combinato con quello precedente namespaceSelector utilizzando l'operatore logico O.
Per selezionare i pod con un determinato etichetta in tutti gli spazi dei nomi, inserisci vuoto namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: admin
policyTypes:
- Ingress 
Etichette multiple vengono unite con E
Le regole del firewall con più oggetti (host, reti, gruppi) vengono combinate usando l'operatore logico O. La seguente regola si attiverà se la fonte del pacchetto corrisponde a Host_1 O Host_2:
| Sorgente | Destinazione | Servizio | Azione |
| ----------------------------------------|
| Host_1 | Subnet_A | HTTPS | Consenti |
| Host_2 | | | |
| ----------------------------------------| Al contrario, in Kubernetes le diverse etichette in podSelector o namespaceSelector vengono combinate con E logico. Ad esempio, la seguente regola selezionerà i pod che possiedono entrambe le etichette, role=db E version=v2:
podSelector:
matchLabels:
role: db
version: v2La stessa logica si applica a tutti i tipi di operatori: selettori degli obiettivi delle policy, selettori dei pod e selettori degli spazi dei nomi.
Sottoreti e indirizzi IP (IPBlocks)
Per segmentare la rete, i firewall utilizzano VLAN, indirizzi IP e sottoreti.
In Kubernetes, gli indirizzi IP vengono assegnati automaticamente ai pod e possono cambiare frequentemente, quindi per selezionare i pod e gli spazi dei nomi nelle policy di rete vengono utilizzate le etichette.
Sottoreti (ipBlocks) sono utilizzate nella gestione delle connessioni esterne (ingress) o in uscita (egress). Ad esempio, questa policy consente a tutti i pod dello spazio dei nomi default l'accesso al servizio DNS di Google:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-dns
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 8.8.8.8/32
ports:
- protocol: UDP
port: 53 
Il selettore vuoto dei pod in questo esempio significa "selezionare tutti i pod nello spazio dei nomi".
Questa policy consente solo l'accesso a 8.8.8.8; l'accesso a qualsiasi altro IP è vietato. Fondamentalmente, hai bloccato l'accesso al servizio DNS interno di Kubernetes. Se desideri comunque consentirlo, specifica esplicitamente.
Di solito ipBlocks e podSelectors sono reciprocamente esclusivi, poiché gli indirizzi IP interni dei pod non vengono utilizzati in ipBlocks. Specificando indirizzi IP interni dei pod, in realtà consentirete le connessioni ai/da pod con questi indirizzi. In pratica non saprete quale indirizzo IP utilizzare, ecco perché non dovrebbero essere utilizzati per la selezione dei pod.
Come controesempio, la seguente politica include tutti gli IP e, di conseguenza, consente l'accesso a tutti gli altri pod:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-any
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0 
È possibile aprire l'accesso solo agli IP esterni, escludendo gli indirizzi IP interni dei pod. Ad esempio, se la sottorete del tuo pod è 10.16.0.0/14:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-any
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.16.0.0/14 
Porte e protocolli
Di solito, i pod ascoltano una sola porta. Questo significa che puoi semplicemente non specificare i numeri di porta nelle politiche e lasciare tutto di default. Tuttavia, si consiglia di rendere le politiche il più restrittive possibile, quindi in alcuni casi è possibile specificare comunque le porte:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- podSelector:
matchLabels:
app: admin
ports: # <<<
- port: 443 # <<<
protocol: TCP # <<<
- port: 80 # <<<
protocol: TCP # <<<
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
Nota che il selettore ports si applica a tutti gli elementi del blocco to o da, in cui è contenuto. Per specificare porte diverse per diversi insiemi di elementi, suddividi ingress o egress in più sotto-sezioni con to o da e in ognuna specifica le tue porte:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
ports: # <<<
- port: 443 # <<<
protocol: TCP # <<<
- from:
- podSelector:
matchLabels:
app: admin
ports: # <<<
- port: 80 # <<<
protocol: TCP # <<<
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
Funzionamento delle porte di default:
- Se ometti completamente la definizione delle porte (
ports), significa tutti i protocolli e tutte le porte; - Se ometti la definizione del protocollo (
protocollo), questo significa TCP; - Se ometti la definizione della porta (
port), questo significa tutte le porte.
Migliore prassi: non affidarti ai valori di default, specifica esplicitamente ciò di cui hai bisogno.
Si prega di notare che è necessario utilizzare le porte dei pod e non quelle dei servizi (maggiore dettaglio nel paragrafo successivo).
Le politiche sono definite per i pod o per i servizi?
Di solito, i pod in Kubernetes comunicano tra loro tramite un servizio, un bilanciatore di carico virtuale che reindirizza il traffico ai pod che implementano il servizio. Si potrebbe pensare che le politiche di rete controllino l'accesso ai servizi, ma non è così. Le politiche di rete di Kubernetes funzionano con le porte dei pod, non con quelle dei servizi.
Ad esempio, se un servizio ascolta sulla porta 80, ma reindirizza il traffico sulla porta 8080 dei propri pod, nella politica di rete deve essere specificata esattamente la 8080.
Un meccanismo simile dovrebbe essere considerato subottimale: quando cambia la configurazione interna del servizio (le cui porte ascoltano i pod) sarà necessario aggiornare le politiche di rete.
Un nuovo approccio architetturale con l'uso di Service Mesh (ad esempio, vedi Istio qui sotto — nota del traduttore.) affronta questo problema.
È necessario specificare sia Ingress che Egress?
La risposta breve è sì, affinché il pod A possa comunicare con il pod B, è necessario consentire a esso di stabilire una connessione in uscita (per questo è necessario configurare la politica egress), e il pod B deve avere la possibilità di accettare una connessione in ingresso (a questo scopo, serve una politica ingress).
Tuttavia, nella pratica si può fare affidamento sulla politica predefinita che consente connessioni in una o entrambe le direzioni.
Se un certo pod-fonte è selezionato da una o più egress-politiche, le restrizioni imposte su di esso saranno definite dalla loro disgiunzione. In questo caso, sarà necessario consentire esplicitamente la connessione al pod-destinatario. Se il pod non è selezionato da alcuna politica, il suo traffico in uscita (egress) è consentito per impostazione predefinita.
In modo analogo, il destino del pod-destinatario, selezionato da una o più ingress-politiche, sarà determinato dalla loro disgiunzione. In questo caso, è necessario consentire esplicitamente di ricevere traffico dal pod-sorgente. Se il pod non è selezionato da alcuna politica, tutto il traffico in ingresso (ingress) per esso è consentito per impostazione predefinita.
Vedi il punto "Stateful o Stateless" qui sotto.
Log
Le politiche di rete di Kubernetes non sono in grado di registrare il traffico. Questo rende difficile determinare se la politica funzioni correttamente e complica notevolmente l'analisi della sicurezza.
Controllo del traffico verso servizi esterni
Le politiche di rete di Kubernetes non consentono di specificare un nome di dominio completo (DNS) nelle sezioni egress. Questo fatto provoca un notevole inconveniente nel tentativo di limitare il traffico verso destinatari esterni privi di un indirizzo IP fisso (come aws.com).
Verifica della politica
I firewall ti avviseranno o persino rifiuteranno di accettare una politica errata. Anche Kubernetes esegue una certa verifica. Quando imposti una politica di rete tramite kubectl, Kubernetes può affermare che è errata e rifiutarsi di accettarla. In altri casi, Kubernetes accetterà la politica e la completerà con i dettagli mancanti. Puoi visualizzarli utilizzando il comando:
kubernetes get networkpolicy -o yamlTieni presente che il sistema di verifica di Kubernetes non è infallibile e può lasciar passare alcuni tipi di errori.
Esecuzione
Kubernetes non implementa le politiche di rete da solo, ma è solo un gateway API che pone il gravoso compito di controllo sul sistema sottostante, chiamato Container Networking Interface (CNI). Impostare politiche in un cluster Kubernetes senza assegnare un CNI corrispondente è come creare politiche su un server di gestione del firewall senza poi installarle nei firewall. Devi assicurarti di avere un CNI adeguato o, nel caso delle piattaforme Kubernetes ospitate nel cloud, (puoi consultare l'elenco dei provider — nota del traduttore), attivare politiche di rete che installeranno il CNI per te.
Nota che Kubernetes non ti avviserà se imposti una politica di rete senza il corrispondente CNI ausiliario.
Stateful o Stateless?
Tutti i CNI Kubernetes che ho incontrato mantengono lo stato (ad esempio, Calico utilizza Linux conntrack). Questo consente al pod di ricevere risposte su una connessione TCP da lui avviata senza doverla ristabilire. Tuttavia, non sono a conoscenza di alcuno standard di Kubernetes che garantisca la conservazione dello stato (statefulness).
Gestione avanzata delle politiche di sicurezza
Ecco alcuni modi per migliorare l'efficacia di esecuzione delle politiche di sicurezza in Kubernetes:
- Il pattern architettonico Service Mesh utilizza contenitori sidecar per fornire telemetria dettagliata e controllo del traffico a livello di servizi. Ad esempio, puoi considerare .
- Alcuni fornitori di CNI hanno arricchito i loro strumenti affinché superassero i limiti delle politiche di rete di Kubernetes.
- fornisce trasparenza e automazione delle politiche di rete di Kubernetes.
Il pacchetto Tufin Orca gestisce le politiche di rete di Kubernetes (e funge da fonte per gli screenshot sopra riportati).
Informazioni aggiuntive
- ;
- ;
- ;
- .
Conclusione
Le politiche di rete di Kubernetes offrono un buon insieme di strumenti per la segmentazione dei cluster; tuttavia, risultano poco intuitive e presentano molte complessità. Credo che, a causa di questa difficoltà, le politiche di molti cluster esistenti contengano errori. Possibili soluzioni a questo problema includono l'automazione delle definizioni delle politiche o l'uso di altri strumenti di segmentazione.
Spero che questa guida possa chiarire alcune questioni e risolvere problemi con cui potresti avere a che fare.
P.S. dal traduttore
Leggi anche nel nostro blog:
- «Tornare ai microservizi con Istio»: , , ;
- «Guida illustrata alla configurazione della rete in Kubernetes»: , ;
- «»;
- «»;
- «».
Fonte: habr.com
