Einrichten des CSI-Treibers für den Geheimnisspeicher zum Aktivieren des NGINX-Eingangsdatencontrollers mit TLS
Dieser Artikel führt Sie schrittweise durch den Prozess zum Sichern eines NGINX-Eingangsdatencontrollers mit TLS mit einem AKS-Cluster (Azure Kubernetes Service) und einer Azure Key Vault-Instanz (AKV). Weitere Informationen finden Sie unter TLS in Kubernetes.
Sie können das eingehende TLS-Zertifikat mit einer der folgenden Methoden in den Cluster importieren:
- Anwendung: Das Anwendungsbereitstellungsmanifest deklariert das Anbietervolume und bindet es ein. Nur wenn Sie die Anwendung bereitstellen, wird das Zertifikat im Cluster verfügbar gemacht. Wenn Sie die Anwendung entfernen, wird auch das Geheimnis entfernt. Dieses Szenario eignet sich für Bereitstellungsteams, die für die Sicherheitsinfrastruktur der Anwendung und ihre Integration in den Cluster verantwortlich sind.
- Eingangsdatencontroller: Die Eingangsbereitstellung wird so geändert, dass das Anbietervolume deklariert und eingebunden wird. Das Geheimnis wird importiert, wenn Eingangspods erstellt werden. Die Pods der Anwendung besitzen keinen Zugriff auf das TLS-Zertifikat. Dieses Szenario eignet sich für Situationen, in denen ein Team (z. B. die IT-Abteilung) Infrastruktur- und Netzwerkkomponenten (einschließlich HTTPS-TLS-Zertifikate) verwaltet und erstellt, während andere Teams den Anwendungslebenszyklus verwalten.
Voraussetzungen
- Wenn Sie kein Azure-Abonnement besitzen, können Sie ein kostenloses Konto erstellen, bevor Sie beginnen.
- Bevor Sie beginnen, stellen Sie sicher, dass Ihre Azure CLI-Version >=
2.30.0
ist, oder installieren Sie die neueste Version. - Ein AKS-Cluster, für den der CSI-Treiber des Geheimnisspeichers konfiguriert ist.
- Eine Azure Key Vault-Instanz.
Generieren eines TLS-Zertifikats
Generieren Sie mit dem folgenden Befehl ein TLS-Zertifikat.
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"
Importieren des Zertifikats in AKV
Exportieren Sie das Zertifikat mit folgendem Befehl in eine PFX-Datei:
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
Importieren Sie das Zertifikat mit dem Befehl
az keyvault certificate import
.az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
Bereitstellen einer SecretProviderClass
Exportieren Sie einen neuen Namespace mit dem folgenden Befehl.
export NAMESPACE=ingress-basic
Erstellen Sie den Namespace mit dem Befehl
kubectl create namespace
.kubectl create namespace $NAMESPACE
Wählen Sie eine Methode aus, um eine Zugriffsidentität bereitzustellen, und konfigurieren Sie Ihre SecretProviderClass-YAML-Datei entsprechend.
- Achten Sie darauf,
objectType=secret
zu verwenden, da dies die einzige Möglichkeit ist, den privaten Schlüssel und das Zertifikat aus AKV abzurufen. - Legen Sie
kubernetes.io/tls
alstype
in Ihrem AbschnittsecretObjects
fest.
Im Folgenden finden Sie ein Beispiel, wie Ihre SecretProviderClass aussehen kann:
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
- Achten Sie darauf,
Wenden Sie die SecretProviderClass mit dem Befehl
kubectl apply
auf Ihren Kubernetes-Cluster an.kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
Bereitstellen des Eingangsdatencontrollers
Hinzufügen des offiziellen Repositorys für das Eingangsdiagramm
Fügen Sie das offizielle Repository für Eingangsdiagramme mithilfe der folgenden
helm
-Befehle hinzu.helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update
Konfigurieren und Bereitstellen des NGINX-Eingangsdatencontrollers
Je nach Szenario können Sie das Zertifikat entweder an die Anwendung oder an den Eingangsdatencontroller binden. Befolgen Sie die Anweisungen unten gemäß Ihrer Auswahl:
Binden eines Zertifikats an eine Anwendung
Binden Sie das Zertifikat mithilfe des Befehls
helm install
an die Anwendung. Die Bereitstellung der Anwendung verweist auf den Azure Key Vault-Anbieter des CSI-Treibers des Geheimnisspeichers.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
Binden eines Zertifikats an den Eingangsdatencontroller
Binden Sie das Zertifikat mithilfe des Befehls
helm install
an den Eingangscontroller. Die Bereitstellung des Eingangsdatencontrollers verweist auf den Azure Key Vault-Anbieter des CSI-Treibers des Geheimnisspeichers.Hinweis
Wenn Sie die vom Pod verwaltete Microsoft Entra-Identität nicht als Zugriffsmethode verwenden, entfernen Sie die Zeile mit
--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME
.Außerdem ist eine Bindung der SecretProviderClass an einen Pod erforderlich, damit der Secrets Store CSI-Treiber den Pod einbindet und das Kubernetes-Geheimnis generiert. Weitere Informationen finden Sie unter Synchronisieren von eingebundenen Inhalten mit einem Kubernetes-Geheimnis.
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
Überprüfen Sie mithilfe des Befehls
kubectl get secret
, ob das Kubernetes-Geheimnis erstellt wurde.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
Bereitstellen der Anwendung
Auch hier ändern sich die Anweisungen je nach Szenario geringfügig. Befolgen Sie die Anweisungen für das Szenario, das Sie ausgewählt haben.
Bereitstellen der Anwendung mithilfe eines Anwendungsverweises
Erstellen Sie eine Datei namens
aks-helloworld-one.yaml
mit folgendem Inhalt.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
Erstellen Sie eine Datei namens
aks-helloworld-two.yaml
mit folgendem Inhalt.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
Wenden Sie mithilfe des Befehls
kubectl apply
den die YAML-Dateien auf Ihren Cluster an.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
Überprüfen Sie mithilfe des Befehls
kubectl get secret
, ob das Kubernetes-Geheimnis erstellt wurde.kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
Bereitstellen der Anwendung mithilfe eines Eingangsdatencontroller-Verweises
Erstellen Sie eine Datei namens
aks-helloworld-one.yaml
mit folgendem Inhalt.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
Erstellen Sie eine Datei namens
aks-helloworld-two.yaml
mit folgendem Inhalt.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
Wenden Sie mithilfe des Befehls
kubectl apply
den die YAML-Dateien auf Ihren Cluster an.kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
Bereitstellen einer Eingangsressource, die auf das Geheimnis verweist
Sie können nun eine Kubernetes-Eingangsressource bereitstellen, die auf das Geheimnis verweist.
Erstellen Sie eine Datei namens
hello-world-ingress.yaml
mit folgendem Inhalt.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
Notieren Sie sich den Abschnitt
tls
, der auf das zuvor erstellte Geheimnis verweist, und wenden Sie die Datei mit dem Befehlkubectl apply
auf Ihren Cluster an.kubectl apply -f hello-world-ingress.yaml -n $NAMESPACE
Abrufen der externen IP-Adresse des Eingangsdatencontrollers
Ermitteln Sie die externe IP-Adresse des Eingangsdatencontrollers mit dem Befehl
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
Testen des mit TLS gesicherten Eingangs
Überprüfen Sie mit dem Befehl
curl
, ob Ihr Eingang ordnungsgemäß mit TLS konfiguriert ist. Stellen Sie sicher, dass Sie die externe IP-Adresse aus dem vorherigen Schritt verwenden.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
Da mit der Adresse kein anderer Pfad angegeben wurde, verendet der Eingangsdatencontroller standardmäßig die Route /. Die erste Demoanwendung wird zurückgegeben, wie in der folgenden verkürzten Beispielausgabe gezeigt:
[...] <!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> [...]
Durch den Parameter -v im
curl
-Befehl werden ausführliche Informationen ausgegeben, einschließlich des erhaltenen TLS-Zertifikats. Während der CURL-Ausgabe können Sie überprüfen, ob Ihr eigenes TLS-Zertifikat verwendet wurde. Durch den Parameter -k wird die Seite auch dann weiterhin geladen, wenn wir ein selbstsigniertes Zertifikat verwenden. Das folgende Beispiel zeigt, dass das Zertifikat issuer: CN=demo.azure.com; O=aks-ingress-tls verwendet wurde:[...] * 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. [...]
Fügen Sie der Adresse den Pfad /hello-world-two hinzu, z. B.
https://demo.azure.com/hello-world-two
, und vergewissern Sie sich, dass die zweite Demoanwendung ordnungsgemäß konfiguriert ist.curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
Die zweite Demoanwendung wird mit dem benutzerdefinierten Titel zurückgegeben, wie in der folgenden verkürzten Beispielausgabe gezeigt:
[...] <!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