Configuración de Azure DNS y TLS con la implementación de la API de Application Routing Gateway

Con la API de Application Routing Gateway, los usuarios pueden exponer fácilmente aplicaciones HTTPS en AKS con sus propios certificados de Azure Key Vault, incluida la publicación automática de nombres de dominio. El operador de enrutamiento de aplicaciones se integra con Azure DNS y Azure Key Vault, y reconcilia un SecretProviderClass, un secreto de Kubernetes para certificados TLS, el campo de escucha certificateRefs y la implementación independienteexternal-dns, por lo que no tiene que administrar estos recursos manualmente.

En este artículo aprenderá a:

  • Aprovisione los recursos previos de Azure necesarios (zona DNS de Azure, Azure Key Vault, identidad administrada asignada por el usuario, asignaciones de roles y credenciales de identidad federadas).
  • Configure un agente de escucha Gateway para realizar la terminación de TLS mediante un certificado almacenado en Azure Key Vault a través de las opciones de TLS del agente kubernetes.azure.com/tls-cert-keyvault-uri y kubernetes.azure.com/tls-cert-service-account.
  • Use los recursos personalizados ClusterExternalDNS y ExternalDNS para publicar registros DNS en Azure DNS en función de los nombres de host de sus recursos Gateway, HTTPRoute y GRPCRoute.

Funcionamiento de la integración

El operador de enrutamiento de aplicaciones expone dos integraciones para automatizar los recursos que, de otro modo, crearía manualmente para poner en línea un recurso Gateway con un dominio personalizado y la terminación de TLS.

Integración de TLS

Cuando un recurso Gateway usa una GatewayClass administrada, ya sea approuting-istio (de la implementación de la API de puerta de enlace de enrutamiento de aplicaciones) o istio (del complemento de malla de servicio Istio), y un agente de escucha incluye las dos opciones de TLS siguientes, el operador de enrutamiento de aplicaciones se encarga de conciliar los recursos necesarios para finalizar TLS mediante un certificado almacenado en Azure Key Vault:

