Étiquette dans x509: certificate signed by unknown authority

Ajouter un certificat self signed dans un cluster TKG

Si vous souhaitez déployer des pods sur un cluster Kubernetes ne connaissant pas le certificat de la registry contenant les images (c’est le cas en général pour les labs ayant des certificat auto-signé et non connu par une autorité), vous risquez de ne pas pouvoir déployer vos images, voyons un exemple en déployant une image Kuard sur ma registry privée Harbor :

(Attention, WordPress remplace les deux tirets par un seul 😥 )

# kubectl run kuard –image=harbor.cpod-velocity.az-fkd.cloud-garage.net/library/kuard-amd64:blue
# kubectl get pods
NAME  READY STATUS   RESTARTS  AGE
kuard    0/1         ImagePullBackOff  0                     7s

# kubectl describe pods kuard
….
Type Reason Age From Message
—- —— —- —- ——-
Normal Scheduled 33s default-scheduler Successfully assigned default/kuard to test-md-0-5d6756b7fd-b9kwl
Normal Pulling 19s (x2 over 32s) kubelet Pulling image “harbor.cpod-velocity.az-fkd.cloud-garage.net/library/kuard-amd64:blue”
Warning Failed 19s (x2 over 32s) kubelet Failed to pull image “harbor.cpod-velocity.az-fkd.cloud-garage.net/library/kuard-amd64:blue”: rpc error: code = Unknown desc = failed to pull and unpack image “harbor.cpod-velocity.az-fkd.cloud-garage.net/library/kuard-amd64:blue”: failed to resolve reference “harbor.cpod-velocity.az-fkd.cloud-garage.net/library/kuard-amd64:blue”: failed to do request: Head “https://harbor.cpod-velocity.az-fkd.cloud-garage.net/v2/library/kuard-amd64/manifests/blue”: x509: certificate signed by unknown authority
Warning Failed 19s (x2 over 32s) kubelet Error: ErrImagePull
Normal BackOff 4s (x2 over 31s) kubelet Back-off pulling image “harbor.cpod-velocity.az-fkd.cloud-garage.net/library/kuard-amd64:blue”
Warning Failed 4s (x2 over 31s) kubelet Error: ImagePullBackOff

Dans cet exemple, j’ai tenté à partir de mon cluster Tanzu Kubernetes Grid (TKG) de déployer  l’image Kuard qui se trouve sur ma registry Harbor privé hébergée sur mon lab. Ce certificat auto signé n’est pas reconnu par une autorité. Pour que cela fonctionne malgré tout, Il faudrait que chaque worker node de mon cluster puisse connaitre ce certificat. Je pourrai le copier sur chacun d’entres-eux mais le principe de TKG est d’avoir un cluster dont le cycle de vie puisse évoluer facilement et de manière automatisée, ajouter des worker nodes, en supprimer, les remplacer lors de mise à jour,… . Cela nécessiterait à chaque ajout de noeud d’y inclure le certificat.

Jesse Hu a écrit une procédure tkg-ytt-overlay-additional-ca-certs · GitHub que j’ai testé en TKG 1.4. Elle fonctionne très bien, elle coule de sens pour ceux qui pratiquent Kubernetes tous les jours mais peut paraître compliquée pour les autres. Je vais tenter de la clarifier. Cela consiste à obtenir le certificat, le codé en base64, d’exécuter les commandes pour faire prendre en compte le certificat par tous les noeuds Kubernetes existant et à venir.

coder en base64 les certificat et le copier

# base64 -w0 ca.crt (le résultat a volontairement été modifié)
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lRREthWmp6NmF4MitZS3RxS0YrUUNKekFOQmdrcWhraUc5dzBCQVFzRkFEQVUKTVJJd0VBWURWUVFERXdsb1lYSmliM0l0WTJFd0hoY05NakV3T0RJek1UVXdNREEwV2hjTk1qSXdPREl6TVRVdwpNREEwV2pBVU1SSXdFQVlEVlFRREV3bG9ZWEppYjNJdFkyRXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRREl0MEhDUEF0ZWxrSVZhOXZtbjJnQWR4VXNaL3lTd2psNi95SzV0eTZ5OW1PbU5peDgKOHAvVFk2SG9MVHlJNUhtNytUYTJ4RGpvUUpmNllWMURsc3Y3d2E2R2pTUXE0WWxQWG1hUUNvVkp5eno5OVRvUgpDbW80VjhRUnJLbE5WL3NFbStrVXhseGFNZTZOMlA3UjB1MHVCV0Q5NW9Ra3RqWC8rS01uT0ErUlZoWkJ1dEFmCjJXSzhIMmRYeWo4bFV3Vk4rWWJqeW83dkdnNERNZlVHMWtDa0hYYURTMGcvWlhyNU1LRTNDWEo4YUVPZFhMNjMKb3BHTXVMQWp4WUZIdng0SnBMN0lNQ2VZMGFCcjcybUUzcy9SMENCMW1zTU5nYWhXTkhNZjhINktsUy9qUVlnUgpQMjV6WmYyOUZ0VFdnOWhZNVJZQngxalcyeXZERGJsMmFGNXBBZ01CQUFHallUQmZNQTRHQTFVZER3RUIvd1FFCkF3SUNwREFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNESUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXcKQXdFQi96QWRCZ05WSFE0RUZnUVVVbTBvVUtiSXBHbTcxL3JzUlBReUJJbkZYYmt3RFFZSktvWklodmNOQVFFTApCUUFEZ2dFQkFEcVJBamwzWTNqVk5JK1JUbHBYdmwvdUYxbXNZUTNzTnFwVXR6eVNCVlNDWlpDMkRSSnpwYWZGCjhPdXN5QjBMTTNlS3VTd0t4STgrT0o5OTlhZkdOazRWTnpySVhOQURaZ1BxbnRFSWRucXNReGg4eFBuOVY0T2QKQUtsTVJycVI4R3g4ejdRM2EvN01uR0sra1l3VmorZ3BBNkFGUEJxSVJrU3Jscmo5b2dXVzBqWTFzL2tNU21ydgpaVEFZWTJqcFhBaGZrdzcrVDN4OHYwa0NRai9NREo5L3dNTnhxeVNGMEhzNXd6THVvbVJOM0VEME03eUNhWjg0CmJuOFZTN1VUSjBaWnhBRmx3TWxySlRYWmFpQmNOeDRNdm4wNXN4RG5KZktCdFloSkZwbGRwR3hLMDRUSmNXWm0KU0dDemZhc2FIK2M1NklNT0IvRllMdlJlelh4cE5mMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=

Retrouvez le contexte de votre cluster de management et le nom du cluster de workload sur lequel vous allez copier le certificat :

# kubectl get-contexts

CURRENT                                     NAME CLUSTER      AUTHINFO                  NAMESPACE
….
my-cluster-admin@my-cluster                 my-cluster        my-cluster-admin
* test-admin@test                           test              test-admin
tkg-mgmt-vsphere-admin@tkg-mgmt-vsphere     tkg-mgmt-vsphere  tkg-mgmt-vsphere-admin
tool-admin@tool                             tool              tool-admin

Editez la configuration du template du contrôleur et du worker pour ajouter le contenu du certificat et la commande pour la prise en compte de ce certificat. Ainsi à chaque ajout de nœud le certificat sera pris en compte. Le contenu du fichier est à ajouter dans la partie files: et la commande dans la partie preKubeadmCommands: comme ci-dessous (J’ai une configuration à base de Photon OS, si vous avez un autre OS il faut utiliser une autre commande. Les copiés/collés ne fonctionnent pas très bien il est préférable de retaper les mots) :

Pour éditer le template du control plane : kubectl edit KubeadmControlPlane test-control-plane –context tkg-mgmt-vsphere-admin@tkg-mgmt-vsphere

……

  files:
  – content: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lRREthWmp6NmF4MitZS3RxS0YrUUNKekFOQmdrcWhraUc5dzBCQVFzRkFEQVUKTVJJd0VBWURWUVFERXdsb1lYSmliM0l0WTJFd0hoY05NakV3T0RJek1UVXdNREEwV2hjTk1qSXdPREl6TVRVdwpNREEwV2pBVU1SSXdFQVlEVlFRREV3bG9ZWEppYjNJdFkyRXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCCkR3QXdnZ0VLQW9JQkFRREl0MEhDUEF0ZWxrSVZhOXZtbjJnQWR4VXNaL3lTd2psNi95SzV0eTZ5OW1PbU5peDgKOHAvVFk2SG9MVHlJNUhtNytUYTJ4RGpvUUpmNllWMURsc3Y3d2E2R2pTUXE0WWxQWG1hUUNvVkp5eno5OVRvUgpDbW80VjhRUnJLbE5WL3NFbStrVXhseGFNZTZOMlA3UjB1MHVCV0Q5NW9Ra3RqWC8rS01uT0ErUlZoWkJ1dEFmCjJXSzhIMmRYeWo4bFV3Vk4rWWJqeW83dkdnNERNZlVHMWtDa0hYYURTMGcvWlhyNU1LRTNDWEo4YUVPZFhMNjMKb3BHTXVMQWp4WUZIdng0SnBMN0lNQ2VZMGFCcjcybUUzcy9SMENCMW1zTU5nYWhXTkhNZjhINktsUy9qUVlnUgpQMjV6WmYyOUZ0VFdnOWhZNVJZQngxalcyeXZERGJsMmFGNXBBZ01CQUFHallUQmZNQTRHQTFVZER3RUIvd1FFCkF3SUNwREFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNESUt3WUJCUVVIQXdJd0R3WURWUjBUQVFIL0JBVXcKQXdFQi96QWRCZ05WSFE0RUZnUVVVbTBvVUtiSXBHbTcxL3JzUlBReUJJbkZYYmt3RFFZSktvWklodmNOQVFFTApCUUFEZ2dFQkFEcVJBamwzWTNqVk5JK1JUbHBYdmwvdUYxbXNZUTNzTnFwVXR6eVNCVlNDWlpDMkRSSnpwYWZGCjhPdXN5QjBMTTNlS3VTd0t4STgrT0o5OTlhZkdOazRWTnpySVhOQURaZ1BxbnRFSWRucXNReGg4eFBuOVY0T2QKQUtsTVJycVI4R3g4ejdRM2EvN01uR0sra1l3VmorZ3BBNkFGUEJxSVJrU3Jscmo5b2dXVzBqWTFzL2tNU21ydgpaVEFZWTJqcFhBaGZrdzcrVDN4OHYwa0NRai9NREo5L3dNTnhxeVNGMEhzNXd6THVvbVJOM0VEME03eUNhWjg0CmJuOFZTN1VUSjBaWnhBRmx3TWxySlRYWmFpQmNOeDRNdm4wNXN4RG5KZktCdFloSkZwbGRwR3hLMDRUSmNXWm0KU0dDemZhc2FIK2M1NklNT0IvRllMdlJlelh4cE5mMD0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    encoding: base64
    owner: root:root
    permissions: “0644”
    path: /etc/ssl/certs/tkg-custom-ca.pem

……

  preKubeadmCommands:

  – ! which rehash_ca_certificates.sh 2>/dev/null || rehash_ca_certificates.sh

……….

La prise en compte est immédiate et un nouveau contrôleur est déployé pour remplacer l’ancien. (ou plusieurs en fonction du plan choisi au moment de la création). Attendre que le temps que le nouveau controleur se déploie et remplace l’ancien.

La même chose pour le worker : kubectl edit KubeadmConfigTemplate test-md-0 –context tkg-mgmt-vsphere-admin@tkg-mgmt-vsphere


La prise en compte pour les worker n’est pas immédiate, il faut exécuter la commande suivante :

# kubectl patch machinedeployment test-md-0 –type merge -p “{\”spec\”:{\”template\”:{\”metadata\”:{\”annotations\”:{\”date\”:\”`date +’%s’`\”}}}}}” –context tkg-mgmt-vsphere-admin@tkg-mgmt -vsphere machinedeployment.cluster.x-k8s.io/test-md-0 patched Attendre un peu que les workers nodes soient remplacés par des nouveaux puis on peut retester de déployer une nouvelle image kuard # kubectl get node NAME STATUS ROLES AGE VERSION test-control-plane-gsmqz Ready control-plane,master 34m v1.21.2+vmware.1 test-md-0-698857566f-8pvt7 Ready <none> 118s v1.21.2+vmware.1 Maintenant on peut redéployer l’image Kuard pour vérifier quelle va bien s’exécuter # kubectl run kuard –image=harbor.cpod-velocity.az-fkd.cloud-garage.net/library/kuard-amd64:blue pod/kuard created

# kg pods
NAME READY STATUS RESTARTS AGE
kuard 1/1 Running 0 17s

Cette procédure est valable pour la prise en compte de certificats si le cluster est déjà déployé. s’il n’a pas encore été créé, il est préférable de faire prendre en compte le certificat dès le départ en utilisant la procédure décrite dans la documentation d’installation.

Ajouter un self-signed certificat dans Kubernetes avec Containerd

Dans cet article (Déployer Harbor avec type loadBalancer) j’ai expliqué comment déployer Habor et utiliser le certificat self-signed pour que Docker puisse l’utiliser. Si vous utilisez Kubernetes avec docker, vous pouvez aussi suivre cette procédure sur chaque worker node. Sinon vous risquez d’avoir l’erreur suivante :

Unknown desc = failed to pull and unpack image “harbor.cpod-tkg.az-lab.shwrfr.com/memecached/hello-world:latest”: failed to resolve reference “harbor.cpod-tkg.az-lab.shwrfr.com/memecached/hello-world:latest”: failed to do request: Head https://harbor.cpod-tkg.az-lab.shwrfr.com/v2/memecached/hello-world/manifests/latest: x509: certificate signed by unknown authority
Warning Failed 12s (x2 over 24s) kubelet, tkg-utility-md-0-798c695db5-pjgsk Error: ErrImagePull

Si vous utilisez Kubernetes avec Containerd, la procédure est différente. Mon collègue Rob Hardt (https://gist.github.com/rhardt-pivotal/) a développé un script pour ça : https://gist.githubusercontent.com/rhardt-pivotal/4aa09ced6302194561936717262bb203/raw/623c707748925c969c525ade4bb432f95b61cff0/node-ca-updater-daemonset.yaml

Il faut néanmoins modifier les 3 champs en rouge :

apiVersion: v1
data:
  ca.pem: |+
    —–BEGIN CERTIFICATE—–
    Mettre votre certificat
    —–END CERTIFICATE—–

kind: ConfigMap
metadata:
 name: trusted-ca-cm
 namespace: default

   —-

apiVersion: v1
data:
    build-ca.sh: “#!/usr/bin/env bash \nset -euxo pipefail\ntdnf update \ntdnf install -y ca-certificates\ntdnf install -y openssl-c_rehash\necho \”$TRUSTED_CERT\” > /etc/ssl/certs/my-trusted-cert.pem\n/usr/bin/rehash_ca_certificates.sh\ncurl -vv https://<Votre URL HARBOR>\n”
kind: ConfigMap
metadata:
    name: rehash-script
    namespace: default
—   
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: trusted-ca-updater
  namespace: default
  labels:
    k8s-app: trusted-ca-updater
spec:
  selector:
    matchLabels:
      name: trusted-ca-updater
  template:
    metadata:
      labels:
        name: trusted-ca-updater
    spec:
      tolerations:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can’t run pods
      – key: node-role.kubernetes.io/master
        effect: NoSchedule
      initContainers:
      – name: script-runner
        image: photon:3.0
        command: [“/bin/sh”, “-c”, “/root/build-ca.sh” ]
        volumeMounts:
        – name: update-trusted-certs-script
          mountPath: /root/
        – name: certs-dir
          mountPath: /etc/ssl/certs
        – name: agg-certs-dir
          mountPath: /etc/pki/tls/certs/
        env:
        – name: TRUSTED_CERT
          valueFrom:
            configMapKeyRef:
              name: trusted-ca-cm
              key: ca.pem   
        resources:
            limits:
              ephemeral-storage: 30G # mettre une plus petite taille
      containers:
      – name: sleepy
        image: photon:3.0
        command: [“/bin/sh”]
        args: [“-c”, “while true; do sleep 3600;done”]
      volumes:
      – name: update-trusted-certs-script
        configMap:
            name: rehash-script
            defaultMode: 0766
      – name: certs-dir
        hostPath:
          path: /etc/ssl/certs
          type: Directory
      – name: agg-certs-dir
        hostPath:
          path: /etc/pki/tls/certs/
          type: Directory

 

Il faut ensuite se connecter sur les workernodes pour relancer containerd. Ci-dessous un exemple pour TKG (Une solution Kubernetes as a Service pour tous les Clouds)

# ssh capv@<ip-YourWokerNode>

capv@YourWokerNode$ sudo systemctl restart containerd