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 adapta a 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 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

Novamente, 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>
    [...]