Configurer le pilote CSI du magasin de secrets pour activer le contrôleur d’entrée NGINX avec TLS

Cet article vous guide tout au long du processus de sécurisation d’un contrôleur d’entrée NGINX avec TLS en utilisant un cluster Azure Kubernetes Service (AKS) et une instance Azure Key Vault (AKV). Pour plus d’informations, consultez TLS dans Kubernetes.

Vous pouvez importer le certificat TLS d’entrée dans le cluster à l’aide de l’une des méthodes suivantes :

  • Application : le manifeste de déploiement de l’application déclare et monte le volume du fournisseur. Ce n’est que lorsque vous déployez l’application que le certificat est disponible dans le cluster. Quand vous supprimez l’application, le secret est également supprimé. Ce scénario convient aux équipes de développement responsables de l’infrastructure de sécurité de l’application et de son intégration au cluster.
  • Contrôleur d’entrée : le déploiement d’entrée est modifié pour déclarer et monter le volume du fournisseur. Le secret est importé pendant la création des pods d’entrée. Les pods de l’application n’ont pas accès au certificat TLS. Ce scénario convient quand une équipe (par exemple le service informatique) gère et crée les composants de l’infrastructure et du réseau (y compris les certificats TLS HTTPS) et que d’autres équipes gèrent le cycle de vie des applications.

Prérequis

Générer un certificat TLS

  • Générez un certificat TLS à l’aide de la commande suivante.

    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"
    

Importer le certificat dans AKV

  1. Exportez le certificat dans un fichier PFX à l’aide de la commande suivante.

    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. Importez le certificat à l’aide de la commande az keyvault certificate import.

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

Déployer une SecretProviderClass

  1. Exportez un nouvel espace de noms à l’aide de la commande suivante.

    export NAMESPACE=ingress-basic
    
  2. Créez l’espace de noms à l’aide de la commande kubectl create namespace.

    kubectl create namespace $NAMESPACE
    
  3. Sélectionnez un mécanisme pour fournir une identité d’accès et configurez votre YAML de SecretProviderClass en conséquence.

    • Veillez à utiliser objectType=secret, qui est la seule façon d’obtenir la clé privée et le certificat d’AKV.
    • Définissez kubernetes.io/tls comme type dans votre section secretObjects.

    Pour obtenir un exemple de ce à quoi peut ressembler votre SecretProviderClass, consultez ce qui suit :

    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. Appliquez SecretProviderClass à votre cluster Kubernetes à l’aide de la commande kubectl apply.

    kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
    

Déployer le contrôleur d’entrée

Ajouter le dépôt de graphiques d’entrée officiel

  • Ajoutez le référentiel de graphique d’entrée officiel à l’aide des commandes helm suivantes.

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

Configurer et déployer l’entrée NGINX

Selon votre scénario, vous pouvez choisir de lier le certificat à l’application ou au contrôleur d’entrée. Suivez les instructions ci-dessous en fonction de votre sélection :

Lier le certificat à l’application

  • Liez le certificat à l’application à l’aide de la commande helm install. Le déploiement de l’application fait référence au fournisseur Azure Key Vault du pilote CSI du magasin de secrets.

    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
    

Lier le certificat au contrôleur d’entrée

  1. Liez le certificat au contrôleur d’entrée à l’aide de la commande helm install. Le déploiement du contrôleur d’entrée fait référence au fournisseur Azure Key Vault du pilote CSI du magasin de secrets.

    Remarque

    • Si vous n’utilisez pas l’identité managée de pod Microsoft Entra comme méthode d’accès, supprimez la ligne qui contient --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME.

    • Par ailleurs, la liaison de SecretProviderClass à un pod est nécessaire pour que le pilote CSI du magasin de secrets le monte et génère le secret Kubernetes. Consultez Synchroniser le contenu monté avec un secret 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. Vérifiez que le secret Kubernetes a été créé à l’aide de la commande kubectl get secret.

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

Déployer l’application

Là encore, les instructions changent légèrement en fonction de votre scénario. Suivez les instructions correspondant au scénario que vous avez sélectionné.

Déployer l’application à l’aide d’une référence d’application

  1. Créez un fichier nommé aks-helloworld-one.yaml avec le contenu suivant :

    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. Créez un fichier nommé aks-helloworld-two.yaml avec le contenu suivant :

    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. Appliquez les fichiers YAML à votre cluster à l’aide de la commande kubectl apply.

    kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE
    kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
    
  4. Vérifiez que le secret Kubernetes a été créé à l’aide de la commande kubectl get secret.

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

Déployer l’application à l’aide d’une référence de contrôleur d’entrée

  1. Créez un fichier nommé aks-helloworld-one.yaml avec le contenu suivant :

    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. Créez un fichier nommé aks-helloworld-two.yaml avec le contenu suivant :

    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. Appliquez les fichiers YAML à votre cluster à l’aide de la commande kubectl apply.

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

Déployer une ressource d’entrée qui référence le secret

Nous pouvons à présent déployer une ressource d’entrée Kubernetes qui fait référence au secret.

  1. Créez un fichier hello-world-ingress.yaml avec le contenu suivant.

    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. Notez la section tls qui fait référence au secret que nous avons créé précédemment et appliquez le fichier à votre cluster à l’aide de la commande kubectl apply.

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

Obtenir l’adresse IP externe du contrôleur d’entrée

  • Obtenez l’adresse IP externe du contrôleur d’entrée à l’aide de la commande kubectl get service.

    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
    

Tester l’entrée sécurisée avec TLS

  1. Vérifiez que votre entrée est correctement configurée avec TLS à l’aide de la commande curl suivante. Veillez à utiliser l’adresse IP externe de l’étape précédente.

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

    Aucun autre chemin n’ayant été fourni avec l’adresse, l’itinéraire par défaut du contrôleur d’entrée est /. La première application de démonstration est retournée, comme l’illustre l’exemple de sortie condensée suivant :

    [...]
    <!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>
    [...]
    

    Le paramètre -v figurant dans la commande curl fournit en sortie des informations détaillées incluant le certificat TLS reçu. À mi-chemin vers la sortie de la commande curl, vous pouvez vérifier que votre propre certificat TLS a été utilisé. Le paramètre -k continue le chargement de la page même si nous utilisons un certificat auto-signé. L’exemple suivant montre que le certificat issuer: CN=demo.azure.com; O=aks-ingress-tls a été utilisé :

    [...]
     * 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. Ajoutez le chemin /hello-world-two à l’adresse, par exemple, https://demo.azure.com/hello-world-two, puis vérifiez que la deuxième application de démonstration est correctement configurée.

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

    La deuxième application de démonstration avec le titre personnalisé est retournée, comme l’illustre l’exemple de sortie condensée suivant :

    [...]
    <!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>
    [...]