Catégorie dans Astuces techniques

Créer un certificat auto-signé LDAPS pour Pinniped

Afin de simplifier l’authentification des clusters Kubernetes fonctionnant sur différents clouds, VMware a développé le projet Pinniped accessible en Opensource. Pinniped a été intégré par défaut dans l’offre VMware Tanzu Kubernetes Grid (TKG) depuis la version 1.3  en remplacement de l’extension Gangway. Pinniped permet l’authentification à partir de sources OIDC ou LDAP. Dans le cas de source LDAP, Pinniped ne se connecte pas directement à LDAP mais s’appuie pour le moment sur le composant Dex comme le faisait déjà Gangway.

Lorsqu’un utilisateur exécute une commande Kubernetes pour la première fois ou après une certaine période d’inactivité, il est invité à s’authentifier une seule fois avec son ses identifiants d’entreprise et peut ensuite consommer plusieurs cluster Kubernetes.

J’ai voulu tester cette fonctionnalité dans mon lab avec un serveur LDAPS/Active Directory sous Windows 2019 et je me suis vite confronté à l’éternel problème de certificat non signés par une autorité connue. Il fallait donc que je créé un certificat qui soit reconnu par le serveur Active Directory. En cherchant des heures sur Internet, j’ai fini par trouver un article (en Anglais) de Peter Mescalchin qui a fonctionné du premier coup : Enable LDAP over SSL (LDAPS) for Microsoft Active Directory servers. – bl.ocks.org.

Cependant, quand j’ai voulu utiliser cette procédure avec Pinniped, ça n’a pas fonctionné car les informations SAN (Subject Alternative Name) n’étaient pas présentes dans le certificat. En croisant plusieurs articles sur le sujet, j’ai pu adapter la solution de Peter Mescalchin afin que les certificats intègrent les informations SAN. Ca donne ceci :

Création du certificat Root

Via OpenSSL (j’ai utilisé un Linux Ubuntu) créer une clé privée (ca.key dans mon exemple) pour pouvoir ensuite créer le certificat root (ca.crt dans mon exemple). La première commande vous demandera un mot de passe et la seconde des renseignements sur votre organisation.

$ openssl genrsa -aes256 -out ca.key 4096
$ openssl req -new -x509 -days 3650 -key ca.key -out ca.crt

 Importer le certificat Root sur le serveur AD

A partir du serveur AD, tapez la commande certlm ou via Control Pannel, tapez computer certificates dans la barre de recherche :

Attention à bien choisir “Manage computer certificates” et non “Manage user certificates »

Importez le ca.crt précédemment généré dans la partie « Trusted Root Certification Authorities\Certificates »

 

Création du certificat Client

Toujours à partir du serveur Active Directory, créer un fichier, dans notre exemple il porte le nom request.inf. En rouge, j’ai apporté les modifications par rapport à la procédure initiale afin d’y ajouter les informations SAN. Attention à bien mettre dans CN le FQDN du serveur AD.

Les valeurs de _continue_= « dns » et _continue_= « ip-address » correspondent aux valeurs SAN, les autres valeurs possibles pour référencer le serveur AD.

[Version]
Signature=”$Windows NT$”

[NewRequest]
Subject = “CN=ad-server.cpod-velocity.az-fkd.cloud-garage.net
KeySpec = 1
KeyLength = 2048
Exportable = TRUE
MachineKeySet = TRUE
SMIME = FALSE
PrivateKeyArchive = FALSE
UserProtected = FALSE
UseExistingKeySet = FALSE
ProviderName = “Microsoft RSA SChannel Cryptographic Provider”
ProviderType = 12
RequestType = PKCS10
KeyUsage = 0xa0

[EnhancedKeyUsageExtension]
OID = 1.3.6.1.5.5.7.3.1 ; Server Authentication

[Extensions]
; SANs can be included in the Extensions section by using the following text format. Note 2.5.29.17 is the OID for a SAN extension.
2.5.29.17 = “{text}”
_continue_ = “dns=ad-server&”
_continue_ = “dns=ad-server.cpod-velocity.az-fkd.cloud-garage.net&”
_continue_ = “dns=cloud-garage.net&”
_continue_ = “ipaddress=172.17.13.9&”

 

Générer le fichier client.csr avec la commande ci-dessous

c:\> certreq -new request.inf client.csr

A partir de la machine Linux :

Créer un fichier d’extension, dans notre exemple, il porte le nom de v3ext.txt. En rouge, j’ai apporté les modifications par rapport à la procédure initiale afin d’y ajouter les informations SAN sous la rubrique v3_ca qui sera référencé dans la prochaine commande.

keyUsage=digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectKeyIdentifier=hash

 # These extensions are added when ‘ca’ signs a request.
[ v3_ca ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = ad-server.cpod-velocity.az-fkd.cloud-garage.net
DNS.2 = ad-server
IP.1 = 172.17.13.9

Toujours à partir de la machine Linux, créer le certificat client.crt à partir des fichiers générés dans les étapes précédentes ca.crt, ca.key, client.csr et v3ext.txt en rouge ce qui a été rajouté par rapport à la commande issue de la procédure initiale

$ openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -extfile v3ext.txt -set_serial 01 -out client.crt -extensions v3_ca

 

Pour vérifier la présence des informations SAN

$ openssl x509 -in client.crt -text
 …..
X509v3 extensions:
      X509v3 Subject Alternative Name:
          DNS:ad-server.cpod-velocity.az-fkd.cloud-garage.net, DNS:ad-server, IP Address:172.17.13.9

 

Importer le certificat Client

A partir du serveur AD

C:\> certreq -accept client.crt

Le certificat devrait ainsi apparaître dans « Personal\Certificates »

Pour que le certificat soit pris en compte, il faut soit redémarrer le serveur AD ou forcer LDAPS à charger le certificat avec la procédure ci-dessous :

Toujours à partir du serveur AD, créer un fichier text, dans notre exemple il se nome ldap-renewservercert.txt avec le contenu ci-dessous (attention la fin du fichier comprend une ligne avec un – (un tiret) :

dn:
changetype: modify
add: renewServerCertificate
renewServerCertificate: 1

Puis tappez la commande ci-dessous :

c:\> ldifde -i -f ldap-renewservercert.txt

Pour tester la prise en compte

Utilisez l’utilitaire ldp.exe en sélectionnant le port 636 (ou un autre s’il est spécifique) et en cochant la case SSL.

Une fois toute la procédure effectuée, il faut récupérer le ca.crt généré à la première étape pour le donner à Pinniped. Cela peut se faire soit au moment de la création du cluster de management TKG ou soit à postériori.

Si le cluster de management n’a pas encore était créé :

$ tanzu management-cluster create –ui
(il y a deux tirets avant l’argument ui mais WordPress n’en n’affiche qu’un seul)

Dans mon test j’ai choisi vSphere comme plate-forme, à l’étape identity manager il faudra copier le certificat dans la partie ROOT CA

 

Si le cluster de management TKG a déjà était créé et que vous souhaitez le mettre à jour :

A partir du contexte Kubernetes du cluster de manager, chiffrez le certificat Root du serveur AD avec la commande base64 et récupérez le résultat :

$ base64 -w 0 ca.crt

Modifier le certificat dans la configmap dex par le résultat de la commande précédente :

$ kubectl edit configmap -n tanzu-system-auth dex
# Please edit the object below. Lines beginning with a ‘#’ will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: v1
data:
  config.yaml: |
    issuer: https://172.17.13.10:30167
    frontend:
        theme: tkg
    web:
        https: 0.0.0.0:5556
        tlsCert: /etc/dex/tls/tls.crt
        tlsKey: /etc/dex/tls/tls.key
    expiry:
        signingKeys: 90m
        idTokens: 5m
    logger:
        level: info
        format: json
    staticClients:
        – id: pinniped-client-id
          name: pinniped-client-id
          redirectURIs:
            – https://172.17.13.10:31234/callback
          secret: 089db7e23b19cb628ba841b17cc32ea4
    connectors:
        – type: ldap
          id: ldap
          name: LDAP
          config:
            host: ad-server.cpod-velocity.az-fkd.cloud-garage.net:636
            insecureSkipVerify: false
bindDN: cn=administrator,cn=Users,dc=velocity,dc=local
            bindPW: $BIND_PW_ENV_VAR
            usernamePrompt: LDAP Username
            rootCAData:
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUdQekNDQkNlZ0F3SUJBZ0lVU2tQd0JPazVYRVFLRlpydXdwZXBoeTlINndzd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2dhNHhDek
KQmdOVkJBWVRBa1pTTVF3d0NnWURWUVFJREFOSlJFWXhEakFNQmdOVkJBY01CVkJoY21segpNUlF3RWdZRFZRUUtEQXRNYjJWcGJDMWtkUzFUUlRFTE1Ba0dBMVVFQ3d3Q1UwVXhPRE
EyQmdOVkJBTU1MMkZrCkxYTmxjblpsY2k1amNHOWtMWFpsYkc5amFYUjVMbUY2TFdaclpDNWpiRzkxWkMxbllYSmhaMlV1Ym1WME1TUXcKSWdZSktvWklodmNOQVFrQkZoVm1ZbVZ1Y
21WcVpHRnNRSFp0ZDJGeVpTNWpiMjB3SGhjTk1qRXdOekEzTURjeQpNekl5V2hjTk16RXdOekExTURjeU16SXlXakNCcmpFTE1Ba0dBMVVFQmhNQ1JsSXhEREFLQmdOVkJBZ01BMGxFClJqRU9NQXdHQTFVRUJ3d0ZVR0Z5YVhNeEZEQVNCZ05WQkFvTUMweHZaV2xzTFdSMUxWTkZNUXN3Q1FZRFZRUUwKREFKVFJURTRNRFlHQTFVRUF3d3ZZV1F0YzJWeWRtVnlMbU53YjJ
RdGRtVnNiMk5wZEhrdVlYb3RabXRrTG1OcwpiM1ZrTFdkaGNtRm5aUzV1WlhReEpEQWlCZ2txaGtpRzl3MEJDUUVXRldaaVpXNXlaV3BrWVd4QWRtMTNZWEpsCkxtTnZiVENDQWlJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFMaWx0WE81WkxNOFRzZ0YKMXFxRFFURi9xV1EzTGkvalU2ZFJqM1VMLys2YitRL0VUVjdIb2VLMi9hK09UdHlRbzY4c
k9ySTVJRjNNWlJqKwpzU0JuWC9SejczczYvVjArWXhJTFozSmNNenlWUzZtR1ZhNTZBTmFZRFRqSkErUzF5enZJczFpZXdMWDR2YlFzCnJRdFE2NVphb3NYbFlMSWpxdzZCY01TZUlX
NUlUWitlUVF3emlkN2t5ZFBYNDdTBSSm1vR…..1
            ….

Relancer le pod dex dans le namespace tanzu-system-auth pour qu’il prenne en compte la modification.

 

Une fois le cluster de management avec le bon certificat

A partir de là, créer un cluster de workload :

$ tanzu cluster create my-cluster -f <fichier-environnement>

Importer le Kubeconfig d’administration du cluster de workload créé :

$ tanzu cluster kubeconfig get my-cluster –admin
(il y a deux tirets avant l’argument admin mais WordPress n’en n’affiche qu’un seul)

Se connecter au cluster de workload avec le context admin, en tant qu’admin pas besoin de compte :

$ kubectl use-context my-cluster-admin@my-cluster

Créer un cluster rôle binding avec le rôle qui vous intéresse (ici cluster-admin) pour les utilisateurs souhaités, ça permettra à l’utilisateur d’utiliser ce cluster une fois authentifié :

$ kubectl create clusterrolebinding admin-fbenrejdal  –clusterrole cluster-admin –user fbe@velocity.local
(il y a deux tirets avant les arguments clusterrole et user mais WordPress n’en n’affiche qu’un seul)

Exporter le kubeconfig du cluster de workload, c’est ce kubeconfig qu’il faudra transmettre aux utilisateurs, il n’a pas de context admin et demandera à l’utilisateur une authentification. L’utilisateur consommera ce cluster en fonction des droits définis dans clusterrolebinding de l’étape précédente :

$ tanzu cluster kubeconfig get my-cluster –export-file my-cluster-kubeconfig
(il y a deux tirets avant l’argument export mais WordPress n’en n’affiche qu’un seul)

Lancez une commande kubernetes avec le fichier kubeconfig généré, ce qui lancera le navigateur pour permettre l’authtentification :

$ kubectl get pods -A –kubeconfig my-cluster-kubeconfig
(il y a deux tirets avant l’argument kubeconfig mais WordPress n’en n’affiche qu’un seul)

Vous devriez être redirigé vers un navigateur avec une page web vous demandant votre nom d’utilisateur et votre mot de passe :

Une fois saisies, vous obtiendrez le résultat de votre dernière commande :

Le résultat de la commande précédemment passée devrait s’afficher :


NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system antrea-agent-q9xpg 2/2 Running 0 7d15h
kube-system antrea-agent-qlmj8 2/2 Running 0 7d15h
kube-system antrea-controller-6bb57bd84-6cj58 1/1 Running 0 7d15h
kube-system coredns-68d49685bd-bjcps 1/1 Running 0 7d15h
kube-system coredns-68d49685bd-vttdw 1/1 Running 0 7d15h
kube-system etcd-my-cluster-control-plane-48n9f 1/1 Running 0 7d15h
kube-system kube-apiserver-my-cluster-control-plane-48n9f 1/1 Running 0 7d15h
kube-system kube-controller-manager-my-cluster-control-plane-48n9f 1/1 Running 0 7d15h
kube-system kube-proxy-dntrc 1/1 Running 0 7d15h
kube-system kube-proxy-k5m9g 1/1 Running 0 7d15h
kube-system kube-scheduler-my-cluster-control-plane-48n9f 1/1 Running 0 7d15h
kube-system kube-vip-my-cluster-control-plane-48n9f 1/1 Running 0 7d15h
kube-system metrics-server-66cb4fb659-xlprc 1/1 Running 0 7d15h
kube-system vsphere-cloud-controller-manager-vmfwl 1/1 Running 1 7d15h
kube-system vsphere-csi-controller-bd8b6cc8c-8ljl8 6/6 Running 0 7d15h
kube-system vsphere-csi-node-6xqf5 3/3 Running 0 7d15h
kube-system vsphere-csi-node-vmbmq 3/3 Running 0 7d15h
pinniped-concierge pinniped-concierge-dcd587f97-lk9n5 1/1 Running 0 7d15h
pinniped-concierge pinniped-concierge-dcd587f97-zrnb7 1/1 Running 0 7d15h
pinniped-concierge pinniped-concierge-kube-cert-agent-8a8e3e38 1/1 Running 0 7d15h
pinniped-supervisor pinniped-post-deploy-job-4ldt7 0/1 Completed 0 7d15h
pinniped-supervisor pinniped-post-deploy-job-m74gz 0/1 Error 0 7d15h
tkg-system kapp-controller-69c4d4bbb4-kwk5l 1/1 Running 0 7d15h

Personnaliser une VM Ubuntu avec Cloud-Init sur vSphere

Cloud-Init semble être l’outil de personnalisation de prédilection pour les OS majeurs visant à être installer sur différents environnement cloud (AWS, Azure, GCP, vSphere, …), il est très puissant, hétérogène mais au début, il est difficile à appréhender.

Les informations de personnalisation sont stockées dans un fichier appelé user-data. Ce fichier est transmis à Cloud-Init grâce à un mécanisme propre à chaque cloud. Dans notre cas, ce sont les VMtools qui vont transmettre le fichier user-data, une fois reçu, Cloud-Init l’exécutera.

J’ai perdu énormément de temps à trouver les étapes minimales pour personnaliser l’OS Ubuntu avec Cloud-Init dans un environnement vSphere. Je recherchais la possibilité de personnaliser l’OS lors des clones à partir de template OVF.

Ci-dessous la procédure que j’utilise pour un Ubuntu 20.04.2 LTS, fraîchement installé et après son premier reboot. J’ai gardé les valeurs par défaut hormis le clavier Français et l’installation de l’option OpenSSH server.

Il faut dire à Cloud-Init de récupérer le fichier de personnalisation user-data via les paramètres OVF de la VM, il y a une étape à faire coté VM et une coté OS.

 

Coté OS :

  • Supprimer le fichier qui met la Datasource à none au lieu d’OVF
    • sudo rm /etc/cloud/cloud.cfg.d/99-installer.cfg
  • Si vous souhaitez que la configuration réseau se fasse, supprimer le fichier qui la désactive
    • sudo rm /etc/cloud/cloud.cfg.d/subiquity-disable-cloudinit-networking.cfg
  • Si vous êtes en DHCP, la VM récupérera toujours la même IP car elle gardera le même machine ID. Pour éviter cela il faut remettre à zéro l’identité de l’OS :
    • sudo truncate -s 0 /etc/machine-id

 

Coté VM :

  • Récupérer le contenu de votre fichier cloud-init user-data et le codé avec base64 :
    • Base64 user-data.yaml
  • A partir du vSphere client, lorsque la VM est arrêtée, Activer les propriétés de l’OVF :
    • Sélectionnez la VM => Configure => vApp Options => vApp Options are disabled … Edit => Cliquer sur “Enable vApp options”
    • Dans l’onglet OVF details => => sélectionner la case VMware Tools
  • A partir du vSphere client, lorsque la VM est arrêtée, ajouter le champ user-data dans les propriétés de l’OVF :
    • => Sélectionnez la VM => Configure => vApp Options => Properties => ADD mettre le Label et Key id  à la valeur user-data.
  • A partir du vSphere client, lorsque la VM est arrêtée, ajouter la valeur au champ user-data dans les propriétés de l’OVF :
    • Sélectionnez la VM => Configure => vApp Options => Properties => SET VALUE, un popup s’ouvre et mettre la clé base64 du contenu du fichier user-data récupérée un peu plus haut

 

 

Maintenant à partir de cette VM, faite directement un clone pour en faire une autre VM ou pour en faire un template. Si vous souhaitez changer le fichier user-data, au moment du déploiement de la VM, changez uniquement la clé base64 par la nouvelle clé.

 

 

Etapes pour la création de VM via kubectl

Pour créer une machine virtuelle avec vSphere with Tanzu via la commande kubectl, il y a des étapes à respecter pour l’administrateur et pour le développeur, elles sont très simples mais ce ne m’a pas empêché de perdre un peu de temps coté personnalisation sur la partie OS.

je vous recommande cet article pour comprendre l’intéret de déployer des VM via Kubernetes : Déployer des VMs dans et via Kubernetes. Le blog de mon collègue : Introducing Virtual Machine Provisioning, via Kubernetes with VM Service | VMware est aussi très bien détaillé.

Dans la dernière partie cet article, je vais apporter quelques précisions sur la partie Content Library et sur la partie YAML. Mais d’abord, revoyons avant les partie à faire coté administrateur et coté développeur

 

Concernant l’administrateur

La première étape consiste à télécharger les images VMs qui sont différentes de celles utilisées pour TKC (Tanzu Kubernetes Cluster aussi appelé Guest Cluster). Les images sont disponibles dans la marketplace VMware, au moment de la rédaction de cet article, il y en a 2 (Ubuntu et Centos), la version Ubuntu actuelle ne permet pas l’utilisation de volume persistent (PVC) car elle est basée sur une version virtual hardware 10 et il faut au minimum une version 12, ce problème va bientôt être corrigé.

Il faut aller sur la marketplace et faire une recherche avec le mot clé « vm service », ça permet de filtrer (un peu) les images compatibles => VMware Marketplace.

Ensuite cliquer sur l’image souhaitée, se connecter avec son compte MyVMware.

Vous avez deux possibilités, la télécharger puis la charger dans une content library locale

ou récupérer l’url de souscription pour créer une content library qui se synchronisera à celle hébergée par VMware.

Une fois l’image chargée ou le lien renseigné, vous devriez avoir une content library de ce type :

Toujours depuis l’interface vSphere, il faut maintenant créer, un namespace, octroyer les droits aux utilisateurs pour qu’ils puissent s’y connecter, affecter la classe de VM, la content library et la classe de stockage, ce qui devrait donner ceci :

 

L’exemple ci-dessus montre une fois le namespace créé, comment affecter une classe de VM, une content library, autoriser les développeurs qui pourront consommer ce namespace, quelle classe de stockage à utiliser et enfin si besoin caper les ressource, CPU, mémoire et stockage.

C’est tout ce qu’il y a à faire coté administrateur d’infrastructure.

 

Concernant le développeur

Il faut un descriptif YAML pour :

  • La configmap qui contient la personnalisation de la VM
  • La création de la VM
  • Le service réseau si vous souhaitez vous y connecter à partir d’un réseau extérieur (optionnel)
  • Le PVC si vous souhaitez utiliser des volumes persistants (optionnel)

Via la commande Kubernetes, le développeur se connecte avec son compte au Namespace fourni, il pourra ainsi lister les classes de services qu’il peut utiliser ainsi que les images qu’il pourra déployer.

kubectl get virtualmachineclass

NAME                  CPU   MEMORY   AGE
best-effort-2xlarge   8     64Gi     22d
best-effort-4xlarge   16    128Gi    22d
best-effort-8xlarge   32    128Gi    22d
best-effort-large     4     16Gi     22d
best-effort-medium    2     8Gi      31d
best-effort-small     2     4Gi      31d
best-effort-xlarge    4     32Gi     22d
best-effort-xsmall    2     2Gi      22d
..
guaranteed-xsmall     2     2Gi      22d

 

kubectl get virtualmachineimage
NAME                                                         VERSION                           OSTYPE                FORMAT   AGE
centos-stream-8-vmservice-v1alpha1-1619529007339                                               centos8_64Guest       ovf      4h8m
ob-15957779-photon-3-k8s-v1.16.8—vmware.1-tkg.3.60d2ffd    v1.16.8+vmware.1-tkg.3.60d2ffd    vmwarePhoton64Guest   ovf      2d19h
ob-16466772-photon-3-k8s-v1.17.7—vmware.1-tkg.1.154236c    v1.17.7+vmware.1-tkg.1.154236c    vmwarePhoton64Guest   ovf      2d19h
ob-16545581-photon-3-k8s-v1.16.12—vmware.1-tkg.1.da7afe7   v1.16.12+vmware.1-tkg.1.da7afe7   vmwarePhoton64Guest   ovf      2d19h
……
ubuntu-20-1621373774638                                                                        ubuntu64Guest         ovf      4h8m

Il peut ainsi créer ses fichiers descriptifs YAML afin de définir ses besoins en ressources pour sa ou ses machines virtuelles et s’ils le souhaitent, il peut la ou les personnaliser afin d’y installer ses outils.

Le fichier descriptif configmap, comprend la personnalisation de la VM. Les 3 champs importants à renseigner pour la personnalisation sont :

  1. Le hostname qui contient le hostname de l’OS
  2. La public-keys, qui contient la clé publique d’un poste à partir duquel on se connectera à l’os en ssh.
  3. La partie user-data est, si vous le souhaitez, l’endroit où on met le contenu du fichier de configuration Cloud Init, il faudra le chiffrer avec la commande base64.

 

cat loeil-du-se-vm-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
    name: loeil-du-se-vm-configmap # Le nom de la ConfigMap, doit être le même que celui référencé dans le YAML de la VirtualMachine
    namespace: loeil-du-se
data:
  # Champs OVF utilisés lors du déploiment de la VM
  hostname: loeil-du-se
  public-keys: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDC4Cclh3rN/l70lBNlwQyK6ZtugxqT/7HeerHZKPSO0hcl5ZWLvz2+7QG5FqvYbkPP6EomvyDhE2MPnQ0kWaIrumVxYXAbVdpBBKKdTI3xJpewWB2syxgVOXP2ZOrw4cRLFv18rnESGHfsohedyaSB1qvubPWAqBFa+PSS4xh3zKalUknwc7Bs14fci8tEwEg8cpvNsqvrPZliJ6qTYFGqKuG6Ct+y449JNW6k6itTepgSYvUdJfjBTxk5tDzBdWz28km5N7lxgUB0rIWgSDl1XLCBrmm+H6bkHtD59MxAuxwLjih4tS4PzspcVjwWiJhd0HH7u2wbsPLCrrAX7am4EP40zphu9IR+fVxk+2jp7eD2uXPS6p9sDPEWHl6wGclI7pnfuoyvcn+CIwCtMweLuUw5MPj2eIIXcBhqUffeVAXVHrx8+e7+yHvqfyhqm2J9Ay3yt3zvAcXW0VqDxfvnfmv8sc9VNUW+8fUeyoo4b4uZRLLSf2DHM8= root@fbenrejdal-z01 # Clé publique SSH du poste permettant de se connecter sans mot de passe à l’OS de la VM
  user-data: | # optionel, le contenu chiffré en base64 du fichier Cloud Init. La clé peut être sur une seule ligne ou sur plusieurs, elle doit démarrer au niveau du “r” sous user-data
     I2Nsb3VkLWNvbmZpZwojIFdBVENIT1VUIHRoZSBmaXJzdCBsaW5lIG11c3Qgc3RhcnQgd2l0aCAj
     Y2xvdWQtY29uZmlnCmdyb3VwczoKICAtIGRldm9wcwp1c2VyczoKICAtIGRlZmF1bHQgIyBDcmVh
     dGUgdGhlIGRlZmF1bHQgdXNlciBmb3IgdGhlIE9TCiAgLSBuYW1lOiBmYmUKICAgIHNzaC1hdXRo
     b3JpemVkLWtleXM6ICMgdGhlIHB1YmxpYyBrZXkgb2YgbXkgbGFwdG9wLCBpdCBjb3VsZCBhbHNv
     IGJlIGZpbGxlZCBpbiB0aGUgT1ZGIHByb3BlcnR5CiAgICAgIC0gc3NoLXJzYSBBQUFBQjNOemFD
     MXljMkVBQUFBREFRQUJBQUFCZ1FEQzRDY2xoM3JOL2w3MGxCTmx3UXlLNlp0dWd4cVRHLzdIZWVy
     SFpLUFNPMGhjbDVaV0x2ejIrN1FHNUZxdllia1BQNkVvbXZ5RGhFMk1QblEwa1dhSXJ1bVZ4WVhB
     YlZkcEJCS0tkVEkzeEpwZXdXL0Iyc3l4Z1ZPWFAyWk9ydzRjUkxGdjE4cm5FU0dIZisvc29oZWR5
     YVNCMXF2dWJQV0FxQkZhK1BTUzR4aDZELzN6S2FsVWtud2M3QnMxNGZjaTh0RXdFZzhjcHZOc3F2
     clBabGlKNnFUWUZHcUt1RzZDdCt5NDQ5Sk5XNms2aXRUZXBnU1l2VWRKZmpCVHhrNXREekJkV3oy
     OGttNU43bHhnVUIwcklXZ1NEbDFYTENCcm1tK0g2YmtIdEQ1OU14QXV4d0xqaWg0dFM0UHpzcGNW
     dGFydCBtb25nb2QK

 

La base64 est obtenu de la manière suivante :
base64  loeil-du-se-vm-cloud-init.yaml

Son contenu en clair :
cat  loeil-du-se-vm-cloud-init.yaml
#cloud-config
# ATTENTION la première ligne doit commencer par #cloud-config
groups:
  – devops
users:
  – default # Créé l’utisateur par défaut
  – name: fbe
  ssh-authorized-keys: # Clé SSH de mon laptop me permettant de me connecter via SSH sans mot de passe. Clé déjà renseignée dans la configmap
    – ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDC4Cclh3rN/l70lBNlwQyK6ZtugxqTG7HeerHZKPSO0hcl5ZWLvz2+7QG5FqvYbkPP6EomvyDhE2MPnQ0kWaIrumVxYXAbVdpBBKKdTI3xJpewWB2syxgVOXP2ZOrw4cRLFv18rnESGHf+sohedyaSB1qvubPWAqBFa+PSS4xh6D3zKalUknwc7Bs14fci8tEwEg8cpvNsqvrPZliJ6qTYFGqKuG6Ct+y449JNW6k6itTepgSYvUdJfjBTxk5tDzBdWz28km5N7lxgUB0rIWgSDl1XLCBrmm+H6bkHtD59MxAuxwLjih4tS4PzspcVjwWiJhd0HH7u2wbsPLCrrAX7am4EP40zphu9IR+fVxk+2jp7eD2uXPS6p9sDPEWHl6wGclI7pnfuoyvcn+CIwCtMweLuUw5MPj2eIIXcBhqUffeVAXVHrx8+e7+yHvqfyhqm2J9Ay3yt3zvAcXW0VqDxfvnfmv8sc9VNUW+8fUeyoo4b4uZRLLSf2DHM8= root@fbenrejdal-z01
      groups: sudo, devops
    shell: /bin/bash
    passwd: VMware1!
    sudo: [‘ALL=(ALL) NOPASSWD:ALL’] # l’utilisateur fbe n’aura pas à rentrer de mot de passe avec la commande sudo
  ssh_pwauth: true
  chpasswd:
  list: |
    fbe:VMware1! # changer le mot de passe de l’utilisateur fbe
    expire: false  # Pour que le mot de passe n’expire pas
runcmd: # Exemple de runcmd pour installer MongoDB. Cloud Init est aussi capable d’utiliser directement APT pour faire des installations
  – echo “deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse” | tee /etc/apt/sources.list.d/mongodb-org-4.4.list
  – wget -qO – https://www.mongodb.org/static/pgp/server-4.4.asc | apt-key add –
  – echo “deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/4.4 multiverse” | tee /etc/apt/sources.list.d/mongodb-org-4.4.list
  – apt-get update
  – apt-get install -y mongodb-org
  – echo “mongodb-org hold” | dpkg –set-selections
  – echo “mongodb-org-server hold” | dpkg –set-selections
  – echo “mongodb-org-shell hold” | dpkg –set-selections
  – echo “mongodb-org-mongos hold” | dpkg –set-selections
  – echo “mongodb-org-tools hold” | dpkg –set-selections
  – sed -i ‘s/127.0.0.1/0.0.0.0/’ /etc/mongod.conf
  – ufw allow from any to any port 27017 proto tcp
  – sleep 2
  – systemctl start mongod

Très très important, le fichier doit absolument commencer par #cloud-config et pas autre chose. Ça reste un fichier Cloud Init classique.

Si vous ne maitrisez pas trop Cloud Init, j’y ai mis des commentaires pour que ce soit un peu plus lisible.

 

Le fichier descriptif de la VM

cat loeil-du-se-vm-deployment.yaml
apiVersion: vmoperator.vmware.com/v1alpha1
kind: VirtualMachine
metadata:
  name: loeil-du-se-vm
  namespace: loeil-du-se
labels:
  vm: loeil-du-se-vm
spec:
  imageName: ubuntu-20-1621373774638 #L’image doit être présente dans la content library et visible via la commande kubectl get virtualmachineimage
  className: best-effort-xsmall
  powerState: poweredOn
  storageClass: silver-storage-policy
  networkInterfaces:
  – networkType: nsx-t # soit nsx-t ou vsphere-distributed en fonction de votre installation
# networkName:
si -networkType est vsphere-distributed il faut mettre le nom du port group des workload
  vmMetadata:
    configMapName: loeil-du-se-vm-configmap # Nom de la configmap où la personnalisation de la VM est stockée
    transport: OvfEnv
#
#  Au moment de l’écriture de cet article l’image ubuntu (ubuntu-20-1621373774638) ne peut pas utiliser les volumes car elle est basée sur la version 10 du virtual hardware est il faut au minimum qu’elle soit en 12
#  L’image centos image (centos-stream-8-vmservice-v1alpha1-1619529007339) peut utiliser des volumes
#  volumes: # au moment de l’écriture de cet article, le paramètre mount n’est pas utilisable, le volume est vu mais doit être monté à la main ou via Cloud Init
#    – name: loeil-du-se-volume
#      persistentVolumeClaim:
#      claimName: loeil-du-se-pvc
#      readOnly: false

 

Optionnel, le fichier descriptif du service réseau

Dans mon exemple, je créé un service de type LoadBalancer pour me connecter en ssh à partir d’un réseau externe à celui des PODs.

Attention, le kind n’est pas Service comme habituellement mais VirtualMachineService

cat loeil-du-se-vm-service.yaml
apiVersion: vmoperator.vmware.com/v1alpha1
kind: VirtualMachineService
metadata:
  name: loeil-du-se-vm
spec:
  selector:
    vm: loeil-du-se-vm
  type: LoadBalancer
  ports:
    – name: ssh
      port: 22
      protocol: TCP
      targetPort: 22

 

Une fois les fichiers YAML créés, il ne reste plus qu’à les faire prendre en compte par Kubernetes.

Kubectl create -f loeil-du-se-vm-configmap.yaml

Kubectl create -f loeil-du-se-vm-deployment.yaml

Kubectl create -f loeil-du-se-vm-service.yaml

 

Pour verifier la creation de la VM :

Kubectl get vm

 

Pour en savoir un peu plus :

Kubectl describe vm loeil-du-se-vm

 

Ca reste une VM classique, donc elle va bénéficier de HA et vMotion (via DRS ou mode maintenance du host). Par contre, elle est « Developer Managed », c’est-à-dire qu’elle n’est pas administrable via le vCenter, vous ne verrez pas par exemple le contenu de la console.

Une astuce tout de même, vérifiez sur quel ESXi la VM s’exécute, ensuite connectez-vous directement sur l’ESXi via un navigateur et là vous aurez accès à la console.

Pour se connecter en ssh, si vous avez comme moi un accès via un loadbalancer vous pouvez vous y connecter directement, sinon vous devrez passer par un POD de rebond (genre busybox, alpine ou autre) et faire un ssh avec l’adresse IP sur le réseau de POD. Vous pouvez la retrouver ainsi :

kubectl get vm loeil-du-se-vm -o jsonpath='{.status.vmIp}’; echo
10.244.0.130

 

Le ssh doit se faire via le user renseigné dans le Cloud Init, j’avais mis fbe, ca donne ça :

kubectl get svc loeil-du-se-vm
NAME             TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)        AGE
loeil-du-se-vm   LoadBalancer   10.96.1.108   172.20.18.71   22:32148/TCP   2d22h

ssh fbe@172.20.18.71

To run a command as administrator (user “root”), use “sudo <command>”.
See “man sudo_root” for details.
fbe@loeil-du-se:~$

 

Si le ssh ne fonctionne pas, c’est que le user n’a pas était pris en compte par Cloud Init, essayez avec root pour obtenir le user par défaut, en générale ubuntu pour Ubuntu et cloud-user pour CentOS :

ssh roo@172.20.18.71
Please login as the user “ubuntu” rather than the user “root”.

 

Si vous avez l’erreur ci-dessous, c’est que le poste à partir duquel vous vous connectez n’a pas la clé ssh publique renseignée ou il y a une erreur dans celle-ci, il faut donc vérifier la clé figurant dans le fichier de configmap :

fbe@172.20.18.71: Permission denied (publickey,password).

Pour debugger Cloud Init, il faut se connecter à l’os de la vm via ssh ou via la console est regardez la log /var/log/cloud-init-output.log

Voilà, n’hésitez pas à me pinger si vous avez besoin d’informations complémentaires.

Déployer Kubeapps pour un usage multi-clusters

 

Dans cet article nous allons voir comment déployer Kubeapps en environnement multi-cluster. Habituellement il se déployait cluster par cluster, ici, l’objectif est d’avoir une seule instance Kubeapps capable de déployer et de gérer les applications sur plusieurs clusters. Pour cela, il faut que chaque cluster soit capable de s’authentifier à une source IdP (Identity Provider).

Dans mon exemple je vais utiliser des clusters TKG 1.2.1 avec l’extension incluse Dex. Dex va permettre l’authentification avec un provider OpenID Connect (OIDC).  Pour info, dans notre exemple l’extension Gangway qui normalement va de pair avec Dex n’est pas utile. Elle sert à générer un Kubeconfig une fois que l’utilisateur s’est authentifié via la page web du cluster. Kubeapps n’a pas besoin de cette extension car il utilise un proxy Oauth2. Sur mon environnement, je vais utiliser des clusters existant qui sont déjà configurés avec l’extension Gangway et 1 que je vais créer sans installer Gangway (2 clusters auraient pu suffire mais c’est tellement simple à déployer avec TKG qu’on ne va pas se priver).

Étape primordiale, c’est d’ avoir l’extension Dex d’installée sur le cluster de management et le configurer pour qu’il puisse faire des requêtes sur une source IdP : https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/1.2/vmware-tanzu-kubernetes-grid-12/GUID-extensions-dex.html. Une fois Dex installé, il faut créer des clusters de workload compatibles OIDC et déployer Kubeapps sur un cluster de préférence distinct (ou commencer par installer Kubeapps et le mettre à jour pour qu’il prenne en compte les nouveaux clusters).

Exporter les variables sur l’environnement du cluster DEX :

export AUTH_MGMT_CLUSTER=”auth-mgmt-cluster-admin@auth-mgmt-cluster” # nom de mon cluster de management
export OIDC_ISSUER_URL=https://172.20.7.10:30167 #IP et Port de mon cluster de management où est installé DEX
export OIDC_USERNAME_CLAIM=email
export OIDC_GROUPS_CLAIM=groups
export OIDC_DEX_CA=$(kubectl get secret dex-cert-tls -n tanzu-system-auth -o ‘go-template={{ index .data “ca.crt” }}’ –context $AUTH_MGMT_CLUSTER| base64 -d | gzip | base64) # certificat du cluster de management

Créer ensuite les clusters de workloads :

tkg create cluster usine-32 –enable-cluster-options oidc –plan dev –vsphere-controlplane-endpoint 172.20.7.17

Logs of the command execution can also be found at: /tmp/tkg-20210106T094128013610360.log
Validating configuration…
Creating workload cluster ‘usine-32’…
Waiting for cluster to be initialized…
Waiting for cluster nodes to be available…
Waiting for addons installation…
Workload cluster ‘usine-32’ created

 

Récupérer le context du cluster pour qu’il soit intégré dans le kubeconfig et ainsi récupérer l’url de l’API server: et le certificat certificateAuthorityData:

tkg get credentials usine-32
Credentials of workload cluster ‘usine-32’ have been saved
You can now access the cluster by running ‘kubectl config use-context usine-32-admin@usine-32’

 

Se connecter au cluster afin d’autoriser les utilisateurs à s’y connecter et de déployer des applications :

kubectl config use-context usine-32-admin@usine-32

cat << EOF | kubectl apply –
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: tkg-users
subjects:
  – kind: Group          # Donner le rôle au groupe, mettre User si vous souhaitez cibler un user en particulier
    name: tkg-users # Mettre le nom du groupe, tous les utilisateurs du groupe seront pris en compte
    apiGroup: “”
roleRef:
  kind: ClusterRole #this must be Role or ClusterRole
  name: cluster-admin # ClusterRole à avoir
  apiGroup: rbac.authorization.k8s.io
EOF

 

Une fois le cluster créé, les droits d’accès positionnés, l’url et le certificat récupérés (si besoin, reproduire les mêmes étapes pour d’autres clusters de workload), il reste deux fichiers à modifier, l’un concerne le fichier de valeurs de l’installation de Kubeapps et l’autre le fichier de configuration DEX.

Modification du fichier de valeurs pour l’installation de Kubeapps (Exemple provenant de mon collègue Michael Nelson : https://liveandletlearn.net/post/kubeapps-on-tkg-management-cluster/) :

# Dans mon exemple Kubeapps est accessible au travers d’un LoadBalancer
frontend:
  service:
    port: 80
    type: LoadBalancer
# Setup the oauth2-proxy running on the frontend to handle the OIDC authentication
authProxy:
  enabled: true
  provider: oidc
  clientID: auth-tools
  ## les deux Secrets ci-dessous sont à générer par vous-même (32 octets max)
  clientSecret: wPmp8+IrTxbGZbVF/yqPPeP4XZzw5mLt
  cookieSecret: fiUrXyEBQx7uWlcw55CxQkbYwZ4a/cC7
  additionalFlags:
    # C’est l’adresse IP et le port de DEX qui est installé sur le cluster de management
    – –oidc-issuer-url=https://172.20.7.10:30167
    # les clusters derrières le mot audience sont les clusters sur lesquels les déploiements seront autorisés, ils doivent aussi figurer en bas de ce fichier et dans le fichier de configuration Dex
    – –scope=openid email groups audience:server:client_id:workload-01 audience:server:client_id:workload-02 audience:server:client_id:usine-01 audience:server:client_id:usine-32
    # Comme j’ai des certificats autosignés, il ne faut pas les vérifier auprès d’une autorité
    – –ssl-insecure-skip-verify=true
    # Since Kubeapps is running without TLS, can’t use secure cookies
    – –cookie-secure=false
    # If you need to access the actual token in the frontend for testing, uncomment the following.
    # – –set-authorization-header=true
# Liste des clusters sur lesquels les déploiements seront autorisés, les mêmes renseignés un peu plus haut
# L’apiServiceURL et le certificateAuthorityData sont ceux récupérés dans le fichier kubeconfig un peu plus haut
# dans mon exemple j’ai 4 clusters de workload
clusters:
  – name: workload-01
  apiServiceURL: https://172.20.7.14:6443
  certificateAuthorityData: USUZJQ0FURS0tQkFRc0ZBREFWTVJNd0……..E9KOFhFQUI1aVBqVDQxWXZzeEE9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  – name: workload-02
  apiServiceURL: https://172.20.7.15:6443
  certificateAuthorityData: LS0tLS1CRUdJTiBDRVJUSUZJQ0FBREFWTVJNd0…….wS1V1UUgvcCtjMWkvYW89Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  – name: usine-01
  apiServiceURL: https://172.20.7.16:6443
  certificateAuthorityData: LS0TkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0….Es2RWpSNys2NkNlT2dpeHcxVUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
  – name: usine-32
  apiServiceURL: https://172.20.7.17:6443
  certificateAuthorityData: BTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0…cldORUNGb3FJelZkdXdKRGNFMTA9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K

 

Maintenant, on peut installer Kubeapps dans un namespace avec comme paramètre ce fichier de valeurs (ici, je l’ai appelé kubeapps-dex.yaml) :

kubectl create namespace kubeapps-system
helm install kubeapps bitnami/kubeapps –namespace kubeapps-system –values kubeapps-dex.yaml

Si vous êtes amené à modifier le fichier de configuration comme par exemple pour ajouter un autre cluster, vous pouvez utiliser cette commande :

helm upgrade kubeapps bitnami/kubeapps –namespace kubeapps-system –values kubeapps-dex.yaml

 

Maintenant, il faut dire à Dex qu’il y a de nouveaux clusters créés

cat ~/tkg/tkg-extensions-v1.2.0+vmware.1//extensions/authentication/dex/vsphere/ldap/dex-data-values.yaml

# Partie à modifier extraite du fichier de configuration utilisait par Dex : ~/tkg/tkg-extensions-v1.2.0+vmware.1//extensions/authentication/dex/vsphere/ldap/dex-data-values.yaml
  #@overlay/replace
  staticClients:
  – id: usine-01 # nom de mon cluster de workload, attention à garder le même nom que dans le fichier de valeurs utilisé par Kubeapps
    redirectURIs:
    – https://172.20.7.16:30166/callback # Adress IP de l’API du cluster de workload et le port normalement utilisé par Gangway
    name: usine-01
    secret: a1094138692761b8bd653e7af36c3d57 # Secret normalement utilisait par Gangway à mettre même si Gangway n’est pas installé, dans ce cas mettez ce que vous voulez
    trustedPeers:
    – auth-tools # nom du cluster Kubeapps
  – id: usine-32
    redirectURIs:
    – https://172.20.7.17:30166/callback
    name: usine-32
    secret: a1094138692721b8bd653e7af36c3d57
    trustedPeers:
    – auth-tools
  – id: workload-01
    redirectURIs:
    – https://172.20.7.14:30166/callback
    name: workload-01
    secret: e36a415d615ccbf37b4c4b8316be9740
    trustedPeers:
    – auth-tools
  – id: workload-02
    redirectURIs:
    – https://172.20.7.15:30166/callback
    name: workload-02
    secret: 85507bc84d6d26899aa9bf1c87600f81
    trustedPeers:
    – auth-tools
  – id: auth-tools
    redirectURIs:
    – http://172.20.7.130/oauth2/callback # Adresse IP de ma VIP qui pointe vers Kubeapps
    name: auth-tools # nom du cluster où j’ai installé Kubeapps, j’ai choisi de l’installer sur un cluster à part
    secret: wPmp8+IrTxbGZbVF/yqPPeP4XZzw5mLt #clé renseignée dans le fichier Kubeapps « clientSecret »

Une fois modifier, il faut dire à Dex de prendre en compte la nouvelle configuration, à faire à partir du cluster de management où Dex est installé :

kubectl create secret generic dex-data-values –from-file ~/tkg/tkg-extensions-v1.2.0+vmware.1/extensions/authentication/dex/vsphere/ldap/dex-data-values.yaml -n tanzu-system-auth -o yaml –dry-run | kubectl replace -f-

Voilà, maintenant Kubeapps est prêt à être utilisé sur les 4 clusters configurés :

A partir d’un navigateur entrez l’adresse où le nom de la VIP kubeapps obtenue et cliquez sur “LOGIN VIA OIDC PROVIDER:”

 

Vous êtes ensuite redirigé vers la page d’authentification DEX, vous remarquerez que l’IP et le port sont ceux renseignés dans le fichier de configuration DEX, entrez votre compte et votre mot de passe :

Vous arrivez ensuite sur la page du cluster et namespace par défaut, l’écran est vide car il n’y a pas eu de déployement via HELM ou via un Operator sur le namespace et cluster défault :

Vous pouvez changer de cluster et de namespace en cliquant sur “Current Context” en haut à droite :

 

 

 

Comment supprimer des containers volumes “orphelins” dans vSphere

Lorsque vous créez des volumes Kubernetes hébergés sur vSphere, cela génère des fichiers VMDKs, ils sont visibles au travers de l’interface graphique

C’est très utile, il est même possible de voir à quel cluster les volumes appartiennent.

Dans certaines situations, vous pouvez vous retrouver avec des volumes dits orphelins, notamment si un cluster Kubernetes est supprimé “brutalement”. Malheureusement il n’est pas possible de supprimer ces volumes/vmdks depuis l’interface graphique (à date de la rédaction de cet article, vSphere 7). Pour ce faire, il existe d’autres possibilités comme par exemple utiliser l’utilitaire govc développé par VMware. Cependant la version habituelle (référence à la version govc version 0.23.0) ne prend pas en charge les options volume.ls et volume.rm, il faut pour cela utiliser une version à compiler soi-même. ci-dessous les étapes à respecter pour y parvenir :

Installer go (sur Ubuntu server dans mon cas), il est important d’avoir une version récente : https://golang.org/doc/install

Lancer la commande go suivante  : go get -u github.com/vmware/govmomi/govc (https://github.com/vmware/govmomi/tree/master/govc). Ca va télécharger les sources dans le répertoire ~/go/src, compiler et stocker le binaire govc dans ~/go/bin.

il faut positionner ensuite un certain nombre de variable à govc afin qu’il puisse se connecter à l’infrastructure, exemple :

export GOVC_URL=<fqdn du vcenter>
export GOVC_USERNAME=<compte avec des droits en consultation>
export GOVC_PASSWORD=<mot de passe du compte>
export GOVC_INSECURE=true (si vous utilisez des certificats non signés)

Grâce à ce govc spécifique, vous pouvez utiliser la commande ~/go/bin/govc volume.ls pour lister tous les volumes et la commande ~/go/bin/govc volume.rm <volume>. Attention à bien choisir les volumes orphelins sinon vous risquez de perdre des données.

Un développeur à fait un script intéressant pour supprimer les volumes orphelins : https://gist.github.com/bburky/fd729f129347b9141255fbc2185c52ea#file-remove-orphaned-cns-volumes-sh-L1 (attention ce script suppose que govc soit dans votre variable $PATH, si ce n’est pas le cas mettez cette variable à jour ou modifier le script pour qu’il pointe sur le bon govc).

Ce script à un petit bémol auquel il faut prêter attention, il suppose qu’il y ait un seul cluster car il utilise la commande kubectl, celle-ci se connecte en utilisant le contexte actif. Si vous avez plusieurs clusters kubernetes hébergés sur votre infrastructure, vous risquez de supprimer des volumes vus comme orphelin alors qu’ils peuvent potentiellement appartenir à d’autres clusters Kubernetes, j’ai soumis au développeur du script cette modification :

> "$temp_dir/kubernetes-temp.txt"
for context in $(kubectl config view -o jsonpath='{.contexts[*].name}')
do
        echo checking context : $context
        kubectl get pv -o jsonpath='{range .items[*]}{.spec.csi.volumeHandle}{"\t"}{.metadata.name}{"\n"}{end}' --context $context  >> "$temp_dir/kubernetes-temp.txt"
done
sort $temp_dir/kubernetes-temp.txt > $temp_dir/kubernetes.txt

Ce n’est pas encore parfait, il peut inclure des volumes provenant de cluster Kubernetes non vSphere mais il n’y aura pas d’incidence sur la suppression des volumes.

 

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

Déployer Kubeapps

Kubeapps est un projet Bitnami. Bitnami a été racheté par VMware en 2019 et fait partie maintenant de la gamme Tanzu et se nomme Tanzu Application Catalog. Kubeapps est un catalogue de déploiement et de management d’applications et de services. Il arrive déjà connecté à la marketplace bitnami et il est possible de synchroniser une registry type docker. https://bitnami.com/kubernetes/kubeapps

La documentation d’installation est assez bien faite, je n’ai trouvé de complexité, juste un peu de vigilance au niveau des rôles si vous êtes en production. Un utilisateur peut avoir un accès en lecture seul et/ou en lecture/écriture (nécessaire pour déployer des applications), le scope des droits peut être le cluster et/ou le namespace. L’utilisateur à la possibilité de créer des namespaces pour y déployer des applications. https://github.com/kubeapps/kubeapps

Installation via Helm (version 3 dans mon exemple)

$ helm repo add bitnami https://charts.bitnami.com/bitnami

$ kubectl create namespace kubeapps

(attention il y a deux tirets normalement, je ne sais pas pourquoi WordPress en affiche qu’un. Si vous faites un copié/collé, enlever le tiret et en mettre deux à la place)

$ helm install kubeapps –namespace kubeapps bitnami/kubeapps –set useHelm3=true –set frontend.service.type=LoadBalancer

 

Créer un compte et le rôle pourvoir accéder à Kubeapps et pour installer des applications, créer des namespace directement depuis l’interface. Récupérez le token pour se logger à l’interface

$ kubectl create -n default serviceaccount loeilduse

$ kubectl create clusterrolebinding loeilduse –clusterrole cluster-admin –serviceaccount=default:loeilduse

 

$ kubectl get -n default secret $(kubectl get -n default serviceaccount loeilduse -o jsonpath='{.secrets[].name}’) -o go-template='{{.data.token | base64decode}}’ && echo

Récupérer le token, il sera demandé lors de la connexion à Kubeapps via le navigateur (ci-dessous un exemple)

eyJhbGciOiJSUzI1NiIsImtpZCI6IkV5bEdwMDU2dkVqTld5dFJtR03RHNVSmhmd09rc1licnJFSm81Nm1EZ3MifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImxvZWlsZHVzZS10b2tlbi1yOGJiZyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZShY2NvdW50Lm5hbWUiOiJsb2VpbGR1c2UiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI5NTMwZjZmNy1jMzEzLTQ5MzctODY2ZS1mMDUwNzY0YmI0MDEiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpb2VpbGR1c2UifQ.kTZhrfFXrOS-S2a3x6oiyO6mqi7d62lrsmy-pTLpFX-XsjAK8NZQ95WaKqJ1gHkQfJa4ah-gvSQOVeI0y8-TueS24iAbrMfFwuocbHOJa6d9x9dfBSNGfxgW2DZaA22TokAVm_VT_DmFbV7uqsOSdFNRC6GnogoUmaO0P2-X1A8HHXuur04zRU5pH-8kNUrmIclIlpUPIaDlkRV1v94nZfn1S0RswG4wzTY1IeqQn4Nn5vh9XKfavp7l42vSWH7F0AHnkpTpY94GN8TNVoninPBkl5ktcF6PZJ7qbYlEK4wz5Y_cEgJFArGYn3kaihzZ aZsAH7a6scVsk7KcTuYRQ

Récupérer l’IP fournit par le service Load Balancer

$ Kubectl get svc -n kubeapps

 

 

Ouvrir la page web avec l’IP fourni par le load balancer et renseigner le token récupéré :

 

Si vous avez le message ci-dessous, revoyez la partie création user/droit décrite juste avant

 

Vous devriez avoir ces types d’écrans

 

Lorsque vous déployez des applications depuis le catalogue Kubeapps, n’oubliez pas de modifier le fichier yaml si vous voulez y accéder depuis l’extérieur de votre cluster Kubernetes. Ci-dessous, un exemple de déploiement de Dokuwiki pour qu’il soit accessible via un load balancer (voir tout en bas) :

 

Déployer Harbor avec type loadBalancer

Pour rédiger mes articles de vulgarisation, je suis amené à tester certains produits. C’est très chronophage surtout quand ça ne fonctionne pas du premier coup. Je fais pas mal de recherche sur Internet pour voir si des posts donnent des astuces mais des fois, il faut tenter d’autres pistes. C’est pour cela que j’ai créé une rubrique Astuces Techniques, j’y posterai un résumé des résultats de mes recherches qui pourrait aider d’autres personnes.

Je consacre ce premier article au déploiement de la registry Harbor développée initialement par VMware puis donné à la CNCF. J’ai beaucoup galéré pour la déployer afin qu’elle soit accessible derrière un loadbalancer, j’avais le message suivant lorsque que docker tentait de s’y connecter :

#docker login harbor.cpod-tkg.az-lab.shwrfr.com
Authenticating with existing credentials…
Login did not succeed, error: Error response from daemon: Get https://harbor.cpod-tkg.az-lab.shwrfr.com/v2/: Get https://core.harbor.domain/service/token?account=admin&client_id=docker&offline_token=true&service=harbor-registry: dial tcp: lookup core.harbor.domain: no such host

J’utilise un environnement vSphere 7 pour héberger un cluster Kubernetes V1.17.3 déployé via TKG V1. Le loadbalancer est un Metallb V0.82, Habor V1.10.1 et HELM 3

Télécharger Harbor via Helm 3 :

#helm repo add harbor https://helm.goharbor.io

#helm fetch harbor/harbor –untar

Créer une storage class nécessaire aux volumes persistent, cette storage class utilise une storage policy que j’ai déjà créé dans vSpehre :

kind: StorageClass

apiVersion: storage.k8s.io/v1

metadata:

  name: silver-storage-class

  annotations:

    storageclass.kubernetes.io/is-default-class: “true”

provisioner: csi.vsphere.vmware.com

parameters:

  storagepolicyname: “silver-storage-class”

Installer Harbor avec les bons paramètres notamment externalURL :

# helm install -n harbor-system registry harbor/harbor –set expose.type=loadBalancer,expose.tls.commonName=harbor.cpod-tkg.az-lab.shwrfr.com,externalURL=https://harbor.cpod-tkg.az-lab.shwrfr.com

Si vous n’utilisez pas de certificats signés, il faut que docker soit autorisé à utiliser une registry “Insecure” :

#cat /etc/docker/daemon.json

{

        “insecure-registries” : [“172.20.4.71”, ’’harbor.cpod-tkg.az-lab.shwrfr.com’’]

}

# systemctl restart docker

Télécharger le certificat depuis l’UI d’Harbor => projets => <votre nom de projet> => Reprositories => REGISTRY CERTIFICATE et le copier dans le répertoire docker prévu à cet effet :

#mkdir -p /etc/docker/certs.d/172.20.4.71 et/ou mkdir -p /etc/docker/certs.d/’harbor.cpod-tkg.az-lab.shwrfr.com’

Normalement vous devriez pouvoir vous connecter à Harbor via Docker :

#docker login harbor.cpod-tkg.az-lab.shwrfr.com
Authenticating with existing credentials…
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded