共用方式為


適用於 Azure Kubernetes Service 的 Istio 服務網格附加元件的安全輸入閘道

部署外部或內部 Istio 輸入文章說明如何設定輸入閘道,以向外部/內部流量公開 HTTP 服務。 本文說明如何使用簡單或相互 TLS 公開安全的 HTTPS 服務。

必要條件

注意

本文參考外部輸入閘道以進行示範,相同的步驟適用於設定內部輸入閘道的相互 TLS。

必要的用戶端/伺服器憑證和金鑰

本文需要數個憑證和金鑰。 您可以使用您慣用的工具來建立它們,也可以使用下列 openssl 命令。

  1. 建立跟證書和私鑰,以簽署範例服務的憑證:

    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
    
  2. 產生 的憑證和私鑰 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
    
  3. 產生客戶端憑證和私鑰:

    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 金鑰保存庫 來裝載憑證/金鑰和 Azure 金鑰保存庫 秘密提供者附加元件,將秘密同步至叢集。

設定 Azure 金鑰保存庫 並將秘密同步至叢集

  1. 建立 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
    
  2. 為叢集上的秘密存放區 CSI 驅動程式附加元件啟用 Azure 金鑰保存庫 提供者。

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. 授權附加元件的使用者指派受控識別,以使用存取原則存取 Azure 金鑰保存庫 資源。 或者,如果您的 金鑰保存庫 針對許可權模型使用 Azure RBAC,請遵循這裡的指示,為附加元件的使用者指派受控識別指派 金鑰保存庫 的 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
    
  4. 使用憑證和金鑰在 Azure 金鑰保存庫 中建立秘密。

    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
    
  5. 使用下列指令清單來部署 SecretProviderClass,為 CSI 驅動程式提供 Azure 金鑰保存庫 特定參數。

    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
    
  6. 使用下列指令清單來部署範例 Pod。 秘密存放區 CSI 驅動程式需要 Pod 來參考 SecretProviderClass 資源,以確保秘密會從 Azure 金鑰保存庫 同步至叢集。

    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
    
    • 確認 productpage-credential 在叢集命名空間 aks-istio-ingress 上建立的秘密,如 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

注意

在閘道定義中,必須符合 secretName SecretProviderClass 資源的 ,而且selector必須依其標籤參考外部輸入閘道,其中標籤的索引鍵是 istio ,而值為 aks-istio-ingressgateway-externalcredentialName 針對內部輸入閘道標籤, 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 存取產品頁面服務:

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。

  1. 刪除目前的秘密並建立新的密碼,以更新輸入閘道認證。 伺服器會使用 CA 憑證來驗證其客戶端,我們必須使用 key 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 金鑰保存庫 同步至叢集。

    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
      
  2. 使用下列指令清單來更新閘道定義,將 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