Condividi tramite


Usare TLS con un controller di ingresso su Azure Kubernetes Service (AKS)

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

È possibile portare i propri certificati e integrarli con il driver CSI di Secrets Store. 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 delle Applicazioni per l'ingresso in AKS. Per ulteriori informazioni, consultare Ingress nginx gestito con il componente aggiuntivo per il routing delle applicazioni.

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 viene utilizzato il controller di 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 presume che tu abbia un cluster AKS esistente con un Azure Container Registry (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.

  • Se si utilizza l'interfaccia della riga di comando di Azure, questo articolo richiede che sia in esecuzione la versione 2.0.64 o successiva. 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 di Secrets Store

Per usare TLS con i tuoi certificati con il Secrets Store CSI Driver, è necessario disporre di un cluster AKS con il Secrets Store CSI Driver configurato e un'istanza di Azure Key Vault.

Per ulteriori informazioni, vedere Configurare il driver CSI del Secrets Store per abilitare il controller di 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 del cert-manager utilizzate dal chart Helm nel Registro dei Contenitori di Azure.

  • Usa az acr import per importare le seguenti immagini nel tuo 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

È possibile importare anche chart Helm nel Registro Azure Container. Per ulteriori informazioni, vedere Eseguire il push e il pull dei chart Helm in Azure Container Registry.

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 AKS.

Quando si aggiorna il controller di ingresso, è necessario passare un parametro alla release di Helm per assicurarsi che il servizio del controller di ingresso sia informato del bilanciatore di carico che verrà ad esso allocato. Per far funzionare correttamente i certificati HTTPS, utilizza un'etichetta DNS per configurare un FQDN per l'indirizzo IP del controller di ingresso.

  1. Ottenere il nome del gruppo di risorse del cluster AKS 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 myAKSPublicIP nel gruppo di risorse del cluster AKS 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 AKS ha autorizzazioni delegate per il gruppo di risorse, come Contributore di 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 bilanciatore del carico di AKS.

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 di 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 dell'area 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 'emittente del cluster dell'autorità di certificazione (CA)

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

  • Un emittente che funziona in un singolo spazio dei nomi.
  • Una risorsa ClusterIssuer che funziona in tutti i namespace.

Per altre informazioni, vedere la documentazione dell'emittente cert-manager.

  1. Creare un issuer del cluster, come cluster-issuer.yaml, utilizzando il seguente esempio di manifesto. 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'emittente usando il comando kubectl apply.

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

Aggiorna i percorsi di 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 in questo modo:

  • 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. Aggiornare la risorsa di ingresso utilizzando 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 di 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 ulteriori informazioni, vedere la documentazione di 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:

  • Verrai reindirizzato per utilizzare HTTPS.
  • Il certificato è 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.

Elimina lo spazio dei nomi di esempio e tutte le risorse.

Eliminando il namespace di esempio, si eliminano anche tutte le risorse nel namespace.

  • 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'emittente del cluster.

    kubectl delete -f cluster-issuer.yaml --namespace ingress-basic
    
  2. Elenca 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 i rilasci 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 stesso namespace. Utilizzare il comando kubectl delete e specificare il nome del proprio spazio dei nomi.

    kubectl delete namespace ingress-basic
    

Passaggi successivi

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

È anche possibile: