Proteger o tráfego de entrada com a implementação da API do Gateway de roteamento de aplicativos

Note

Este artigo descreve como configurar manualmente a terminação TLS em um recurso Gateway criando o seu próprio SecretProviderClass, montando o provedor do Azure Key Vault para o Driver CSI do repositório de segredos por meio de um pod de exemplo e referenciando o Segredo do Kubernetes resultante diretamente no Gateway do ouvintecertificateRefs. Essa abordagem é útil se você precisar de controle total sobre o fluxo de trabalho de sincronização de certificados ou preferir gerenciar esses recursos por conta própria.

Para a maioria dos usuários, o caminho recomendado é a integração automatizada entre o DNS do Azure e o Azure Key Vault, viabilizada pelo operador de Roteamento de Aplicativos, que provisiona e reconcilia a SecretProviderClass, o Segredo do Kubernetes sincronizado e o ouvinte certificateRefs para você com base em um par de ouvintes tls.options. Para usar o fluxo de trabalho automatizado, consulte Configurar DNS do Azure e TLS com a implementação da API do Gateway de roteamento de aplicativos.

O complemento de roteamento de aplicativos dá suporte à sincronização de segredos do AKV (Azure Key Vault) para proteger o tráfego de entrada da API do Gateway com o encerramento do TLS. Siga as etapas abaixo para criar certificados e chaves para encerrar o tráfego TLS no Gateway.

Pré-requisitos

Os certificados e as chaves de cliente/servidor são necessários

  1. Crie um certificado raiz e uma chave privada para assinar os certificados dos serviços de exemplo:
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. Gerar um certificado e uma chave 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

Configurar um gateway de entrada do TLS

Configurar o Azure Key Vault e sincronizar segredos para o cluster

  1. Criar Azure Key Vault

    Você precisa de um recurso do Azure Key Vault para fornecer o certificado e as entradas de chave para o complemento de roteamento de aplicativos.

    export AKV_NAME=<azure-key-vault-resource-name>  
    az keyvault create --name $AKV_NAME --resource-group $RESOURCE_GROUP --location $LOCATION
    
  2. Habilite o Provedor do Azure Key Vault no complemento do Driver CSI da Loja Secreta no seu cluster.

    az aks enable-addons --addons azure-keyvault-secrets-provider --resource-group $RESOURCE_GROUP --name $CLUSTER
    
  3. Se o Key Vault estiver usando o RBAC do Azure para o modelo de permissões, siga as instruções aqui para atribuir uma função do Azure de Usuário de Segredos do Key Vault para a identidade gerenciada atribuída pelo usuário do complemento. Alternativamente, se o seu cofre de chaves estiver usando o modelo de permissões de política de acesso ao cofre, autorize a identidade gerenciada atribuída pelo usuário do complemento a acessar o recurso do Azure Key Vault usando a política de acesso:

    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. Escolha como fornecer o certificado TLS.

    Azure Key Vault dá suporte a diferentes tipos de objeto. Para este passo a passo, escolha uma das seguintes opções de ponta a ponta e, depois, continue com as etapas comuns de validação e Gateway.

    Option Use essa opção quando Armazenamento do Key Vault Resultado do Segredo do Kubernetes
    Opção 1: armazenar o certificado e a chave como segredos Key Vault Você tem arquivos separados de certificado PEM (.crt) e chave privada (.key), como os arquivos gerados anteriormente neste artigo. Dois segredos do Key Vault. Um segredo TLS do Kubernetes sincronizado chamado httpbin-credential.
    Opção 2: Referenciar um objeto de certificado Key Vault diretamente Seu certificado já está armazenado no Key Vault como um objeto de certificado, como um certificado importado .pfx. Um objeto de certificado do Key Vault. Um segredo TLS sincronizado do Kubernetes chamado httpbin-credential.

    Importante

    Não siga as duas opções. Se você usar a Opção 1, faça upload dos arquivos de certificado e chave como segredos do Key Vault e, em seguida, aplique o manifesto da Opção 1 SecretProviderClass. Se você usar a Opção 2, pule a etapa de upload do segredo no Key Vault e aplique o manifesto da Opção 2 SecretProviderClass.

Opção 1: Armazenar o certificado e a chave como segredos do Key Vault

Use essa opção quando você tiver arquivos separados de certificado PEM (.crt) e chave privada (.key), como os arquivos gerados anteriormente neste artigo.

  1. Carregue os arquivos de certificado e de chave para o Key Vault como segredos:

    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

    Sempre que você rotacionar (alterar) o certificado ou a chave, execute esta etapa novamente para carregar as novas versões como segredos. Para sincronizar automaticamente os valores atualizados com o cluster, habilite a autorotação no provedor do Azure Key Vault para o Secrets Store CSI Driver. Para obter mais informações, consulte a visão geral da autorotação e da sincronização secreta. Se você preferir ter Key Vault gerenciar o ciclo de vida do certificado, use a Opção 2.

  2. Crie o SecretProviderClass que faz referência aos dois segredos que você criou no 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
    

Opção 2: Referenciar um objeto de certificado Key Vault diretamente

Use essa opção quando o certificado já estiver armazenado em Azure Key Vault como um objeto de certificado. Você não precisa fazer upload dos arquivos .crt e .key como segredos separados no Key Vault.

Neste exemplo, test-httpbin-cert-pfx é o nome do objeto de certificado no Azure Key Vault. Para importar um certificado existente para Key Vault como um objeto de certificado, consulte Importar um certificado para Key Vault. Para obter mais informações sobre os parâmetros de objeto, consulte obter certificados e chaves.

  1. Crie o SecretProviderClass que faz referência ao 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
    

Sincronizar o segredo com o cluster

Após concluir a Opção 1 ou a Opção 2, implante um pod de exemplo para sincronizar o segredo com o cluster. O Secrets Store CSI Driver exige que um pod faça referência ao recurso SecretProviderClass para que os segredos sejam sincronizados do Azure Key Vault com o cluster.

  1. Use o manifesto a seguir para implantar um pod de exemplo:

    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
    
    • Verifique se o httpbin-credential segredo foi criado no default namespace conforme definido no recurso SecretProviderClass.

      kubectl describe secret/httpbin-credential
      

      Exemplo de saída:

      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
      

Implantar gateway do TLS

  1. Crie um Gateway do Kubernetes que faça referência ao segredo httpbin-credential na configuração 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
    

    Em seguida, crie um elemento correspondente HTTPRoute para configurar as rotas de tráfego de entrada do 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
    

    Obtenha o endereço e a porta do 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. Envie uma solicitação HTTPS para acessar o httpbin serviço:

    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"
    

    Você deverá ver o serviço httpbin retornar o código 418 "I’m a Teapot".