Usare TLS con un controller in ingresso nel servizio Azure Kubernetes

Il protocollo TLS (Transport Layer Security) usa certificati per garantire la sicurezza delle comunicazioni, la crittografia, l'autenticazione e l'integrità. L'uso di TLS con un controller in ingresso del servizio Azure Kubernetes consente di proteggere le comunicazioni tra le applicazioni e di usufruire dei vantaggi di un controller in ingresso.

È possibile usare certificati personalizzati e integrarli con il driver CSI dell'archivio segreti. In alternativa, è possibile usare cert-manager, che genera e configura automaticamente i certificati Let's Encrypt. Vengono eseguite due applicazioni nel cluster del servizio Azure Kubernetes, ognuna delle quali è accessibile tramite un singolo indirizzo IP.

Importante

È consigliabile usare il componente aggiuntivo Instradamento dell’applicazione per l'ingresso nel servizio Azure Kubernetes. Per ulteriori informazioni, consultare Ingresso nginx gestito con il componente aggiuntivo Instradamento dell’applicazione.

Importante

Microsoft non gestisce o supporta cert-manager e eventuali problemi derivanti dal suo uso. Per problemi relativi a cert-manager, vedere la documentazione sulla risoluzione dei problemi di cert-manager.

Sono disponibili due controller in ingresso open source per Kubernetes basati su Nginx: uno gestito dalla community di Kubernetes (kubernetes/ingress-nginx) e uno gestito da NGINX, Inc. (nginxinc/kubernetes-ingress). In questo articolo si fa riferimento al controller in ingresso della community Kubernetes.

Operazioni preliminari

  • Questo articolo presuppone che il controller in ingresso e le applicazioni siano stati configurati. Per un esempio di controller in ingresso o delle applicazioni, vedere Creare un controller in ingresso.

  • In questo articolo viene usato Helm 3 per installare il controller in ingresso NGINX in una versione supportata di Kubernetes. Assicurarsi di usare la versione più recente di Helm e di avere accesso ai repository Helm ingress-nginx e jetstack. I passaggi descritti in questo articolo potrebbero non essere compatibili con le versioni precedenti del grafico Helm, del controller in ingresso NGINX o di Kubernetes.

  • Questo articolo presuppone che sia già presente un cluster del servizio Azure Kubernetes con un servizio Registro Azure Container (ACR) integrato. Per altre informazioni sulla creazione di un cluster del servizio Azure Kubernetes con un servizio Registro Azure Container integrato, vedere Eseguire l'autenticazione con Registro Azure Container dal servizio Azure Kubernetes.

  • In questo articolo si presuppone che sia in esecuzione l’interfaccia della riga di comando di Azure versione 2.0.64 o versione successiva se si usa l'interfaccia della riga di comando di Azure. Eseguire az --version per trovare la versione. Se è necessario eseguire l'installazione o l'aggiornamento, vedere Installare l'interfaccia della riga di comando di Azure.

  • In questo articolo si presuppone che sia in esecuzione Azure PowerShell versione 5.9.0 o una versione successiva se si usa Azure PowerShell. Eseguire Get-InstalledModule -Name Az per trovare la versione. Se è necessario eseguire l'installazione o l'aggiornamento, vedere Installare Azure PowerShell.

Usare TLS con certificati personalizzati con il driver CSI dell'archivio segreti

Per usare TLS con certificati personalizzati con il driver CSI dell'archivio segreti, è necessario un cluster del servizio Azure Kubernetes con il driver CSI dell'archivio segreti configurato e un'istanza di Azure Key Vault.

Per altre informazioni, vedere Configurare il driver CSI dell'archivio segreti per abilitare il controller in ingresso NGINX con TLS.

Usare TLS con i certificati Let's Encrypt

Per usare TLS con i certificati Let's Encrypt, è necessario distribuire cert-manager, che genera e configura automaticamente i certificati Let's Encrypt.

Importare le immagini cert-manager usate dal grafico Helm in Registro Azure Container

  • Usare az acr import per importare le immagini seguenti in Registro Azure Container.

    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

