Configurare il driver CSI dell'archivio segreti per abilitare il controller di ingresso NGINX con TLS
Questo articolo illustra il processo di protezione di un controller di ingresso NGINX con TLS con un cluster del servizio Azure Kubernetes e un'istanza di Azure Key Vault (AKV). Per altre informazioni, vedere TLS in Kubernetes.
È possibile importare il certificato TLS in ingresso nel cluster usando uno dei metodi seguenti:
- Applicazione: il manifesto della distribuzione dell'applicazione dichiara e monta il volume del provider. Solo quando si distribuisce l'applicazione è il certificato reso disponibile nel cluster. Quando si rimuove l'applicazione, viene rimosso anche il segreto. Questo scenario si adatta ai team di sviluppo responsabili dell'infrastruttura di sicurezza dell'applicazione e della relativa integrazione con il cluster.
- Controller di ingresso: la distribuzione in ingresso viene modificata per dichiarare e montare il volume del provider. Il segreto viene importato quando vengono creati pod in ingresso. I pod dell'applicazione non hanno accesso al certificato TLS. Questo scenario si adatta agli scenari in cui un team (ad esempio, l'IT) gestisce e crea componenti di infrastruttura e rete (inclusi i certificati TLS HTTPS) e altri team gestiscono il ciclo di vita delle applicazioni.
Prerequisiti
- Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare.
- Prima di iniziare, assicurarsi che la versione dell'interfaccia della riga di comando di Azure sia >=
2.30.0
o installare la versione più recente. - Un cluster del servizio Azure Kubernetes con il driver CSI dell'archivio segreti configurato.
- Una Istanza di Azure Key Vault.
Generare un certificato TLS
Generare un certificato TLS usando il comando seguente.
export CERT_NAME=aks-ingress-cert openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -out aks-ingress-tls.crt \ -keyout aks-ingress-tls.key \ -subj "/CN=demo.azure.com/O=aks-ingress-tls"
Importare il certificato in AKV
Esportare il certificato in un file PFX usando il seguente comando.
export AKV_NAME="[YOUR AKV NAME]" openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key -out $CERT_NAME.pfx # skip Password prompt
Importare il certificato usando il comando
az keyvault certificate import
.az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
Distribuire secretProviderClass
Esportare un nuovo spazio dei nomi usando il comando seguente.
export NAMESPACE=ingress-basic
Creare lo spazio dei nomi usando il comando
kubectl create namespace
.kubectl create namespace $NAMESPACE
Selezionare un metodo per fornire un'identità di accesso e configurare di conseguenza secretProviderClass YAML.
- Assicurarsi di usare
objectType=secret
, che è l'unico modo per ottenere la chiave privata e il certificato da AKV. - Impostare
kubernetes.io/tls
cometype
nella sezionesecretObjects
.
Vedere l'esempio seguente dell'aspetto di SecretProviderClass:
apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: azure-tls spec: provider: azure secretObjects: # secretObjects defines the desired state of synced K8s secret objects - secretName: ingress-tls-csi type: kubernetes.io/tls data: - objectName: $CERT_NAME key: tls.key - objectName: $CERT_NAME key: tls.crt parameters: usePodIdentity: "false" useVMManagedIdentity: "true" userAssignedIdentityID: <client id> keyvaultName: $AKV_NAME # the name of the AKV instance objects: | array: - | objectName: $CERT_NAME objectType: secret tenantId: $TENANT_ID # the tenant ID of the AKV instance
- Assicurarsi di usare
Applicare SecretProviderClass al cluster Kubernetes usando il comando
kubectl apply
.kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
Distribuire il controller in ingresso
Aggiungere il repository ufficiale del grafico in ingresso
Aggiungere il repository ufficiale del grafico in ingresso usando i comandi seguenti
helm
.helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update
Configurare e distribuire l'ingresso NGINX
A seconda dello scenario, è possibile scegliere di associare il certificato all'applicazione o al controller di ingresso. Seguire le istruzioni seguenti in base alla selezione:
Associare il certificato all'applicazione
Associare il certificato all'applicazione usando il comando
helm install
. La distribuzione dell'applicazione fa riferimento al provider azure Key Vault del driver CSI dell'archivio segreti.helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux
Associare il certificato al controller di ingresso
Associare il certificato al controller di ingresso usando il comando
helm install
. La distribuzione del controller in ingresso fa riferimento al provider azure Key Vault del driver CSI dell'archivio segreti.Nota
Se non si usa l'identità gestita dal pod di Microsoft Entra come metodo di accesso, rimuovere la riga con
--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME
.Inoltre, l'associazione di SecretProviderClass a un pod è necessaria per il driver CSI dell'archivio segreti per montarlo e generare il segreto Kubernetes. Vedere Sincronizzare il contenuto montato con un segreto Kubernetes.
helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \ -f - <<EOF controller: extraVolumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" extraVolumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true EOF
Verificare che il segreto Kubernetes sia stato creato usando il comando
kubectl get secret
.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
Distribuire l'applicazione
Anche in questo caso, le istruzioni cambiano leggermente a seconda dello scenario. Seguire le istruzioni corrispondenti allo scenario selezionato.
Distribuire l'applicazione usando un riferimento all'applicazione
Creare un file denominato
aks-helloworld-one.yaml
con il contenuto seguente.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
Creare un file denominato
aks-helloworld-two.yaml
con il contenuto seguente.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
Applicare i file YAML al cluster usando il comando
kubectl apply
.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
Verificare che il segreto Kubernetes sia stato creato usando il comando
kubectl get secret
.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
Distribuire l'applicazione usando un riferimento al controller di ingresso
Creare un file denominato
aks-helloworld-one.yaml
con il contenuto seguente.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
Creare un file denominato
aks-helloworld-two.yaml
con il contenuto seguente.apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
Applicare i file YAML al cluster usando il comando
kubectl apply
.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
Distribuire una risorsa in ingresso che fa riferimento al segreto
È ora possibile distribuire una risorsa di ingresso Kubernetes che fa riferimento al segreto.
Creare un nome del file
hello-world-ingress.yaml
con il contenuto seguente.apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-tls annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx tls: - hosts: - demo.azure.com secretName: ingress-tls-csi rules: - host: demo.azure.com 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
Prendere nota della sezione
tls
che fa riferimento al segreto creato in precedenza e applicare il file al cluster usando il comandokubectl apply
.kubectl apply -f hello-world-ingress.yaml -n $NAMESPACE
Ottenere l'indirizzo IP esterno del controller di ingresso
Ottenere l'indirizzo IP esterno per il controller di ingresso usando il comando
kubectl get service
.kubectl get service --namespace $NAMESPACE --selector app.kubernetes.io/name=ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-1588032400-controller LoadBalancer 10.0.255.157 EXTERNAL_IP 80:31293/TCP,443:31265/TCP 19m nginx-ingress-1588032400-default-backend ClusterIP 10.0.223.214 <none> 80/TCP 19m
Testare l'ingresso protetto con TLS
Verificare che l'ingresso sia configurato correttamente con TLS usando il comando seguente
curl
. Assicurarsi di usare l'indirizzo IP esterno del passaggio precedente.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
Poiché non è stato fornito un altro percorso con l'indirizzo, il controller di ingresso usa per impostazione predefinita la route /. Viene restituita la prima applicazione demo, come illustrato nell'output di esempio condensato seguente:
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>Welcome to Azure Kubernetes Service (AKS)</title> [...]
Il parametro - v nel comando
curl
restituisce informazioni dettagliate, tra cui il certificato TLS ricevuto. A metà dell'output di curl, è possibile verificare che sia stato usato il proprio certificato TLS. Il parametro -k continua il caricamento della pagina anche se viene usato un certificato autofirmato. L'esempio seguente mostra che è stato usato il certificato autorità di certificazione: CN=demo.azure.com; O=aks-ingress-tls:[...] * Server certificate: * subject: CN=demo.azure.com; O=aks-ingress-tls * start date: Oct 22 22:13:54 2021 GMT * expire date: Oct 22 22:13:54 2022 GMT * issuer: CN=demo.azure.com; O=aks-ingress-tls * SSL certificate verify result: self signed certificate (18), continuing anyway. [...]
Aggiungere il percorso /hello-world-two all'indirizzo, ad esempio
https://demo.azure.com/hello-world-two
, e verificare che la seconda applicazione demo sia configurata correttamente.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
Viene restituita la seconda applicazione demo con titolo personalizzato, come illustrato nell'output di esempio condensato seguente:
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>AKS Ingress Demo</title> [...]
Azure Kubernetes Service