6 Mar 2023

Brokers Choria, kubernetes et Ca Vault


Introduction

Lors du passage de Puppet 5 à Puppet 6 l’un des plus gros changement était pour nous la disparition de mcollective et ActiveMQ. Heureusement il ne s’agissait pas d’une disparition mais d’une ré-écriture complète et une migration vers choria, qui offre beaucoup plus de possibilité.

Tout comme Mcolvective, Choria est un outil d’orchestration fonctionnant sur un principe de client <-> broker <-> servers. À l’inverse des modèles habituels, où ce sont des clients installés via des agents sur les noeuds à manager, choria se distringue sur le fait que nous installons des serveurs sur nos noeuds à manager, qui seront connecter à un ou des brokers. Par la suite c’est un client qui vas envoyer des messages d’actions dans la queue pour être consommés par les servers. Le tout se basant principallement sur la librairy nats, et d’une authentification par certificat x509, rendant l’ensemble très puissant avec un faible coût d’infrastructure (la documentation indique un coût d’une simple broker de 4G de RAM pour 50k servers).

Choix de l’architecture

Dans notre ancienne architecture mcollective nous avions un cluster activemq installé sur 6 Puppetservers, puis passé à un cluster de 3 noeuds actifs en raison d’une consommation élevé et non nécessaire de connexion sur le haproxy. Pour Choria il avait été décidé de partir sur le même concepte, et nous avons pris l’architecture la plus simple, mais en mettant en place 3 brokers afin d’avoir une haute disponnibilité.

Juste avant la mise en place de la solution pour la production j’ai décidé de rajouter deux objectifs:

  1. Mettre en place la solution dans un context kubernetes onepremise (l’offre interne commençait à émerger et je souhaitais monter en compétance pour, à terme, déporter toute l’infra Puppet dans kubernetes)
  2. Utiliser la Ca Puppet et la stocker dans vault (contrairement Ă  notre architecture mcollective qui utilisait sa propre CA et un seul jeu de certificat client et server)

Mise en place dans Kubernetes

La mise en place dans Kubernetes est assez simple d’access, une chart helm est disponnible et contient plus ou moins tout ce qui est nécessaire. Il est néamoins bon de noter, pour une raison que j’ignore (probablement lié à la création du certificats, bien que je pense que ce soit contournable), que les brokers sont en StatefulSets. Cela peut amener à réfléchir sur la répartition de ses pods.

La partie plus complexe est la mise en place de gestion de la CA via vault. En effet bien que la chart helm propose une Ca, elle n’est pas suffisante car il s’agit d’une Ca stocker en secret. De mon côté j’ai utilisé cert-manager afin de déclarer mon issuer vault avec une authentification via appRole:

---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: vault-issuer
spec:
  vault:
    path: {{ .Values.vault.path }}
    server: {{ .Values.vault.addr }}
    auth:
      appRole:
        path: approle
        roleId: {{ .Values.vault.roleId }}
        secretRef:
          name: cert-manager-vault-approle
          key: secretId

En pré-requis il est nécessaire d’avoir:

  1. Importé votre Ca Puppet dans vault
  2. Se créer une policy avec les droits ["list", "read", "create", "update"]
  3. Un appRole rattaché à votre policy dans vault
  4. Un secretId qui vas servir à la création de token lié à l’appRole, ce dernier sera à stocker dans un secret cert-manager-vault-approle dans la clé secretId.
  5. Les valeurs aditionelles dans votre values.yaml, ex:

     ---
     vault:
       addr: https://vault.wtf.org
       roleId: db02de05-fa39-4855-059b-67221c5c2f63
       path: pki_puppet_ca/sign/puppet
    
  6. L’ajout des autorisations RBAC nécessaires, car ce seront les pods choria qui feront directement appels à cert-manager pour obtenir leur certificat. J’ai re-pris ce qui est mis dans la chart ca choria

     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: Role
     metadata:
       name: choria:csraccess
     rules:
       - apiGroups: ["cert-manager.io"]
         resources: ["certificaterequests", "certificaterequest"]
         verbs: ["get", "create", "delete", "post"]
    
     ---
     apiVersion: rbac.authorization.k8s.io/v1
     kind: RoleBinding
     metadata:
       name: choria:csracess
     subjects:
       - kind: ServiceAccount
         name: choria-csraccess
         apiGroup: ""
     roleRef:
       kind: Role
       name: choria:csraccess
       apiGroup: rbac.authorization.k8s.io
    
     ---
     apiVersion: v1
     kind: ServiceAccount
     metadata:
       name: choria-csraccess
    
  7. Ajouter la référence de l’issuer dans les la configuration du broker dans le values.yaml

     broker:
       broker:
         certManagerIssuer: vault-issuer
    

Utilisation

Pour l’utilisation, les clients choria doivent utiliser un certificat x509 créé par la CA avec un Common Name qui serivira dans les policies. Plutôt que faire des certificats par mainteneur et de changer policies, j’ai créé une machine dédié pour l’utilisation du client et filtré par des groupes AD sur la connexion. Tout les utilisateurs possédait ensuite un droit sudo pour passer sur l’utilisateur choria qui était habilité à lire le certificat que j’ai généré avec le puppetserver puppetserver ca generate --certname choria.mcollective.

Nous avions une utilisation très limite de choria, principalement pour lister des états de paquets ou desactiver/activer l’agent puppet sur tout le parc en quelques ms, mais il existe beaucoup de possibilité que je n’ai pas pu tester comme créer des playbooks, orchestrer les tasks puppet ou avoir une architure plus poussé en fédérations.

NOTE: Lors de la création de cet environment j’ai appris ce que le champ Common Name des certificats x509 est déprécié depuis May 2000 via la RFC2818, mais ce champ est obligatoire lors de la creation d’un certificat dans un pki vault


Tags: