Partilhar via


Configurar o driver CSI do Secrets Store para habilitar o NGINX Ingress Controller com TLS

Este artigo orienta você pelo processo de proteção de um Controlador de Ingresso NGINX com TLS com um cluster do Serviço Kubernetes do Azure (AKS) e uma instância do Azure Key Vault (AKV). Para obter mais informações, consulte TLS no Kubernetes.

Você pode importar o certificado TLS de entrada para o cluster usando um dos seguintes métodos:

  • Aplicativo: O manifesto de implantação do aplicativo declara e monta o volume do provedor. Somente quando você implanta o aplicativo é que o certificado é disponibilizado no cluster. Quando você remove o aplicativo, o segredo também é removido. Esse cenário se encaixa nas equipes de desenvolvimento responsáveis pela infraestrutura de segurança do aplicativo e sua integração com o cluster.
  • Ingress Controller: A implantação de ingresso é modificada para declarar e montar o volume do provedor. O segredo é importado quando os pods de entrada são criados. Os pods do aplicativo não têm acesso ao certificado TLS. Esse cenário se encaixa em cenários em que uma equipe (por exemplo, TI) gerencia e cria componentes de infraestrutura e rede (incluindo certificados HTTPS TLS) e outras equipes gerenciam o ciclo de vida do aplicativo.

Pré-requisitos

Gerar um certificado TLS

  • Gere um certificado TLS usando o seguinte comando.

    export CERT_NAME=aks-ingress-cert
    openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
        -out aks-ingress-tls.crt \
        -keyout aks-ingress-tls.key \
        -subj "/CN=demo.azure.com/O=aks-ingress-tls"
    

Importar o certificado para AKV

  1. Exporte o certificado para um arquivo PFX usando o seguinte comando.

    export AKV_NAME="[YOUR AKV NAME]"
    openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key  -out $CERT_NAME.pfx
    # skip Password prompt
    
  2. Importe o certificado usando o az keyvault certificate import comando.

    az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
    

Implantar um SecretProviderClass

  1. Exporte um novo namespace usando o comando a seguir.

    export NAMESPACE=ingress-basic
    
  2. Crie o namespace usando o kubectl create namespace comando.

    kubectl create namespace $NAMESPACE
    
  3. Selecione um método para fornecer uma identidade de acesso e configure seu YAML SecretProviderClass de acordo.

    • Certifique-se de usar objectType=secret, que é a única maneira de obter a chave privada e o certificado da AKV.
    • Defina kubernetes.io/tls como o type na sua secretObjects seção.

    Veja o exemplo a seguir de como seu SecretProviderClass pode parecer:

    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
      name: azure-tls
    spec:
      provider: azure
      secretObjects:                            # secretObjects defines the desired state of synced K8s secret objects
        - secretName: ingress-tls-csi
          type: kubernetes.io/tls
          data: 
            - objectName: $CERT_NAME
              key: tls.key
            - objectName: $CERT_NAME
              key: tls.crt
      parameters:
        usePodIdentity: "false"
        useVMManagedIdentity: "true"
        userAssignedIdentityID: <client id>
        keyvaultName: $AKV_NAME                 # the name of the AKV instance
        objects: |
          array:
            - |
              objectName: $CERT_NAME
              objectType: secret
        tenantId: $TENANT_ID                    # the tenant ID of the AKV instance
    
  4. Aplique o SecretProviderClass ao cluster do Kubernetes usando o kubectl apply comando.

    kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
    

Implantar o controlador de ingresso

Adicione o repositório oficial do gráfico de entrada

  • Adicione o repositório oficial do gráfico de entrada usando os seguintes helm comandos.

    helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    helm repo update
    

Configurar e implantar a entrada NGINX

Dependendo do cenário, você pode optar por vincular o certificado ao aplicativo ou ao controlador de entrada. Siga as instruções abaixo de acordo com a sua seleção:

Vincular certificado ao aplicativo

  • Vincule o certificado ao aplicativo usando o helm install comando. A implantação do aplicativo faz referência ao provedor do Azure Key Vault do Driver CSI do Secrets Store.

    helm install ingress-nginx/ingress-nginx --generate-name \
        --namespace $NAMESPACE \
        --set controller.replicaCount=2 \
        --set controller.nodeSelector."kubernetes\.io/os"=linux \
        --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
        --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux
    

Vincular certificado ao controlador de ingresso

  1. Vincule o certificado ao controlador de entrada usando o helm install comando. A implantação do controlador de ingresso faz referência ao provedor do Azure Key Vault do Driver CSI do Secrets Store.

    Nota

    • Se não estiver usando a identidade gerenciada pelo pod do Microsoft Entra como seu método de acesso, remova a linha com --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME .

    • Além disso, vincular o SecretProviderClass a um pod é necessário para que o driver CSI do Secrets Store o monte e gere o segredo do Kubernetes. Consulte Sincronizar conteúdo montado com um segredo do Kubernetes .

    helm install ingress-nginx/ingress-nginx --generate-name \
        --namespace $NAMESPACE \
        --set controller.replicaCount=2 \
        --set controller.nodeSelector."kubernetes\.io/os"=linux \
        --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \
        --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
        --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \
        -f - <<EOF
    controller:
      extraVolumes:
          - name: secrets-store-inline
            csi:
              driver: secrets-store.csi.k8s.io
              readOnly: true
              volumeAttributes:
                secretProviderClass: "azure-tls"
      extraVolumeMounts:
          - name: secrets-store-inline
            mountPath: "/mnt/secrets-store"
            readOnly: true
    EOF
    
  2. Verifique se o segredo do Kubernetes foi criado usando o kubectl get secret comando.

    kubectl get secret -n $NAMESPACE
    
    NAME                                             TYPE                                  DATA   AGE
    ingress-tls-csi                                  kubernetes.io/tls                     2      1m34s
    

Implementar a aplicação

Mais uma vez, as instruções mudam ligeiramente dependendo do seu cenário. Siga as instruções correspondentes ao cenário selecionado.

Implantar o aplicativo usando uma referência de aplicativo

  1. Crie um arquivo nomeado aks-helloworld-one.yaml com o seguinte conteúdo.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: aks-helloworld-one  
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: aks-helloworld-one
      template:
        metadata:
          labels:
            app: aks-helloworld-one
        spec:
          containers:
          - name: aks-helloworld-one
            image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
            ports:
            - containerPort: 80
            env:
            - name: TITLE
              value: "Welcome to Azure Kubernetes Service (AKS)"
            volumeMounts:
            - name: secrets-store-inline
              mountPath: "/mnt/secrets-store"
              readOnly: true
          volumes:
          - name: secrets-store-inline
            csi:
              driver: secrets-store.csi.k8s.io
              readOnly: true
              volumeAttributes:
                secretProviderClass: "azure-tls"
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: aks-helloworld-one  
    spec:
      type: ClusterIP
      ports:
      - port: 80
      selector:
        app: aks-helloworld-one
    
  2. Crie um arquivo nomeado aks-helloworld-two.yaml com o seguinte conteúdo.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: aks-helloworld-two  
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: aks-helloworld-two
      template:
        metadata:
          labels:
            app: aks-helloworld-two
        spec:
          containers:
          - name: aks-helloworld-two
            image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
            ports:
            - containerPort: 80
            env:
            - name: TITLE
              value: "AKS Ingress Demo"
            volumeMounts:
            - name: secrets-store-inline
              mountPath: "/mnt/secrets-store"
              readOnly: true
          volumes:
          - name: secrets-store-inline
            csi:
              driver: secrets-store.csi.k8s.io
              readOnly: true
              volumeAttributes:
                secretProviderClass: "azure-tls"
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: aks-helloworld-two
    spec:
      type: ClusterIP
      ports:
      - port: 80
      selector:
        app: aks-helloworld-two
    
  3. Aplique os arquivos YAML ao cluster usando o kubectl apply comando.

    kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE
    kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
    
  4. Verifique se o segredo do Kubernetes foi criado usando o kubectl get secret comando.

    kubectl get secret -n $NAMESPACE
    
    NAME                                             TYPE                                  DATA   AGE
    ingress-tls-csi                                  kubernetes.io/tls                     2      1m34s
    

