適用於 Azure Kubernetes Service 的 Istio 服務網格附加元件的安全輸入閘道
部署外部或內部 Istio 輸入一文說明如何設定輸入閘道,以向外部/內部流量公開 HTTP 服務。 本文說明如何使用簡單或相互 TLS 公開安全的 HTTPS 服務。
必要條件
注意
本文參考外部輸入閘道進行示範,相同的步驟適用於設定內部輸入閘道的相互 TLS。
必要的用戶端/伺服器憑證和金鑰
本文需要數個憑證和金鑰。 您可使用慣用的工具來建立它們,或使用下列 openssl 命令。
建立根憑證和私密金鑰,以便簽署範例服務的憑證:
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
為
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
產生用戶端憑證和私密金鑰:
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
設定 TLS 輸入閘道
建立輸入閘道的 Kubernetes TLS 秘密;使用 Azure Key Vault 來裝載憑證/金鑰和 Azure Key Vault 秘密提供者附加元件將秘密同步至叢集。
設定 Azure Key Vault 並將秘密同步至叢集
建立 Azure Key Vault
您需要 Azure Key Vault 資源,才能將憑證和金鑰輸入提供給 Istio 附加元件。
export AKV_NAME=<azure-key-vault-resource-name> az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
在叢集上啟用祕密存放區 CSI 驅動程式的 Azure Key Vault 提供者附加元件。
az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
授權附加元件的使用者指派受控識別,以使用存取元件存取 Azure Key Vault 資源。 或者,如果 Key Vault 針對權限模型使用 Azure RBAC,請遵循這裡的指示,為附加元件的使用者指派受控識別指派 Key Vault 的 Azure 角色。
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
使用憑證和金鑰在 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
使用下列資訊清單來部署 SecretProviderClass,以提供 CSI 驅動程式的 Azure Key Vault 特定參數。
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
使用下列資訊清單來部署範例 Pod。 秘密存放區 CSI 驅動程式需要 Pod 來參考 SecretProviderClass 資源,以確保秘密會從 Azure Key Vault 同步至叢集。
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
確認在叢集命名空間
aks-istio-ingress
上建立的秘密productpage-credential
如 SecretProviderClass 資源中所定義。kubectl describe secret/productpage-credential -n aks-istio-ingress
範例輸出:
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
設定輸入閘道和虛擬服務
透過 Istio 輸入閘道將 HTTPS 流量路由傳送至範例應用程式。 使用下列資訊清單來部署閘道和虛擬服務資源。
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
注意
在閘道定義中,credentialName
必須符合 SecretProviderClass 資源中的 secretName
,而 selector
必須依其標籤參考外部輸入閘道,其中標籤的索引鍵是 istio
且值為 aks-istio-ingressgateway-external
。 對於內部輸入閘道,標籤是 istio
且值為 aks-istio-ingressgateway-internal
。
設定適用於外部輸入主機和連接埠的環境變數:
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"
驗證
傳送 HTTPS 要求,以透過 HTTPS 存取 productpage 服務:
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>"
確認範例應用程式的產品頁面可供存取。 預期的輸出為:
<title>Simple Bookstore App</title>
注意
若要設定對 HTTPS 服務的 HTTPS 輸入存取,也就是設定輸入閘道以對傳入要求執行 SNI 傳遞而不是 TLS 終止,請將閘道定義中的 tls 模式更新為 PASSTHROUGH
。 這會指示閘道依「原狀」傳遞輸入流量,而不需終止 TLS。
設定相互 TLS 輸入閘道
擴充閘道定義以支援相互 TLS。
刪除目前的秘密並建立新的秘密,以更新輸入閘道認證。 伺服器會使用 CA 憑證來驗證其用戶端,而我們必須使用金鑰 ca.crt 來保存 CA 憑證。
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
使用下列資訊清單以使用 CA 憑證重新建立 SecretProviderClass。
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
使用下列資訊清單來重新部署範例 Pod,以將秘密從 Azure Key Vault 同步至叢集。
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
驗證在叢集命名空間
productpage-credential
上建立的aks-istio-ingress
秘密。kubectl describe secret/productpage-credential -n aks-istio-ingress
範例輸出:
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
使用下列資訊清單來更新閘道定義,將 TLS 模式設定為 MUTUAL。
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
驗證
嘗試使用先前的方法傳送 HTTPS 要求 (不需傳遞用戶端憑證) 並看到失敗。
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"
範例輸出:
...
* 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
將用戶端具有 --cert
旗標的憑證和具有 --key
旗標的私密金鑰傳遞至 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>"
確認範例應用程式的產品頁面可供存取。 預期的輸出為:
<title>Simple Bookstore App</title>
刪除資源
如果您想要清除 Istio 服務網格和輸入 (留下叢集),請執行下列命令:
az aks mesh disable --resource-group ${RESOURCE_GROUP} --name ${CLUSTER}
如果您想要清除從 Istio 操作指南文件建立的所有資源,請執行下列命令:
az group delete --name ${RESOURCE_GROUP} --yes --no-wait