Proteggere il traffico in ingresso con l'implementazione dell'API gateway di routing dell'applicazione

Note

Questo articolo descrive come configurare manualmente la terminazione TLS in una risorsa Gateway creando il proprio SecretProviderClass, montando il provider Azure Key Vault per il driver CSI dell'archivio segreti tramite un pod di esempio e facendo riferimento al segreto Kubernetes risultante direttamente nel Gateway del listener certificateRefs. Questo approccio è utile se è necessario il controllo completo sul flusso di lavoro di sincronizzazione certificati o se si preferisce gestire manualmente queste risorse.

Per la maggior parte degli utenti, l'approccio consigliato è l'integrazione automatica di DNS di Azure e Azure Key Vault basata sull'operatore Application Routing, che esegue il provisioning e riconcilia il SecretProviderClass, il Secret Kubernetes sincronizzato e il listener certificateRefs per l'utente in base a una coppia di listener tls.options. Per usare il flusso di lavoro automatizzato, vedere Configurare DNS di Azure e TLS con l'implementazione dell'API del gateway di routing dell'applicazione.

Il componente aggiuntivo di routing dell'applicazione supporta la sincronizzazione dei segreti da Azure Key Vault (AKV) per proteggere il traffico in ingresso dell'API del gateway con terminazione TLS. Seguire questa procedura per creare certificati e chiavi per terminare il traffico TLS nel gateway.

Prerequisiti

Certificati e chiavi client/server necessari

  1. Creare un certificato radice e una chiave privata per firmare i certificati per i servizi di esempio:
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. Generare un certificato e una chiave privata per 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

Configurare un gateway di ingresso TLS

Configurare Azure Key Vault e sincronizzare i segreti nel cluster

  1. Creare un Azure Key Vault

    È necessaria una risorsa di Azure Key Vault per fornire il certificato e gli input della chiave al componente aggiuntivo di routing dell'applicazione.

    export AKV_NAME=<azure-key-vault-resource-name>  
    az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
    
  2. Abilitare il componente aggiuntivo sul cluster provider di Azure Key Vault per il driver CSI dell'archivio segreto.

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. Se il Key Vault utilizza Azure RBAC per il modello di autorizzazioni, seguire le istruzioni qui per assegnare un ruolo Azure di Key Vault Secrets User all'identità gestita assegnata dall'utente del componente aggiuntivo. In alternativa, se il Key Vault utilizza il modello di autorizzazioni dei criteri di accesso, autorizzare l'identità gestita assegnata dall'utente dell'add-on ad accedere alla risorsa di Azure Key Vault utilizzando i criteri di accesso:

    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. Scegliere come specificare il certificato TLS.

    Azure Key Vault supporta tipi di oggetto diversi. Per questa procedura guidata, scegli una delle seguenti opzioni complete e quindi procedi con i passaggi comuni di convalida e di Gateway.

    Option Usare questa opzione quando archivi di Key Vault Risultato del segreto Kubernetes
    Opzione 1: Archiviare il certificato e la chiave come segreti Key Vault Sono disponibili file di certificato PEM (.crt) e chiave privata (.key), ad esempio i file generati in precedenza in questo articolo. Due segreti di Key Vault. Un segreto TLS Kubernetes sincronizzato denominato httpbin-credential.
    Opzione 2: Fare riferimento direttamente a un oggetto certificato Key Vault Il certificato è già archiviato in Key Vault come oggetto certificato, ad esempio un oggetto importato.pfx. Un oggetto certificato Key Vault. Un segreto TLS Kubernetes sincronizzato denominato httpbin-credential.

    Importante

    Non seguire entrambe le opzioni. Se si utilizza l'Opzione 1, carica i file del certificato e della chiave come segreti di Key Vault, quindi applica il manifest dell'Opzione 1 SecretProviderClass. Se si utilizza l'opzione 2, saltare il passaggio di caricamento del segreto in Key Vault e applicare il manifest di Opzione 2 SecretProviderClass.

Opzione 1: Archiviare il certificato e la chiave come segreti Key Vault

Usare questa opzione quando sono presenti file separati di certificato PEM (.crt) e chiave privata (.key), ad esempio i file generati in precedenza in questo articolo.

  1. Caricate i file del certificato e della chiave come segreti di 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

    Ogni volta che si ruota (modifica) il certificato o la chiave, eseguire nuovamente questo passaggio per caricare le nuove versioni come segreti. Per sincronizzare automaticamente nel cluster i valori aggiornati, abilita la rotazione automatica nel provider Azure Key Vault per Secrets Store CSI Driver. Per altre informazioni, vedi Panoramica della rotazione automatica e della sincronizzazione dei segreti. Se si preferisce avere Key Vault gestire il ciclo di vita del certificato, usare invece l'opzione 2.

  2. Creare l'oggetto SecretProviderClass che fa riferimento ai due segreti creati in 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
    

Opzione 2: Fare riferimento direttamente a un oggetto certificato Key Vault

Usare questa opzione quando il certificato è già archiviato in Azure Key Vault come oggetto certificato. Non è necessario caricare i .crt file e .key come segreti Key Vault separati.

In questo esempio è test-httpbin-cert-pfx il nome dell'oggetto certificato in Azure Key Vault. Per importare un certificato esistente in Key Vault come oggetto certificato, vedere Importare un certificato in Key Vault. Per altre informazioni sui parametri dell'oggetto, vedere Ottenere certificati e chiavi.

  1. Creare l'oggetto SecretProviderClass che fa riferimento all'oggetto certificato 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
    

Sincronizzare il segreto con il cluster

Dopo aver completato l'opzione 1 o l'opzione 2, distribuisci un pod di esempio per sincronizzare il segreto all'interno del cluster. Secrets Store CSI Driver richiede che un pod faccia riferimento alla risorsa SecretProviderClass affinché i segreti vengano sincronizzati da Azure Key Vault al cluster.

  1. Usare il manifesto seguente per distribuire un pod di esempio:

    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
    
    • Verificare che il segreto httpbin-credential venga creato nello spazio dei nomi default come definito nella risorsa SecretProviderClass.

      kubectl describe secret/httpbin-credential
      

      Output di esempio:

      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
      

Distribuire il gateway TLS

  1. Creare un gateway Kubernetes che faccia riferimento al httpbin-credential segreto nella configurazione 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
    

    Creare quindi un oggetto corrispondente HTTPRoute per configurare le route di traffico in ingresso del gateway:

    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
    

    Ottenere l'indirizzo e la porta del gateway:

    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. Inviare una richiesta HTTPS per accedere al httpbin servizio:

    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"
    

    Verrà visualizzato il servizio httpbin che restituisce il codice 418 I'm a Teapot.