No alternative text provided

Evitez les secrets dans Git : OpenLDAP en toute sécurité

TL;DR : Ne stockez plus vos mots de passe dans Git ! Générez un mot de passe OpenLDAP sécurisé via un Job Kubernetes, tout en apprenant les bases de RBAC.


🔐 Contexte

Cet article fait suite à cet article, dans lequel j'ai mis en place un service d'email forwarding auto-hébergé avec OpenLDAP et Docker Mailserver (DMS).

Un point noir dans cette première version : j'avais laissé le mot de passe admin LDAP en clair dans mon repo Git. C'est clairement une mauvaise pratique, surtout si vous utilisez ArgoCD et une stratégie GitOps pour gérer vos déploiements.

Heureusement, le chart jp-gouin/helm-openldap permet de passer un secret déjà existant via la valeur global.existingSecret.

Problème : on veut que ce secret soit créé dynamiquement, avec un mot de passe aléatoire, sans interaction manuelle.

👉 Et c'est là que Kubernetes Job entre en scène !


🧪 C'est quoi un Job Kubernetes ?

Un Job Kubernetes est une tâche unique, exécutée jusqu'à complétion. C'est parfait pour les traitements par lot, les migrations one-shot, ou la génération de secrets comme ici.

Notre Job va :

  • Vérifier si le secret ldap-passwords existe
  • Sinon, générer deux mots de passe aléatoires
  • Créer le secret via kubectl

🎯 Pourquoi pas kubectl, Vault ou Sealed Secrets ?

  • kubectl ? OK, mais il faut le lancer à la main
  • Vault ? Un peu trop lourd pour mon petit cluster
  • Sealed Secrets ? Toujours dans Git, même chiffré...

Ici, on va faire une création automatique in-cluster, sans toucher au Git repo. Propre, sûr et GitOps-friendly ✨


🛠️ Les ressources Kubernetes nécessaires

Pour que notre pod (le Job) puisse créer un secret, il faut l'y autoriser via le mécanisme RBAC (Role-Based Access Control).

🔍 Décomposition RBAC :

  • ServiceAccount : identité utilisée par le Job
  • Role : décrit les permissions (ici : création de secrets)
  • RoleBinding : associe un Role à une ServiceAccount

🔐 YAML à déployer

1apiVersion: v1
2kind: ServiceAccount
3metadata:
4  name: ldap-admin-key-generator
5---
6apiVersion: rbac.authorization.k8s.io/v1
7kind: Role
8metadata:
9  name: ldap-admin-key-generator
10rules:
11  - apiGroups: [""]
12    resources: ["secrets"]
13    verbs: ["get", "create", "update", "patch"]
14---
15apiVersion: rbac.authorization.k8s.io/v1
16kind: RoleBinding
17metadata:
18  name: ldap-admin-key-generator
19roleRef:
20  apiGroup: rbac.authorization.k8s.io
21  kind: Role
22  name: ldap-admin-key-generator
23subjects:
24  - kind: ServiceAccount
25    name: ldap-admin-key-generator

🚀 Le Job de génération du mot de passe

Voici le YAML du Job :

1apiVersion: batch/v1
2kind: Job
3metadata:
4  name: ldap-admin-key-generator
5spec:
6  template:
7    spec:
8      restartPolicy: Never
9      serviceAccountName: ldap-admin-key-generator
10      containers:
11        - name: key-generator
12          image: bitnami/kubectl:latest
13          command:
14            - /bin/sh
15            - -c
16            - |
17              if kubectl get secret ldap-passwords -o jsonpath='{.data.LDAP_ADMIN_PASSWORD}' 2>/dev/null | grep . >/dev/null && \
18                 kubectl get secret ldap-passwords -o jsonpath='{.data.LDAP_CONFIG_ADMIN_PASSWORD}' 2>/dev/null | grep . >/dev/null; then
19                  echo "Le secret existe déjà, on ne fait rien"
20                  exit 0
21              fi
22
23              LDAP_ADMIN_PASSWORD="$(openssl rand -hex 16 | tr -d '\n')"
24              LDAP_CONFIG_ADMIN_PASSWORD="$(openssl rand -hex 16 | tr -d '\n')"
25
26              kubectl create secret generic ldap-passwords \
27                --from-literal=LDAP_ADMIN_PASSWORD="$LDAP_ADMIN_PASSWORD" \
28                --from-literal=LDAP_CONFIG_ADMIN_PASSWORD="$LDAP_CONFIG_ADMIN_PASSWORD" \
29                --dry-run=client -o yaml | kubectl apply -f -
30
31              echo "Nouveau secret ldap-passwords généré avec succès"

🔗 Intégration avec le chart Helm

Une fois le secret généré, on peut le référencer dans values.yaml :

1# values.yaml
2
3global:
4  existingSecret: ldap-passwords

🧾 Bonus : récupérer le mot de passe

1kubectl --namespace ldap get secret ldap-passwords -o jsonpath='{.data.LDAP_ADMIN_PASSWORD}' | base64 -d

🧠 Conclusion

Ce pattern — créer dynamiquement un secret avec un Job, protégé par RBAC — est très réutilisable. C'est simple, sûr, et 100% compatible GitOps 💪

Faites-moi signe si vous voulez une version Helm chart ou Kustomize reusable !


🖖 Bon self-hosting !