Usare Firewall di Azure per proteggere i cluster del servizio Azure Kubernetes
Questo articolo illustra come proteggere i cluster del servizio Azure Kubernetes usando Firewall di Azure per proteggere il traffico in uscita e in ingresso.
Background
Il servizio Azure Kubernetes offre un cluster Kubernetes gestito in Azure. Per altre informazioni, vedere Servizio Azure Kubernetes.
Nonostante sia una soluzione completamente gestita, il servizio Azure Kubernetes non offre una soluzione predefinita per proteggere il traffico in ingresso e in uscita tra il cluster e le reti esterne. Firewall di Azure offre una soluzione a questo problema.
I cluster del servizio Azure Kubernetes vengono distribuiti in una rete virtuale. Questa rete può essere gestita (creata dal servizio Azure Kubernetes) o personalizzata (preconfigurata dall'utente). In entrambi i casi, il cluster ha dipendenze in uscita da servizi esterni alla rete virtuale (il servizio non ha dipendenze in ingresso). A scopi di gestione e operativi, i nodi in un cluster del servizio Azure Kubernetes devono poter accedere a porte e nomi di dominio completi (FQDN) specifici che descrivono tali dipendenze in uscita. Questa operazione è necessaria per varie funzioni, tra cui, ad esempio, i nodi che comunicano con il server API Kubernetes. Scaricano e installano i componenti principali del cluster Kubernetes e gli aggiornamenti della sicurezza dei nodi o eseguono il pull delle immagini del contenitore di base dal Registro Container Microsoft e così via. Le dipendenze in uscita sono quasi interamente definite con nomi di dominio completo, senza indirizzi statici sottostanti. L'assenza di indirizzi statici determina l'impossibilità di usare i gruppi di sicurezza di rete per bloccare il traffico in uscita da un ambiente del servizio Azure Kubernetes. Per questo motivo, i cluster del servizio Azure Kubernetes hanno accesso illimitato a Internet in uscita. Questo livello di accesso alla rete consente a nodi e servizi in esecuzione di accedere alle risorse esterne in base alle esigenze.
Tuttavia, in un ambiente di produzione, le comunicazioni con un cluster Kubernetes devono essere protette per evitare l'esfiltrazione dei dati insieme ad altre vulnerabilità. Tutto il traffico di rete in ingresso e in uscita deve essere monitorato e controllato in base a un set di regole di sicurezza. Se si vuole eseguire questa operazione, è necessario limitare il traffico in uscita, ma un numero limitato di porte e indirizzi deve rimanere accessibile per mantenere le attività di manutenzione del cluster integre e soddisfare le dipendenze in uscita indicate in precedenza.
La soluzione più semplice consiste nell'usare un dispositivo firewall in grado di controllare il traffico in uscita in base ai nomi di dominio. In genere un firewall stabilisce una barriera tra una rete attendibile e una rete non attendibile, ad esempio Internet. Firewall di Azure, ad esempio, può limitare il traffico HTTP e HTTPS in uscita in base al nome di dominio completo della destinazione, offrendo un controllo del traffico in uscita con granularità fine, ma allo stesso tempo consente di fornire l'accesso ai nomi di dominio completi che includono le dipendenze in uscita di un cluster del servizio Azure Kubernetes (una cosa che i gruppi di sicurezza di rete non possono fare). Analogamente, è possibile controllare il traffico in ingresso e aumentare la sicurezza abilitando il filtro basato sull'intelligence sulle minacce in un Firewall di Azure distribuito a una rete perimetrale condivisa. Questi filtri possono fornire avvisi e rifiutare il traffico da e verso indirizzi IP e domini dannosi noti.
Vedere il video seguente per una rapida panoramica di come funziona in pratica in un ambiente di esempio:
È possibile scaricare dall'Area download Microsoft un file ZIP che contiene un file script bash e un file YAML per configurare automaticamente l'ambiente di esempio usato nel video. Configura Firewall di Azure per proteggere il traffico in ingresso e in uscita. Le guide seguenti illustrano in modo più dettagliato ogni passaggio dello script permettendo di impostare una configurazione personalizzata.
Il diagramma seguente illustra l'ambiente di esempio del video configurato dallo script e dalla guida:
Esiste una differenza tra lo script e la guida seguente. Lo script usa identità gestite, la guida invece usa un'entità servizio. Vengono illustrati due modi diversi per creare un'identità per gestire e creare risorse del cluster.
Limitare il traffico in uscita usando Firewall di Azure
Impostare la configurazione tramite variabili di ambiente
Definire un set di variabili di ambiente da usare durante la creazione di risorse.
PREFIX="aks-egress"
RG="${PREFIX}-rg"
LOC="eastus"
PLUGIN=azure
AKSNAME="${PREFIX}"
VNET_NAME="${PREFIX}-vnet"
AKSSUBNET_NAME="aks-subnet"
# DO NOT CHANGE FWSUBNET_NAME - This is currently a requirement for Azure Firewall.
FWSUBNET_NAME="AzureFirewallSubnet"
FWNAME="${PREFIX}-fw"
FWPUBLICIP_NAME="${PREFIX}-fwpublicip"
FWIPCONFIG_NAME="${PREFIX}-fwconfig"
FWROUTE_TABLE_NAME="${PREFIX}-fwrt"
FWROUTE_NAME="${PREFIX}-fwrn"
FWROUTE_NAME_INTERNET="${PREFIX}-fwinternet"
Creare una rete virtuale con più subnet
Creare una rete virtuale con due subnet separate: una per il cluster e una per il firewall. Facoltativamente, è possibile crearne una per l'ingresso del servizio interno.
Creare un gruppo di risorse che conterrà tutte le risorse.
# Create Resource Group
az group create --name $RG --location $LOC
Creare una rete virtuale con due subnet per ospitare il cluster del servizio Azure Kubernetes e Firewall di Azure. Ognuno ha la propria subnet. Si inizierà con la rete del servizio Azure Kubernetes.
# Dedicated virtual network with AKS subnet
az network vnet create \
--resource-group $RG \
--name $VNET_NAME \
--location $LOC \
--address-prefixes 10.42.0.0/16 \
--subnet-name $AKSSUBNET_NAME \
--subnet-prefix 10.42.1.0/24
# Dedicated subnet for Azure Firewall (Firewall name cannot be changed)
az network vnet subnet create \
--resource-group $RG \
--vnet-name $VNET_NAME \
--name $FWSUBNET_NAME \
--address-prefix 10.42.2.0/24
Creare e configurare un'istanza di Firewall di Azure con una route definita dall'utente
È necessario configurare le regole in ingresso e in uscita di Firewall di Azure. Il firewall viene usato principalmente per consentire alle organizzazioni di configurare regole granulari di traffico in ingresso e in uscita all'interno e all'esterno del cluster del servizio Azure Kubernetes.
Importante
Se il cluster o l'applicazione crea un numero elevato di connessioni in uscita dirette allo stesso subset di destinazioni o a un piccolo subset di destinazioni, potrebbe essere necessario un numero maggiore di indirizzi IP front-end del firewall per evitare il numero massimo di porte per IP front-end. Per altre informazioni su come creare un'istanza di Firewall di Azure con più indirizzi IP, vedere qui
Creare una risorsa indirizzo IP pubblico con SKU standard che verrà usata come indirizzo front-end di Firewall di Azure.
az network public-ip create -g $RG -n $FWPUBLICIP_NAME -l $LOC --sku "Standard"
Registrare l'estensione dell'interfaccia della riga di comando di anteprima per creare un'istanza di Firewall di Azure.
# Install Azure Firewall preview CLI extension
az extension add --name azure-firewall
# Deploy Azure Firewall
az network firewall create -g $RG -n $FWNAME -l $LOC --enable-dns-proxy true
È ora possibile assegnare l'indirizzo IP creato in precedenza al front-end del firewall.
Nota
La configurazione dell'indirizzo IP pubblico per Firewall di Azure può richiedere alcuni minuti. Per sfruttare il nome di dominio completo nelle regole di rete, è necessario abilitare il proxy DNS; se abilitato, il firewall sarà in ascolto sulla porta 53 e inoltrerà le richieste DNS al server DNS specificato in precedenza. In questo modo il firewall può convertire automaticamente il nome di dominio completo.
# Configure Firewall IP Config
az network firewall ip-config create -g $RG -f $FWNAME -n $FWIPCONFIG_NAME --public-ip-address $FWPUBLICIP_NAME --vnet-name $VNET_NAME
Dopo aver eseguito il comando precedente, salvare l'indirizzo IP del front-end del firewall per eseguire la configurazione in un secondo momento.
# Capture Firewall IP Address for Later Use
FWPUBLIC_IP=$(az network public-ip show -g $RG -n $FWPUBLICIP_NAME --query "ipAddress" -o tsv)
FWPRIVATE_IP=$(az network firewall show -g $RG -n $FWNAME --query "ipConfigurations[0].privateIPAddress" -o tsv)
# set fw as vnet dns server so dns queries are visible in fw logs
az network vnet update -g $RG --name $VNET_NAME --dns-servers $FWPRIVATE_IP
Nota
Se si usa l'accesso sicuro al server API del servizio Azure Kubernetes con intervalli di indirizzi IP autorizzati, è necessario aggiungere l'indirizzo IP pubblico del firewall all'intervallo IP autorizzato.
Creare una route definita dall'utente con un hop a Firewall di Azure
Azure effettua il routing automatico del traffico tra subnet di Azure, reti virtuali e reti locali. Per modificare il routing predefinito di Azure è necessario creare una tabella di route.
Creare una tabella di route vuota da associare a una determinata subnet. Firewall di Azure creato in precedenza verrà impostato come hop successivo nella tabella di route. A ogni subnet può essere associata una o nessuna tabella di route.
# Create UDR and add a route for Azure Firewall
az network route-table create -g $RG -l $LOC --name $FWROUTE_TABLE_NAME
az network route-table route create -g $RG --name $FWROUTE_NAME --route-table-name $FWROUTE_TABLE_NAME --address-prefix 0.0.0.0/0 --next-hop-type VirtualAppliance --next-hop-ip-address $FWPRIVATE_IP
az network route-table route create -g $RG --name $FWROUTE_NAME_INTERNET --route-table-name $FWROUTE_TABLE_NAME --address-prefix $FWPUBLIC_IP/32 --next-hop-type Internet
Vedere la documentazione relativa alle tabelle di route della rete virtuale per informazioni su come eseguire l'override delle route di sistema predefinite di Azure o su come aggiungere altre route alla tabella di route di una subnet.
Aggiunta di regole del firewall
Nota
Per le applicazioni esterne agli spazi dei nomi kube-system o gatekeeper-system che devono comunicare con il server API, è necessaria una regola di rete aggiuntiva per consentire la comunicazione TCP alla porta 443 per l'IP del server API oltre all'aggiunta della regola dell'applicazione per fqdn-tag AzureKubernetesService.
Per configurare il firewall, è possibile usare le tre regole di rete seguenti. Potrebbe essere necessario adattare queste regole in base alla distribuzione. La prima regola di rete consente l'accesso alla porta 9000 tramite TCP. La seconda regola di rete consente l'accesso alle porte 1194 e 123 tramite UDP. Entrambe queste regole consentono solo il traffico destinato al CIDR dell'area di Azure in uso qui, in questo caso Stati Uniti orientali.
Infine, si aggiunge una terza regola di rete che apre la porta 123 a un nome di dominio completo del server di riferimento ora di Internet (ad esempio:ntp.ubuntu.com
) tramite UDP. L'aggiunta di un nome di dominio completo come regola di rete è una delle funzionalità specifiche di Firewall di Azure, quindi è necessario adattarla quando si usano le proprie opzioni.
Dopo aver impostato le regole di rete, verrà aggiunta anche una regola dell'applicazione usando AzureKubernetesService
, che copre i nomi di dominio completi necessari accessibili tramite la porta TCP 443 e la porta 80. Potrebbe anche essere necessario configurare più regole di rete e applicazione in base alla distribuzione. Per ulteriori informazioni, vedi Regole di rete e FQDN (nome di dominio completo) in uscita per i cluster del servizio Azure Kubernetes.
Aggiungere regole di rete FW
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'apiudp' --protocols 'UDP' --source-addresses '*' --destination-addresses "AzureCloud.$LOC" --destination-ports 1194 --action allow --priority 100
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'apitcp' --protocols 'TCP' --source-addresses '*' --destination-addresses "AzureCloud.$LOC" --destination-ports 9000
az network firewall network-rule create -g $RG -f $FWNAME --collection-name 'aksfwnr' -n 'time' --protocols 'UDP' --source-addresses '*' --destination-fqdns 'ntp.ubuntu.com' --destination-ports 123
Aggiungere regole di applicazione FW
az network firewall application-rule create -g $RG -f $FWNAME --collection-name 'aksfwar' -n 'fqdn' --source-addresses '*' --protocols 'http=80' 'https=443' --fqdn-tags "AzureKubernetesService" --action allow --priority 100
# set fw application rule to allow kubernettes to reach storage and image resources
az network firewall application-rule create -g $RG -f $FWNAME --collection-name 'aksfwarweb' -n 'storage' --source-addresses '10.42.1.0/24' --protocols 'https=443' --target-fqdns '*.blob.storage.azure.net' '*.blob.core.windows.net' --action allow --priority 101
az network firewall application-rule create -g $RG -f $FWNAME --collection-name 'aksfwarweb' -n 'website' --source-addresses '10.42.1.0/24' --protocols 'https=443' --target-fqdns 'ghcr.io' '*.docker.io' '*.docker.com' '*.githubusercontent.com'
Per altre informazioni sul servizio Firewall di Azure, vedere la documentazione di Firewall di Azure.
Associare la tabella di route al servizio Azure Kubernetes
Per associare il cluster al firewall, la subnet dedicata per la subnet del cluster deve fare riferimento alla tabella di route creata in precedenza. È possibile eseguire l'associazione inviando un comando alla rete virtuale che contiene sia il cluster che il firewall per aggiornare la tabella di route della subnet del cluster.
# Associate route table with next hop to Firewall to the AKS subnet
az network vnet subnet update -g $RG --vnet-name $VNET_NAME --name $AKSSUBNET_NAME --route-table $FWROUTE_TABLE_NAME
Distribuire il servizio Azure Kubernetes con il tipo in uscita con route definita dall'utente nella rete esistente
È ora possibile distribuire un cluster del servizio Azure Kubernetes nella rete virtuale esistente. È anche possibile usare tipo in uscita userDefinedRouting
, una funzionalità che garantisce che qualsiasi traffico in uscita venga forzato attraverso il firewall e che non esistano altri percorsi in uscita (per impostazione predefinita è possibile usare il tipo in uscita Load Balancer).
Per definire la subnet di destinazione in cui eseguire la distribuzione, si usa la variabile di ambiente $SUBNETID
. La variabile $SUBNETID
non è stata definita nei passaggi precedenti. Per impostare il valore per l'ID subnet, è possibile usare il comando seguente:
SUBNETID=$(az network vnet subnet show -g $RG --vnet-name $VNET_NAME --name $AKSSUBNET_NAME --query id -o tsv)
Si definisce il tipo in uscita in modo da usare la route definita dall'utente già esistente nella subnet. Questa configurazione consente al servizio Azure Kubernetes di ignorare l'installazione e il provisioning IP per il servizio di bilanciamento del carico.
Importante
Per altre informazioni sull'UDR del tipo in uscita, incluse le limitazioni, vedere UDR del tipo in uscita.
Suggerimento
È possibile aggiungere altre funzionalità alla distribuzione del cluster, ad esempio Cluster privato, o cambiare lo SKU del sistema operativo.
È possibile aggiungere la funzionalità del servizio Azure Kubernetes per intervalli IP autorizzati del server API per limitare l'accesso al server API solo all'endpoint pubblico del firewall. La funzionalità degli intervalli IP autorizzati è indicata nel diagramma come facoltativo. Quando si abilita la funzionalità degli intervalli IP autorizzati per limitare l'accesso al server API, gli strumenti di sviluppo devono usare un JumpBox dalla rete virtuale del firewall oppure è necessario aggiungere tutti gli endpoint sviluppatore all'intervallo di indirizzi IP autorizzati.
az aks create -g $RG -n $AKSNAME -l $LOC \
--node-count 3 \
--network-plugin azure \
--outbound-type userDefinedRouting \
--vnet-subnet-id $SUBNETID \
--api-server-authorized-ip-ranges $FWPUBLIC_IP
Nota
Per creare e usare la propria rete virtuale e la propria tabella di route con il plug-in di rete kubenet
, è necessario usare un'identità gestita assegnata dall'utente. Per un'identità gestita assegnata dal sistema, non è possibile ottenere l'ID identità prima di creare il cluster e questo causa un ritardo nell'entrata in vigore dell'assegnazione di ruolo.
Per creare e usare la propria tabella di route e rete virtuale con il plug-in di rete azure
, sono supportate sia le identità gestite assegnate dal sistema sia quelle assegnate dall'utente.
Consentire agli sviluppatori di accedere al server API
Se nel passaggio precedente sono stati usati intervalli IP autorizzati per il cluster, è necessario aggiungere gli indirizzi IP degli strumenti per sviluppatori all'elenco di cluster del servizio Azure Kubernetes degli intervalli IP approvati, in modo da accedere al server API da questa posizione. Un'altra opzione consiste nel configurare un JumpBox con gli strumenti necessari all'interno di una subnet separata nella rete virtuale di Firewall.
Aggiungere un altro indirizzo IP agli intervalli approvati con il comando seguente
# Retrieve your IP address
CURRENT_IP=$(dig @resolver1.opendns.com ANY myip.opendns.com +short)
# Add to AKS approved list
az aks update -g $RG -n $AKSNAME --api-server-authorized-ip-ranges $CURRENT_IP/32
Usare il comando az aks get-credentials per configurare kubectl
per la connessione al cluster Kubernetes appena creato.
az aks get-credentials -g $RG -n $AKSNAME
Limitare il traffico in ingresso usando Firewall di Azure
È ora possibile iniziare a esporre i servizi e distribuire applicazioni in questo cluster. In questo esempio verrà esposto un servizio pubblico, ma è anche possibile scegliere di esporre un servizio interno usando un servizio di bilanciamento del carico interno.
Esaminare il manifesto di avvio rapido della demo dello Store del servizio Azure Kubernetes per visualizzare tutte le risorse che verranno create.
Distribuire il servizio usando il comando
kubectl apply
.kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/aks-store-demo/main/aks-store-quickstart.yaml
Aggiungere una regola DNAT a Firewall di Azure
Importante
Quando si usa Firewall di Azure per limitare il traffico in uscita e creare una route definita dall'utente (UDR) per forzare tutto il traffico in uscita, assicurarsi di creare una regola DNAT appropriata nel firewall per consentire correttamente il traffico in ingresso. L'uso del servizio Firewall di Azure con una route definita dall'utente interrompe la configurazione in ingresso a causa del routing asimmetrico. Questo problema si verifica se la subnet del servizio Azure Kubernetes ha una route predefinita verso l'indirizzo IP privato del firewall, ma si sta usando un servizio di bilanciamento del carico pubblico in ingresso o del servizio Kubernetes di tipo LoadBalancer. In questo caso, il traffico del servizio di bilanciamento del carico in ingresso viene ricevuto tramite l'indirizzo IP pubblico, ma il percorso di ritorno passa attraverso l'indirizzo IP privato del firewall. Poiché il firewall è con stato, elimina il pacchetto di ritorno perché il firewall non è a conoscenza del fatto che è stata stabilita una sessione. Per informazioni su come integrare Firewall di Azure con il servizio di bilanciamento del carico in ingresso o del servizio, vedere Integrare Firewall di Azure con Azure Load Balancer Standard.
Per configurare la connettività in ingresso, è necessario scrivere una regola DNAT in Firewall di Azure. Per testare la connettività al cluster, viene definita una regola per l'indirizzo IP pubblico del front-end del firewall da indirizzare all'IP interno esposto dal servizio interno.
È possibile personalizzare l'indirizzo di destinazione perché corrisponde alla porta del firewall a cui accedere. L'indirizzo convertito deve essere l'indirizzo IP del bilanciamento del carico interno. La porta convertita deve essere la porta esposta per il servizio Kubernetes.
È necessario specificare l'indirizzo IP interno assegnato al servizio di bilanciamento del carico creato dal servizio Kubernetes. Per recuperare l'indirizzo, eseguire:
kubectl get services
L'indirizzo IP necessario è indicato nella colonna EXTERNAL-IP e sarà simile a quanto illustrato di seguito.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.41.0.1 <none> 443/TCP 10h
store-front LoadBalancer 10.41.185.82 203.0.113.254 80:32718/TCP 9m
order-service ClusterIP 10.0.104.144 <none> 3000/TCP 11s
product-service ClusterIP 10.0.237.60 <none> 3002/TCP 10s
rabbitmq ClusterIP 10.0.161.128 <none> 5672/TCP,15672/TCP 11s
Ottenere l'indirizzo IP del servizio eseguendo:
SERVICE_IP=$(kubectl get svc store-front -o jsonpath='{.status.loadBalancer.ingress[*].ip}')
Aggiungere la regola NAT eseguendo:
az network firewall nat-rule create --collection-name exampleset --destination-addresses $FWPUBLIC_IP --destination-ports 80 --firewall-name $FWNAME --name inboundrule --protocols Any --resource-group $RG --source-addresses '*' --translated-port 80 --action Dnat --priority 100 --translated-address $SERVICE_IP
Convalidare la connettività
In un browser accedere all'indirizzo IP front-end di Firewall di Azure per convalidare la connettività.
Verrà visualizzata l'app dello Store del servizio Azure Kubernetes. In questo esempio l'indirizzo IP pubblico del firewall era 203.0.113.32
.
In questa pagina è possibile visualizzare i prodotti, aggiungerli al carrello e quindi effettuare un ordine.
Pulire le risorse
Per pulire le risorse di Azure, eliminare il gruppo di risorse del servizio Azure Kubernetes.
az group delete -g $RG
Passaggi successivi
- Per altre informazioni sul servizio Azure Kubernetes, vedere Concetti di base relativi a Kubernetes per il servizio Azure Kubernetes.