Asegure el tráfico de ingreso con la implementación de la API Gateway de enrutamiento de aplicaciones

Note

En este artículo se describe cómo configurar manualmente la terminación TLS en un recurso Gateway creando su propio SecretProviderClass, montando el proveedor de Azure Key Vault para Secrets Store CSI Driver mediante un pod de ejemplo y haciendo referencia directamente al secreto de Kubernetes resultante en el GatewaycertificateRefs del agente de escucha. Este enfoque es útil si necesita control total sobre el flujo de trabajo de sincronización de certificados o prefiere administrar estos recursos usted mismo.

Para la mayoría de los usuarios, la ruta de acceso recomendada es la integración automatizada de Azure DNS y Azure Key Vault con tecnología del operador de enrutamiento de aplicaciones, que aprovisiona y reconcilia SecretProviderClass, el secreto de Kubernetes sincronizado y el agente de escucha certificateRefs en función de un par de agentes de escuchatls.options. Para usar el flujo de trabajo automatizado, consulte Configuración de Azure DNS y TLS con la implementación de la API de puerta de enlace de enrutamiento de aplicaciones.

El complemento de enrutamiento de aplicaciones admite la sincronización de secretos desde Azure Key Vault (AKV) para proteger el tráfico entrante de la API de puerta de enlace con la terminación TLS. Siga los pasos siguientes para crear certificados y claves para finalizar el tráfico TLS en la puerta de enlace.

Prerrequisitos

  • Habilitar la implementación de la API de Gateway de enrutamiento de aplicaciones
  • Habilite la instalación de la API de puerta de enlace administrada.
  • Establecer variables de entorno:
    export CLUSTER=<cluster-name>
    export RESOURCE_GROUP=<resource-group-name>
    export LOCATION=<location>
    

Claves y certificados cliente y servidor necesarios

  1. Cree un certificado raíz y una clave privada para firmar los certificados de los servicios de ejemplo:
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. Genere un certificado y una clave privada para 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

Configuración de una puerta de enlace de entrada TLS

Configuración de Azure Key Vault y sincronización de secretos con el clúster

  1. Crear una instancia de Azure Key Vault

    Necesita un recurso de Azure Key Vault para proporcionar el certificado y las entradas de clave al complemento de enrutamiento de aplicaciones.

    export AKV_NAME=<azure-key-vault-resource-name>  
    az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
    
  2. Habilite el complemento del proveedor de Azure Key Vault para el controlador CSI del almacén de secretos en su clúster.

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. Si Key Vault está utilizando RBAC de Azure para el modelo de permisos, siga las instrucciones que se indican aquí para asignar un rol de Azure de Usuario de Secretos de Key Vault a la identidad administrada asignada por el usuario del complemento. Como alternativa, si el almacén de claves usa el modelo de permisos de directiva de acceso del almacén, autorice la identidad administrada asignada por el usuario del complemento para que pueda acceder al recurso de Azure Key Vault mediante la directiva de acceso.

    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. Elija cómo proporcionar el certificado TLS.

    Azure Key Vault admite diferentes tipos de objeto. Para este tutorial, elija una de las siguientes opciones de un extremo a otro y, a continuación, continúe con los pasos comunes de validación y puerta de enlace.

    Option Use esta opción cuando almacenes de Key Vault Resultado de Kubernetes Secret
    Opción 1: Almacenar el certificado y la clave como secretos de Key Vault Tiene archivos independientes de certificado PEM (.crt) y clave privada (.key), como los archivos generados anteriormente en este artículo. Dos secretos de Key Vault. Un secreto TLS de Kubernetes sincronizado denominado httpbin-credential.
    Opción 2: Hacer referencia directamente a un objeto de certificado de Key Vault El certificado ya está almacenado en Key Vault como un objeto de certificado, como un objeto importado.pfx. Un objeto de certificado Key Vault. Un secreto TLS sincronizado de Kubernetes llamado httpbin-credential.

    Importante

    No siga ambas opciones. Si usa la opción 1, cargue los archivos del certificado y de la clave como secretos de Key Vault y, a continuación, aplique el manifiesto de la opción 1 SecretProviderClass. Si usa la opción 2, omita el paso de carga del secreto de Key Vault y aplique el manifiesto de la opción 2 SecretProviderClass.

Opción 1: Almacenar el certificado y la clave como secretos de Key Vault

Use esta opción cuando tenga archivos independientes de certificado PEM (.crt) y clave privada (.key), como los archivos generados anteriormente en este artículo.

  1. Cargue los archivos de certificado y clave como secretos de 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

    Cada vez que gire (cambie) el certificado o la clave, vuelva a ejecutar este paso para cargar las nuevas versiones como secretos. Para sincronizar automáticamente los valores actualizados con el clúster, habilite la rotación automática en el proveedor de Azure Key Vault para Secrets Store CSI Driver. Para obtener más información, consulte Descripción general de la rotación automática y la sincronización de secretos. Si prefiere tener Key Vault administrar el ciclo de vida del certificado, use la opción 2 en su lugar.

  2. Cree el objeto SecretProviderClass que hace referencia a los dos secretos que creó en 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
    

Opción 2: Hacer referencia directamente a un objeto de certificado de Key Vault

Use esta opción cuando el certificado ya esté almacenado en Azure Key Vault como un objeto de certificado. No es necesario subir los archivos .crt y .key como secretos independientes en Key Vault.

En este ejemplo, test-httpbin-cert-pfx es el nombre del objeto de certificado en Azure Key Vault. Para importar un certificado existente en Key Vault como un objeto de certificado, consulte Importación de un certificado en Key Vault. Para obtener más información sobre los parámetros de objeto, consulte Obtención de certificados y claves.

  1. Cree el SecretProviderClass objeto que hace referencia al objeto de certificado 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
    

Sincronización del secreto con el clúster

Después de completar la opción 1 o la opción 2, implemente un pod de ejemplo para sincronizar el secreto con el clúster. El controlador CSI de Secrets Store requiere que un pod haga referencia al recurso SecretProviderClass para que los secretos se sincronicen desde Azure Key Vault con el clúster.

  1. Use el siguiente manifiesto para implementar un pod de ejemplo:

    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
    
    • Compruebe que el secreto httpbin-credential se crea en el espacio de nombres default como se define en el recurso SecretProviderClass.

      kubectl describe secret/httpbin-credential
      

      Ejemplo de resultado:

      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
      

Implementación de TLS Gateway

  1. Cree una puerta de enlace de Kubernetes que haga referencia al httpbin-credential secreto en la configuración de 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
    

    A continuación, cree un HTTPRoute correspondiente para configurar las rutas de tráfico entrante de la puerta de enlace.

    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
    

    Obtenga la dirección y el puerto de la puerta de enlace:

    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. Envíe una solicitud HTTPS para acceder al httpbin servicio:

    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"
    

    Debería ver que el servicio httpbin devuelve el código 418 "I'm a Teapot".