Configurer Azure DNS et TLS avec l’implémentation de l’API Application Routing Gateway

Avec l’API Application Routing Gateway, les utilisateurs peuvent facilement exposer des applications HTTPS sur AKS avec leurs propres certificats Azure Key Vault, y compris la publication automatique de noms de domaine. L’opérateur Application Routing s’intègre à Azure DNS et Azure Key Vault, et réconcilie un SecretProviderClass, un secret Kubernetes pour les certificats TLS, le champ certificateRefs de l’écouteur et le déploiement external-dns distinct pour que vous n’ayez pas à gérer manuellement ces ressources.

Cet article vous montre comment :

  • Provisionnez les ressources requises Azure (zone Azure DNS, Azure Key Vault, identité managée affectée par l’utilisateur, attributions de rôles et informations d’identification d’identité fédérée).
  • Configurez un écouteur Gateway pour terminer TLS à l’aide d’un certificat stocké dans Azure Key Vault via les options TLS de l’écouteur kubernetes.azure.com/tls-cert-keyvault-uri et kubernetes.azure.com/tls-cert-service-account.
  • Utilisez les ressources personnalisées ClusterExternalDNS et ExternalDNS pour publier des enregistrements DNS dans Azure DNS en fonction des noms d’hôte de vos ressources Gateway, HTTPRoute et GRPCRoute.

Fonctionnement de l’intégration

L’opérateur Application Routing expose deux intégrations permettant d’automatiser les ressources que vous devriez autrement créer manuellement pour rendre une ressource Gateway accessible en ligne avec un domaine personnalisé et une terminaison TLS.

Intégration TLS

Lorsqu’une ressource Gateway utilise une GatewayClass gérée — soit approuting-istio (provenant de l’implémentation de l’API Application Routing Gateway), soit istio (provenant du module complémentaire de maillage de services Istio) — et qu’un listener comporte les deux options TLS suivantes, l’opérateur Application Routing met en conformité les ressources nécessaires pour terminer TLS à l’aide d’un certificat stocké dans Azure Key Vault :

Clé d’option TLS Valeur
kubernetes.azure.com/tls-cert-keyvault-uri URI de certificat Azure Key Vault à partir duquel sourcer le certificat TLS. Utilisez un URI non versionné (par exemple) https://<vault>.vault.azure.net/certificates/<cert>afin que l’opérateur récupère automatiquement les rotations de certificats dans Azure Key Vault.
kubernetes.azure.com/tls-cert-service-account Nom d’un ServiceAccount Kubernetes dans le même espace de noms que le Gateway. Le ServiceAccount doit être lié à une identité managée attribuée par l’utilisateur via Microsoft Entra Workload Identity, et cette identité managée doit disposer du rôle Key Vault Secrets User sur le coffre de clés Azure cible.

Pour chaque écouteur qui comporte les deux options TLS, l’opérateur :

  1. Provisionne un SecretProviderClass nommé kv-gw-cert-<gateway-name>-<listener-name> dans l'espace de noms de Gateway, configuré pour récupérer le certificat depuis Azure Key Vault à l'aide de l'authentification par identité de charge de travail.
  2. Déclenche le fournisseur Azure Key Vault pour le pilote CSI Secrets Store afin de synchroniser le certificat sous la forme d'un secret Kubernetes kubernetes.io/tls portant le même nom dans l'espace de noms de Gateway.
  3. Met à jour le champ tls.certificateRefs de l'écouteur afin qu'il fasse référence au secret Kubernetes synchronisé.

Intégration DNS

L’opérateur De routage des applications gère une external-dns instance pour vous via deux ressources personnalisées :

Ressource personnalisée Scope
ClusterExternalDNS (clusterexternaldnses.approuting.kubernetes.azure.com) Étendue limitée au cluster. Surveille les ressources Gateway, HTTPRoute et GRPCRoute dans tous les espaces de noms du cluster.
ExternalDNS (externaldnses.approuting.kubernetes.azure.com) Étendue limitée à l'espace de noms. Surveille uniquement Gateway, HTTPRouteet GRPCRoute les ressources dans le même espace de noms que la ressource personnalisée.

Les deux ressources personnalisées acceptent des sélecteurs facultatifs filters pour restreindre davantage les ressources que l’instance external-dns gérée observe dans son périmètre :

Filter Ce qu’il réduit
filters.gatewayLabels Limite les ressources Gateway que le contrôleur observe.
filters.routeAndIngressLabels Limite les ressources HTTPRoute et Ingress observées par le contrôleur.

Pour chaque ressource personnalisée, l’opérateur Routage des applications :

  1. Déploie une instance managée external-dns, configurée pour extraire les enregistrements à partir des ressources HTTPRoute et GRPCRoute, et cible les zones Azure DNS spécifiées.
  2. S’authentifie auprès d’Azure DNS à l’aide de l’identité de charge de travail Microsoft Entra, via le compte de service référencé dans le champ identity de la ressource personnalisée.
  3. Publie des enregistrements A dans chacune des zones Azure DNS répertoriées pour chaque nom d’hôte HTTPRoute ou GRPCRoute associé à une ressource managée Gateway dans le périmètre.

Prerequisites

  • Un cluster AKS avec les deux fonctionnalités suivantes activées :

    • Le module complémentaire Routage des applications (--enable-app-routing). Ce module complémentaire déploie l’opérateur De routage des applications sur le cluster, qui est le composant qui rapproche les intégrations DNS et TLS documentées dans cet article. Sur un cluster existant, vous pouvez également activer cette fonctionnalité à l’aide de az aks approuting enable.
    • Une implémentation gérée de la Gateway API avec laquelle l’opérateur peut s’intégrer. Choisissez l’une des options suivantes (les deux options s’excluent mutuellement et ne peuvent pas être activées en même temps) :

    Pour utiliser ces intégrations, activez le module complémentaire De routage des applications (à l’aide az aks approuting enable) et l’une des implémentations de l’API de passerelle managée répertoriées précédemment.

  • L’installation de l’API de passerelle gérée activée sur le cluster.

  • La fonctionnalité Microsoft Entra Workload Identity activée sur le cluster, ainsi que l’émetteur OIDC. Vous pouvez activer les deux fonctionnalités en utilisant les indicateurs --enable-oidc-issuer et --enable-workload-identity sur az aks create ou az aks update.

  • Le module complémentaire Azure Key Vault provider for Secrets Store CSI Driver est activé sur le cluster. Vous pouvez l’activer à l’aide de la az aks enable-addons commande avec --addons azure-keyvault-secrets-provider, ou en passant --enable-kv à az aks approuting enable ou az aks approuting update.

  • Azure CLI version 2.86.0 ou ultérieure. Exécutez az --version pour rechercher votre azure-cli version et exécutez az upgrade la mise à niveau.

  • Un contrôle d'accès en fonction du rôle Azure (RBAC) suffisant sur votre propre identité pour créer des affectations de rôles et des informations d'identification d'identité fédérée. Le Owner rôle ou une combinaison de Role Based Access Control Administrator et Managed Identity Contributor est suffisant.

Note

Les indicateurs --attach-kv et --attach-zones de az aks approuting update (ainsi que les sous-commandes az aks approuting zone) sont conçus pour l’expérience héritée basée sur NGINX, dans laquelle la propre identité managée attribuée par l’utilisateur du module complémentaire Application Routing se voit accorder un accès Azure RBAC à une seule instance d’Azure Key Vault et à une seule zone DNS. Ils ne sont pas utilisés par l’intégration de l’API de passerelle documentée dans cet article. La nouvelle expérience repose sur l’identité de charge de travail Microsoft Entra plutôt que sur l’identité managée du module complémentaire. Vous devez donc créer votre propre identité managée affectée par l’utilisateur, lui accorder les rôles Azure DNS et Azure Key Vault appropriés, et créer des informations d’identification d’identité fédérée qui la lient aux objets ServiceAccount Kubernetes auxquels vous faites référence dans vos options TLS de l’écouteur Gateway et vos ressources personnalisées ExternalDNS/ClusterExternalDNS.

Définissez les variables d’environnement suivantes. La procédure pas à pas les réutilise dans chaque commande suivante :

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

Récupérer les identifiants du cluster pour kubectl:

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

Créer l’infrastructure Azure

Créer la zone Azure DNS

Si vous disposez déjà d’une zone Azure DNS dans laquelle vous souhaitez que l’opérateur de routage d’applications gère les enregistrements, vous pouvez ignorer cette étape et définir ZONE_NAME sur le nom de votre zone existante.

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)

Créer le Azure Key Vault et le certificat

Créez le Azure Key Vault qui stocke le certificat TLS. Configurez le coffre pour utiliser Azure RBAC comme système d'autorisation, qui constitue le modèle d'autorisation recommandé :

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

Note

Pour créer le certificat à l'étape suivante, votre identité Azure doit disposer du rôle Key Vault Certificates Officer (ou Key Vault Administrator) sur le coffre. Accordez ce rôle sur le coffre-fort avant de continuer.

Créez un certificat générique auto-signé dans Azure Key Vault. Pour les déploiements de production, importez plutôt un certificat signé par une autorité de certification (CA) à l’aide de 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

Capturez l’URI de certificat non converti. L’opérateur Routage des applications utilise cet URI pour configurer le SecretProviderClass. Un URI sans version garantit que l’opérateur prend en charge les nouvelles versions du certificat dans Azure Key Vault lors de la rotation du certificat.

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"

Créer l’identité managée affectée par l’utilisateur et attribuer des rôles Azure RBAC

Créez une identité managée affectée par l'utilisateur que le déploiement de l'opérateur de routage des applications external-dns et la synchronisation TLS de l'écouteur de passerelle utilisent pour s'authentifier auprès d'Azure DNS et d'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)

Accordez à l’identité managée le DNS Zone Contributor rôle sur la zone de Azure DNS cible et le Key Vault Secrets User rôle sur le Azure Key Vault cible :

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)

Créer les espaces de noms, les comptes de service et les identifiants d’identité fédérée

Les intégrations TLS et DNS de l’opérateur Application Routing s’authentifient toutes deux auprès d’Azure via un ServiceAccount Kubernetes lié à l’identité managée attribuée par l’utilisateur au moyen d’un justificatif d’identité fédérée (FIC). Chaque (namespace, ServiceAccount) paire qui doit s’authentifier nécessite un FIC.

Capturez l’URL de l’émetteur OIDC du cluster :

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

Pour chaque espace de noms dans lequel vous envisagez de déployer une Gateway ressource qui utilise l’intégration TLS ou une ExternalDNS ressource, créez l’espace de noms, les informations d’identification d’identité fédérée pour ServiceAccount et le ServiceAccount lui-même. L’exemple suivant crée deux espaces de noms, app-a et app-b, chacun avec un ServiceAccount nommé 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’annotation azure.workload.identity/client-id associe le ServiceAccount à l’identité managée, et le label azure.workload.identity/use: "true" indique au webhook Microsoft Entra Workload Identity d’injecter un jeton fédéré dans les pods qui utilisent le ServiceAccount. Les deux sont nécessaires pour que les intégrations TLS et DNS de l'opérateur De routage des applications s'authentifient auprès de Azure avec succès.

Configurer l’arrêt TLS sur une passerelle

Déployez un exemple httpbin de charge de travail dans chaque espace de noms :

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

Créez une Gateway ressource dans chaque espace de noms avec un écouteur HTTPS qui référence le certificat Azure Key Vault via les options TLS. Chacun Gateway utilise son propre sous-hôte de la zone Azure DNS (par exemple, a.<zone> etb.<zone>) :

Note

Les exemples de cet article utilisent gatewayClassName: approuting-istio, gatewayClass fourni par l’implémentation de l’API Application Routing Gateway. Si vous avez plutôt activé le module complémentaire de maillage de services Istio, définissez gatewayClassName: istio sur vos ressources Gateway. Les intégrations DNS et TLS se comportent de manière identique pour les deux classes de passerelle managées.

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

Attendez que chacun Gateway atteigne la Programmed condition :

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

Vérifiez que l’opérateur de routage des applications a créé un SecretProviderClass et que le fournisseur Azure Key Vault pour Secrets Store CSI Driver a synchronisé le certificat dans un Secret kubernetes.io/tls dans chaque espace de noms :

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

Exemple de sortie pour un espace de noms :

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

Configurer des enregistrements Azure DNS à l’aide de ClusterExternalDNS

Déployez une instance external-dns à portée de cluster qui publie des enregistrements A pour les ressources Gateway dans n’importe quel espace de noms en appliquant une ressource personnalisée 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

Le resourceNamespace champ spécifie l’espace de noms où l’opérateur Routage des applications déploie l’instance managée external-dns . ServiceAccount référencé par identity.serviceAccount doit exister dans cet espace de noms.

Après environ une minute, deux enregistrements A apparaissent dans la zone Azure DNS , un pour chacun 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

Configurer les enregistrements DNS Azure à l’aide d’un ExternalDNS limité à un espace de noms

Pour publier des enregistrements uniquement pour un sous-ensemble de ressources Gateway, utilisez la ressource personnalisée ExternalDNS limitée à un espace de noms. Contrairement à ClusterExternalDNS, la variante limitée à l’espace de noms observe uniquement les ressources Gateway, HTTPRoute et GRPCRoute dans le même espace de noms que la ressource personnalisée. Comme avec ClusterExternalDNS, vous pouvez, si vous le souhaitez, restreindre davantage le périmètre à l’aide des sélecteurs filters.gatewayLabels et filters.routeAndIngressLabels.

Tout d’abord, supprimez l’étape ClusterExternalDNS précédente :

kubectl delete clusterexternaldns demo-cluster-dns

Déployez un nouveau Gateway dans app-a avec l’étiquette zone: c et un élément correspondant HTTPRoute:

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

Appliquez une ressource ExternalDNS limitée à un espace de noms dans app-a avec un filtre d’étiquette pour 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

Deux règles de portée s’appliquent :

  • La portée de l’espace de noms de ExternalDNS exclut b-gateway, car il appartient à l’espace de noms app-b.
  • Le filtre d’étiquette zone=c exclut a-gateway parce qu’il se trouve dans app-a mais qu’il est étiqueté zone=a.

L’opérateur Routage des applications publie un nouvel enregistrement A pour c.${ZONE_NAME}:

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

Vérifier le trafic HTTPS terminé par TLS

Résolvez le nom d'hôte de Gateway via le serveur de noms faisant autorité de la zone DNS Azure, puis envoyez une requête 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"

Vous devriez voir une HTTP/2 200 réponse. Le certificat TLS présenté par la passerelle est celui synchronisé à partir de Azure Key Vault. Si vous avez importé un certificat signé par une autorité de certification, remplacez-le -k--cacert <path-to-ca-chain> pour valider la chaîne de certificats.

Note

L’exemple utilise curl --resolve pour contourner la résolution DNS locale et diriger la requête vers l’adresse IP externe de la passerelle. Cette méthode est utile pour les tests avant de déléguer la zone DNS à un bureau d’enregistrement. Pour une utilisation en production, configurez votre bureau d’enregistrement de domaines pour déléguer la zone aux serveurs de noms Azure DNS retournés par az network dns zone show --query 'nameServers'.

Limitations

  • Les intégrations DNS et TLS s’appliquent uniquement aux ressources Gateway qui utilisent une GatewayClass gérée : approuting-istio (l’implémentation de l’API Application Routing Gateway) ou istio (le module complémentaire Istio service mesh). Gateway les ressources qui utilisent une autre classe de passerelle ne sont pas prises en charge.
  • Une ressource ClusterExternalDNS ou une ressource personnalisée ExternalDNS peut faire référence à jusqu’à sept zones DNS Azure via dnsZoneResourceIDs. Toutes les zones référencées dans une ressource personnalisée unique doivent se trouver dans le même abonnement Azure et groupe de ressources. Ils doivent également être du même type (public ou privé).
  • L’instance managée external-dns ne supprime pas automatiquement les enregistrements DNS lorsque vous supprimez la ressource personnalisée ClusterExternalDNS ou ExternalDNS. Pour supprimer les enregistrements orphelins, supprimez-les directement de la zone Azure DNS après la suppression de la ressource personnalisée.
  • La réconciliation des enregistrements DNS issus de ressources TLSRoute n’est actuellement pas prise en charge. L’instance gérée external-dns ne récupère des enregistrements qu’à partir des ressources Gateway, HTTPRoute et GRPCRoute.

Étapes suivantes