Clave de opción TLS Value
kubernetes.azure.com/tls-cert-keyvault-uri URI del certificado de Azure Key Vault desde el que obtener el certificado TLS. Use un URI sin inversión (por ejemplo, https://<vault>.vault.azure.net/certificates/<cert>) para que el operador recoja automáticamente las rotaciones de certificados en Azure Key Vault.
kubernetes.azure.com/tls-cert-service-account Nombre de una instancia de Kubernetes ServiceAccount en el mismo espacio de nombres que Gateway. La ServiceAccount debe estar vinculada a una identidad administrada asignada por el usuario mediante Microsoft Entra Workload Identity, y esa identidad administrada debe tener el rol Key Vault Secrets User en la instancia de Azure Key Vault de destino.

Para cada listener que incluye ambas opciones de TLS, el operador:

  1. Aprovisiona un SecretProviderClass llamado kv-gw-cert-<gateway-name>-<listener-name> en el espacio de nombres de Gateway, configurado para obtener el certificado desde Azure Key Vault mediante autenticación de identidad de carga de trabajo.
  2. Activa el proveedor de Azure Key Vault para Secrets Store CSI Driver para sincronizar el certificado como un secreto de Kubernetes kubernetes.io/tls con el mismo nombre en el espacio de nombres de Gateway.
  3. Aplica un parche al campo del agente de escucha tls.certificateRefs para que haga referencia al Secret de Kubernetes sincronizado.

Integración de DNS

El operador de enrutamiento de aplicaciones administra una external-dns instancia para usted a través de dos recursos personalizados:

Recurso personalizado Ámbito
ClusterExternalDNS (clusterexternaldnses.approuting.kubernetes.azure.com) Limitado a clúster. Supervisa los recursos Gateway, HTTPRoute y GRPCRoute en todos los espacios de nombres del clúster.
ExternalDNS (externaldnses.approuting.kubernetes.azure.com) Limitado a espacio de nombres. Observa únicamente los recursos Gateway, HTTPRoute y GRPCRoute del mismo espacio de nombres que el recurso personalizado.

Ambos recursos personalizados aceptan selectores opcionales filters para restringir aún más qué recursos observa la instancia administrada external-dns dentro de su ámbito:

Filtro Lo que restringe
filters.gatewayLabels Restringe qué recursos Gateway observa el controlador.
filters.routeAndIngressLabels Restringe los recursos HTTPRoute y Ingress que observa el controlador.

Para cada recurso personalizado, el operador de enrutamiento de aplicaciones:

  1. Implementa una instancia administrada external-dns, configurada para obtener registros de los recursos HTTPRoute y GRPCRoute, y dirigida a las zonas de Azure DNS especificadas.
  2. Se autentica con Azure DNS mediante la Identidad de carga de trabajo de Microsoft Entra, a través de la ServiceAccount a la que se hace referencia en el campo identity del recurso personalizado.
  3. Publica registros A en cada una de las zonas de Azure DNS indicadas para cada nombre de host HTTPRoute o GRPCRoute que esté vinculado a un recurso administrado Gateway dentro del ámbito.

Prerequisites

  • Un clúster de AKS con las dos características siguientes habilitadas:

    • El complemento de enrutamiento de aplicaciones (--enable-app-routing). Este complemento implementa el operador de enrutamiento de aplicaciones en el clúster, que es el componente que reconcilia las integraciones de DNS y TLS documentadas en este artículo. En un clúster existente, también puede habilitar esta característica mediante az aks approuting enable.
    • Una implementación de la API de puerta de enlace administrada con la que el operador se va a integrar. Elija una de las siguientes opciones (las dos opciones son mutuamente excluyentes y no se pueden habilitar al mismo tiempo):

    Para usar estas integraciones, habilite tanto el complemento de enrutamiento de aplicaciones (mediante az aks approuting enable) como una de las implementaciones de api de puerta de enlace administrada enumeradas anteriormente.

  • La instalación de la Managed Gateway API habilitada en el clúster.

  • La característica Identidad de carga de trabajo de Microsoft Entra habilitada en el clúster, junto con el emisor de OIDC. Puede habilitar ambas funciones mediante los indicadores --enable-oidc-issuer y --enable-workload-identity en az aks create o az aks update.

  • Complemento proveedor de Azure Key Vault para Secrets Store CSI Driver habilitado en el clúster. Puede habilitarlo mediante el az aks enable-addons comando con --addons azure-keyvault-secrets-providero pasando --enable-kv a az aks approuting enable o az aks approuting update.

  • CLI de Azure versión 2.86.0 o posterior. Ejecute az --version para buscar la azure-cli versión y ejecute az upgrade para actualizar.

  • Control de acceso basado en roles de Azure (RBAC) suficiente sobre su propia identidad para crear asignaciones de roles y credenciales de identidad federada. El Owner rol o una combinación de Role Based Access Control Administrator y Managed Identity Contributor es suficiente.

Note

Los indicadores --attach-kv y --attach-zones de az aks approuting update (y los subcomandos az aks approuting zone) están diseñados para la experiencia heredada basada en NGINX, en la que a la propia identidad administrada asignada por el usuario del complemento Application Routing se le concede acceso de Azure RBAC a una única instancia de Azure Key Vault y a una zona DNS. No se usan en la integración con la API de Gateway documentada en este artículo. La nueva experiencia se basa en la Identidad de carga de trabajo de Microsoft Entra en lugar de la identidad administrada del complemento, por lo que debe crear su propia identidad administrada asignada por el usuario, concederle los roles adecuados de Azure DNS y Azure Key Vault, y crear credenciales de identidad federadas que la vinculen a las cuentas de servicio de Kubernetes a las que hace referencia en las opciones TLS del agente de escucha de Gateway y en los recursos personalizados ExternalDNS/ClusterExternalDNS.

Establezca las siguientes variables de entorno. El tutorial los reutiliza en todos los comandos siguientes:

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

Extracción de credenciales de clúster para kubectl:

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

Creación de la infraestructura de Azure

Creación de la zona de Azure DNS

Si ya tiene una zona de Azure DNS en la que desea que el operador de enrutamiento de aplicaciones administre los registros, puede omitir este paso y asignar el valor de ZONE_NAME al nombre de la zona existente.

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)