È anche possibile importare grafici Helm in Registro Azure Container. Per altre informazioni, vedere Eseguire il push e il pull dei grafici Helm in Registro Azure Container.

Opzioni di configurazione per il controller in ingresso

È possibile configurare il controller in ingresso NGINX usando un indirizzo IP pubblico statico o un indirizzo IP pubblico dinamico. Se si usa un dominio personalizzato, è necessario aggiungere un record A alla zona DNS. Se non si usa un dominio personalizzato, è possibile configurare un nome di dominio completo (FQDN) per l'indirizzo IP del controller in ingresso.

Creare un indirizzo IP pubblico statico o dinamico

Usare un indirizzo IP pubblico statico

È possibile configurare il controller in ingresso con un indirizzo IP pubblico statico. L'indirizzo IP pubblico statico viene mantenuto dopo l’eliminazione del controller in ingresso. L'indirizzo IP non viene mantenuto se si elimina il cluster del servizio Azure Kubernetes.

Quando si aggiorna il controller in ingresso, è necessario passare un parametro alla versione Helm per assicurarsi che il servizio del controller in ingresso sia informato del servizio di bilanciamento del carico che verrà allocato. Per un uso corretto dei certificati HTTPS, è necessario configurare un nome di dominio completo per l'indirizzo IP del controller in ingresso.

  1. Ottenere il nome del gruppo di risorse del cluster del servizio Azure Kubernetes con il comando az aks show.

    az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv
    
  2. Creare un indirizzo IP pubblico con il metodo di allocazione statica usando il comando az network public-ip create. Nell'esempio seguente viene creato un indirizzo IP pubblico denominato myservizio Azure KubernetesPublicIP nel gruppo di risorse cluster servizio Azure Kubernetes ottenuto nel passaggio precedente.

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

Nota

In alternativa, è possibile creare un indirizzo IP in un gruppo di risorse diverso, che è possibile gestire separatamente dal cluster del servizio Azure Kubernetes. Se si crea un indirizzo IP in un gruppo di risorse diverso, verificare che siano soddisfatte le condizioni seguenti:

  • L'identità del cluster usata dal cluster del servizio Azure Kubernetes ha autorizzazioni delegate per il gruppo di risorse, ad esempio Collaboratore rete.
  • Aggiungere il parametro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>". Sostituire <RESOURCE_GROUP> con il nome del gruppo di risorse in cui risiede l'indirizzo IP.
  1. Aggiungere il parametro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>". È possibile impostare l'etichetta DNS durante la prima distribuzione del controller in ingresso oppure configurarlo in un secondo momento.

  2. Aggiungere il parametro --set controller.service.loadBalancerIP="<STATIC_IP>". Specificare l’indirizzo IP pubblico creato nel passaggio precedente.

    DNS_LABEL="<DNS_LABEL>"
    NAMESPACE="ingress-basic"
    STATIC_IP=<STATIC_IP>
    
    helm upgrade ingress-nginx 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 \
      --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz
    

Per altre informazioni, vedere Usare un indirizzo IP pubblico statico e un'etichetta DNS con il servizio di bilanciamento del carico del servizio Azure Kubernetes.

Usare un indirizzo IP pubblico dinamico

Al momento della creazione viene creato un indirizzo IP pubblico di Azure per il controller in ingresso. L'indirizzo IP pubblico è statico per la durata del controller in ingresso. L'indirizzo IP pubblico non viene mantenuto se si elimina il controller in ingresso. Se si crea un nuovo controller in ingresso, verrà assegnato un nuovo indirizzo IP pubblico. L'output dovrebbe essere simile al seguente esempio.

  • Usare il comando kubectl get service per ottenere l'indirizzo IP pubblico per il controller in ingresso.

    # Get the public IP address for your ingress controller
    
    kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller
    
    # Sample output
    
    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
    

Aggiungere un record A alla zona DNS

Se si usa un dominio personalizzato, è necessario aggiungere un record A alla zona DNS. Se non si usa un dominio personalizzato, è possibile configurare l'indirizzo IP pubblico con un nome di dominio completo.

  • Aggiungere un record A alla zona DNS con l'indirizzo IP esterno del servizio NGINX usando 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
    

Configurare un nome di dominio completo per il controller in ingresso

Facoltativamente, è possibile configurare un nome di dominio completo per l'indirizzo IP del controller in ingresso anziché un dominio personalizzato impostando un'etichetta DNS. Il nome di dominio completo deve seguire questo formato: <CUSTOM DNS LABEL>.<AZURE REGION NAME>.cloudapp.azure.com.

Importante

L'etichetta DNS deve essere univoca all'interno della posizione di Azure.

È possibile configurare il nome di dominio completo usando uno dei metodi seguenti:

  • Impostare l'etichetta DNS usando l'interfaccia della riga di comando di Azure o Azure PowerShell.
  • Impostare l'etichetta DNS usando le impostazioni del grafico Helm.

Per altre informazioni, vedere Etichette dei nomi DNS per l'indirizzo IP pubblico.

Impostare l'etichetta DNS usando l'interfaccia della riga di comando di Azure o Azure PowerShell

Assicurarsi di sostituire <DNS_LABEL> con l'etichetta DNS univoca.

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

# Name to associate with public IP address
DNSLABEL="<DNS_LABEL>"

# 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 $DNSLABEL

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

Impostare l'etichetta DNS usando le impostazioni del grafico Helm

È possibile passare un'impostazione di annotazione alla configurazione del grafico Helm usando il parametro --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name". È possibile impostare questo parametro durante la prima distribuzione del controller in ingresso oppure configurarlo in un secondo momento.

Nell'esempio seguente viene illustrato come aggiornare questa impostazione dopo la distribuzione del controller. Assicurarsi di sostituire <DNS_LABEL> con l'etichetta DNS univoca.

DNSLABEL="<DNS_LABEL>"
NAMESPACE="ingress-basic"

helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNSLABEL \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz

Installare cert-manager

Il controller di ingresso NGINX supporta la terminazione TLS. Esistono diversi modi per recuperare e configurare i certificati per HTTPS. Questo articolo descrive l'uso di cert-manager, che consente di generare automaticamente il certificato Let's Encrypt e che dispone di funzionalità di gestione.

Per installare il controller di cert-manager, usare i comandi seguenti.

# 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

Per altre informazioni sulla configurazione di cert-manager, vedere progetto cert-manager.

Creare un'autorità di certificazione (CA) cluster

Prima del rilascio dei certificati, cert-manager richiede una delle seguenti autorità di certificazione:

Per altre informazioni, vedere la documentazione relativa all'autorità di certificazione cert-manager.

  1. Creare un'autorità di certificazione del cluster, ad esempio cluster-issuer.yaml, tramite il manifesto di esempio seguente. Sostituire MY_EMAIL_ADDRESS con un indirizzo valido dell'organizzazione.

    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
    
  2. Applicare l'autorità di certificazione usando il comando kubectl apply.

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

Aggiornare le route in ingresso

È necessario aggiornare le route in ingresso per gestire il traffico verso il nome di dominio completo o il dominio personalizzato.

Nell'esempio seguente il traffico viene instradato come tale:

  • Il traffico diretto a hello-world-ingress.MY_CUSTOM_DOMAIN viene instradato al servizio aks-helloworld-one.
  • Il traffico diretto a hello-world-ingress.MY_CUSTOM_DOMAIN/hello-world-two viene instradato al servizio aks-helloworld-two.
  • Il traffico diretto a hello-world-ingress.MY_CUSTOM_DOMAIN/static viene instradato al servizio denominato aks-helloworld-one per gli asset statici.

Nota

Se è stato configurato un nome di dominio completo per l'indirizzo IP del controller in ingresso anziché un dominio personalizzato, usare il nome di dominio completo anziché hello-world-ingress.MY_CUSTOM_DOMAIN.

Ad esempio, se il nome di dominio completo è demo-aks-ingress.eastus.cloudapp.azure.com, sostituire hello-world-ingress.MY_CUSTOM_DOMAIN con demo-aks-ingress.eastus.cloudapp.azure.com in hello-world-ingress.yaml.

  1. Creare o aggiornare il file hello-world-ingress.yaml usando il file YAML di esempio seguente. Aggiornare spec.tls.hosts e spec.rules.host al nome DNS creato in un passaggio precedente.

    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
    
  2. Creare la risorsa in ingresso con il comando kubectl apply.

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

Verificare che sia stato creato un oggetto certificato

Successivamente, è necessario creare una risorsa certificato. La risorsa certificato definisce il certificato X.509 desiderato. Per altre informazioni, vedere cert-manager certificates (Certificati cert-manager).

Cert-manager crea utomaticamente un oggetto certificato per l'uso in ingress-shim, che viene distribuito automaticamente con cert-manager dalla versione 0.2.2. Per altre informazioni, consultare la documentazione su ingress-shim.

Per verificare che il certificato sia stato creato correttamente, usare il comando kubectl get certificate --namespace ingress-basic e verificare che READY sia impostato su True. Potrebbero essere necessari alcuni minuti per ottenere l'output.

kubectl get certificate --namespace ingress-basic

L'output seguente mostra lo stato del certificato.

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

Testare la configurazione di ingresso

Aprire un Web browser visualizzando hello-world-ingress.MY_CUSTOM_DOMAIN o il nome di dominio completo del controller in ingresso Kubernetes. Accertarsi che si verifichino le condizioni seguenti:

  • Si venga reindirizzati all'uso di HTTPS.
  • Il certificato sia attendibile.
  • L'applicazione demo venga visualizzata nel Web browser.
  • Aggiungere /hello-world-two alla fine del dominio e assicurarsi che venga visualizzata la seconda applicazione demo con il titolo personalizzato.

Pulire le risorse

Questo articolo ha usato Helm per installare i componenti di ingresso, i certificati e le app di esempio. Quando si distribuisce un grafico Helm, vengono create numerose risorse Kubernetes. Queste risorse includono pod, distribuzioni e servizi. Per pulire queste risorse, è possibile eliminare l'intero spazio dei nomi di esempio o eliminare le risorse singolarmente.

Eliminare lo spazio dei nomi di esempio e tutte le risorse

L'eliminazione dello spazio dei nomi di esempio elimina anche tutte le risorse nello spazio dei nomi .

  • Per eliminare l'intero spazio dei nomi di esempio, usare il comando kubectl delete e specificare il nome dello spazio dei nomi.

    kubectl delete namespace ingress-basic
    

Eliminare le risorse singolarmente

In alternativa, è possibile eliminare la risorsa singolarmente.

  1. Rimuovere le risorse dell'autorità di certificazione del cluster.

    kubectl delete -f cluster-issuer.yaml --namespace ingress-basic
    
  2. Elencare le versioni di Helm con il comando helm list. Cercare i grafici denominati nginx e cert-manager, come illustrato nell'output di esempio seguente.

    $ 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
    
  3. Disinstallare le versioni usando il comando helm uninstall. L'esempio mostra la disinstallazione delle distribuzioni NGINX in ingresso e di cert-manager.

    $ helm uninstall cert-manager nginx --namespace ingress-basic
    
    release "cert-manager" uninstalled
    release "nginx" uninstalled
    
  4. Successivamente, rimuovere le due applicazioni di esempio.

    kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
    kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic
    
  5. Rimuovere la route in ingresso che ha indirizzato il traffico verso le app di esempio.

    kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic
    
  6. Eliminare lo spazio dei nomi stesso. Usare il comando kubectl delete e specificare il nome dello spazio dei nomi.

    kubectl delete namespace ingress-basic
    

Passaggi successivi

In questo articolo sono stati inclusi alcuni componenti esterni ad servizio Azure Kubernetes. Per altre informazioni su questi componenti, vedere le pagine di progetto seguenti:

È anche possibile: