使用應用程式路由 Gateway API 實作來保護輸入流量

Note

本文說明如何在 資源上Gateway設定 TLS 終止,方法是自行撰寫 SecretProviderClass、透過範例 Pod 掛載 Secrets Store CSI Driver 的 Azure Key Vault 提供者,並直接在 Gateway 接聽程式的 certificateRefs 中參考所產生的 Kubernetes Secret。 如果你需要完全掌控憑證同步工作流程,或偏好自行管理這些資源,這種方法很有用。

對於大多數使用者,建議路徑是由應用程式路由操作員提供支援的自動化 Azure DNS 和 Azure Key Vault 整合SecretProviderClass,該操作員會根據一組接聽程式 certificateRefs,為您佈建並協調 SecretProviderClass、已同步的 Kubernetes 秘密,以及接聽程式 tls.options。 要使用自動化工作流程,請參考「配置 Azure DNS 與 TLS 並搭配應用程式路由閘道 API 實作」。

應用程式路由增益集支援從 Azure Key Vault (AKV) 同步祕密,以透過 TLS 終止來保護 Gateway API 輸入流量。 請依照以下步驟建立憑證與金鑰,以在閘道器終止 TLS 流量。

先決條件

所需用戶端/伺服器憑證和金鑰

  1. 建立根憑證和私人金鑰,以簽署樣本服務的憑證:
mkdir httpbin_certs
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -subj '/O=example Inc./CN=example.com' -keyout httpbin_certs/example.com.key -out httpbin_certs/example.com.crt
  1. 產生 httpbin.example.com 的憑證與私鑰。
openssl req -out httpbin_certs/httpbin.example.com.csr -newkey rsa:2048 -nodes -keyout httpbin_certs/httpbin.example.com.key -subj "/CN=httpbin.example.com/O=httpbin organization"
openssl x509 -req -sha256 -days 365 -CA httpbin_certs/example.com.crt -CAkey httpbin_certs/example.com.key -set_serial 0 -in httpbin_certs/httpbin.example.com.csr -out httpbin_certs/httpbin.example.com.crt

設定 TLS 入口閘道

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

  1. 建立 Azure Key Vault

    你需要一個 Azure Key Vault 資源 來提供應用程式路由外掛的憑證和金鑰輸入。

    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 RBAC 作為權限模型,請依 照此處的指示,將 Azure 角色 "金鑰保存庫 Secrets User" 分配給該附加元件的使用者指派管理身份。 或者,如果您的金鑰庫正在使用金庫存取原則權限模型,請授權該附加元件的使用者指派受控識別,以使用存取原則存取 Azure Key Vault 資源:

    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. 選擇如何提供 TLS 證書。

    Azure Key Vault 支援不同的物件類型。 在本次逐步解說中,請從以下端對端選項中選擇 一個,然後繼續執行通用的驗證和 Gateway 步驟。

    Option 當…時使用此選項 金鑰保存庫 商店 Kubernetes Secret 結果
    選項一:將憑證和金鑰儲存為 金鑰保存庫 秘密 你有分開的 PEM 憑證(.crt)和私鑰(.key)檔案,就像本文前面產生的那些。 兩個 金鑰保存庫 的秘密。 有一個同步的 Kubernetes TLS 秘密,名為 httpbin-credential。
    選項二:直接參考 金鑰保存庫 憑證物件 你的憑證已經以憑證物件形式儲存在 金鑰保存庫 中,例如匯入的 .pfx。 一個 金鑰保存庫 憑證物件。 有一個同步的 Kubernetes TLS 秘密,名為 httpbin-credential。

    Important

    不要同時採用兩種選項。 如果您使用選項 1,請將憑證和金鑰檔案上傳至 金鑰保存庫 並儲存為祕密,然後套用選項 1 的 SecretProviderClass 資訊清單。 如果你使用選項 2,跳過 金鑰保存庫 秘密上傳步驟,直接套用選項 2 SecretProviderClass 的清單。

選項一:將憑證和金鑰儲存為 金鑰保存庫 秘密

當您有獨立的 PEM 憑證(.crt)和私鑰(.key)檔案時,請使用此選項,例如本文前述產生的檔案。

  1. 將憑證與金鑰檔案上傳為 金鑰保存庫 秘密:

    az keyvault secret set --vault-name $AKV_NAME --name test-httpbin-key --file httpbin_certs/httpbin.example.com.key
    az keyvault secret set --vault-name $AKV_NAME --name test-httpbin-crt --file httpbin_certs/httpbin.example.com.crt
    

    Note

    每次你輪換(更改)憑證或金鑰時,都重新執行這個步驟,將新版本上傳為秘密。 要將更新後的值自動同步到叢集,請在 Secrets Store CSI 驅動程式的 Azure Key Vault 提供者上啟用自動旋轉功能。 更多資訊請參閱 自動旋轉與秘密同步總覽。 如果你偏好讓 金鑰保存庫 管理憑證生命週期,建議改用選項 2。

  2. 建立參考你在 金鑰保存庫 中建立的兩個祕密的 SecretProviderClass:

    cat <<EOF | kubectl apply -f -
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: httpbin-credential-spc
    spec:
      provider: azure
      secretObjects:
      - secretName: httpbin-credential
        type: kubernetes.io/tls
        data:
        - objectName: test-httpbin-key
          key: tls.key
        - objectName: test-httpbin-crt
          key: tls.crt
      parameters:
        useVMManagedIdentity: "true"
        userAssignedIdentityID: $CLIENT_ID 
        keyvaultName: $AKV_NAME
        cloudName: ""
        objects:  |
          array:
            - |
              objectName: test-httpbin-key
              objectType: secret
              objectAlias: "test-httpbin-key"
            - |
              objectName: test-httpbin-crt
              objectType: secret
              objectAlias: "test-httpbin-crt"
        tenantId: $TENANT_ID
    EOF
    

選項二:直接參考 金鑰保存庫 憑證物件

當憑證已經以憑證物件儲存在 Azure Key Vault 時,請使用此選項。 你不需要將 .crt 和 .key 檔案作為個別的 金鑰保存庫 祕密上傳。

在此範例中, test-httpbin-cert-pfx 是 Azure 金鑰保存庫中憑證物件的名稱。 若要將現有憑證匯入 金鑰保存庫 作為憑證物件,請參見「將憑證匯入 金鑰保存庫」。 欲了解更多物件參數資訊,請參閱 取得憑證與金鑰。

  1. 建立參考 金鑰保存庫 憑證物件的 SecretProviderClass:

    cat <<EOF | kubectl apply -f -
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: httpbin-credential-spc
    spec:
      provider: azure
      secretObjects:
      - secretName: httpbin-credential
        type: kubernetes.io/tls
        data:
        - objectName: test-httpbin-key
          key: tls.key
        - objectName: test-httpbin-crt
          key: tls.crt
      parameters:
        useVMManagedIdentity: "true"
        userAssignedIdentityID: $CLIENT_ID 
        keyvaultName: $AKV_NAME
        cloudName: ""
        objects:  |
          array:
            - |
              objectName: test-httpbin-cert-pfx  #certificate object name from keyvault
              objectType: secret
              objectAlias: "test-httpbin-key"
            - |
              objectName: test-httpbin-cert-pfx #certificate object name from keyvault
              objectType: cert
              objectAlias: "test-httpbin-crt"
        tenantId: $TENANT_ID
    EOF
    

將秘密同步到叢集

完成「選項 1」或「選項 2」後,部署一個範例 Pod,以將 Secret 同步至叢集。 Secrets Store CSI 驅動程式需要 Pod 參考 SecretProviderClass 資源,才能將 Azure Key Vault 中的祕密同步至叢集中。

  1. 請使用以下清單部署範例艙:

    cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: secrets-store-sync-httpbin
    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: "httpbin-credential-spc"
    EOF
    
    • 驗證在httpbin-credential命名空間中建立的default密碼是否如 SecretProviderClass 資源中所定義。

      kubectl describe secret/httpbin-credential
      

      輸出範例:

      Name:         httpbin-credential
      Namespace:    default
      Labels:       secrets-store.csi.k8s.io/managed=true
      Annotations:  <none>
      
      Type:  kubernetes.io/tls
      
      Data
      ====
      tls.crt:  1180 bytes
      tls.key:  1675 bytes
      

部署 TLS 閘道器

  1. 建立一個 Kubernetes Gateway,在 TLS 設定下引用該 httpbin-credential 機密:

    cat <<EOF | kubectl apply -f -
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: httpbin-gateway
    spec:
      gatewayClassName: approuting-istio
      listeners:
      - name: https
        hostname: "httpbin.example.com"
        port: 443
        protocol: HTTPS
        tls:
          mode: Terminate
          certificateRefs:
          - name: httpbin-credential
        allowedRoutes:
          namespaces:
            from: Selector
            selector:
              matchLabels:
                kubernetes.io/metadata.name: default
    EOF
    

    接著,建立對應 HTTPRoute 的介面來配置閘道的入口流量路由:

    cat <<EOF | kubectl apply -f -
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: httpbin
    spec:
      parentRefs:
      - name: httpbin-gateway
      hostnames: ["httpbin.example.com"]
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /status
        - path:
            type: PathPrefix
            value: /delay
        backendRefs:
        - name: httpbin
          port: 8000
    EOF
    

    取得閘道位址和埠口:

    kubectl wait --for=condition=programmed gateways.gateway.networking.k8s.io httpbin-gateway
    export INGRESS_HOST=$(kubectl get gateways.gateway.networking.k8s.io httpbin-gateway -o jsonpath='{.status.addresses[0].value}')
    export SECURE_INGRESS_PORT=$(kubectl get gateways.gateway.networking.k8s.io httpbin-gateway -o jsonpath='{.spec.listeners[?(@.name=="https")].port}')
    
  2. 發送 HTTPS 請求以存取服務 httpbin :

    curl -v -HHost:httpbin.example.com --resolve "httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST" \
    --cacert httpbin_certs/example.com.crt "https://httpbin.example.com:$SECURE_INGRESS_PORT/status/418"
    

    你應該會看到 httpbin 服務回傳 418 I’m a Teapot 狀態碼。