Uso de TLS con un controlador de entrada en Azure Kubernetes Service (AKS)

La seguridad de la capa de transporte (TLS) es un protocolo que proporciona seguridad en la comunicación, como el cifrado, la autenticación y la integridad, mediante certificados. El uso de TLS con un controlador de entrada en AKS le permite proteger la comunicación entre las aplicaciones, a la vez que presenta las ventajas de un controlador de entrada.

Puede traer sus propios certificados e integrarlos con el controlador CSI del almacén de secretos. Como alternativa, también puede usar cert-manager, que se utiliza para generar y configurar automáticamente los certificados de Let's Encrypt. Por último, en el clúster de AKS se ejecutan dos aplicaciones, a las que se puede acceder con una sola dirección IP.

Nota:

Hay dos controladores de entrada de código abierto para Kubernetes basados en Nginx: uno lo mantiene la comunidad de Kubernetes (kubernetes/ingress-nginx) y el otro, NGINX, Inc. (nginxinc/kubernetes-ingress). En este artículo se usa el controlador de entrada de la comunidad de Kubernetes.

Antes de empezar

En este artículo también se supone que tiene configurado un controlador de entrada y aplicaciones. Si necesita un controlador de entrada o aplicaciones de ejemplo, consulte Creación de un controlador de entrada.

En este artículo se usa Helm 3 para instalar el controlador de entrada NGINX en una versión de Kubernetes compatible. Asegúrese de que usa la versión más reciente de Helm y de que tiene acceso a los repositorios ingress-nginx y jetstack de Helm. Es posible que los pasos descritos en este artículo no sean compatibles con versiones anteriores del gráfico de Helm, el controlador de entrada NGINX o Kubernetes.

Para obtener más información sobre cómo configurar y usar Helm, consulte Instalación de aplicaciones con Helm en Azure Kubernetes Service (AKS). Para obtener instrucciones de actualización, vea la documentación de instalación de Helm.

Además, en este artículo se da por hecho que ya tiene un clúster de AKS con Azure Container Registry (ACR) integrado. Para una información más detallada sobre cómo crear un clúster de AKS con ACR integrado, consulte Autenticación con Azure Container Registry desde Azure Kubernetes Service.

En este artículo también se requiere que ejecute la versión 2.0.64 de la CLI de Azure o una versión posterior. Ejecute az --version para encontrar la versión. Si necesita instalarla o actualizarla, vea Instalación de la CLI de Azure.

Uso de TLS con sus propios certificados con el controlador CSI del almacén de secretos

Para utilizar TLS con sus propios certificados con el controlador CSI del almacén de secretos, necesitará un clúster de AKS con el controlador CSI del almacén de secretos configurado y una instancia de Azure Key Vault. Para más información, consulte Configuración del controlador CSI del almacén de secretos para habilitar el controlador de entrada NGINX con TLS.

Uso de TLS con certificados de Let's Encrypt

Para utilizar TLS con los certificados de Let's Encrypt, implementará cert-manager, que se usa para generar y configurar automáticamente los certificados de Let's Encrypt.

Importación de las imágenes de cert-manager usadas por el gráfico de Helm a ACR

Use az acr import para importar esas imágenes en el ACR.

REGISTRY_NAME=<REGISTRY_NAME>
CERT_MANAGER_REGISTRY=quay.io
CERT_MANAGER_TAG=v1.8.0
CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller
CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook
CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector

az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG

Nota

Además de importar imágenes de contenedor en el ACR, también puede importar gráficos de Helm en el ACR. Para más información, consulte Inserción y extracción de gráficos de Helm en Azure Container Registry.

Opciones de configuración del controlador de entrada

De manera predeterminada, se crea un controlador de entrada NGINX con una asignación de una nueva dirección IP pública. Esta dirección IP pública solo es estática mientras esté vigente el controlador de entrada y se pierde si el controlador se elimina y se vuelve a crear.

Tiene la opción de elegir uno de los métodos siguientes:

  • Uso de una dirección IP pública dinámica
  • Uso de una dirección IP pública estática

Uso de una dirección IP pública estática

Un requisito de configuración común es proporcionar una dirección IP pública estática existente al controlador de entrada NGINX. La dirección IP pública estática se conserva si se elimina el controlador de entrada.

Los comandos siguientes crean una dirección IP que se eliminará si suprime el clúster de AKS.

Obtenga primero el nombre del grupo de recursos del clúster de AKS con el comando az aks show:

az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv

Después, cree una dirección IP pública con el método de asignación estático mediante el comando az network public-ip create. En el ejemplo siguiente se crea una dirección IP pública denominada myAKSPublicIP en el grupo de recursos del clúster AKS obtenido en el paso anterior:

az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv

Como alternativa, puede crear una dirección IP en otro grupo de recursos que se pueda administrar de forma independiente del clúster de AKS. Si crea una dirección IP en otro grupo de recursos, asegúrese de que lo siguiente sea verdadero:

  • La identidad de clúster que usa el clúster de AKS tiene permisos delegados para el grupo de recursos, como Colaborador de la red.
  • Agregue el parámetro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>". Reemplace <RESOURCE_GROUP> por el nombre del grupo de recursos donde reside la dirección IP.

Al actualizar el controlador de entrada, debe pasar un parámetro a la versión de Helm para que el controlador de entrada tenga en cuenta la dirección IP estática del equilibrador de carga que se va a asignar al servicio del controlador de entrada. Para que los certificados HTTPS funcionen correctamente, se usa una etiqueta de nombre DNS para configurar un FQDN para la dirección IP del controlador de entrada.

  1. Agregue el parámetro --set controller.service.loadBalancerIP="<EXTERNAL_IP>". Especifique su propia dirección IP pública creada en el paso anterior.
  2. Agregue el parámetro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>". La etiqueta DNS se puede establecer cuando el controlador de entrada se implementa por primera vez, o bien más adelante.
DNS_LABEL="demo-aks-ingress"
NAMESPACE="ingress-basic"
STATIC_IP=<STATIC_IP>

helm upgrade nginx-ingress ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL \
  --set controller.service.loadBalancerIP=$STATIC_IP

Para obtener más información, consulte Uso de una dirección IP pública estática y una etiqueta DNS con el equilibrador de carga de AKS.

Uso de una dirección IP dinámica

Cuando se crea el controlador de entrada, se crea una dirección IP pública de Azure para ese controlador. Esta dirección IP pública es estática durante el período de vida del controlador de entrada. Si elimina el controlador de entrada, se pierde la asignación de dirección IP pública. Si después crea otro controlador de entrada, se asigna una dirección IP pública nueva.

Para obtener la dirección IP pública, use el comando kubectl get service.

kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller

En la salida de ejemplo se muestran los detalles sobre el controlador de entrada:

NAME                                     TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE   SELECTOR
nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.74.133   EXTERNAL_IP     80:32486/TCP,443:30953/TCP   44s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx

Si usa un dominio personalizado, deberá agregar un registro D a la zona DNS. De lo contrario, deberá configurar la dirección IP pública con un nombre de dominio completo (FQDN).

Adición de un registro A a la zona DNS

Agregue un registro A a la zona DNS con la dirección IP externa del servicio de NGINX mediante az network dns record-set a add-record.

az network dns record-set a add-record \
    --resource-group myResourceGroup \
    --zone-name MY_CUSTOM_DOMAIN \
    --record-set-name "*" \
    --ipv4-address MY_EXTERNAL_IP

Configuración de un FQDN para el controlador de entrada

Si quiere, puede configurar un FQDN para la dirección IP del controlador de entrada en lugar de un dominio personalizado. Este FQDN tendrá el formato <CUSTOM LABEL>.<AZURE REGION NAME>.cloudapp.azure.com.

Método 1: Establecimiento de la etiqueta DNS mediante la CLI de Azure

Este ejemplo es para un shell de Bash.

# Public IP address of your ingress controller
IP="MY_EXTERNAL_IP"

# Name to associate with public IP address
DNSNAME="demo-aks-ingress"

# Get the resource-id of the public ip
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)

# Update public ip address with DNS name
az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME

# Display the FQDN
az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv

Método 2: Establecimiento de la etiqueta DNS mediante la configuración del gráfico de Helm

Puede pasar una configuración de anotación a la configuración del gráfico de Helm mediante el parámetro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name". Este parámetro se puede establecer cuando el controlador de entrada se implementa por primera vez, o bien más adelante. En el ejemplo siguiente se muestra cómo actualizar esta configuración una vez implementado el controlador.

DNS_LABEL="demo-aks-ingress"
NAMESPACE="ingress-basic"

helm upgrade nginx-ingress ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL

Instalar cert-manager

El controlador de entrada NGINX es compatible con la terminación de TLS. Hay varias maneras de recuperar y configurar certificados para HTTPS. En este artículo se muestra cómo utilizar cert manager, que proporciona la generación automática de certificados Lets Encrypt y la funcionalidad de administración.

Para instalar el controlador cert-manager:

# Set variable for ACR location to use for pulling images
ACR_URL=<REGISTRY_URL>

# Label the ingress-basic namespace to disable resource validation
kubectl label namespace ingress-basic cert-manager.io/disable-validation=true

# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update your local Helm chart repository cache
helm repo update

# Install the cert-manager Helm chart
helm install cert-manager jetstack/cert-manager \
  --namespace ingress-basic \
  --version $CERT_MANAGER_TAG \
  --set installCRDs=true \
  --set nodeSelector."kubernetes\.io/os"=linux \
  --set image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CONTROLLER \
  --set image.tag=$CERT_MANAGER_TAG \
  --set webhook.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_WEBHOOK \
  --set webhook.image.tag=$CERT_MANAGER_TAG \
  --set cainjector.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CAINJECTOR \
  --set cainjector.image.tag=$CERT_MANAGER_TAG

Para obtener más información sobre la configuración cert-manager, consulte el proyecto cert-manager.

Creación de un emisor de clúster de entidad de certificación

Para poder emitir certificados, cert-manager requiere un recurso Issuer o ClusterIssuer. La funcionalidad de los recursos de Kubernetes es idéntica, pero Issuer funciona en un espacio de nombres único, mientras que ClusterIssuer funciona en todos los espacios de nombres. Para obtener más información, consulte la documentación de cert-manager issuer.

Cree un emisor de clúster, como cluster-issuer.yaml, con el manifiesto de ejemplo siguiente. Actualice la dirección de correo electrónico con una dirección válida de su organización:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: MY_EMAIL_ADDRESS
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - http01:
        ingress:
          class: nginx
          podTemplate:
            spec:
              nodeSelector:
                "kubernetes.io/os": linux

Para crear el emisor, use el comando kubectl apply.

kubectl apply -f cluster-issuer.yaml

Actualización de las rutas de entrada

Deberá actualizar las rutas de entrada para administrar el tráfico al nombre de dominio completo o al dominio personalizado.

En el ejemplo siguiente, el tráfico a la dirección hello-world-ingress.MY_CUSTOM_DOMAIN se enruta al servicio aks-helloworld-one. El tráfico a la dirección hello-world-ingress.MY_CUSTOM_DOMAIN/hello-world-two se enruta al servicio aks-helloworld-two. El tráfico a hello-world-ingress.MY_CUSTOM_DOMAIN/static se enruta al servicio denominado aks-helloworld-one para los recursos estáticos.

Nota

Si ha configurado FQDN para la dirección IP del controlador de entrada en lugar de un dominio personalizado, use FQDN en lugar de hello-world-ingress.MY_CUSTOM_DOMAIN. Por ejemplo, si FQDN es demo-aks-ingress.eastus.cloudapp.azure.com, reemplace hello-world-ingress.MY_CUSTOM_DOMAIN por demo-aks-ingress.eastus.cloudapp.azure.com en hello-world-ingress.yaml.

Cree o actualice el archivo hello-world-ingress.yaml con el siguiente ejemplo de YAML. Actualice los spec.tls.hosts y el spec.rules.host al nombre DNS que creó en un paso anterior.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/use-regex: "true"
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    http:
      paths:
      - path: /hello-world-one(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80
      - path: /hello-world-two(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-two
            port:
              number: 80
      - path: /(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port:
              number: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress-static
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /static/$2
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    http:
      paths:
      - path: /static(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port: 
              number: 80

Actualice el recurso de entrada con el comando kubectl apply.

kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic

Verificación de la creación de un objeto de certificado

A continuación, se debe crear un recurso de certificado. El recurso de certificado define el certificado X.509 deseado. Para obtener más información, consulte los certificados de cert-manager. Es probable que el elemento cert-manager haya creado automáticamente un objeto de certificado mediante las correcciones de compatibilidad (shim) de entrada, que se implementan automáticamente con el elemento cert-manager desde v0.2.2. Para obtener más información, consulte la documentación sobre corrección de compatibilidad (shim) de entrada.

Para verificar que el certificado se haya creado correctamente, use el comando kubectl get certificate --namespace ingress-basic y compruebe que la opción LISTO esté establecida en True, lo que puede tardar varios minutos.

kubectl get certificate --namespace ingress-basic

En la salida de ejemplo siguiente se muestra el estado del certificado:

NAME         READY   SECRET       AGE
tls-secret   True    tls-secret   11m

Prueba de la configuración de entrada

Abra un explorador web en la dirección hello-world-ingress.MY_CUSTOM_DOMAIN o el nombre de dominio completo del controlador de entrada de Kubernetes. Tenga en cuenta que se le redirige al uso de HTTPS, que el certificado es de confianza, y la aplicación de demostración se muestra en el explorador web. Agregue la ruta de acceso /hello-world-two y observe que se muestra la segunda aplicación de demostración con el título personalizado.

Limpieza de recursos

En este artículo, se usa Helm para instalar los componentes de entrada, los certificados y las aplicaciones de ejemplo. Al implementar un gráfico de Helm, se crean muchos recursos de Kubernetes. Estos recursos incluyen pods, implementaciones y servicios. Para limpiar estos recursos, puede eliminar el espacio de nombres de ejemplo completo o los recursos individuales.

Eliminación del espacio de nombres de ejemplo y de todos los recursos

Para eliminar el espacio de nombres de ejemplo completo, use el comando kubectl delete y especifique el nombre del espacio de nombres. Todos los recursos del espacio de nombres se eliminan.

kubectl delete namespace ingress-basic

Eliminación de recursos individualmente

Como alternativa, un enfoque más pormenorizado consiste en eliminar los recursos individuales creados. En primer lugar, quite los recursos del emisor del clúster:

kubectl delete -f cluster-issuer.yaml --namespace ingress-basic

Despliegue una lista de las versiones de Helm con el comando helm list. Busque los gráficos denominados nginx y cert-manager, tal y como se muestra en la salida del ejemplo siguiente:

$ helm list --namespace ingress-basic

NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
cert-manager            ingress-basic   1               2020-01-15 10:23:36.515514 -0600 CST    deployed        cert-manager-v0.13.0    v0.13.0    
nginx                   ingress-basic   1               2020-01-15 10:09:45.982693 -0600 CST    deployed        nginx-ingress-1.29.1    0.27.0  

Desinstale las versiones con el comando helm uninstall. En el ejemplo siguiente se desinstalan las implementaciones de entrada de NGINX y de cert-manager.

$ helm uninstall cert-manager nginx --namespace ingress-basic

release "cert-manager" uninstalled
release "nginx" uninstalled

Luego, quite las dos aplicaciones de ejemplo:

kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic

Elimine la ruta de entrada que dirige el tráfico a las aplicaciones de ejemplo:

kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic

Por último, puede eliminar el propio espacio de nombres. Use el comando kubectl delete y especifique el nombre del espacio de nombres:

kubectl delete namespace ingress-basic

Pasos siguientes

En este artículo se incluyen algunos componentes externos a AKS. Para más información sobre estos componentes, consulte las siguientes páginas del proyecto:

También puede: