Konfigurowanie sterownika CSI magazynu wpisów tajnych w celu włączenia kontrolera ruchu przychodzącego NGINX za pomocą protokołu TLS

W tym artykule przedstawiono proces zabezpieczania kontrolera ruchu przychodzącego NGINX przy użyciu protokołu TLS z klastrem usługi Azure Kubernetes Service (AKS) i wystąpieniem usługi Azure Key Vault (AKV). Aby uzyskać więcej informacji, zobacz TLS w rozwiązaniu Kubernetes.

Certyfikat TLS ruchu przychodzącego można zaimportować do klastra przy użyciu jednej z następujących metod:

  • Aplikacja: manifest wdrożenia aplikacji deklaruje i instaluje wolumin dostawcy. Tylko podczas wdrażania aplikacji jest certyfikat udostępniony w klastrze. Usunięcie aplikacji spowoduje również usunięcie wpisu tajnego. Ten scenariusz pasuje do zespołów programistycznych odpowiedzialnych za infrastrukturę zabezpieczeń aplikacji i jej integrację z klastrem.
  • Kontroler ruchu przychodzącego: wdrożenie ruchu przychodzącego jest modyfikowane w celu deklarowania i instalowania woluminu dostawcy. Wpis tajny jest importowany podczas tworzenia zasobników ruchu przychodzącego. Zasobniki aplikacji nie mają dostępu do certyfikatu TLS. Ten scenariusz pasuje do scenariuszy, w których jeden zespół (na przykład IT) zarządza i tworzy składniki infrastruktury i sieci (w tym certyfikaty PROTOKOŁU TLS PROTOKOŁU HTTPS) i inne zespoły zarządzają cyklem życia aplikacji.

Wymagania wstępne

Generowanie certyfikatu TLS

  • Wygeneruj certyfikat TLS przy użyciu następującego polecenia.

    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"
    

Importowanie certyfikatu do usługi AKV

  1. Wyeksportuj certyfikat do pliku PFX przy użyciu następującego polecenia.

    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. Zaimportuj az keyvault certificate import certyfikat przy użyciu polecenia .

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

Wdrażanie klasy SecretProviderClass

  1. Wyeksportuj nową przestrzeń nazw przy użyciu następującego polecenia.

    export NAMESPACE=ingress-basic
    
  2. Utwórz przestrzeń nazw przy użyciu kubectl create namespace polecenia .

    kubectl create namespace $NAMESPACE
    
  3. Wybierz metodę , aby zapewnić tożsamość dostępu i odpowiednio skonfigurować klucz YAML SecretProviderClass.

    • Pamiętaj, aby użyć metody objectType=secret, która jest jedynym sposobem uzyskania klucza prywatnego i certyfikatu z usługi AKV.
    • Ustaw kubernetes.io/tls jako element type w secretObjects sekcji .

    Zapoznaj się z poniższym przykładem tego, jak może wyglądać klasa SecretProviderClass:

    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. Zastosuj klasę SecretProviderClass do klastra Kubernetes przy użyciu kubectl apply polecenia .

    kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
    

Wdrażanie kontrolera ruchu przychodzącego

Dodawanie oficjalnego repozytorium wykresu przychodzącego

  • Dodaj oficjalne repozytorium wykresów przychodzących przy użyciu następujących helm poleceń.

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

Konfigurowanie i wdrażanie ruchu przychodzącego NGINX

W zależności od scenariusza można powiązać certyfikat z aplikacją lub z kontrolerem ruchu przychodzącego. Postępuj zgodnie z poniższymi instrukcjami zgodnie z wyborem:

Wiązanie certyfikatu z aplikacją

  • Powiąż certyfikat z aplikacją przy użyciu helm install polecenia . Wdrożenie aplikacji odwołuje się do dostawcy usługi Azure Key Vault sterownika CSI magazynu wpisów tajnych.

    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
    

