Implémentation de référence de l'équilibrage de charge de couche 7 NGINX

Google Distributed Cloud (GDC) air-gapped fournit un équilibreur de charge géré de couche 4 (L4) intégré, mais de nombreuses applications d'entreprise nécessitent des fonctionnalités avancées de couche 7 (L7), telles que le routage basé sur l'hôte, la gestion centralisée de TLS et la répartition complexe du trafic. Historiquement, cela est réalisé à l'aide de l'API Ingress, qui est désormais considérée comme une fonctionnalité figée dans la communauté Kubernetes.

Cette architecture de référence fournit une solution d'équilibrage de charge de couche 7 autogérée. En déployant le contrôleur Open Source NGINX Gateway Fabric sur un cluster GDC Standard, les clients peuvent acheminer de manière transparente le trafic L7 vers des environnements hybrides. Cette architecture utilise la terminaison TLS (HTTPRoute) pour acheminer le trafic en fonction de l'indication du nom du serveur (SNI) vers les pods conteneurisés intégrés et les applications hébergées sur des machines virtuelles externes.

Architecture

Diagramme de l'architecture pour l'équilibrage de charge NGINX de couche 7 sur GDC sous air gap.

Les principaux composants de la solution sont les suivants :

  • Client : entité qui lance des requêtes HTTPS pour interagir avec les applications.
  • Cluster GDC Standard : GDC fournit un moyen intégré de créer des clusters Kubernetes Vanilla. Dans cette solution, le cluster hébergera l'équilibreur de charge L7 et ses contrôleurs, ainsi que les charges de travail et le service sans adresse IP de cluster pour les VM externes.
  • Équilibreur de charge GDC L4 : équilibreur de charge L4 intégré servant de point d'entrée, distribuant le trafic TCP/443 directement aux pods Kubernetes exécutant les contrôleurs Gateway.
  • Contrôleurs Gateway : opérateurs NGINX exécutés dans le cluster standard. Ils surveillent les ressources de l'API Gateway (telles que Gateway et HTTPRoute) et mettent à jour dynamiquement les proxys sous-jacents. Nginx Gateway Fabric sera utilisé pour la solution.
  • Passerelle (avec HTTPRoute) : ressources Kubernetes standardisées définissant le port d'écoute physique (443) et les règles de routage d'hôte basées sur SNI avec terminaison TLS.
  • Charge de travail conteneurisée (pods) : déploiement Kubernetes standard exposé en interne avec un Service Kubernetes régulier.
  • Charge de travail basée sur une VM (externe) : charge de travail hébergée sur une VM externe sur le réseau du projet, exposée au proxy avec un Service Kubernetes sans adresse IP de cluster et un point de terminaison personnalisé contenant l'adresse IP directe de la VM.
  • Registre Harbor : registre de conteneurs privé utilisé pour stocker et diffuser les images de proxy et d'application dans l'environnement air-gapped.

Dans le cluster standard, vous créez quatre espaces de noms :

  • L'espace de noms nginx-gateway qui héberge les ressources Nginx Gateway Fabric :

    Ressources de l'espace de noms nginx-gateway.

  • L'espace de noms load-balancer qui héberge les ressources Gateway :

    Ressources de l'espace de noms de l'équilibreur de charge.

  • L'espace de noms vm-app héberge l'adresse IP de la VM externe vm-app, un service sans adresse IP de cluster, un EndpointSlice qui pointe vers l'adresse IP externe et un HTTPRoute pour la Gateway :

    Ressources de l'espace de noms vm-app.

  • L'espace de noms hello-app héberge le Deployment, un Service, un HTTPRoute et une Gateway pour la charge de travail du conteneur de démonstration :

    Ressources de l'espace de noms hello-app.

Avant de commencer

Avant de déployer cette solution, assurez-vous de disposer des prérequis suivants :

  • Logiciels requis : helm, docker, kubectl
  • Connexion à la CLI et configuration locale : téléchargez la CLI gdcloud depuis la console GDC et configurez votre environnement localement.

    export USER_NAME="USER_NAME"
    export PROJECT_ID="PROJECT_ID"
    export ZONE="ZONE"
    export ORG_NAME="ORG_NAME"
    export GDCH_URL="GDC_URL"
    
    gdcloud components install gdcloud-k8s-auth-plugin
    
    gdcloud config set core/organization_console_url \
      https://console.$ORG_NAME.$ZONE.$GDC_URL
    gdcloud config set core/zone $ZONE
    gdcloud config set core/project ${PROJECT_ID}
    
    gdcloud auth login # use --login-config-cert option in case of TLS error
    
  • Configuration du projet : créez un projet dans votre environnement GDC sous air gap pour contenir les ressources.

    gdcloud projects create $PROJECT_ID
    
  • Rôles IAM : accordez à votre utilisateur les rôles Administrateur de cluster et Administrateur de cluster standard pour gérer les ressources Kubernetes, ainsi que le rôle Administrateur d'instance Harbor pour envoyer des images.

    # Grant standard cluster and cluster admin roles
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=cluster-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=standard-cluster-admin
    
    # Grant Harbor instance admin role
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member="user:${USER_NAME}" \
      --role=harbor-instance-admin
    

Créer un cluster standard

Cette section vous explique comment configurer un cluster Kubernetes standard dans votre environnement GDC sous air gap. Un cluster standard fournit une base flexible et robuste pour déployer diverses charges de travail, y compris le contrôleur Nginx Gateway et vos applications personnalisées. Les étapes suivantes vous permettront de vous assurer que votre cluster est correctement configuré et accessible pour les déploiements ultérieurs.

  1. Identifiez les types d'images de machine virtuelle disponibles en exécutant la commande suivante :

    gdcloud compute machine-types list
    
  2. Sélectionnez un type de machine approprié pour les nœuds de calcul de votre cluster. Pour ce tutoriel, nous vous recommandons un type de machine avec au moins 4 processeurs virtuels.

    export MACHINE_TYPE="MACHINE_TYPE"
    
  3. Obtenez le fichier kubeconfig du serveur d'API de gestion et définissez un alias :

    export CLUSTER_NAME="CLUSTER_NAME"
    
    KUBECONFIG=kubeconfig-admin.yaml gdcloud clusters \
      get-credentials ${ORG_NAME}-admin
    
    alias km="kubectl --kubeconfig kubeconfig-admin.yaml"
    
  4. Créez un cluster standard avec deux nœuds de calcul :

    km create -f - <<EOF
    apiVersion: cluster.gdc.goog/v1
    kind: Cluster
    metadata:
      name: ${CLUSTER_NAME}
      namespace: ${PROJECT_ID}
    spec:
      nodePools:
      - machineTypeName: ${MACHINE_TYPE}
        nodeCount: 2
        name: ${CLUSTER_NAME}-node-pool
    EOF
    

    Pour en savoir plus sur les options disponibles, consultez la documentation.

    La création d'un cluster standard peut prendre jusqu'à 60 minutes. Pour vérifier l'état, exécutez la commande suivante :

    km get clusters/${CLUSTER_NAME} \
      -n ${PROJECT_ID} \
      --watch
    

    Une fois le cluster prêt, le résultat doit afficher l'état "Running" (En cours d'exécution), comme suit :

    NAME         STATE     K8S VERSION
    my-cluster   Running   1.30.12-gke.300
    
  5. Une fois le cluster prêt, récupérez ses identifiants :

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml gdcloud clusters \
      get-credentials ${CLUSTER_NAME} \
      --standard \
      --project ${PROJECT_ID} \
      --zone ${ZONE}
    
  6. Créez un alias pour que les commandes kubectl soient plus concises dans le reste de ce guide. Cet alias sera utilisé pour interagir avec le cluster standard :

    alias kk="kubectl --kubeconfig kubeconfig-${CLUSTER_NAME}.yaml"
    
  7. Créez des espaces de noms pour le contrôleur, l'application conteneurisée de démonstration "hello-app" et l'application de démonstration basée sur une VM :

    kk create namespace load-balancer
    kk create namespace hello-app
    kk create namespace vm-app
    

Créer et intégrer un registre Harbor

Harbor est un registre d'images de conteneurs avec une assistance intégrée dans GDC sous air gap. Cette section vous explique comment intégrer un registre Harbor à votre cluster standard, y compris comment configurer les identifiants et les secrets pour permettre l'extraction et l'envoi sécurisés d'images.

  1. Créez une instance Harbor dans votre projet.
  2. Créez un projet Harbor dans votre instance Harbor.
  3. Définissez les variables d'environnement :

    export HARBOR_INSTANCE_NAME="HARBOR_INSTANCE_NAME"
    export HARBOR_INSTANCE_URL="HARBOR_INSTANCE_URL"
    export HARBOR_PROJECT="HARBOR_INSTANCE_PROJECT"
    export IMAGE_PULL_SECRET_NAME="harbor-secret"
    
  4. Connectez-vous à l'instance Harbor à l'aide d'un compte robot :

    docker --config=./docker login ${HARBOR_INSTANCE_URL}
    
  5. Créez les secrets dans le cluster standard :

    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n load-balancer
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n hello-app
    

Déployer une application conteneurisée de démonstration

Cette section décrit le déploiement d'une application conteneurisée de démonstration (hello-app) dans votre cluster Kubernetes GDC sous air gap. Vous allez créer les ressources Kubernetes Deployment et Service nécessaires pour exécuter hello-app et l'exposer en interne dans le cluster, en le préparant à l'accès à l'aide de l'équilibreur de charge L7.

  1. Importez un exemple d'image pour l'application conteneurisée de démonstration dans Harbor :

    docker pull gcr.io/google-samples/hello-app:1.0 \
      --platform linux/amd64
    docker tag gcr.io/google-samples/hello-app:1.0 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
    
  2. Déployez le fichier manifeste suivant dans le cluster standard :

    cat << EOF > hello-app.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: hello-app
      template:
        metadata:
          labels:
            app: hello-app
        spec:
          containers:
          - name: hello-server
            image: ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/hello-app:1.0
            ports:
            - containerPort: 8080
          imagePullSecrets:
          - name: ${IMAGE_PULL_SECRET_NAME}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: hello-app
      namespace: hello-app
    spec:
      type: ClusterIP
      selector:
        app: hello-app
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
    EOF
    
    kk apply -f hello-app.yaml
    

Vérifiez ensuite que le déploiement et le service sont présents :

kk get svc,deploy -n hello-app

Déployer une application de démonstration dans une VM

Cette section décrit le déploiement d'une application de démonstration dans une machine virtuelle (VM) en dehors de votre cluster Kubernetes. En configurant un serveur HTTP sur une VM, vous simulerez une application externe que l'équilibreur de charge peut exposer, ce qui démontrera sa capacité à gérer le trafic vers des ressources à l'intérieur et à l'extérieur du cluster.

Commencez par créer une VM pour l'application de démonstration.

  1. Ouvrez la console GDC dans votre navigateur Web.
  2. Sélectionnez le même projet que celui dans lequel vous avez créé votre cluster Kubernetes standard.
  3. Ouvrez le menu, puis cliquez sur Virtual machines (Machines virtuelles).
  4. Cliquez sur Create Instance (Créer une instance).
  5. Nommez la VM vm-workload. Une image à deux processeurs virtuels suffit pour cet exemple.
  6. Pour l'image du disque de démarrage, sélectionnez une distribution Ubuntu 22.04, qui est fournie avec Python préinstallé.
  7. Cliquez sur Create (Créer).
  8. Attendez quelques minutes que la VM soit prête.
  9. Établissez une connexion SSH avec la VM :
    1. Dans la console GDC, cliquez sur la VM.
    2. Cliquez sur Connect with SSH (Se connecter avec SSH).

Une fois connecté à la console SSH, exécutez la commande suivante :

mkdir ~/simple-server
cd ~/simple-server
echo 'Welcome to my VM!' > index.html
python3 -m http.server --bind 0.0.0.0 8080 &

Pour acheminer le trafic vers une VM, créez un service sans adresse IP de cluster (sans sélecteurs). Il sera mappé manuellement à l'adresse IP interne de la VM à l'aide d'une ressource EndpointSlice.

kk apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: vm-app-svc
  namespace: vm-app
spec:
  ports:
  - protocol: TCP
    port: 443
    targetPort: 443
EOF

Obtenez l'adresse IP de la VM vm-workload en exécutant la commande suivante :

gdcloud compute instances list --project ${PROJECT_ID} \
  | grep workload-vm | awk '{print $3}'

Le résultat correspondra à l'adresse IP de la VM qui sera nécessaire pour configurer la ressource EndpointSlice.

Créez la ressource EndpointSlice qui se connectera au service sans sélecteur de l'application de VM et adressez l'adresse IP de la VM vers laquelle le trafic doit être acheminé.

apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: vm-app-endpoints
  namespace: vm-app
  labels:
    kubernetes.io/service-name: vm-app-svc
addressType: IPv4
ports:
  - port: 8080
endpoints:
  - addresses:
    - "VM_IP"
    conditions:
      ready: true

Créer des certificats autosignés

Cette section vous explique comment générer des certificats TLS autosignés pour vos applications. Ce guide utilise des certificats autosignés pour plus de commodité, mais dans les environnements de production, vous devez utiliser des certificats de qualité production, comme décrit dans la section Facultatif : Utiliser des certificats prêts pour la production. Ces certificats sont essentiels pour activer la terminaison HTTPS au niveau de la passerelle Nginx, ce qui garantit une communication chiffrée entre les clients et l'équilibreur de charge pour les charges de travail conteneurisées et celles basées sur des VM.

  1. Créez un certificat pour l'application conteneurisée :

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-containerized.key \
      -out tls-containerized.crt \
      -subj "/CN=k8s-app.example.com" \
      -days 365
    
    kk create secret tls tls-containerized \
      --namespace load-balancer \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
    kk create secret tls tls-containerized \
      --namespace hello-app \
      --key tls-containerized.key \
      --cert tls-containerized.crt
    
  2. Créez un certificat pour l'application de VM :

    openssl req -x509 -newkey rsa:2048 -nodes \
      -keyout tls-vm.key \
      -out tls-vm.crt \
      -subj "/CN=vm-app.example.com" \
      -days 365
    
    kk create secret tls tls-vm \
      --namespace load-balancer \
      --key tls-vm.key \
      --cert tls-vm.crt
    
    kk create secret tls tls-vm \
      --namespace vm-app \
      --key tls-vm.key \
      --cert tls-vm.crt
    

Déployer NGINX

Cette section décrit les étapes à suivre pour déployer le contrôleur Nginx Gateway, y compris l'installation des définitions de ressources personnalisées (CRD) de l'API Gateway, la configuration de Nginx Gateway Fabric à l'aide de Helm et la vérification de l'installation dans votre cluster standard. Cela prépare l'infrastructure pour le routage avancé de couche 7.

Installer des CRD de l'API Gateway

L'API Gateway nécessite l'installation de définitions de ressources personnalisées (CRD) dans le cluster avant le déploiement du contrôleur. Nous utiliserons les définitions de ressources personnalisées (CRD) expérimentales officielles du projet d'API Gateway (la version 1.2.0 est utilisée pour ce guide).

  1. Installez les CRD expérimentales :

    kk apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/experimental-install.yaml
    
  2. Vérifiez que les CRD sont correctement installées en exécutant la commande kk get crd gateways.gateway.networking.k8s.io.

Installer NGINX Gateway Fabric

Déployez le contrôleur NGINX Gateway Fabric à l'aide de Helm. Ce contrôleur surveillera les ressources de l'API Gateway et configurera NGINX pour gérer le trafic.

  1. Définissez le tag d'image NGINX :

    helm template nfg oci://ghcr.io/nginx/charts/nginx-gateway-fabric | grep "image:" # get the tag of the nginx-gateway-fabric (in following case 2.4.2)
    
    export NGINX_TAG="2.4.2"
    
  2. Extrayez les images NGINX Gateway Fabric et NGINX, puis transférez-les vers votre registre Harbor :

    docker pull ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG}
    docker tag ghcr.io/nginx/nginx-gateway-fabric:${NGINX_TAG} \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric:${NGINX_TAG}
    
    docker pull nginx:1.27.3
    docker tag nginx:1.27.3 \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    docker --config=./docker push \
      ${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx:1.27.3
    
  3. Créez l'espace de noms nginx-gateway et ajoutez le secret d'extraction d'image Harbor :

    kk create namespace nginx-gateway
    
    kk create secret docker-registry ${IMAGE_PULL_SECRET_NAME} \
      --from-file=.dockerconfigjson=./docker/config.json \
      -n nginx-gateway
    
  4. Déployez NGINX Gateway Fabric avec Helm, en pointant vers les images de votre registre Harbor :

    KUBECONFIG=kubeconfig-${CLUSTER_NAME}.yaml helm upgrade --install ngf \
      oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
      --create-namespace -n nginx-gateway \
      --set nginxGateway.image.tag="${NGINX_TAG}" \
      --set nginxGateway.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx-gateway-fabric" \
      --set nginx.image.repository="${HARBOR_INSTANCE_URL}/${HARBOR_PROJECT}/nginx" \
      --set nginxGateway.serviceAccount.imagePullSecret="${IMAGE_PULL_SECRET_NAME}" \
      --set nginx.imagePullSecret="${IMAGE_PULL_SECRET_NAME}"
    

    Le déploiement Kubernetes extrait de manière sécurisée les images de Harbor à l'aide du secret fourni (${IMAGE_PULL_SECRET_NAME}), qui contient les identifiants du compte robot Harbor.

  5. Vérifiez que les ressources GatewayClass sont acceptées :

    kk get gatewayclass
    

    nginx doit s'afficher avec ACCEPTED = True.

Créer l'instance Gateway

Définissez l'instance d'équilibreur de charge logique écoutant sur le port 443. Nous allons la configurer pour le mode Terminate, ce qui signifie que la passerelle effectuera la terminaison TLS et déchiffrera le trafic avant de le transmettre.

Créez et appliquez gateway.yaml :

cat << EOF > gateway.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
  namespace: load-balancer
spec:
  gatewayClassName: nginx
  listeners:
  - name: https-k8s-workload
    hostname: "k8s-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-containerized 
  - name: https-vm-workload
    hostname: "vm-app.example.com"
    port: 443
    protocol: HTTPS
    allowedRoutes: 
      namespaces: 
        from: All
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: tls-vm 
EOF

kk apply -f gateway.yaml

Vérifiez que la passerelle est correctement déployée en vérifiant si PROGRAMMED est True :

kk get gateway my-gateway --n load-balancer

Vérifiez qu'un équilibreur de charge GDC L4 géré a été déployé en tant que service avec la passerelle.

kk get services -n load-balancer

Vérifiez que le service Nginx est créé et configuré. Le résultat doit se présenter comme suit :

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)         AGE
my-gateway-nginx   LoadBalancer   10.252.19.148   10.200.32.43   443:30649/TCP   45h

Définir la logique de routage L7 (HTTPRoute)

Associez des HTTPRoute à votre passerelle pour définir la manière dont le trafic doit être distribué en fonction du nom d'hôte demandé (SNI).

Créez et appliquez routing.yaml :

cat << EOF > routing.yaml 
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: k8s-http-route
  namespace: hello-app
spec:
  parentRefs:
  - name: my-gateway 
    namespace: load-balancer
  hostnames:
  - "k8s-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: hello-app 
      namespace: hello-app
      port: 80          
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: vm-http-route
  namespace: vm-app
spec:
  parentRefs:
  - name: my-gateway
    namespace: load-balancer
  hostnames:
  - "vm-app.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: vm-app-svc  
      namespace: vm-app
      port: 443       
EOF

kk apply -f routing.yaml   

Récupérer l'adresse IP de l'équilibreur de charge

Exécutez la commande pour obtenir l'adresse IP de l'équilibreur de charge Nginx.

kk get services/my-gateway-nginx \
  -n load-balancer \
  -o jsonpath='{.status.loadBalancer.ingress[0].ip}'

Cette adresse sera nécessaire pour vérifier l'accès aux applications. Elle sera appelée LOAD_BALANCER_IP.

Créer une VM cliente

Suivez la procédure pour créer une VM cliente.

  1. Ouvrez la console GDC dans votre navigateur Web.
  2. Ouvrez le menu, puis cliquez sur Virtual machines (Machines virtuelles).
  3. Cliquez sur Create Instance (Créer une instance).
  4. Créez une VM nommée client, sélectionnez un petit type de machine, puis sélectionnez Rocky Linux ou Ubuntu, qui sont fournis avec curl préinstallé.
  5. Cliquez sur Create (Créer).
  6. Attendez quelques minutes que la VM soit prête.
  7. Une fois la VM prête, établissez une connexion SSH avec la VM :
    1. Dans la console GDC, cliquez sur la VM.
    2. Cliquez sur Connect with SSH (Se connecter avec SSH).

Vérifier l'accès et le routage

Pour tester le routage, exécutez des commandes curl à partir de votre VM cliente. Vous pouvez vous connecter aux deux applications à l'aide de leurs noms d'hôte définis avec l'adresse IP de l'équilibreur de charge.

En transmettant le flag --resolve dans curl, vous pouvez forcer la résolution des noms de domaine en adresse IP de votre équilibreur de charge L4 GDC sous air gap. Notez que nous transmettons l'option -k pour approuver les certificats autosignés.

Testez l'application conteneurisée Kubernetes :

curl -k --resolve k8s-app.example.com:443:$LOAD_BALANCER_IP https://k8s-app.example.com -v

Testez l'application de VM externe :

curl -k --resolve vm-app.example.com:443:$LOAD_BALANCER_IP https://vm-app.example.com -v

Si la configuration est correcte, le contrôleur Gateway agira de manière transparente en tant que terminateur TLS et transmettra le trafic à la destination.

Facultatif : Utiliser des certificats prêts pour la production

Cette section explique comment utiliser le service d'autorité de certification GDC sous air gap pour créer une autorité de certification racine privée, émettre des certificats signés pour vos charges de travail et mettre à jour de manière sécurisée votre cluster standard GDC sous air gap et vos VM clientes.

Cette section explique comment utiliser le service d'autorité de certification GDC sous air gap CA Service pour créer une autorité de certification racine privée et émettre des certificats valides pour vos applications. En installant cette autorité de certification racine sur votre VM cliente, vous pouvez vérifier que la terminaison TLS fonctionne de manière transparente avec des certificats approuvés, sans avoir à contourner les avertissements SSL (par exemple, à l'aide de curl -k).

Accorder les autorisations nécessaires et obtenir les identifiants

Pour gérer le service d'autorité de certification et émettre des certificats, votre utilisateur doit disposer des rôles IAM appropriés dans le projet.

  1. Accordez les rôles certificate-authority-service-admin et certificate-requester :

    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-authority-service-admin
    
    gdcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member=user:${USER_NAME} \
      --role=certificate-requester
    
  2. Obtenez les identifiants du serveur d'API de gestion :

    gdcloud clusters get-credentials ${ORG_NAME}-admin
    

Créer l'autorité de certification racine

Vous allez créer une autorité de certification dans le serveur d'API de gestion au sein de l'espace de noms de votre projet.

  1. Appliquez la ressource CertificateAuthority :

    km apply -f - <<EOF
    apiVersion: pki.security.gdc.goog/v1
    kind: CertificateAuthority
    metadata:
      name: my-root-ca
      namespace: ${PROJECT_ID}
    spec:
      caProfile:
        commonName: "My Root CA"
        duration: 87600h # 10 years
        keyAlgorithm: RSA_2048
        maxChainLength: 1
      caType: ROOT
      keyLocation: HSM
      rotationPolicy:
        cronTime: 0 0 1 1 *
    EOF
    
    km -n ${PROJECT_ID} get \
    certificateauthority.pki.security.gdc.goog/my-root-ca -ojson \
    | jq -r '
    .status.conditions[] | select( .type as $id | "Ready" | index($id)) .status'
    

Émettre et déployer des certificats

Une fois l'autorité de certification prête, vous demanderez des certificats pour l'application conteneurisée et l'application basée sur une VM. Ces requêtes ont lieu dans le serveur d'API de gestion, et les clés résultantes doivent être déplacées vers votre cluster standard.

Créez des requêtes pour les deux domaines :

km apply -f - <<EOF
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-containerized-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "k8s-app.example.com"
      dnsNames:
      - "k8s-app.example.com"
  signedCertificateSecret: tls-containerized-signed
---
apiVersion: pki.security.gdc.goog/v1
kind: CertificateRequest
metadata:
  name: tls-vm-req
  namespace: ${PROJECT_ID}
spec:
  certificateAuthorityRef:
    name: my-root-ca
    namespace: ${PROJECT_ID}
  certificateConfig:
    subjectConfig:
      commonName: "vm-app.example.com"
      dnsNames:
      - "vm-app.example.com"
  signedCertificateSecret: tls-vm-signed
EOF

Attendez quelques instants que les certificats soient émis. Vous pouvez vérifier qu'ils sont prêts lorsque la condition "Ready" (Prêt) est "True" :

km get certificaterequests -n ${PROJECT_ID}

Mettre à jour le cluster standard

Si vous avez suivi les sections précédentes de ce guide, vous disposez de secrets autosignés dans votre cluster standard. Vous devez les supprimer avant de créer les nouvelles versions signées :

kk delete secret tls-containerized -n load-balancer
kk delete secret tls-vm -n load-balancer

kk delete secret tls-containerized -n hello-app
kk delete secret tls-vm -n vm-app

Extrayez maintenant les certificats signés du serveur d'API de gestion et créez les nouveaux secrets dans le cluster standard.

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-containerized-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-containerized.key

kk create secret tls tls-containerized \
  --namespace load-balancer \
  --key tls-containerized.key \
  --cert tls-containerized.crt

kk create secret tls tls-containerized \
  --namespace hello-app \
  --key tls-containerized.key \
  --cert tls-containerized.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > tls-vm.crt

km get secret -n ${PROJECT_ID} tls-vm-signed \
  -o jsonpath='{.data.tls\.key}' \
  | base64 -d > tls-vm.key

kk create secret tls tls-vm \
  --namespace load-balancer \
  --key tls-vm.key \
  --cert tls-vm.crt

kk create secret tls tls-vm \
  --namespace vm-app \
  --key tls-vm.key \
  --cert tls-vm.crt

Les nouveaux secrets seront obtenus automatiquement et actualisés par les équilibreurs de charge.

Configurer l'approbation du client

Pour vérifier la configuration, vous devez indiquer à votre VM cliente d'approuver votre nouvelle autorité de certification racine.

Extrayez le certificat CA racine dans un fichier :

km get secret -n ${PROJECT_ID} my-root-ca-secret \
  -o jsonpath='{.data.tls\.crt}' \
  | base64 -d > my-root-ca.crt

Transférez le certificat vers votre VM cliente. (Vous pouvez copier le contenu de my-root-ca.crt et le coller dans un fichier sur la VM cliente.)

Sur la VM cliente, mettez à jour le magasin de confiance.

Si la VM client est Ubuntu :

sudo cp my-root-ca.crt /usr/local/share/ca-certificates/
sudo chmod 644 /usr/local/share/ca-certificates/my-root-ca.crt
sudo update-ca-certificates

Si la VM client est Rocky Linux :

sudo cp my-root-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust

Vérifier l'accès

Vous pouvez désormais accéder à vos applications à l'aide de curl sans l'option -k. La connexion sera entièrement approuvée.

Testez l'application conteneurisée Kubernetes :

curl -v --resolve k8s-app.example.com:443:LOAD_BALANDER_IP https://k8s-app.example.com

Testez l'application de VM :

curl -v --resolve vm.example.com:443:LOAD_BALANDER_IP https://vm-app.example.com

Si l'opération réussit, le résultat de l'application s'affiche immédiatement, sans aucun avertissement de certificat SSL.