Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Il presente articolo illustra come utilizzare le regole di rete in uscita e il nome di dominio completo (FQDN) per i cluster AKS al fine di controllare il traffico in uscita usando il Firewall di Azure. Per semplificare questa configurazione, Firewall di Azure fornisce un tag FQDN del servizio Azure Kubernetes (AzureKubernetesService) che limita il traffico in uscita dal cluster del servizio Azure Kubernetes.
Prerequisiti
- Un account Azure con una sottoscrizione attiva. Se non ne hai uno, crea un account gratuito prima di iniziare.
- Installare e configurare Terraform.
- interfaccia della riga di comando di Azure installata e con accesso effettuato con
az login, usata per verificare la distribuzione. Installare interfaccia della riga di comando di Azure se non è già disponibile. -
kubectlinstallato per connettersi al cluster. Se si usa Azure Cloud Shell,kubectlè già installato. Per installarlo in locale, usare ilaz aks install-clicomando .
Requisiti IP front-end del firewall
- Punto di partenza per la produzione: prevedere almeno 20 indirizzi IP frontend in Firewall di Azure e dimensionare la configurazione in base al carico di lavoro per evitare l'esaurimento delle porte di SNAT.
- Cluster a traffico elevato: se il cluster crea molte connessioni in uscita verso le stesse destinazioni, potrebbero essere necessari più indirizzi IP frontend o l'integrazione di Firewall di Azure con NAT Gateway per aumentare la capacità SNAT.
- Protezione del server API: aggiungere l'IP front-end pubblico del firewall agli intervalli IP autorizzati del server API per una maggiore sicurezza
- Accesso per sviluppatori: quando si usano intervalli IP autorizzati, usare un jumpbox nella rete virtuale (VNet) del firewall o aggiungere indirizzi IP degli endpoint per sviluppatori all'intervallo autorizzato
Queste linee guida si applicano durante il processo di configurazione descritto in questo articolo.
Note
Il tag FQDN contiene tutti i nomi di dominio completi elencati nelle regole di rete in uscita e FQDN per i cluster AKS e viene aggiornato automaticamente.
Panoramica dell'architettura
Il diagramma seguente illustra l'architettura di un cluster AKS con traffico in uscita limitato attraverso Firewall di Azure:
Il diagramma mostra i nodi agente di AKS in una subnet dedicata che instradano il traffico in uscita attraverso Firewall di Azure mediante una UDR. Per il traffico in ingresso, una regola DNAT converte l'indirizzo IP pubblico del firewall nell'indirizzo IP front-end del servizio di bilanciamento del carico pubblico.
I componenti chiave di questa architettura includono:
-
L'ingresso pubblico viene forzato a passare attraverso i filtri firewall:
- I nodi dell'agente di AKS sono isolati in una subnet dedicata.
- Firewall di Azure viene distribuito nella propria subnet.
- Una regola DNAT converte l'INDIRIZZO IP pubblico del firewall nell'indirizzo IP front-end del servizio di bilanciamento del carico.
-
Le richieste in uscita iniziano dai nodi agente all'indirizzo IP privato Firewall di Azure usando una route definita dall'utente:Outbound requests start from agent nodes to the Firewall di Azure private IP using a user-defined route (UDR):
- Le richieste provenienti dai nodi agente del servizio Azure Kubernetes seguono una route definita dall'utente che è stata inserita nella subnet in cui è stato distribuito il cluster del servizio Azure Kubernetes.
- Firewall di Azure esce dalla rete virtuale da un front-end IP pubblico.
- L'accesso alla rete Internet pubblica o ad altri servizi di Azure passa da e verso l'indirizzo IP front-end del firewall.
- È possibile proteggere l'accesso al piano di controllo dell'Azure Kubernetes Service usando intervalli IP autorizzati del server API, incluso l'indirizzo IP front-end pubblico del firewall.
-
Traffico interno:
- È possibile usare un servizio di bilanciamento del carico interno per il traffico interno, che è possibile isolare nella propria subnet, invece di o insieme a un servizio di bilanciamento del carico pubblico.
Configurare le variabili di ambiente
Nella tabella seguente sono elencate le variabili di ambiente usate in questo articolo. Impostare queste variabili nella shell prima di procedere o modificare i comandi per usare i propri valori.
| Variable | Description | Valore di esempio |
|---|---|---|
RESOURCE_GROUP |
Nome del gruppo di risorse | aks-egress-rg |
LOCATION |
Area di Azure per le risorse | eastus |
CLUSTER_NAME |
Nome del cluster AKS | aks-egress |
VNET_NAME |
Nome della rete virtuale | aks-egress-vnet |
AKS_SUBNET_NAME |
Nome della subnet per AKS | aks-subnet |
FW_SUBNET_NAME |
Nome della subnet per Firewall di Azure | AzureFirewallSubnet |
FW_NAME |
Nome del firewall di Azure | aks-egress-fw |
FW_PUBLICIP_NAME |
Nome dell'indirizzo IP pubblico per Firewall di Azure | aks-egress-fwpublicip |
FW_IPCONFIG_NAME |
Nome della configurazione IP per Firewall di Azure | aks-egress-fwconfig |
FW_ROUTE_TABLE_NAME |
Nome della tabella di route per Firewall di Azure | aks-egress-fwrt |
FW_ROUTE_NAME_1 |
Nome della route per Firewall di Azure | aks-egress-fwrn |
FW_ROUTE_NAME_2 |
Nome della route Internet per Firewall di Azure | aks-egress-fwrn-internet |
Creare un gruppo di risorse
Creare un gruppo di risorse usando il comando
az group create.az group create --name $RESOURCE_GROUP --location $LOCATION
Creare una rete virtuale con più subnet
Effettuare il provisioning di 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. Il diagramma seguente illustra la topologia di rete vuota prima di distribuire qualsiasi risorsa:
Il diagramma mostra la VNet con subnet separate per AKS e Firewall di Azure prima della distribuzione delle risorse.
Creare una rete virtuale usando il
az network vnet createcomando .az network vnet create \ --resource-group $RESOURCE_GROUP \ --name $VNET_NAME \ --location $LOCATION \ --address-prefixes 10.42.0.0/16 \ --subnet-name $AKS_SUBNET_NAME \ --subnet-prefix 10.42.1.0/24Creare una subnet per Firewall di Azure usando il
az network vnet subnet createcomando .# Dedicated subnet for Azure Firewall (subnet must be named "AzureFirewallSubnet") az network vnet subnet create \ --resource-group $RESOURCE_GROUP \ --vnet-name $VNET_NAME \ --name $FW_SUBNET_NAME \ --address-prefix 10.42.2.0/24
Creare un indirizzo IP pubblico per Firewall di Azure
Creare una risorsa IP pubblico SKU standard usando il comando
az network public-ip create. Usare questa risorsa come indirizzo IP front-end per il Firewall di Azure. La configurazione a ip singolo in questo articolo è destinata ai test. Per la produzione, usare i requisiti IP front-end del firewall per pianificare la capacità SNAT per il carico di lavoro.az network public-ip create --resource-group $RESOURCE_GROUP --name $FW_PUBLICIP_NAME --location $LOCATION --sku "Standard"
Installare l'estensione CLI di Firewall di Azure
Registrare l'estensione dell'interfaccia della riga di comando di Firewall di Azure per creare un Firewall di Azure usando il comando
az extension add.az extension add --name azure-firewall
Creare un firewall di Azure e abilitare il proxy DNS
Note
Per gli scenari con traffico elevato, vedere la sezione requisiti IP front-end del firewall .
Per altre informazioni su come creare un firewall di Azure con più indirizzi IP, vedere Creare un firewall di Azure con più indirizzi IP pubblici usando Bicep.
Il diagramma mostra Firewall di Azure distribuito nella propria subnet, con una route definita dall'utente (UDR) che indirizza il traffico dalla subnet di AKS all'indirizzo IP privato del firewall.
Creare un firewall di Azure e abilitare il proxy DNS usando il
az network firewall createcomando con--enable-dns-proxyimpostato sutrue.az network firewall create --resource-group $RESOURCE_GROUP --name $FW_NAME --location $LOCATION --enable-dns-proxy trueLa configurazione dell'indirizzo IP pubblico in Firewall di Azure potrebbe richiedere alcuni minuti. Una volta pronto, è possibile assegnare l'indirizzo IP al front-end del firewall.
Note
Per usare FQDN nelle regole di rete, è necessario abilitare il proxy DNS. Quando il proxy DNS è abilitato, il firewall è in ascolto sulla porta 53 e inoltra le richieste DNS al server DNS specificato. Questa impostazione consente al firewall di tradurre automaticamente il FQDN (nome di dominio completamente qualificato).
Creare una configurazione IP per Firewall di Azure
Creare una configurazione IP di Firewall di Azure usando il comando
az network firewall ip-config create.az network firewall ip-config create --resource-group $RESOURCE_GROUP --firewall-name $FW_NAME --name $FW_IPCONFIG_NAME --public-ip-address $FW_PUBLICIP_NAME --vnet-name $VNET_NAME
Ottenere gli indirizzi IP di Firewall di Azure
Salvare gli indirizzi IP front-end del firewall pubblico e privato per la configurazione in un secondo momento usando i comandi seguenti:
export FW_PUBLIC_IP=$(az network public-ip show --resource-group $RESOURCE_GROUP --name $FW_PUBLICIP_NAME --query "ipAddress" -o tsv) export FW_PRIVATE_IP=$(az network firewall show --resource-group $RESOURCE_GROUP --name $FW_NAME --query "ipConfigurations[0].privateIPAddress" -o tsv)Note
Per la sicurezza del server API, vedere la sezione requisiti IP front-end del firewall .
Configurare la rete virtuale per l'uso di Firewall di Azure come server DNS
Configurare la rete virtuale per usare l'indirizzo IP privato Firewall di Azure come server DNS usando il
az network vnet updatecomando . Questa configurazione garantisce che i nodi AKS e Firewall di Azure risolvano in modo coerente gli FQDN di destinazione nelle regole di rete.az network vnet update \ --resource-group $RESOURCE_GROUP \ --name $VNET_NAME \ --dns-servers $FW_PRIVATE_IP
Requisiti UDR per il traffico in uscita di AKS tramite Firewall di Azure
Azure instrada automaticamente il traffico tra subnet di Azure, reti virtuali e reti locali. Per modificare il routing predefinito, creare una tabella di route con i requisiti seguenti:
| Categoria | Requisito | Valore o descrizione |
|---|---|---|
| Parametro di route | Destination |
0.0.0.0/0 (tutto il traffico) |
| Parametro di route | Tipo di passaggio successivo | Appliance virtuale di rete |
| Parametro di route | Indirizzo IP dell'hop successivo | Indirizzo IP privato di Firewall di Azure |
| Parametro di route | Associazione | Una tabella di route per subnet (zero o uno consentito) |
| Vincolo UDR | Route Internet predefinita |
0.0.0.0/0 esiste già, ma richiede un indirizzo IP pubblico per SNAT. |
| Vincolo UDR | Hop successivo | La route deve puntare a un gateway o a un'appliance virtuale di rete, non direttamente a Internet. |
| Vincolo UDR | Convalida di AKS | AKS convalida la configurazione di routing e impedisce route dirette verso Internet. |
| Vincolo UDR | Limite della tabella di instradamento | Ogni subnet supporta un massimo di una tabella di route associata. |
| Impatto sul tipo in uscita | UDR (userDefinedRouting) |
Non viene creato alcun indirizzo IP pubblico del servizio di bilanciamento del carico per le richieste in uscita. |
| Impatto del tipo di uscita | Indirizzo IP pubblico del servizio di bilanciamento del carico | Creato solo per le richieste in ingresso che usano un LoadBalancer servizio. |
| Impatto del tipo di uscita | Configurazione SNAT | Richiede un indirizzo IP pubblico configurato correttamente per la connettività in uscita. |
Per altre informazioni, vedere Regole in uscite per Azure Load Balancer.
Creare una route con un hop a Firewall di Azure
Creare una tabella di route vuota usando il
az network route-table createcomando . La tabella di route definisce il Firewall di Azure come hop successivo. A ogni subnet può essere associata zero o una tabella di route.az network route-table create --resource-group $RESOURCE_GROUP --location $LOCATION --name $FW_ROUTE_TABLE_NAMECreare route nella tabella di route per le subnet usando il comando
az network route-table route create.az network route-table route create --resource-group $RESOURCE_GROUP --name $FW_ROUTE_NAME_1 --route-table-name $FW_ROUTE_TABLE_NAME --address-prefix 0.0.0.0/0 --next-hop-type VirtualAppliance --next-hop-ip-address $FW_PRIVATE_IP az network route-table route create --resource-group $RESOURCE_GROUP --name $FW_ROUTE_NAME_2 --route-table-name $FW_ROUTE_TABLE_NAME --address-prefix $FW_PUBLIC_IP/32 --next-hop-type Internet
Per informazioni su come eseguire l'override delle route di sistema predefinite di Azure o aggiungere altre route alla tabella di route di una subnet, vedere la documentazione della tabella di route di rete virtuale.
Regole in uscita necessarie per il traffico in uscita di AKS attraverso Firewall di Azure
Note
Per le applicazioni al di fuori degli 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 a dover aggiungere una regola applicativa per fqdn-tag di AzureKubernetesService.
Le regole di rete seguenti consentono il traffico in uscita usato in questo articolo:
- La prima e la seconda regola di rete consentono di recuperare i container da GitHub Container Registry (
ghcr.io) e Docker Hub (docker.io).
I cluster del servizio Azure Kubernetes che usano l'agente konnectivity, incluso il cluster creato in questo articolo, non richiedono l'accesso in uscita sulla porta TCP 9000 o sulla porta UDP 1194. Anche i nodi di cui è stato effettuato il provisioning dopo marzo 2021 non richiedono l'accesso NTP in uscita sulla porta UDP 123. Per le regole richieste da altre configurazioni di cluster e altri ambienti cloud di Azure, vedi regole di rete in uscita e FQDN per i cluster AKS.
Creare regole di rete in Firewall di Azure
Creare le regole di rete usando i comandi seguenti
az network firewall network-rule create.az network firewall network-rule create --resource-group $RESOURCE_GROUP --firewall-name $FW_NAME --collection-name 'aksfwnr' --name 'ghcr' --protocols 'TCP' --source-addresses '*' --destination-fqdns ghcr.io pkg-containers.githubusercontent.com --destination-ports '443' --action allow --priority 100 az network firewall network-rule create --resource-group $RESOURCE_GROUP --firewall-name $FW_NAME --collection-name 'aksfwnr' --name 'docker' --protocols 'TCP' --source-addresses '*' --destination-fqdns docker.io registry-1.docker.io production.cloudflare.docker.com --destination-ports '443'
Creare regole dell'applicazione in Firewall di Azure
Creare la regola dell'applicazione usando il comando
az network firewall application-rule create.az network firewall application-rule create --resource-group $RESOURCE_GROUP --firewall-name $FW_NAME --collection-name 'aksfwar' --name 'fqdn' --source-addresses '*' --protocols 'http=80' 'https=443' --fqdn-tags "AzureKubernetesService" --action allow --priority 100
Per altre informazioni su 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 del cluster deve fare riferimento alla tabella di routing.
Associare la tabella di routing al servizio AKS usando il comando
az network vnet subnet update.az network vnet subnet update --resource-group $RESOURCE_GROUP --vnet-name $VNET_NAME --name $AKS_SUBNET_NAME --route-table $FW_ROUTE_TABLE_NAME
Distribuire un cluster del servizio Azure Kubernetes che segue le regole in uscita
È ora possibile distribuire un cluster AKS nel VNet esistente. Si usa il userDefinedRouting tipo in uscita, che garantisce che qualsiasi traffico in uscita venga forzato attraverso il firewall e che non esistano altri percorsi in uscita. È anche possibile utilizzare il loadBalancer tipo outbound.
Il diagramma mostra il cluster AKS distribuito nella VNet esistente, con il traffico in uscita instradato tramite Firewall di Azure usando UDR.
Impostare una variabile di ambiente per l'ID subnet della subnet di destinazione usando il comando seguente:
SUBNET_ID=$(az network vnet subnet show --resource-group $RESOURCE_GROUP --vnet-name $VNET_NAME --name $AKS_SUBNET_NAME --query id -o tsv)
Definisci il tipo di uscita per utilizzare la UDR già esistente nella sottorete. Questa configurazione consente ad AKS di saltare l'installazione e il provisioning IP per il bilanciamento del carico.
Suggerimento
È possibile aggiungere funzionalità aggiuntive alla distribuzione del cluster, ad esempio cluster privati.
Per le considerazioni sulla configurazione degli intervalli IP autorizzati del server API e sull'accesso agli sviluppatori, vedere la sezione Requisiti IP front-end del firewall .
Creare un cluster AKS con un'identità del piano di controllo assegnata dal sistema
Note
Questo cluster utilizza un'identità del piano di controllo assegnata dal sistema. AKS crea un'identità kubelet assegnata dall'utente nel gruppo di risorse del nodo se non si specifica una propria identità gestita kubelet.
Per il routing definito dall'utente, l'identità assegnata dal sistema supporta solo il plug-in di rete CNI.
Creare un cluster del servizio Azure Kubernetes usando un'identità gestita assegnata dal sistema con il plug-in di rete CNI usando il comando
az aks create.az aks create --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --location $LOCATION \ --node-count 3 \ --network-plugin azure \ --outbound-type userDefinedRouting \ --vnet-subnet-id $SUBNET_ID \ --api-server-authorized-ip-ranges $FW_PUBLIC_IP \ --generate-ssh-keys
Creare identità gestite assegnate dall'utente
Se non si dispone di identità assegnate dall'utente, seguire la procedura descritta in questa sezione. Se si dispone già di identità assegnate dall'utente, passare a Creare un cluster del servizio Azure Kubernetes con identità assegnate dall'utente.
Creare un'identità gestita usando il comando
az identity create.az identity create --name myIdentity --resource-group $RESOURCE_GROUPL'output dovrebbe essere simile all'output di esempio seguente:
{ ... "id": "/subscriptions/<subscriptionid>/resourcegroups/aks-egress-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myIdentity", "location": "eastus", "name": "myIdentity", ... "type": "Microsoft.ManagedIdentity/userAssignedIdentities" }Creare un'identità gestita kubelet usando il comando
az identity create.az identity create --name myKubeletIdentity --resource-group $RESOURCE_GROUPL'output dovrebbe essere simile all'output di esempio seguente:
{ ... "id": "/subscriptions/<subscriptionid>/resourcegroups/aks-egress-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myKubeletIdentity", "location": "eastus", "name": "myKubeletIdentity", ... "resourceGroup": "aks-egress-rg", ... "type": "Microsoft.ManagedIdentity/userAssignedIdentities" }
Note
Se si crea una propria rete virtuale e una tabella di route in cui le risorse si trovano all'esterno del gruppo di risorse del nodo di lavoro, l'interfaccia della riga di comando aggiunge automaticamente l'assegnazione di ruolo. Se si usa un modello di Resource Manager o un altro metodo, è necessario usare l'ID dell’entità di sicurezza dell'identità gestita del cluster per eseguire un'assegnazione di ruolo.
Creare un cluster AKS con identità assegnate dall'utente
Creare un cluster del servizio Azure Kubernetes con le identità gestite assegnate dall'utente esistenti nella subnet tramite il comando
az aks create. Specificare l'ID della risorsa dell'identità gestita per il piano di controllo e l'ID della risorsa dell'identità kubelet.az aks create \ --resource-group $RESOURCE_GROUP \ --name $CLUSTER_NAME \ --location $LOCATION \ --node-count 3 \ --network-plugin azure \ --network-plugin-mode overlay \ --outbound-type userDefinedRouting \ --vnet-subnet-id $SUBNET_ID \ --api-server-authorized-ip-ranges $FW_PUBLIC_IP \ --assign-identity <identity-resource-id> \ --assign-kubelet-identity <kubelet-identity-resource-id> \ --generate-ssh-keys
Esaminare il codice Terraform
Note
Il codice di esempio per questo articolo si trova nel repository GitHub Azure Terraform. È possibile visualizzare il log dei risultati del test per le versioni correnti e precedenti di Terraform.
Vedere altri articoli e codice di esempio che illustrano come usare Terraform per gestire le risorse di Azure.
L'esempio Terraform distribuisce le risorse seguenti:
- Una rete virtuale Azure con due subnet: una per i nodi del cluster del servizio Azure Kubernetes e una dedicata
AzureFirewallSubnetper Firewall di Azure. - Un indirizzo IP pubblico dello SKU standard e un Firewall di Azure (SKU
AZFW_VNet, livelloStandard) che usa un criterio firewall di Azure con proxy DNS abilitato. - Un gruppo di raccolte di regole dei criteri del firewall che contiene le regole di rete e applicative necessarie per il traffico in uscita di AKS: regole di rete per le porte del server API (TCP/9000, UDP/1194), NTP (
ntp.ubuntu.comsu UDP/123), GitHub Container Registry e Docker Hub, oltre a una regola applicativa che usa il tag FQDNAzureKubernetesServicesulle porte 80 e 443. - Tabella di route con una route predefinita (
0.0.0.0/0) che punta all'indirizzo IP privato del firewall come hop successivo dell'appliance virtuale e una route che invia l'indirizzo IP pubblico del firewall direttamente a Internet per evitare il routing asimmetrico. La tabella di instradamento è associata solo alla subnet AKS. - Un cluster AKS che usa un'identità gestita assegnata dal sistema, il plug-in di rete
azure, il tipo di uscitauserDefinedRoutingeapi_server_access_profile.authorized_ip_rangeslimitato all'indirizzo IP pubblico del firewall. - Un'assegnazione di ruolo che concede all'identità gestita del cluster AKS il ruolo
Network Contributorsul gruppo di risorse, in modo che il cluster possa gestire le risorse di rete da cui dipende.
L'esempio non crea un carico di lavoro demo, una regola DNAT o un servizio di bilanciamento del carico. Dopo aver verificato il cluster, usare kubectl per distribuire la propria applicazione e quindi seguire le indicazioni riportate in precedenza in questo articolo per aggiungere una regola DNAT in Firewall di Azure se è necessaria la connettività in ingresso.
Creare una directory per testare il codice Terraform di esempio e impostarla come directory corrente.
Creare un file denominato
main.tfe inserire il codice seguente:terraform { required_version = ">= 1.5.0" required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 4.0" } } } provider "azurerm" { features {} } variable "prefix" { type = string default = "aks-egress" } variable "location" { type = string default = "eastus" } variable "node_count" { type = number default = 3 } variable "vnet_cidr" { type = string default = "10.42.0.0/16" } variable "aks_subnet_cidr" { type = string default = "10.42.1.0/24" } variable "firewall_subnet_cidr" { type = string default = "10.42.2.0/24" } locals { resource_group_name = "${var.prefix}-rg" vnet_name = "${var.prefix}-vnet" aks_subnet_name = "aks-subnet" firewall_subnet_name = "AzureFirewallSubnet" firewall_name = "${var.prefix}-fw" firewall_public_ip = "${var.prefix}-fwpublicip" firewall_policy_name = "${var.prefix}-fwpolicy" firewall_ipconfig_name = "${var.prefix}-fwconfig" route_table_name = "${var.prefix}-fwrt" default_route_name = "${var.prefix}-fwrn" firewall_public_route = "${var.prefix}-fwrn-internet" aks_name = var.prefix } resource "azurerm_resource_group" "this" { name = local.resource_group_name location = var.location } resource "azurerm_virtual_network" "this" { name = local.vnet_name location = azurerm_resource_group.this.location resource_group_name = azurerm_resource_group.this.name address_space = [var.vnet_cidr] } resource "azurerm_subnet" "aks" { name = local.aks_subnet_name resource_group_name = azurerm_resource_group.this.name virtual_network_name = azurerm_virtual_network.this.name address_prefixes = [var.aks_subnet_cidr] } resource "azurerm_subnet" "firewall" { name = local.firewall_subnet_name resource_group_name = azurerm_resource_group.this.name virtual_network_name = azurerm_virtual_network.this.name address_prefixes = [var.firewall_subnet_cidr] } resource "azurerm_public_ip" "firewall" { name = local.firewall_public_ip location = azurerm_resource_group.this.location resource_group_name = azurerm_resource_group.this.name allocation_method = "Static" sku = "Standard" } resource "azurerm_firewall_policy" "this" { name = local.firewall_policy_name location = azurerm_resource_group.this.location resource_group_name = azurerm_resource_group.this.name dns { proxy_enabled = true } } resource "azurerm_firewall" "this" { name = local.firewall_name location = azurerm_resource_group.this.location resource_group_name = azurerm_resource_group.this.name sku_name = "AZFW_VNet" sku_tier = "Standard" firewall_policy_id = azurerm_firewall_policy.this.id ip_configuration { name = local.firewall_ipconfig_name subnet_id = azurerm_subnet.firewall.id public_ip_address_id = azurerm_public_ip.firewall.id } } resource "azurerm_firewall_policy_rule_collection_group" "aks_rules" { name = "aks-egress-rules" firewall_policy_id = azurerm_firewall_policy.this.id priority = 100 network_rule_collection { name = "aks-network-rules" priority = 100 action = "Allow" rule { name = "apitcp" protocols = ["TCP"] source_addresses = ["*"] destination_addresses = ["AzureCloud.${var.location}"] destination_ports = ["9000"] } rule { name = "apiudp" protocols = ["UDP"] source_addresses = ["*"] destination_addresses = ["AzureCloud.${var.location}"] destination_ports = ["1194"] } rule { name = "time" protocols = ["UDP"] source_addresses = ["*"] destination_fqdns = ["ntp.ubuntu.com"] destination_ports = ["123"] } rule { name = "ghcr" protocols = ["TCP"] source_addresses = ["*"] destination_fqdns = [ "ghcr.io", "pkg-containers.githubusercontent.com" ] destination_ports = ["443"] } rule { name = "docker" protocols = ["TCP"] source_addresses = ["*"] destination_fqdns = [ "docker.io", "registry-1.docker.io", "production.cloudflare.docker.com" ] destination_ports = ["443"] } } application_rule_collection { name = "aks-application-rules" priority = 200 action = "Allow" rule { name = "fqdn" source_addresses = ["*"] destination_fqdn_tags = ["AzureKubernetesService"] protocols { type = "Http" port = 80 } protocols { type = "Https" port = 443 } } } } resource "azurerm_route_table" "this" { name = local.route_table_name location = azurerm_resource_group.this.location resource_group_name = azurerm_resource_group.this.name } resource "azurerm_route" "default_to_firewall" { name = local.default_route_name resource_group_name = azurerm_resource_group.this.name route_table_name = azurerm_route_table.this.name address_prefix = "0.0.0.0/0" next_hop_type = "VirtualAppliance" next_hop_in_ip_address = azurerm_firewall.this.ip_configuration[0].private_ip_address } resource "azurerm_route" "firewall_public_ip_to_internet" { name = local.firewall_public_route resource_group_name = azurerm_resource_group.this.name route_table_name = azurerm_route_table.this.name address_prefix = "${azurerm_public_ip.firewall.ip_address}/32" next_hop_type = "Internet" } resource "azurerm_subnet_route_table_association" "aks" { subnet_id = azurerm_subnet.aks.id route_table_id = azurerm_route_table.this.id } resource "azurerm_kubernetes_cluster" "this" { name = local.aks_name location = azurerm_resource_group.this.location resource_group_name = azurerm_resource_group.this.name dns_prefix = "${var.prefix}-dns" default_node_pool { name = "system" vm_size = "Standard_D2s_v3" node_count = var.node_count vnet_subnet_id = azurerm_subnet.aks.id upgrade_settings { max_surge = "10%" drain_timeout_in_minutes = 0 node_soak_duration_in_minutes = 0 } } identity { type = "SystemAssigned" } network_profile { network_plugin = "azure" outbound_type = "userDefinedRouting" } api_server_access_profile { authorized_ip_ranges = [ "${azurerm_public_ip.firewall.ip_address}/32" ] } depends_on = [ azurerm_route.default_to_firewall, azurerm_subnet_route_table_association.aks, azurerm_firewall_policy_rule_collection_group.aks_rules ] } resource "azurerm_role_assignment" "network_contributor" { scope = azurerm_resource_group.this.id role_definition_name = "Network Contributor" principal_id = azurerm_kubernetes_cluster.this.identity[0].principal_id } output "resource_group_name" { value = azurerm_resource_group.this.name } output "aks_cluster_name" { value = azurerm_kubernetes_cluster.this.name } output "firewall_public_ip" { value = azurerm_public_ip.firewall.ip_address } output "firewall_private_ip" { value = azurerm_firewall.this.ip_configuration[0].private_ip_address }
Inizializza Terraform
Eseguire terraform init per inizializzare l'implementazione di Terraform. Questo comando scarica il azurerm provider necessario per gestire le risorse Azure.
terraform init -upgrade
Formattare e convalidare la configurazione
Eseguire terraform fmt per formattare il file di configurazione e terraform validate per verificare che la configurazione sia sintatticamente valida.
terraform fmt
terraform validate
Crea un piano di esecuzione di Terraform
Eseguire terraform plan per creare un piano di esecuzione.
terraform plan -out main.tfplan
Applicare un piano di esecuzione Terraform
Eseguire terraform apply per applicare il piano di esecuzione alla sottoscrizione Azure.
terraform apply main.tfplan
La creazione della rete virtuale, di Firewall di Azure e del cluster AKS richiede alcuni minuti.
Verificare la configurazione del traffico in uscita, del firewall e delle route
Ottenere il nome del gruppo di risorse, il nome del cluster e l'indirizzo IP pubblico del firewall dagli output di Terraform.
RESOURCE_GROUP=$(terraform output -raw resource_group_name) CLUSTER_NAME=$(terraform output -raw aks_cluster_name) FW_PUBLIC_IP=$(terraform output -raw firewall_public_ip)Verifica che il cluster usi il tipo in uscita
userDefinedRoutinge sia limitato all'indirizzo IP pubblico del firewall usando il comandoaz aks show.az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --query "{outboundType:networkProfile.outboundType, authorizedIpRanges:apiServerAccessProfile.authorizedIpRanges}"Verificare che la tabella di routing della subnet di AKS inoltri il traffico predefinito all'indirizzo IP privato del firewall. Ottenere il nome della tabella di route usando il
az network route-table listcomando e quindi elencarne le route usando ilaz network route-table route listcomando .ROUTE_TABLE_NAME=$(az network route-table list --resource-group $RESOURCE_GROUP --query "[0].name" -o tsv) az network route-table route list --resource-group $RESOURCE_GROUP --route-table-name $ROUTE_TABLE_NAME --output tableVerificare che siano presenti le regole di rete e applicazione. Ottenere il nome dei criteri del firewall usando il
az network firewall policy listcomando e quindi visualizzare il gruppo di raccolta regole usando ilaz network firewall policy rule-collection-group showcomando .FW_POLICY_NAME=$(az network firewall policy list --resource-group $RESOURCE_GROUP --query "[0].name" -o tsv) az network firewall policy rule-collection-group show --resource-group $RESOURCE_GROUP --policy-name $FW_POLICY_NAME --name aks-egress-rules --query "ruleCollections[].name" -o tsv
Connettersi al cluster
Configurare kubectl per connettersi al cluster usando il az aks get-credentials comando e quindi verificare la connessione usando il kubectl get nodes comando .
az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME
kubectl get nodes
Il traffico in uscita dal cluster ora viene instradato attraverso Firewall di Azure. Il criterio del firewall consente gli endpoint AKS necessari e blocca per impostazione predefinita tutte le altre connessioni in uscita.
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 di sviluppo all'elenco di cluster del servizio Azure Kubernetes degli intervalli IP approvati in modo da accedere al server API da questa posizione. È anche possibile configurare un jumpbox con gli strumenti necessari all'interno di una subnet separata nella rete virtuale del firewall.
Recuperare l'indirizzo IP usando il comando seguente:
CURRENT_IP=$(dig @resolver1.opendns.com ANY myip.opendns.com +short)Aggiungere l'indirizzo IP agli intervalli approvati usando il
az aks updatecomando . L'opzione--api-server-authorized-ip-rangessostituisce l'elenco corrente, quindi includere l'indirizzo IP pubblico del firewall quando si aggiunge l'indirizzo IP dello sviluppatore.az aks update --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --api-server-authorized-ip-ranges $FW_PUBLIC_IP,$CURRENT_IP/32
Connettersi al cluster AKS
Configurare
kubectlper connettersi al cluster del servizio Azure Kubernetes usando il comandoaz aks get-credentials.az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME
Distribuire un servizio pubblico nel servizio Azure Kubernetes
È ora possibile iniziare a esporre i servizi e distribuire applicazioni in questo cluster. In questo esempio viene esposto un servizio pubblico, ma è anche possibile esporre un servizio interno usando un servizio di bilanciamento del carico interno.
Il diagramma mostra il traffico pubblico in ingresso che arriva all'indirizzo IP pubblico del firewall, viene tradotto dalla regola DNAT e inoltrato all'indirizzo IP frontend del servizio di bilanciamento del carico pubblico per il servizio AKS.
Esaminare il manifesto di Avvio rapido della demo AKS Store per comprendere i componenti di distribuzione.
Distribuire il servizio usando il
kubectl applycomando .kubectl apply -f https://raw.githubusercontent.com/Azure-Samples/aks-store-demo/main/aks-store-quickstart.yaml
Ottenere l'IP front-end pubblico del Load Balancer
Ottenere l'indirizzo IP front-end pubblico assegnato al servizio di bilanciamento del carico usando il
kubectl get servicescomando .kubectl get servicesL'indirizzo IP deve essere elencato nella
EXTERNAL-IPcolonna , come illustrato nell'output di esempio seguente:NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 9m10s 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 store-front LoadBalancer 10.0.89.139 20.39.18.6 80:32271/TCP 10sSalvare l'indirizzo IP front-end del servizio di bilanciamento del carico pubblico usando il
kubectl get svc store-frontcomando .SERVICE_IP=$(kubectl get svc store-front -o jsonpath='{.status.loadBalancer.ingress[*].ip}')
Creare una regola DNAT in Firewall di Azure
Importante
Quando si utilizza Firewall di Azure per limitare il traffico in uscita e si crea una UDR (route definita dall'utente) per instradare tutto il traffico in uscita, assicurarsi di configurare in Firewall di Azure una regola DNAT appropriata 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é Firewall di Azure è un firewall con stato, scarta il pacchetto di ritorno perché Firewall di Azure non riconosce una sessione già stabilita. 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, creare una regola DNAT per Firewall di Azure. Per testare la connettività al cluster, la regola converte l'indirizzo IP pubblico front-end del firewall nell'indirizzo IP front-end del servizio di bilanciamento del carico pubblico salvato in $SERVICE_IP. È possibile personalizzare l'indirizzo di destinazione. La porta convertita deve essere la porta esposta per il servizio Kubernetes. Per una topologia che usa invece un indirizzo IP front-end privato, configurare un servizio di bilanciamento del carico interno e usare il relativo indirizzo IP privato come indirizzo convertito.
Aggiungere la regola NAT usando il comando
az network firewall nat-rule create.az network firewall nat-rule create --collection-name exampleset --destination-addresses $FW_PUBLIC_IP --destination-ports 80 --firewall-name $FW_NAME --name inboundrule --protocols Any --resource-group $RESOURCE_GROUP --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à. Dovrebbe essere visualizzata l'app dello store AKS. In questo esempio l'indirizzo IP pubblico del firewall era
52.253.228.132:In questa pagina è possibile visualizzare i prodotti, aggiungerli al carrello e quindi effettuare un ordine.
Pulire le risorse
Se le risorse create in questo articolo non sono più necessarie, è possibile eliminarle per evitare di incorrere in costi futuri.
Eliminare il gruppo di risorse del servizio AKS usando il comando
az group delete.az group delete --name $RESOURCE_GROUP
Firewall di Azure fattura ogni ora indipendentemente dal fatto che stia elaborando attivamente il traffico, oltre agli addebiti per l'elaborazione dei dati. Non lasciare il firewall (o il resto di questo esempio) in esecuzione più a lungo di quanto necessario.
Avvertimento
Se si lavora con risorse esistenti o di produzione nella stessa directory di lavoro, esaminare attentamente il piano di esecuzione prima di eliminarle. L'esecuzione terraform destroy rimuove tutte le risorse rilevate nel file di stato terraform per questa configurazione, tra cui la rete virtuale, le subnet, Firewall di Azure, i criteri e le regole del firewall, la tabella di route, il cluster del servizio Azure Kubernetes e l'assegnazione di ruolo. Evitare di eseguirlo su un'infrastruttura condivisa, a meno che non si sia certi che sia sicuro rimuoverlo.
Esegui terraform plan con il flag -destroy per verificare cosa rimuove Terraform.
terraform plan -destroy -out main.destroy.tfplan
Eseguire terraform apply per applicare il piano di eliminazione definitiva e rimuovere tutte le risorse create da questo esempio, incluse le Firewall di Azure.
terraform apply main.destroy.tfplan