Sicheres Eingangsgateway für das Istio-Dienstgitter-Add-On für Azure Kubernetes Service
Im ArtikelBereitstellen eines externen oder internen Istio-Eingangs wird beschrieben, wie Sie ein Eingangsgateway konfigurieren, sodass ein HTTP-Dienst für externen/internen Datenverkehr verfügbar gemacht wird. In diesem Artikel wird gezeigt, wie Sie einen sicheren HTTPS-Dienst mit einfachem TLS oder mTLS (mutual TLS) verfügbar machen.
Voraussetzungen
Aktivieren des Istio-Add-Ons im Cluster gemäß der Dokumentation
Bereitstellen eines externen Istio-Eingangsgateways gemäß der Dokumentation
Hinweis
Dieser Artikel bezieht sich zu Demonstrationszwecken auf das externe Eingangsgateway. Die gleichen Schritte gelten für die Konfiguration von mTLS für ein internes Eingangsgateway.
Erforderliche Client-/Serverzertifikate und Schlüssel
Für diesen Artikel sind mehrere Zertifikate und Schlüssel erforderlich. Sie können sie mit Ihrem bevorzugten Tool erstellen oder hierzu die folgenden openssl-Befehle verwenden.
Erstellen Sie ein Stammzertifikat und einen privaten Schlüssel zum Signieren der Zertifikate für Beispieldienste:
mkdir bookinfo_certs openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=bookinfo Inc./CN=bookinfo.com' -keyout bookinfo_certs/bookinfo.com.key -out bookinfo_certs/bookinfo.com.crt
Generieren Sie ein Zertifikat und einen privaten Schlüssel für
productpage.bookinfo.com
:openssl req -out bookinfo_certs/productpage.bookinfo.com.csr -newkey rsa:2048 -nodes -keyout bookinfo_certs/productpage.bookinfo.com.key -subj "/CN=productpage.bookinfo.com/O=product organization" openssl x509 -req -sha256 -days 365 -CA bookinfo_certs/bookinfo.com.crt -CAkey bookinfo_certs/bookinfo.com.key -set_serial 0 -in bookinfo_certs/productpage.bookinfo.com.csr -out bookinfo_certs/productpage.bookinfo.com.crt
Generieren Sie ein Clientzertifikat und einen privaten Schlüssel:
openssl req -out bookinfo_certs/client.bookinfo.com.csr -newkey rsa:2048 -nodes -keyout bookinfo_certs/client.bookinfo.com.key -subj "/CN=client.bookinfo.com/O=client organization" openssl x509 -req -sha256 -days 365 -CA bookinfo_certs/bookinfo.com.crt -CAkey bookinfo_certs/bookinfo.com.key -set_serial 1 -in bookinfo_certs/client.bookinfo.com.csr -out bookinfo_certs/client.bookinfo.com.crt
Konfigurieren eines TLS-Eingangsgateways
Erstellen Sie ein Kubernetes-TLS-Geheimnis für das Eingangsgateway. Verwenden Sie Azure Key Vault als Host für Zertifikate/Schlüssel und das Azure Key Vault Secrets Provider-Add-On, um geheime Schlüssel mit dem Cluster zu synchronisieren.
Einrichten von Azure Key Vault und Synchronisieren geheimer Schlüssel mit dem Cluster
Erstellen eines Azure Key Vault
Sie benötigen eine Azure Key Vault-Ressource, um das Zertifikat und die Schlüsseleingaben für das Istio-Add-On bereitstellen zu können.
export AKV_NAME=<azure-key-vault-resource-name> az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
Aktivieren Sie das Add-On Azure Key Vault-Anbieter für den Geheimnisspeicher-CSI-Treiber in Ihrem Cluster.
az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
Autorisieren Sie die benutzerseitig zugewiesene verwaltete Identität des Add-Ons mittels Zugriffsrichtlinie zum Zugriff auf die Azure Key Vault-Ressource. Wenn Ihr Key Vault Azure als Berechtigungsmodell RBAC verwendet, folgen Sie den hier aufgeführten Anweisungen, um der benutzerseitig zugewiesenen verwalteten Identität des Add-Ons eine Azure-Rolle von Key Vault zuzuweisen.
OBJECT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.objectId' -o tsv | tr -d '\r') CLIENT_ID=$(az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER --query 'addonProfiles.azureKeyvaultSecretsProvider.identity.clientId') TENANT_ID=$(az keyvault show --resource-group $RESOURCE_GROUP --name $AKV_NAME --query 'properties.tenantId') az keyvault set-policy --name $AKV_NAME --object-id $OBJECT_ID --secret-permissions get list
Erstellen Sie mithilfe der Zertifikate und der Schlüssel Geheimnisse in Azure Key Vault.
az keyvault secret set --vault-name $AKV_NAME --name test-productpage-bookinfo-key --file bookinfo_certs/productpage.bookinfo.com.key az keyvault secret set --vault-name $AKV_NAME --name test-productpage-bookinfo-crt --file bookinfo_certs/productpage.bookinfo.com.crt az keyvault secret set --vault-name $AKV_NAME --name test-bookinfo-crt --file bookinfo_certs/bookinfo.com.crt
Verwenden Sie das folgende Manifest, um SecretProviderClass bereitzustellen, um für Azure Key Vault spezifische Parameter für den CSI-Treiber bereitzustellen.
cat <<EOF | kubectl apply -f - apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: productpage-credential-spc namespace: aks-istio-ingress spec: provider: azure secretObjects: - secretName: productpage-credential type: tls data: - objectName: test-productpage-bookinfo-key key: key - objectName: test-productpage-bookinfo-crt key: cert parameters: useVMManagedIdentity: "true" userAssignedIdentityID: $CLIENT_ID keyvaultName: $AKV_NAME cloudName: "" objects: | array: - | objectName: test-productpage-bookinfo-key objectType: secret objectAlias: "test-productpage-bookinfo-key" - | objectName: test-productpage-bookinfo-crt objectType: secret objectAlias: "test-productpage-bookinfo-crt" tenantId: $TENANT_ID EOF
Verwenden Sie das folgende Manifest, um einen Beispielpod bereitzustellen. Der CSI-Treiber für den Geheimnisspeicher erfordert, dass ein Pod auf die SecretProviderClass-Ressource verweist, um die Synchronisierung der Geheimnisse von Azure Key Vault mit dem Cluster sicherzustellen.
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: secrets-store-sync-productpage namespace: aks-istio-ingress spec: containers: - name: busybox image: mcr.microsoft.com/oss/busybox/busybox:1.33.1 command: - "/bin/sleep" - "10" volumeMounts: - name: secrets-store01-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store01-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "productpage-credential-spc" EOF
Überprüfen Sie, ob das Geheimnis
productpage-credential
im Clusternamespaceaks-istio-ingress
erstellt wurde, wie in der SecretProviderClass-Ressource definiert.kubectl describe secret/productpage-credential -n aks-istio-ingress
Beispielausgabe:
Name: productpage-credential Namespace: aks-istio-ingress Labels: secrets-store.csi.k8s.io/managed=true Annotations: <none> Type: tls Data ==== cert: 1066 bytes key: 1704 bytes
Konfigurieren des Eingangsgateways und des virtuellen Diensts
Leiten Sie HTTPS-Datenverkehr über das Istio-Eingangsgateway an die Beispielanwendungen weiter. Verwenden Sie das folgende Manifest, um Gateway- und virtuelle Dienstressourcen bereitzustellen.
cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: aks-istio-ingressgateway-external
servers:
- port:
number: 443
name: https
protocol: HTTPS
tls:
mode: SIMPLE
credentialName: productpage-credential
hosts:
- productpage.bookinfo.com
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: productpage-vs
spec:
hosts:
- productpage.bookinfo.com
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
port:
number: 9080
host: productpage
EOF
Hinweis
In der Gatewaydefinition muss credentialName
dem Parameter secretName
SecretProviderClass-Ressource entsprechen, und selector
muss über die Beschriftung auf das externe Eingangsgateway verweisen, in dem der Schlüssel der Bezeichnung istio
und der Wert aks-istio-ingressgateway-external
lautet. Die Bezeichnung des internen Eingangsgateways lautet istio
und der Wert aks-istio-ingressgateway-internal
.
Legen Sie Umgebungsvariablen für den Host und die Ports des externen Eingangsgateways fest:
export INGRESS_HOST_EXTERNAL=$(kubectl -n aks-istio-ingress get service aks-istio-ingressgateway-external -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export SECURE_INGRESS_PORT_EXTERNAL=$(kubectl -n aks-istio-ingress get service aks-istio-ingressgateway-external -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
export SECURE_GATEWAY_URL_EXTERNAL=$INGRESS_HOST_EXTERNAL:$SECURE_INGRESS_PORT_EXTERNAL
echo "https://$SECURE_GATEWAY_URL_EXTERNAL/productpage"
Überprüfung
Senden Sie eine HTTPS-Anforderung, um über HTTPS auf den Productpage-Dienst zuzugreifen:
curl -s -HHost:productpage.bookinfo.com --resolve "productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL:$INGRESS_HOST_EXTERNAL" --cacert bookinfo_certs/bookinfo.com.crt "https://productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL/productpage" | grep -o "<title>.*</title>"
Vergewissern Sie sich, dass auf die Produktseite der Beispielanwendung zugegriffen werden kann. Die erwartete Ausgabe lautet:
<title>Simple Bookstore App</title>
Hinweis
Um den HTTPS-Eingangszugriff mit einem HTTPS-Dienst zu konfigurieren, d. h. ein Ingress-Gateway so zu konfigurieren, dass bei eingehenden Anforderungen ein SNI-Passthrough anstelle eines TLS-Abschlusses durchgeführt wird, ändern bzw. aktualisieren Sie den TLS-Modus in der Gatewaydefinition in PASSTHROUGH
. Dadurch wird das Gateway angewiesen, den eingehenden Datenverkehr unverändert weiterzuleiten, ohne TLS zu beenden.
Konfigurieren eines mTLS-Eingangsgateways
Erweitern Sie Ihre Gatewaydefinition, sodass mTLS unterstützt wird.
Aktualisieren Sie die Anmeldeinformationen des Eingangsgateways, indem Sie den aktuellen geheimen Schlüssel löschen und einen neuen erstellen. Der Server verwendet das Zertifizierungsstellenzertifikat, um seine Clients zu überprüfen, und wir müssen den Schlüssel ca.crt verwenden, um das Zertifizierungsstellenzertifikat zu speichern.
kubectl delete secretproviderclass productpage-credential-spc -n aks-istio-ingress kubectl delete secret/productpage-credential -n aks-istio-ingress kubectl delete pod/secrets-store-sync-productpage -n aks-istio-ingress
Verwenden Sie das folgende Manifest, um SecretProviderClass mit dem Zertifizierungsstellenzertifikat neu zu erstellen.
cat <<EOF | kubectl apply -f - apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: productpage-credential-spc namespace: aks-istio-ingress spec: provider: azure secretObjects: - secretName: productpage-credential type: opaque data: - objectName: test-productpage-bookinfo-key key: tls.key - objectName: test-productpage-bookinfo-crt key: tls.crt - objectName: test-bookinfo-crt key: ca.crt parameters: useVMManagedIdentity: "true" userAssignedIdentityID: $CLIENT_ID keyvaultName: $AKV_NAME cloudName: "" objects: | array: - | objectName: test-productpage-bookinfo-key objectType: secret objectAlias: "test-productpage-bookinfo-key" - | objectName: test-productpage-bookinfo-crt objectType: secret objectAlias: "test-productpage-bookinfo-crt" - | objectName: test-bookinfo-crt objectType: secret objectAlias: "test-bookinfo-crt" tenantId: $TENANT_ID EOF
Verwenden Sie das folgende Manifest, um den Beispielpod erneut bereitzustellen, sodass geheime Schlüssel aus Azure Key Vault mit dem Cluster synchronisiert werden.
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: secrets-store-sync-productpage namespace: aks-istio-ingress spec: containers: - name: busybox image: registry.k8s.io/e2e-test-images/busybox:1.29-4 command: - "/bin/sleep" - "10" volumeMounts: - name: secrets-store01-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store01-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "productpage-credential-spc" EOF
Überprüfen Sie den geheimen Schlüssel
productpage-credential
, der im Clusternamespaceaks-istio-ingress
erstellt wurde.kubectl describe secret/productpage-credential -n aks-istio-ingress
Beispielausgabe:
Name: productpage-credential Namespace: aks-istio-ingress Labels: secrets-store.csi.k8s.io/managed=true Annotations: <none> Type: opaque Data ==== ca.crt: 1188 bytes tls.crt: 1066 bytes tls.key: 1704 bytes
Verwenden Sie das folgende Manifest, um die Gatewaydefinition zu aktualisieren, um den TLS-Modus auf MUTUAL festzulegen.
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: bookinfo-gateway spec: selector: istio: aks-istio-ingressgateway-external # use istio default ingress gateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: MUTUAL credentialName: productpage-credential # must be the same as secret hosts: - productpage.bookinfo.com EOF
Überprüfung
Versuchen Sie, HTTPS-Anforderung mithilfe des vorherigen Ansatzes – ohne das Clientzertifikat zu übergeben – zu senden. Sie werden dann feststellen, dass die Anforderung fehlschlägt.
curl -v -HHost:productpage.bookinfo.com --resolve "productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL:$INGRESS_HOST_EXTERNAL" --cacert bookinfo_certs/bookinfo.com.crt "https://productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL/productpage"
Beispielausgabe:
...
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS alert, unknown (628):
* OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0
* Failed receiving HTTP2 data
* OpenSSL SSL_write: SSL_ERROR_ZERO_RETURN, errno 0
* Failed sending HTTP2 data
* Connection #0 to host productpage.bookinfo.com left intact
curl: (56) OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0
Übergeben Sie das Zertifikat Ihres Clients mit dem Flag --cert
und den privaten Schlüssel mit dem Flag --key
an curl.
curl -s -HHost:productpage.bookinfo.com --resolve "productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL:$INGRESS_HOST_EXTERNAL" --cacert bookinfo_certs/bookinfo.com.crt --cert bookinfo_certs/client.bookinfo.com.crt --key bookinfo_certs/client.bookinfo.com.key "https://productpage.bookinfo.com:$SECURE_INGRESS_PORT_EXTERNAL/productpage" | grep -o "<title>.*</title>"
Vergewissern Sie sich, dass auf die Produktseite der Beispielanwendung zugegriffen werden kann. Die erwartete Ausgabe lautet:
<title>Simple Bookstore App</title>
Löschen von Ressourcen
Wenn Sie das Istio-Dienstnetz und die Eingangsgateways bereinigen (und den Cluster zurücklassen) möchten, führen Sie den folgenden Befehl aus:
az aks mesh disable --resource-group ${RESOURCE_GROUP} --name ${CLUSTER}
Wenn Sie alle Ressourcen bereinigen möchten, die in den Istio-Anleitungsdokumenten erstellt wurden, führen Sie den folgenden Befehl aus:
az group delete --name ${RESOURCE_GROUP} --yes --no-wait
Azure Kubernetes Service