Поделиться через


Безопасный шлюз входящего трафика для надстройки сетки службы Istio для Служба Azure Kubernetes

В статье "Развертывание внешнего или внутреннего Istio Ingress" описывается, как настроить шлюз входящего трафика для предоставления http-службы внешнему или внутреннему трафику. В этой статье показано, как предоставить безопасную службу HTTPS с помощью простого или взаимного TLS.

Необходимые компоненты

Примечание.

Эта статья относится к внешнему шлюзу ingress для демонстрации, те же действия будут применяться для настройки взаимной TLS для внутреннего шлюза входящего трафика.

Обязательные сертификаты и ключи клиента или сервера

В этой статье требуется несколько сертификатов и ключей. Вы можете использовать избранное средство для их создания или использовать следующие команды opensl .

  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

Создайте секрет TLS Kubernetes для шлюза входящего трафика; используйте Azure Key Vault для размещения сертификатов и ключей и надстройки поставщика секретов Azure Key Vault для синхронизации секретов с кластером.

Настройка Azure Key Vault и синхронизация секретов с кластером

  1. Создание хранилища Azure Key Vault

    Для предоставления входных данных сертификата и ключа надстройке Istio требуется ресурс Azure Key Vault.

    export AKV_NAME=<azure-key-vault-resource-name>  
    az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
    
  2. Включите поставщик Azure Key Vault для надстройки CSI Driver для хранилища секретов в кластере.

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. Авторизация управляемого удостоверения, назначаемого пользователем надстройки, для доступа к ресурсу Azure Key Vault с помощью политики доступа. Кроме того, если хранилище ключей использует Azure RBAC для модели разрешений, следуйте инструкциям, приведенным здесь , чтобы назначить роль 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. Создайте секреты в 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, чтобы предоставить Azure Key Vault определенные параметры драйверу CSI.

    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
    
    • Проверьте 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
      

Настройка шлюза входящего трафика и виртуальной службы

Маршрутизация трафика HTTPS через шлюз Istio ingress в примеры приложений. Используйте следующий манифест для развертывания ресурсов шлюза и виртуальной службы.

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 шлюза должен соответствовать ресурсу secretName SecretProviderClass и 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-запрос для доступа к службе productpage через 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.crt.

    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
    

    Используйте следующий манифест, чтобы повторно создать 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