Creación del Azure Key Vault y el certificado

Cree el Azure Key Vault que almacena el certificado TLS. Configure el almacén de claves para usar Azure RBAC para la autorización, que es el modelo de permisos recomendado:

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

Note

Para crear el certificado en el siguiente paso, su propia identidad de Azure necesita el rol Key Vault Certificates Officer (o Key Vault Administrator) en el almacén de claves. Asigne este rol en el almacén de claves antes de continuar.

Crear un certificado comodín autofirmado en Azure Key Vault. En el caso de las implementaciones de producción, importe un certificado firmado por una entidad de certificación (CA) mediante az keyvault certificate import en su lugar.

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

Anote el URI del certificado sin versión. El operador de enrutamiento de aplicaciones usa este URI para configurar el SecretProviderClass. Un URI sin versión garantiza que el operador detecte las nuevas versiones del certificado en Azure Key Vault a medida que el certificado se renueva.

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"

Cree la identidad administrada asignada por el usuario y asigne roles de RBAC de Azure

Cree una identidad administrada asignada por el usuario para que la implementación del operador de Application Routing external-dns y la sincronización TLS de la escucha de la puerta de enlace la usen para autenticarse en Azure DNS y 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)

Asigne a la identidad administrada el rol DNS Zone Contributor sobre la zona DNS de Azure de destino y el rol Key Vault Secrets User sobre el Azure Key Vault de destino:

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)

Crear los espacios de nombres, las cuentas de servicio y las credenciales de identidad federada

Las integraciones TLS y DNS del operador de enrutamiento de aplicaciones se autentican en Azure a través de una instancia de Kubernetes ServiceAccount enlazada a la identidad administrada asignada por el usuario mediante una credencial de identidad federada (FIC). Cada (namespace, ServiceAccount) par que necesita autenticarse requiere un FIC.

Capture la dirección URL del emisor de OIDC del clúster:

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

Para cada espacio de nombres en el que planee implementar un recurso de Gateway que utilice la integración de TLS o un recurso de ExternalDNS, cree el espacio de nombres, una credencial de identidad federada para la ServiceAccount y la propia ServiceAccount. En el ejemplo siguiente se crean dos espacios de nombres, app-a y app-b, cada uno con un ServiceAccount denominado 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

La anotación azure.workload.identity/client-id asocia la ServiceAccount con la identidad administrada, y la etiqueta azure.workload.identity/use: "true" indica al webhook de Microsoft Entra Workload Identity que proyecte un token federado en pods que consumen la ServiceAccount. Ambos son necesarios para que las integraciones TLS y DNS del operador de enrutamiento de aplicaciones se autentiquen correctamente en Azure.

Configuración de la terminación TLS en una puerta de enlace

Implemente una carga de trabajo de ejemplo httpbin en cada espacio de nombres:

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

Cree un Gateway recurso en cada espacio de nombres con un agente de escucha HTTPS que haga referencia al certificado Azure Key Vault a través de las opciones de TLS. Cada Gateway uno usa su propio sub host de la zona Azure DNS (por ejemplo, a.<zone> y b.<zone>):

Note

En los ejemplos de este artículo se usa gatewayClassName: approuting-istio, la clase GatewayClass proporcionada por la implementación de la API de Application Routing Gateway. Si en su lugar ha habilitado el complemento de malla de servicios Istio, establezca gatewayClassName: istio en sus recursos Gateway. Las integraciones de DNS y TLS se comportan de forma idéntica para ambas GatewayClasses gestionadas.

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

Espere a que cada uno Gateway alcance la Programmed condición:

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

Compruebe que el operador Application Routing creó un SecretProviderClass y que el proveedor de Azure Key Vault para Secrets Store CSI Driver sincronizó el certificado como un secreto kubernetes.io/tls en cada espacio de nombres:

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