Implantar o aplicativo usando uma referência de controlador de entrada

  1. Crie um arquivo nomeado aks-helloworld-one.yaml com o seguinte conteúdo.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: aks-helloworld-one  
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: aks-helloworld-one
      template:
        metadata:
          labels:
            app: aks-helloworld-one
        spec:
          containers:
          - name: aks-helloworld-one
            image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
            ports:
            - containerPort: 80
            env:
            - name: TITLE
              value: "Welcome to Azure Kubernetes Service (AKS)"
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: aks-helloworld-one
    spec:
      type: ClusterIP
      ports:
      - port: 80
      selector:
        app: aks-helloworld-one
    
  2. Crie um arquivo nomeado aks-helloworld-two.yaml com o seguinte conteúdo.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: aks-helloworld-two  
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: aks-helloworld-two
      template:
        metadata:
          labels:
            app: aks-helloworld-two
        spec:
          containers:
          - name: aks-helloworld-two
            image: mcr.microsoft.com/azuredocs/aks-helloworld:v1
            ports:
            - containerPort: 80
            env:
            - name: TITLE
              value: "AKS Ingress Demo"
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: aks-helloworld-two  
    spec:
      type: ClusterIP
      ports:
      - port: 80
      selector:
        app: aks-helloworld-two
    
  3. Aplique os arquivos YAML ao cluster usando o kubectl apply comando.

    kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE
    kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
    

Implantar um recurso de entrada fazendo referência ao segredo

Agora podemos implantar um recurso de ingresso do Kubernetes fazendo referência ao segredo.

  1. Crie um nome hello-world-ingress.yaml de arquivo com o seguinte conteúdo.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-tls
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /$2
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - demo.azure.com
        secretName: ingress-tls-csi
      rules:
      - host: demo.azure.com
        http:
          paths:
          - path: /hello-world-one(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
          - path: /hello-world-two(/|$)(.*)
            pathType: Prefix      
            backend:
              service:
                name: aks-helloworld-two
                port:
                  number: 80
          - path: /(.*)
            pathType: Prefix      
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
    
  2. Anote a tls seção que faz referência ao segredo criado anteriormente e aplique o arquivo ao cluster usando o kubectl apply comando.

    kubectl apply -f hello-world-ingress.yaml -n $NAMESPACE
    

Obter o endereço IP externo do controlador de entrada

  • Obtenha o endereço IP externo para o controlador de entrada usando o kubectl get service comando.

    kubectl get service --namespace $NAMESPACE --selector app.kubernetes.io/name=ingress-nginx
    
    NAME                                       TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)                      AGE
    nginx-ingress-1588032400-controller        LoadBalancer   10.0.255.157   EXTERNAL_IP      80:31293/TCP,443:31265/TCP   19m
    nginx-ingress-1588032400-default-backend   ClusterIP      10.0.223.214   <none>           80/TCP                       19m
    

Ingresso de teste protegido com TLS

  1. Verifique se sua entrada está configurada corretamente com TLS usando o comando a seguir curl . Certifique-se de usar o IP externo da etapa anterior.

    curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
    

    Como outro caminho não foi fornecido com o endereço, o controlador de entrada assume como padrão a / rota. O primeiro aplicativo de demonstração é retornado, como mostrado na seguinte saída de exemplo condensado:

    [...]
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <link rel="stylesheet" type="text/css" href="/static/default.css">
        <title>Welcome to Azure Kubernetes Service (AKS)</title>
    [...]
    

    O parâmetro -v no curl comando produz informações detalhadas, incluindo o certificado TLS recebido. Na metade da saída de ondulação, você pode verificar se seu próprio certificado TLS foi usado. O parâmetro -k continua carregando a página mesmo que estejamos usando um certificado autoassinado. O exemplo a seguir mostra o emissor: CN=demo.azure.com; O=aks-ingress-tls foi utilizado certificado:

    [...]
     * Server certificate:
     *  subject: CN=demo.azure.com; O=aks-ingress-tls
     *  start date: Oct 22 22:13:54 2021 GMT
     *  expire date: Oct 22 22:13:54 2022 GMT
     *  issuer: CN=demo.azure.com; O=aks-ingress-tls
     *  SSL certificate verify result: self signed certificate (18), continuing anyway.
    [...]
    
  2. Adicione o caminho /hello-world-two ao endereço, como https://demo.azure.com/hello-world-two, e verifique se o segundo aplicativo de demonstração está configurado corretamente.

    curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
    

    O segundo aplicativo de demonstração com o título personalizado é retornado, conforme mostrado na seguinte saída de exemplo condensado:

    [...]
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <link rel="stylesheet" type="text/css" href="/static/default.css">
        <title>AKS Ingress Demo</title>
    [...]