共用方式為


適用於 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 Key Vault 來裝載憑證/金鑰和 Azure Key Vault 秘密提供者附加元件將秘密同步至叢集。

設定 Azure Key Vault 並將秘密同步至叢集

  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 Key Vault 提供者附加元件。

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. 授權附加元件的使用者指派受控識別,以使用存取元件存取 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
    
  4. 使用憑證和金鑰在 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
    
  5. 使用下列資訊清單來部署 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
    
  6. 使用下列資訊清單來部署範例 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。

  1. 刪除目前的秘密並建立新的秘密,以更新輸入閘道認證。 伺服器會使用 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
      
  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