Configura DNS di Azure e TLS con l'implementazione API di Application Routing Gateway

Con l'Application Routing Gateway API, gli utenti possono esporre facilmente applicazioni HTTPS su AKS con i propri certificati di Azure Key Vault, inclusa la pubblicazione automatica del nome di dominio. L'operatore di routing dell'applicazione si integra con DNS di Azure e Azure Key Vault e riconcilia un SecretProviderClasssegreto Kubernetes per i certificati TLS, il campo listener certificateRefs e la distribuzione separata external-dns in modo da non dover gestire manualmente queste risorse.

Questo articolo illustra come:

  • Effettuare il provisioning delle risorse Azure prerequisiti (area DNS di Azure, Azure Key Vault, identità gestita assegnata dall'utente, assegnazioni di ruolo e credenziali di identità federate).
  • Configurare un listener Gateway per eseguire la terminazione TLS usando un certificato memorizzato in Azure Key Vault tramite le opzioni TLS del listener kubernetes.azure.com/tls-cert-keyvault-uri e kubernetes.azure.com/tls-cert-service-account.
  • Usare le risorse personalizzate ClusterExternalDNS e ExternalDNS per pubblicare record DNS in DNS di Azure in base ai nomi host delle risorse Gateway, HTTPRoute e GRPCRoute.

Funzionamento dell'integrazione

L'operatore di routing delle applicazioni espone due integrazioni per automatizzare le risorse che altrimenti creeresti manualmente per portare online una risorsa Gateway con un dominio personalizzato e terminazione TLS.

Integrazione TLS

Quando una risorsa Gateway usa una GatewayClass gestita, ovvero approuting-istio (dall'implementazione dell'API di Application Routing Gateway) oppure istio (dal componente aggiuntivo service mesh Istio), e un listener presenta le due opzioni TLS seguenti, l'operatore di Application Routing esegue la riconciliazione delle risorse necessarie per la terminazione TLS usando un certificato archiviato in Azure Key Vault:

Chiave dell'opzione TLS Value
kubernetes.azure.com/tls-cert-keyvault-uri URI del certificato di Azure Key Vault da cui recuperare il certificato TLS. Usare un URI non modificato ,ad esempio , https://<vault>.vault.azure.net/certificates/<cert>in modo che l'operatore rilevi automaticamente le rotazioni dei certificati in Azure Key Vault.
kubernetes.azure.com/tls-cert-service-account Il nome di un ServiceAccount Kubernetes nello stesso namespace di Gateway. Il ServiceAccount deve essere vincolato a un'identità gestita assegnata dall'utente tramite Microsoft Entra Workload Identity e tale identità gestita deve avere il ruolo Key Vault Secrets User nell'Azure Key Vault di destinazione.

Per ogni listener che include entrambe le opzioni TLS, l'operatore :

  1. Eseguire il provisioning di un SecretProviderClass denominato kv-gw-cert-<gateway-name>-<listener-name> nello spazio dei nomi di Gateway, configurato per ottenere il certificato da Azure Key Vault tramite l'Identity Authentication del carico di lavoro.
  2. Attiva il provider Azure Key Vault per il driver CSI dell'archivio segreti per sincronizzare il certificato come segreto Kubernetes kubernetes.io/tls con lo stesso nome nello spazio dei nomi di Gateway.
  3. Applica una patch al campo tls.certificateRefs del listener in modo che faccia riferimento al segreto di Kubernetes sincronizzato.

Integrazione DNS

L'operatore Application Routing gestisce per te un'istanza external-dns tramite due risorse personalizzate:

Risorsa personalizzata Scope
ClusterExternalDNS (clusterexternaldnses.approuting.kubernetes.azure.com) Con ambito cluster. Monitora le risorse Gateway, HTTPRoute e GRPCRoute in tutti i namespace del cluster.
ExternalDNS (externaldnses.approuting.kubernetes.azure.com) Con ambito spazio dei nomi. Monitora solo le risorse Gateway, HTTPRoute e GRPCRoute nello stesso namespace della risorsa personalizzata.

Entrambe le risorse personalizzate accettano selettori facoltativi filters per restringere ulteriormente le risorse osservate dall'istanza gestita external-dns all'interno dell'ambito:

Filter Cosa restringe
filters.gatewayLabels Limita le Gateway risorse osservate dal controller.
filters.routeAndIngressLabels Limita le risorse HTTPRoute e Ingress osservate dal controller.

Per ogni risorsa personalizzata, l'operatore di routing dell'applicazione:

  1. Distribuisce un'istanza gestita external-dns, configurata per ottenere i record dalle risorse HTTPRoute e GRPCRoute e usare come destinazione le zone di DNS di Azure specificate.
  2. Si autentica ad DNS di Azure usando Microsoft Entra Workload Identity, tramite il ServiceAccount a cui si fa riferimento nel campo identity della risorsa personalizzata.
  3. Pubblica record A in ognuna delle zone DNS di Azure elencate per ogni nome host HTTPRoute o GRPCRoute associato a una risorsa gestita Gateway che rientra nell'ambito.

Prerequisites

  • Un cluster AKS con entrambe le funzionalità seguenti abilitate:

    • Il componente aggiuntivo per l'instradamento dell'applicazione (--enable-app-routing). Questo componente aggiuntivo distribuisce l'operatore application routing nel cluster, che è il componente che riconcilia le integrazioni DNS e TLS documentate in questo articolo. In un cluster esistente è anche possibile abilitare questa funzionalità usando az aks approuting enable.
    • Implementazione dell'API gateway gestita con cui l'operatore deve integrarsi. Scegliere una delle opzioni seguenti (le due opzioni si escludono a vicenda e non possono essere abilitate contemporaneamente):

    Per usare queste integrazioni, abilitare sia il componente aggiuntivo Routing delle applicazioni (usando az aks approuting enable) che una delle implementazioni dell'API del gateway gestito elencate in precedenza.

  • Installazione dell'API gateway gestita abilitata nel cluster.

  • La funzionalità Identità del carico di lavoro Microsoft Entra abilitata nel cluster, insieme all'autorità emittente OIDC. È possibile abilitare entrambe le funzionalità usando i --enable-oidc-issuer flag e --enable-workload-identity in az aks create o az aks update.

  • Il provider di Azure Key Vault per il driver CSI dell'archivio segreti abilitato nel cluster. È possibile abilitarlo usando il az aks enable-addons comando con --addons azure-keyvault-secrets-providero passando --enable-kv a az aks approuting enable o az aks approuting update.

  • interfaccia della riga di comando di Azure versione 2.86.0 o successiva. Eseguire az --version per trovare la azure-cli versione ed eseguire az upgrade per eseguire l'aggiornamento.

  • Controllo degli accessi in base al ruolo di Azure (RBAC) sufficiente per la propria identità per creare assegnazioni di ruolo e credenziali di identità federate. Il Owner ruolo o una combinazione di Role Based Controllo di accesso Administrator e Managed Identity Contributor è sufficiente.

Note

I flag --attach-kv e --attach-zones in az aks approuting update (e i sottocomandi az aks approuting zone) sono progettati per l'esperienza legacy basata su NGINX, in cui all'identità gestita assegnata dall'utente del componente aggiuntivo Application Routing viene concesso l'accesso RBAC di Azure a un singolo Azure Key Vault e a una zona DNS. Non vengono usati dall'integrazione dell'API gateway documentata in questo articolo. La nuova esperienza si basa su Microsoft Entra Workload Identity anziché sull'identità gestita del componente aggiuntivo, quindi è necessario creare una propria identità gestita assegnata dall'utente, assegnarle i ruoli appropriati di DNS di Azure e Azure Key Vault e creare credenziali di identità federata che la associno ai ServiceAccount di Kubernetes a cui si fa riferimento nelle opzioni TLS del listener Gateway e nelle risorse personalizzate ExternalDNS/ClusterExternalDNS.

Impostare le variabili di ambiente seguenti. La guida dettagliata li riutilizza in ciascun comando successivo:

export RESOURCE_GROUP=<resource-group-name>
export CLUSTER=<cluster-name>
export LOCATION=<azure-region>

Eseguire il pull delle credenziali del cluster per kubectl:

az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER

Creare l'infrastruttura Azure

Creare la zona DNS di Azure

Se si dispone già di una zona DNS di Azure in cui si vuole che l'operatore di routing dell'applicazione gestisca i record, è possibile ignorare questo passaggio e assegnare il valore di al nome della ZONE_NAME zona esistente.

export ZONE_NAME=<dns-zone-name>
az network dns zone create --resource-group $RESOURCE_GROUP --name $ZONE_NAME
export ZONE_ID=$(az network dns zone show --resource-group $RESOURCE_GROUP --name $ZONE_NAME --query id -o tsv)

Creare il Azure Key Vault e il certificato

Creare il Azure Key Vault che archivia il certificato TLS. Configurare l'insieme di credenziali per usare RBAC di Azure per l'autorizzazione, che è il modello di autorizzazione consigliato:

export KV_NAME=<key-vault-name>
az keyvault create \
  --name $KV_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --enable-rbac-authorization true

Note

Per creare il certificato nel passaggio successivo, la propria identità Azure deve avere il ruolo Key Vault Certificates Officer (o Key Vault Administrator) nell'insieme di credenziali. Assegnare questo ruolo all'insieme di credenziali prima di continuare.

Creare un certificato con carattere jolly autofirmato in Azure Key Vault. Per le distribuzioni in produzione, importare un certificato firmato da un'autorità di certificazione (CA) utilizzando invece az keyvault certificate import.

cat > cert-policy.json <<EOF
{
  "issuerParameters": { "name": "Self" },
  "keyProperties": { "exportable": true, "keyType": "RSA", "keySize": 2048, "reuseKey": false },
  "secretProperties": { "contentType": "application/x-pkcs12" },
  "x509CertificateProperties": {
    "subject": "CN=*.${ZONE_NAME}",
    "subjectAlternativeNames": { "dnsNames": ["*.${ZONE_NAME}", "${ZONE_NAME}"] },
    "validityInMonths": 12,
    "keyUsage": ["digitalSignature", "keyEncipherment"]
  }
}
EOF

az keyvault certificate create \
  --vault-name $KV_NAME \
  --name approuting-demo-cert \
  --policy @cert-policy.json

Acquisire l'URI del certificato non modificato. L'operatore di instradamento dell'applicazione usa questo URI per configurare il SecretProviderClass. Un URI senza versione garantisce che l'operatore recuperi le nuove versioni del certificato in Azure Key Vault quando il certificato viene rinnovato.

export CERT_URI=$(az keyvault certificate show \
  --vault-name $KV_NAME \
  --name approuting-demo-cert \
  --query id -o tsv | sed 's|/[^/]*$||')
echo "Cert URI: $CERT_URI"

Creare l'identità gestita assegnata dall'utente e assegnare i ruoli RBAC di Azure

Creare un'identità gestita assegnata dall'utente che la distribuzione dell'operatore di Instradamento dell'applicazione external-dns e la sincronizzazione TLS del listener del gateway usano per autenticarsi su DNS di Azure e Azure Key Vault.

export UAMI_NAME=<managed-identity-name>
az identity create --resource-group $RESOURCE_GROUP --name $UAMI_NAME --location $LOCATION
export UAMI_CLIENT_ID=$(az identity show --resource-group $RESOURCE_GROUP --name $UAMI_NAME --query clientId -o tsv)
export UAMI_PRINCIPAL_ID=$(az identity show --resource-group $RESOURCE_GROUP --name $UAMI_NAME --query principalId -o tsv)

Concedere all'identità gestita il DNS Zone Contributor ruolo nella zona di DNS di Azure di destinazione e al Key Vault Secrets User ruolo nel Azure Key Vault di destinazione:

az role assignment create \
  --assignee-object-id $UAMI_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --role "DNS Zone Contributor" \
  --scope $ZONE_ID

az role assignment create \
  --assignee-object-id $UAMI_PRINCIPAL_ID \
  --assignee-principal-type ServicePrincipal \
  --role "Key Vault Secrets User" \
  --scope $(az keyvault show --name $KV_NAME --query id -o tsv)

Crea i namespace, i ServiceAccounts e le credenziali di identità federata

Le integrazioni TLS e DNS dell'operatore di routing dell'applicazione eseguono entrambe l'autenticazione per Azure tramite un ServiceAccount Kubernetes associato all'identità gestita assegnata dall'utente usando una credenziale di identità federata (FIC). Ogni coppia (namespace, ServiceAccount) che deve autenticarsi richiede un FIC.

Recupera l'URL dell'emittente OIDC del cluster:

export OIDC_ISSUER=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER --query oidcIssuerProfile.issuerUrl -o tsv)

Per ogni namespace in cui si intende distribuire una risorsa Gateway che usa l'integrazione TLS o una risorsa ExternalDNS, crea il namespace, una credenziale di identità federata per il ServiceAccount e il ServiceAccount stesso. L'esempio seguente crea due namespace, app-a e app-b, ciascuno dei quali con un ServiceAccount denominato approuting-demo-sa:

export SA_NAME=approuting-demo-sa
for ns in app-a app-b; do
  kubectl create namespace $ns

  az identity federated-credential create \
    --identity-name $UAMI_NAME \
    --resource-group $RESOURCE_GROUP \
    --name approuting-demo-fic-$ns \
    --issuer $OIDC_ISSUER \
    --subject "system:serviceaccount:$ns:$SA_NAME" \
    --audiences "api://AzureADTokenExchange"

  kubectl apply -n $ns -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: $SA_NAME
  annotations:
    azure.workload.identity/client-id: $UAMI_CLIENT_ID
  labels:
    azure.workload.identity/use: "true"
EOF
done

L'annotazione azure.workload.identity/client-id associa il ServiceAccount all'identità gestita e l'etichetta azure.workload.identity/use: "true" indica al webhook Microsoft Entra Workload Identity di proiettare un token federato nei pod che usano il ServiceAccount. Entrambi sono necessari affinché le integrazioni TLS e DNS dell'operatore di routing delle applicazioni possano autenticarsi correttamente ad Azure.

Configurare la terminazione TLS in un gateway

Distribuisci un carico di lavoro di esempio httpbin in ciascuno spazio dei nomi:

for ns in app-a app-b; do
  kubectl apply -n $ns -f https://raw.githubusercontent.com/istio/istio/release-1.27/samples/httpbin/httpbin.yaml
done

Crea una risorsa Gateway in ogni namespace con un listener HTTPS che fa riferimento al certificato di Azure Key Vault tramite le opzioni TLS. Ognuno Gateway usa il proprio sub-host della zona DNS di Azure (ad esempio, a.<zone> e b.<zone>):

Note

Gli esempi in questo articolo usano gatewayClassName: approuting-istio, la classe Gateway fornita dall'implementazione dell'API del gateway di routing dell'applicazione. Se invece hai abilitato il componente aggiuntivo service mesh di Istio, imposta gatewayClassName: istio nelle risorse Gateway. Le integrazioni DNS e TLS si comportano in modo identico per entrambe le classi gateway gestite.

for pair in "app-a:a" "app-b:b"; do
  ns=${pair%%:*}
  sub=${pair##*:}
  fqdn=${sub}.${ZONE_NAME}
  kubectl apply -n $ns -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: ${sub}-gateway
  labels:
    app: approuting-demo
    zone: ${sub}
spec:
  gatewayClassName: approuting-istio
  listeners:
  - name: https
    hostname: $fqdn
    port: 443
    protocol: HTTPS
    tls:
      mode: Terminate
      options:
        kubernetes.azure.com/tls-cert-keyvault-uri: $CERT_URI
        kubernetes.azure.com/tls-cert-service-account: $SA_NAME
    allowedRoutes:
      namespaces:
        from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: ${sub}-route
spec:
  parentRefs:
  - name: ${sub}-gateway
  hostnames: ["$fqdn"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /get
    backendRefs:
    - name: httpbin
      port: 8000
EOF
done

Attendere che ognuna Gateway raggiunga la Programmed condizione:

kubectl wait -n app-a --for=condition=programmed gateway a-gateway --timeout=300s
kubectl wait -n app-b --for=condition=programmed gateway b-gateway --timeout=300s

Verificate che l'operatore Application Routing abbia creato un SecretProviderClass e che il provider Azure Key Vault per Secrets Store CSI Driver abbia sincronizzato il certificato in un segreto kubernetes.io/tls in ogni namespace:

kubectl get secretproviderclass,secret -n app-a
kubectl get secretproviderclass,secret -n app-b

Output di esempio per uno spazio dei nomi:

NAME                                                                        AGE
secretproviderclass.secrets-store.csi.x-k8s.io/kv-gw-cert-a-gateway-https   2m

NAME                                TYPE                DATA   AGE
secret/kv-gw-cert-a-gateway-https   kubernetes.io/tls   2      2m

Configurazione dei record DNS di Azure usando ClusterExternalDNS

Distribuisci un'istanza external-dns con ambito cluster che pubblica record A per le risorse Gateway in qualsiasi namespace applicando una risorsa personalizzata ClusterExternalDNS.

kubectl apply -f - <<EOF
apiVersion: approuting.kubernetes.azure.com/v1alpha1
kind: ClusterExternalDNS
metadata:
  name: demo-cluster-dns
spec:
  resourceName: demo-cluster-dns
  resourceNamespace: app-a
  dnsZoneResourceIDs:
  - $ZONE_ID
  resourceTypes:
  - gateway
  identity:
    type: workloadIdentity
    serviceAccount: $SA_NAME
EOF

Il campo resourceNamespace specifica il namespace in cui l'operatore Application Routing distribuisce l'istanza gestita external-dns. Il ServiceAccount a cui fa riferimento identity.serviceAccount deve esistere in quel namespace.

Dopo circa un minuto, due record A vengono visualizzati nella zona DNS di Azure , uno per ogni Gateway:

az network dns record-set a list --resource-group $RESOURCE_GROUP --zone-name $ZONE_NAME -o table
Name    ResourceGroup              Ttl    Type    AutoRegistered    Metadata
------  -------------------------  -----  ------  ----------------  --------
a       <your-rg>                  300    A       False
b       <your-rg>                  300    A       False

Configurare i record DNS di Azure usando un ExternalDNS con ambito namespace

Per pubblicare record per solo un sottoinsieme di risorse Gateway, utilizza la risorsa personalizzata con ambito namespace ExternalDNS. A differenza di ClusterExternalDNS, la variante con ambito del namespace osserva solo le risorse Gateway, HTTPRoute e GRPCRoute nello stesso namespace della risorsa personalizzata. Come con ClusterExternalDNS, facoltativamente è possibile restringere ulteriormente l'ambito usando i filters.gatewayLabels selettori e filters.routeAndIngressLabels .

Prima di tutto, eliminare l'oggetto ClusterExternalDNS dal passaggio precedente:

kubectl delete clusterexternaldns demo-cluster-dns

Distribuisci un nuovo oggetto Gateway in app-a con l'etichetta zone: c e il HTTPRoute corrispondente:

kubectl apply -n app-a -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: c-gateway
  labels:
    app: approuting-demo
    zone: c
spec:
  gatewayClassName: approuting-istio
  listeners:
  - name: https
    hostname: c.${ZONE_NAME}
    port: 443
    protocol: HTTPS
    tls:
      mode: Terminate
      options:
        kubernetes.azure.com/tls-cert-keyvault-uri: $CERT_URI
        kubernetes.azure.com/tls-cert-service-account: $SA_NAME
    allowedRoutes:
      namespaces:
        from: Same
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: c-route
spec:
  parentRefs:
  - name: c-gateway
  hostnames: ["c.${ZONE_NAME}"]
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /get
    backendRefs:
    - name: httpbin
      port: 8000
EOF

kubectl wait -n app-a --for=condition=programmed gateway c-gateway --timeout=300s

Applicare una risorsa con ambito dello spazio dei nomi ExternalDNS in app-a con un filtro di etichette per zone=c:

kubectl apply -n app-a -f - <<EOF
apiVersion: approuting.kubernetes.azure.com/v1alpha1
kind: ExternalDNS
metadata:
  name: demo-ns-dns
spec:
  resourceName: demo-ns-dns
  dnsZoneResourceIDs:
  - $ZONE_ID
  resourceTypes:
  - gateway
  identity:
    type: workloadIdentity
    serviceAccount: $SA_NAME
  filters:
    gatewayLabels: "zone=c"
EOF

Si applicano due regole di ambito:

  • L'ambito dello spazio dei nomi di ExternalDNS esclude b-gateway perché appartiene allo spazio dei nomi app-b.
  • Il filtro di etichetta zone=c esclude a-gateway perché si trova in app-a ma è etichettato zone=a.

L'operatore di routing dell'applicazione pubblica un nuovo record A per c.${ZONE_NAME}:

az network dns record-set a list --resource-group $RESOURCE_GROUP --zone-name $ZONE_NAME -o table

Verificare il traffico HTTPS con terminazione TLS

Risolvi il nome host di Gateway tramite il nameserver autorevole della zona DNS di Azure e invia una richiesta HTTPS:

NS=$(az network dns zone show --resource-group $RESOURCE_GROUP --name $ZONE_NAME --query 'nameServers[0]' -o tsv | sed 's/\.$//')
GATEWAY_IP=$(dig +short @${NS} a.${ZONE_NAME} | tail -1)
curl -k -I --resolve "a.${ZONE_NAME}:443:${GATEWAY_IP}" "https://a.${ZONE_NAME}/get"

Verrà visualizzata una HTTP/2 200 risposta. Il certificato TLS presentato dal gateway è quello sincronizzato da Azure Key Vault. Se è stato importato un certificato firmato dalla CA, sostituire -k con --cacert <path-to-ca-chain> per convalidare la catena di certificati.

Note

L'esempio usa curl --resolve per ignorare la risoluzione DNS locale e indirizzare la richiesta all'indirizzo IP esterno del gateway. Questo metodo è utile per i test prima di delegare la zona DNS a un registrar. Per l'uso in produzione, configurare il registrar del dominio in modo che deleghi la zona ai name server di DNS di Azure restituiti da az network dns zone show --query 'nameServers'.

Limitations

  • Le integrazioni DNS e TLS si applicano solo alle risorse Gateway che utilizzano una GatewayClass gestita: approuting-istio (l'implementazione dell'API Application Routing Gateway) o istio (il componente aggiuntivo del service mesh Istio). Gateway le risorse che usano qualsiasi altra classe GatewayClass non sono supportate.
  • Una risorsa personalizzata ClusterExternalDNS o ExternalDNS può fare riferimento a un massimo di sette zone DNS di Azure tramite dnsZoneResourceIDs. Tutte le zone a cui si fa riferimento in una singola risorsa personalizzata devono trovarsi nello stesso Azure sottoscrizione e gruppo di risorse. Devono anche essere tutti dello stesso tipo (pubblico o privato).
  • L'istanza gestita external-dns non elimina automaticamente i record DNS quando viene eliminata la risorsa personalizzata ClusterExternalDNS o ExternalDNS. Per rimuovere i record orfani, eliminarli direttamente dalla zona DNS di Azure dopo l'eliminazione della risorsa personalizzata.
  • La riconciliazione dei record DNS dalle TLSRoute risorse non è attualmente supportata. L'istanza gestita external-dns ricava i record solo dalle risorse Gateway, HTTPRoute e GRPCRoute.

Passaggi successivi