Wiązanie certyfikatu z kontrolerem ruchu przychodzącego

  1. Powiąż certyfikat z kontrolerem ruchu przychodzącego helm install przy użyciu polecenia . Wdrożenie kontrolera ruchu przychodzącego odwołuje się do dostawcy usługi Azure Key Vault sterownika CSI magazynu wpisów tajnych.

    Uwaga

    • Jeśli nie używasz tożsamości zarządzanej przez zasobnika firmy Microsoft jako metody dostępu, usuń wiersz za pomocą polecenia --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME .

    • Ponadto powiązanie klasy SecretProviderClass z zasobnikiem jest wymagane, aby sterownik CSI magazynu wpisów tajnych zainstalować go i wygenerować wpis tajny Kubernetes. Zobacz Synchronizowanie zainstalowanej zawartości za pomocą wpisu tajnego platformy 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. Sprawdź, czy wpis tajny kubernetes został utworzony przy użyciu kubectl get secret polecenia .

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

Wdrażanie aplikacji

Ponownie instrukcje zmieniają się nieco w zależności od scenariusza. Postępuj zgodnie z instrukcjami odpowiadającymi wybranemu scenariuszowi.

Wdrażanie aplikacji przy użyciu odwołania do aplikacji

  1. Utwórz plik o nazwie z aks-helloworld-one.yaml następującą zawartością.

    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. Utwórz plik o nazwie z aks-helloworld-two.yaml następującą zawartością.

    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. Zastosuj pliki YAML do klastra kubectl apply przy użyciu polecenia .

    kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE
    kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
    
  4. Sprawdź, czy wpis tajny kubernetes został utworzony przy użyciu kubectl get secret polecenia .

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

Wdrażanie aplikacji przy użyciu odwołania kontrolera ruchu przychodzącego

  1. Utwórz plik o nazwie z aks-helloworld-one.yaml następującą zawartością.

    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. Utwórz plik o nazwie z aks-helloworld-two.yaml następującą zawartością.

    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. Zastosuj pliki YAML do klastra kubectl apply przy użyciu polecenia .

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

Wdrażanie zasobu przychodzącego odwołującego się do wpisu tajnego

Teraz możemy wdrożyć zasób przychodzący Kubernetes odwołujący się do wpisu tajnego.

  1. Utwórz nazwę hello-world-ingress.yaml pliku z następującą zawartością.

    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. Zanotuj tls sekcję odwołującą się do utworzonego wcześniej wpisu tajnego i zastosuj plik do klastra kubectl apply przy użyciu polecenia .

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

Uzyskiwanie zewnętrznego adresu IP kontrolera ruchu przychodzącego

  • Pobierz zewnętrzny adres IP kontrolera ruchu przychodzącego przy użyciu kubectl get service polecenia .

    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
    

Testowanie ruchu przychodzącego zabezpieczonego przy użyciu protokołu TLS

  1. Sprawdź, czy ruch przychodzący został prawidłowo skonfigurowany przy użyciu protokołu TLS, używając następującego curl polecenia. Upewnij się, że używasz zewnętrznego adresu IP z poprzedniego kroku.

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

    Ponieważ inna ścieżka nie została podana z adresem, kontroler ruchu przychodzącego domyślnie jest kierowany do / trasy. Zwracana jest pierwsza aplikacja demonstracyjna, jak pokazano w następujących skondensowanych przykładowych danych wyjściowych:

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

    Parametr -v w poleceniu curl zwraca pełne informacje, w tym odebrany certyfikat TLS. W połowie danych wyjściowych narzędzia curl możesz sprawdzić, czy użyto własnego certyfikatu TLS. Parametr -k kontynuuje ładowanie strony, mimo że używamy certyfikatu z podpisem własnym. W poniższym przykładzie przedstawiono wystawcę : CN=demo.azure.com; Użyto certyfikatu O=aks-ingress-tls :

    [...]
     * 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. Dodaj /hello-world-two ścieżkę do adresu, na przykład https://demo.azure.com/hello-world-two, i sprawdź, czy druga aplikacja demonstracyjna jest poprawnie skonfigurowana.

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

    Zwracana jest druga aplikacja demonstracyjna z tytułem niestandardowym, jak pokazano w następujących skondensowanych przykładowych danych wyjściowych:

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