Zabezpieczanie ruchu przychodzącego przy użyciu implementacji Gateway API do routingu aplikacji

Note

W tym artykule opisano, jak ręcznie skonfigurować terminację TLS w zasobie Gateway, tworząc własny obiekt SecretProviderClass, podłączając dostawcę Azure Key Vault dla sterownika Secrets Store CSI Driver przy użyciu przykładowego poda oraz odwołując się bezpośrednio do utworzonego wpisu tajnego Kubernetes w elemencie Gateway odbiornika certificateRefs. Takie podejście jest przydatne, jeśli potrzebujesz pełnej kontroli nad przepływem pracy synchronizacji certyfikatów lub chcesz samodzielnie zarządzać tymi zasobami.

Dla większości użytkowników zalecanym rozwiązaniem jest automatyczna integracja usługi Azure DNS i usługi Azure Key Vault realizowana przez operator routingu aplikacji, która na podstawie pary elementów listener SecretProviderClass tworzy i uzgadnia element certificateRefs, zsynchronizowany sekret Kubernetes oraz nasłuch tls.options. Aby użyć zautomatyzowanego przepływu pracy, zobacz Konfigurowanie Azure DNS i protokołu TLS przy użyciu implementacji interfejsu API routingu aplikacji.

Dodatek do routingu aplikacji obsługuje synchronizowanie tajnych danych z usługi Azure Key Vault (AKV) w celu zabezpieczania ruchu przychodzącego przez interfejs API bramy z zakończeniem sesji TLS. Wykonaj poniższe kroki, aby utworzyć certyfikaty i klucze w celu przerwania ruchu TLS w bramie.

Wymagania wstępne

Wymagane certyfikaty i klucze klienta/serwera

  1. Utwórz certyfikat główny i klucz prywatny na potrzeby podpisywania certyfikatów dla przykładowych usług:
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. Wygeneruj certyfikat i klucz prywatny dla elementu 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

Konfigurowanie bramy wejściowej TLS

Skonfiguruj Azure Key Vault i zsynchronizuj sekrety z klastrem

  1. Tworzenie usługi Azure Key Vault

    Potrzebny jest zasób usługi Azure Key Vault , aby dostarczyć certyfikat i kluczowe dane wejściowe do dodatku routingu aplikacji.

    export AKV_NAME=<azure-key-vault-resource-name>  
    az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
    
  2. Włącz dodatek dostawcy Azure Key Vault dla sterownika CSI magazynu tajemnic w klastrze.

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. Jeśli Key Vault używa Azure RBAC do modelu uprawnień, postępuj zgodnie z podanymi instrukcjami, aby przydzielić rolę użytkownika do zarządzania tajemnicami w Key Vault dla tożsamości zarządzanej użytkownika dodatku. Alternatywnie, jeśli magazyn kluczy korzysta z modelu uprawnień zasad dostępu magazynu, autoryzuj przypisaną przez użytkownika, zarządzaną tożsamość dodatku w celu uzyskania dostępu do zasobu usługi Azure Key Vault przy użyciu zasad dostępu.

    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. Wybierz sposób dostarczania certyfikatu TLS.

    Azure Key Vault obsługuje różne typy obiektów. W tym przewodniku wybierz jedną z poniższych kompleksowych opcji, a następnie przejdź do wspólnych kroków walidacji i bramy.

    Option Użyj tej opcji, gdy magazyny Key Vault Wynik wpisu tajnego platformy Kubernetes
    Opcja 1: Przechowuj certyfikat i klucz jako wpisy tajne w usłudze Key Vault Masz oddzielne pliki certyfikatu PEM (.crt) i klucza prywatnego (.key), takie jak pliki wygenerowane wcześniej w tym artykule. Dwa wpisy tajne usługi Key Vault. Jeden zsynchronizowany sekret TLS platformy Kubernetes o nazwie httpbin-credential.
    Opcja 2: Odwołaj się bezpośrednio do obiektu certyfikatu usługi Key Vault Twój certyfikat jest już przechowywany w Key Vault jako obiekt certyfikatu, na przykład zaimportowany .pfx. Jeden obiekt certyfikatu Key Vault. Jeden zsynchronizowany sekret TLS platformy Kubernetes o nazwie httpbin-credential.

    Ważna

    Nie przestrzegaj obu opcji. Jeśli używasz opcji 1, prześlij pliki certyfikatu i klucza jako wpisy tajne usługi Key Vault, a następnie zastosuj manifest dla opcji 1 SecretProviderClass. Jeśli używasz opcji 2, pomiń krok przesyłania wpisu tajnego do usługi Key Vault i zastosuj manifest opcji 2 SecretProviderClass.

Opcja 1: Przechowuj certyfikat i klucz jako wpisy tajne usługi Key Vault

Użyj tej opcji, jeśli masz oddzielne pliki certyfikatu PEM (.crt) i klucza prywatnego (.key), takie jak pliki wygenerowane wcześniej w tym artykule.

  1. Prześlij pliki certyfikatu i klucza jako wpisy tajne w usłudze Key Vault:

    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

    Za każdym razem, gdy zmieniasz certyfikat lub klucz, powtórz ten krok, aby przesłać nowe wersje jako sekrety. Aby automatycznie synchronizować zaktualizowane wartości w klastrze, włącz automatyczną rotację dla dostawcy Azure Key Vault w Secrets Store CSI Driver. Aby uzyskać więcej informacji, zobacz Automatyczna rotacja i omówienie synchronizacji sekretów. Jeśli wolisz Key Vault zarządzać cyklem życia certyfikatu, zamiast tego użyj opcji 2.

  2. Utwórz obiekt SecretProviderClass, który odwołuje się do dwóch sekretów utworzonych w usłudze Key Vault:

    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
    

Opcja 2: Bezpośrednie odwołanie do obiektu certyfikatu usługi Key Vault

Użyj tej opcji, gdy certyfikat jest już przechowywany w Azure Key Vault jako obiekt certyfikatu. Nie musisz przesyłać plików .crt i .key jako osobnych wpisów tajnych w usłudze Key Vault.

W tym przykładzie test-httpbin-cert-pfx jest nazwą obiektu certyfikatu w usłudze Azure Key Vault. Aby zaimportować istniejący certyfikat do Key Vault jako obiekt certyfikatu, zobacz Importowanie certyfikatu do Key Vault. Aby uzyskać więcej informacji na temat parametrów obiektu, zobacz uzyskiwanie certyfikatów i kluczy.

  1. Utwórz element SecretProviderClass, który odwołuje się do obiektu certyfikatu usługi Key Vault:

    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
    

Synchronizuj klucz tajny z klastrem

Po ukończeniu opcji 1 albo opcji 2 wdroż przykładowy pod, aby zsynchronizować secret z klastrem. Sterownik Secrets Store CSI wymaga, aby zasobnik odwoływał się do zasobu SecretProviderClass, aby sekrety były synchronizowane z usługi Azure Key Vault do klastra.

  1. Użyj następującego manifestu, aby wdrożyć przykładowy zasobnik:

    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
    
    • Sprawdź, czy wpis httpbin-credential tajny został utworzony w przestrzeni nazw zgodnie z definicją default w zasobie SecretProviderClass.

      kubectl describe secret/httpbin-credential
      

      Przykładowy wynik:

      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
      

Wdrażanie bramy TLS

  1. Utwórz bramę Kubernetes, która odwołuje się do sekretu httpbin-credential w ramach konfiguracji protokołu TLS.

    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
    

    Następnie utwórz odpowiedni element HTTPRoute, aby skonfigurować trasy ruchu przychodzącego bramy.

    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
    

    Pobierz adres i port bramy:

    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. Wyślij żądanie HTTPS, aby uzyskać dostęp do httpbin usługi:

    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"
    

    Usługa httpbin powinna zwrócić kod 418 "I'm a Teapot".