Salida de ejemplo para un espacio de nombres:

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

Configuración de registros de Azure DNS mediante ClusterExternalDNS

Implemente una instancia de ámbito de clúster external-dns que publique registros A para los recursos Gateway de cualquier espacio de nombres aplicando un recurso personalizado 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

El resourceNamespace campo especifica el espacio de nombres donde el operador de enrutamiento de aplicaciones implementa la instancia administrada external-dns . La ServiceAccount a la que hace referencia identity.serviceAccount debe existir en ese espacio de nombres.

Después de aproximadamente un minuto, dos registros A aparecen en la zona Azure DNS: una para cada 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

Configurar registros de Azure DNS mediante ExternalDNS con ámbito de espacio de nombres

Para publicar registros únicamente para un subconjunto de recursos Gateway, use el recurso personalizado ExternalDNS con ámbito de espacio de nombres. A diferencia de ClusterExternalDNS, la variante con ámbito de espacio de nombres solo observa los recursos Gateway, HTTPRoute y GRPCRoute en el mismo espacio de nombres que el recurso personalizado. Al igual que con ClusterExternalDNS, puede, opcionalmente, restringir aún más el ámbito mediante los selectores filters.gatewayLabels y filters.routeAndIngressLabels.

En primer lugar, elimine el ClusterExternalDNS del paso anterior:

kubectl delete clusterexternaldns demo-cluster-dns

Implemente un nuevo Gateway elemento en app-a con la etiqueta zone: c y un elemento correspondiente 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

Aplique un recurso ExternalDNS de ámbito de espacio de nombres en app-a con un filtro de etiquetas para 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

Se aplican dos reglas de ámbito:

  • El ámbito de espacio de nombres de ExternalDNS excluye b-gateway porque reside en el app-b espacio de nombres.
  • El filtro de etiqueta zone=c excluye a-gateway porque está en app-a pero tiene la etiqueta zone=a.

El operador De enrutamiento de aplicaciones publica un nuevo registro A para c.${ZONE_NAME}:

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

Verifique el tráfico HTTPS terminado en TLS

Resuelva el nombre de host de Gateway mediante el servidor de nombres autoritativo de la zona DNS de Azure y envíe una solicitud 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"

Debería ver una respuesta HTTP/2 200. El certificado TLS que presenta la puerta de enlace es el que se sincroniza desde Azure Key Vault. Si importó un certificado firmado por entidad de certificación, reemplace por -k--cacert <path-to-ca-chain> para validar la cadena de certificados.

Note

En el ejemplo se usa curl --resolve para omitir la resolución DNS local y dirigir la solicitud a la dirección IP externa de la puerta de enlace. Este método es útil para realizar pruebas antes de delegar la zona DNS a un registrador. Para su uso en producción, configure el registrador de dominios para delegar la zona en los servidores de nombres de Azure DNS devueltos por az network dns zone show --query 'nameServers'.

Limitaciones

  • Las integraciones de DNS y TLS solo se aplican a Gateway los recursos que usan una clase GatewayClass administrada: approuting-istio (la implementación de la API de Application Routing Gateway) o istio (el complemento de malla de servicio Istio). Gateway No se admiten recursos que usen ninguna otra clase GatewayClass.
  • Un ClusterExternalDNS recurso personalizado o ExternalDNS puede hacer referencia a hasta siete zonas Azure DNS a través de dnsZoneResourceIDs. Todas las zonas a las que se hace referencia en un único recurso personalizado deben estar en la misma suscripción Azure y grupo de recursos. También deben ser todos del mismo tipo (público o privado).
  • La instancia administrada external-dns no elimina automáticamente los registros DNS al eliminar el ClusterExternalDNS recurso personalizado o ExternalDNS . Para quitar registros huérfanos, elimínelos directamente de la zona de Azure DNS después de eliminar el recurso personalizado.
  • Actualmente no se admite la conciliación de registros DNS de TLSRoute recursos. La instancia administrada external-dns solo obtiene registros de los recursos Gateway, HTTPRoute y GRPCRoute.

Pasos siguientes