Chez Cockpit io, nous recommandons d’utiliser autant que possible du code pour piloter l’infrastructure et notamment les clusters Kubernetes. En suivant la philosophie GitOps, ce code est stocké et versionné dans des dépôts git. Pour fonctionner, la plupart des applications ont besoin de paramètres ou d’éléments de configuration sensibles, que nous appelons des “secrets”. Citons par exemple le mot de passe pour qu’une application se connecte à une base de données. Or la sensibilité de telles informations implique qu’il est dangereux de les stocker en clair dans le code d’infrastructure. Une solution est donc de chiffrer ces informations. Nous allons voir comment faire cela avec Selead Secrets de Bitnami.
1. Pré-requis
- Un cluster Kubernetes
- Kubectl
- Helm
2. Présentation de Sealed Secrets
Sealed Secrets est un projet open source, maintenu par Bitnami, composé de deux parties : un contrôleur qui tourne dans le cluster Kubernetes, et une application en ligne de commande (cli), kubeseal
à installer sur le poste de l’opérateur. Les secrets sont créés par ce-dernier, qui va utiliser la cli kubeseal
pour les chiffrer, puis déployer les secrets chiffrés dans le cluster Kubernetes. C’est le contrôleur qui va se charger de déchiffrer les secrets, depuis le cluster, et de créer les secrets en clair1 dans le cluster.
Le chiffrement est asymétrique : une clé publique et une clé privée sont générées lors de l’installation de Sealed Secrets. La clé privée reste dans le cluster et seule la clé publique est utilisée par l’opérateur. Avec cette clé publique, il va pouvoir chiffrer les secrets. Ceux-ci ne pourront être déchiffrés qu’avec la clé privée. D’autres paires de clé publique et privée peuvent être ajoutées.
Ainsi, un opérateur qui dispose de la clé publique ne peut pas déchiffrer lui-même des secrets chiffrés.
3. Installer Selead Secrets sur Kubernetes
L’installation est proposée par le déploiement d’un manifeste Kubernetes, qui peut être surchargé avec Kustomize, ou par le déploiement d’un Helm Chart.
Pour l’exemple nous allons déployer un Helm Chart :
1helm repo add sealed-secrets https://bitnami-labs.github.io/sealed-secrets
2helm install sealed-secrets sealed-secrets/sealed-secrets
4. Installer la cli sur son poste
La cli kubeseal
peut être installée sur Linux et Mac. Il nous faut installer une version qui soit identique à celle du contrôleur déployé sur le cluster Kubernetes.
Dans notre exemple, nous avons déployé la version 0.26.2 du contrôleur, alors voici comment installer la cli adaptée sur Linux (amd64) :
1KUBESEAL_VERSION='0.26.2'
2wget "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION:?}/kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz"
3tar -xvzf kubeseal-${KUBESEAL_VERSION:?}-linux-amd64.tar.gz kubeseal
4sudo install -m 755 kubeseal /usr/local/bin/kubeseal
5. Chiffrer un secret
Commençons par générer un manifeste contenant un secret générique, avec deux mots de passe :
1$ kubectl create secret generic my-secret --from-literal=key1=supersecret \
2--from-literal=key2=topsecret --dry-run=client -o yaml | tee mysecret.yaml
3
4apiVersion: v1
5data:
6 key1: c3VwZXJzZWNyZXQ=
7 key2: dG9wc2VjcmV0
8kind: Secret
9metadata:
10 creationTimestamp: null
11 name: my-secret
6. Déployer un manifeste contenant un secret chiffré
Maintenant nous pouvons chiffrer ce secret avec la cli kubeseal
1$ kubeseal -f mysecret.yaml -w mysecret-sealed.yaml -o yaml \
2--controller-name sealed-secrets --controller-namespace default
Cette commande crée un objet de type kind: SealedSecret
dans l’apiVersion: bitnami.com/v1alpha1
, en voici le manifeste :
1cat mysecret-sealed.yaml
2---
3apiVersion: bitnami.com/v1alpha1
4kind: SealedSecret
5metadata:
6 creationTimestamp: null
7 name: my-secret
8 namespace: default
9spec:
10 encryptedData:
11 key1: xxxxxxxxxxxxx
12 key2: xxxxxxxxxxxxx
13 template:
14 metadata:
15 creationTimestamp: null
16 name: my-secret
17 namespace: default
Nous retrouvons bien la structure de données de notre secret initial, le nom de la ressource est identique, my-secret
, et il y a bien deux clés, key1
et key2
, dont les valeurs sont désormais chiffrées. Appliquons ce manifeste :
1$ kubectl apply -f mysecret-sealed.yaml
2
3sealedsecret.bitnami.com/my-secret created
4
5$ kubectl get SealedSecret
6NAME STATUS SYNCED AGE
7my-secret True 5s
8
9$ kubectl get secret
10NAME TYPE DATA AGE
11my-secret Opaque 2 41s
Dès que la ressource SealedSecret est créée, le contrôleur sealed-secrets (qui s’exécute sur le cluster Kubernetes) la déchiffre et crée le secret. Nous pouvons vérifier cela en consultant les logs :
1kubectl logs deploy/sealed-secrets
2
3time=2024-04-23T14:49:41.881Z level=INFO msg="Event(v1.ObjectReference{Kind:\"SealedSecret\", Namespace:\"default\", Name:\"my-secret\", UID:\"3346b241-2d24-4b47-8873-d4cf7970900e\", APIVersion:\"bitnami.com/v1alpha1\", ResourceVersion:\"92259\", FieldPath:\"\"}): type: 'Normal' reason: 'Unsealed' SealedSecret unsealed successfully"
Voici le secret créé par le contrôleur :
1$ kubectl get secret my-secret -o yaml
2apiVersion: v1
3data:
4 key1: c3VwZXJzZWNyZXQ=
5 key2: dG9wc2VjcmV0
6kind: Secret
7metadata:
8 creationTimestamp: "2024-04-23T14:49:41Z"
9 name: my-secret
10 namespace: default
11 ownerReferences:
12 - apiVersion: bitnami.com/v1alpha1
13 controller: true
14 kind: SealedSecret
15 name: my-secret
16 uid: 3346b241-2d24-4b47-8873-d4cf7970900e
17 resourceVersion: "92260"
18 uid: 84b8bf63-754d-41df-9d2f-60a155406c54
19type: Opaque
Le contrôleur de Sealed Secrets est capable de suivre le cycle de vie des secrets : la mise à jour ou la suppression des ressources de type SealedSecret
sont reflétées respectivement par la mise à jour ou la suppression de ressources de type secret
.
7. GitOps
Avec Sealed Secrets, nous pouvons chiffrer de manière sûre les manifestes contenant des secrets. Ainsi, il est possible de versionner ces manifestes dans un dépôt git et de continuer à travailler avec la méthodologie GitOps.
Par exemple, les secrets chiffrés peuvent être déployés automatiquement par les solutions ArgoCD ou FluxCD. Une fois ce déploiement effectué sur le cluster Kubernetes, le contrôleur de Sealed Secrets se chargera de créer les secrets équivalents en clair1 au sein du même cluster. Les secrets n’existeront en clair1 qu’au sein du cluster Kubernetes.
Par ailleurs, les secrets étant chiffrés avec une paire de clés asymétriques, nous pouvons accorder à une personne la possibilité de chiffrer des secrets en lui fournissant la clé publique nécessaire, mais celle-ci ne sera pas en mesure de déchiffrer elle-même les secrets chiffrés préexistants, si elle n’a ni clé privée ni la possibilité de la récupérer depuis le cluster Kubernetes.
8. Pour aller plus loin
a. Sauvegarder les clés privées
Une des particularités de Sealed Secrets est son fonctionnement avec des clés publiques et privées, et la conservation des clés privées dans le cluster Kubernetes. Comme dit plus haut, c’est seulement grâce à ces clés privées qu’il est possible de déchiffrer les secrets. Dans le cas où nous voudrions pouvoir accéder à des secrets chiffrés manuellement, par exemple en cas de perte du cluster Kubernetes, ces clés privées seraient nécessaires. Ainsi, il serait prudent d’en conserver une copie, en un lieu de stockage sûr, accessible seulement en cas de nécessité.
Voici comment obtenir les clés privées :
1kubectl get secret -n default -l sealedsecrets.bitnami.com/sealed-secrets-key -o yaml
2apiVersion: v1
3items:
4- apiVersion: v1
5 data:
6 tls.crt: xxxxxxxxxxxxxxxxxxxxx
7 tls.key: xxxxxxxxxxxxxxxxxxxxx
8 kind: Secret
9 metadata:
10 creationTimestamp: "2024-04-22T15:03:19Z"
11 generateName: sealed-secrets-key
12 labels:
13 sealedsecrets.bitnami.com/sealed-secrets-key: active
14 name: sealed-secrets-keyl59jb
15 namespace: default
16 resourceVersion: "73121"
17 uid: 9a424dd5-8c50-4b8a-939b-befe7f5e788d
18 type: kubernetes.io/tls
19kind: List
20metadata:
21 resourceVersion: ""
b. Rotation des clés et secrets
Une des bonnes pratiques lorsque nous utilisons des secrets est de les changer régulièrement, c’est ce que nous appelons la rotation des secrets. L’utilisation de Sealed Secrets ne nous prémunie pas d’opérer cette rotation des secrets. En complément, le contrôleur de Sealed Secrets génère tous les 30 jours (cette durée peut être personnalisée) une nouvelle paire de clés publique et privée.
-
Dans les clusters Kubernetes, les secrets sont stockés durablement dans la base de données
etcd
. Nous vous recommandons fortement d’activer le chiffrement au repos pour ces secrets (et toutes les autres ressources qui pourraient contenir des données sensibles). Ainsi, ces secrets n’existeront en clair, que durant le fonctionnement du cluster, et seront conservés chiffrés sur le support de stockage utilisé paretcd
. ↩︎ ↩︎ ↩︎