Contactez-nous
-
kubernetes

Synchronisation des Secrets dans votre cluster Kubernetes avec External Secrets

Synchronisation des Secrets dans votre cluster Kubernetes avec External Secrets
Synchronisation des Secrets dans votre cluster Kubernetes avec External Secrets
5:21

Sommaire

En guise d’introduction

La gestion des secrets dans Kubernetes peut s'avérer complexe. Heureusement, External Secrets fournit une solution transparente pour gérer vos secrets en toute sécurité en s'intégrant à des fournisseurs de secrets comme AWS Secrets Manager, HashiCorp Vault …

Si External Secrets est généralement utilisé pour synchroniser des secrets depuis des sources externes, notre besoin est légèrement différent dans le cadre de notre Internal Developer Platform (IDP). Nous avons dû gérer la synchronisation des secrets entre namespaces au sein d’un même cluster ainsi qu’entre différents clusters. Cet article détaille notre approche pour répondre à ces défis en utilisant External Secrets.

Nos besoins spécifiques

Premier besoin : Synchroniser les secrets d’un namespace à l’autre au sein du même cluster.

Par exemple, nous auto-générons le secret de Harbor dans notre namespace registry, mais nous voulons l'utiliser dans le namespace idp pour Backstage ou encore dans le namespace orchestrator pour les API internes. 

Deuxième besoin : synchroniser les secrets entre différents clusters.

Par exemple, les secrets des outils tels que Harbor, Woodpecker ou encore external-dns sont gérés dans un cluster Platform, mais vivent également dans les clusters des payloads : Dev, Staging, Prod, etc. 

Concepts généraux

Avant d’adresser nos besoins spécifiques, il est essentiel de comprendre le fonctionnement général de l’opérateur External Secrets (ESO).

L'External Secrets Operator étend Kubernetes avec des Custom Resource Definitions (CRDs) qui définissent où se trouvent les secrets et comment les synchroniser. Le contrôleur récupère les secrets depuis une API externe et crée des Secrets Kubernetes. Si le secret change dans l’API externe, le contrôleur met à jour le secret dans Kubernetes.

SecretStore et ExternalSecret

  • SecretStore : Définit la configuration pour récupérer des secrets depuis un fournisseur externe. Il précise le backend de stockage des secrets et les paramètres d'authentification.
  • ExternalSecret : Définit comment un secret est synchronisé depuis un fournisseur externe vers un Secret Kubernetes.

En résumé : ExternalSecret définit ce qu’il faut récupérer, SecretStore définit comment y accéder.

ClusterSecretStore

Le ClusterSecretStore est un SecretStore à l'échelle du cluster qui peut être référencé par tous les ExternalSecrets de tous les namespaces. C’est cette ressource qui nous permet de recopier des secrets entre namespaces.

Providers

External Secrets supporte plusieurs Providers (AWS Secrets Manager, HashiCorp Vault, Google Secret Manager, etc.). Pour notre cas de synchronisation de secrets au sein du cluster, nous avons utilisé le provider Kubernetes.

Armés de ces concepts nous pouvons  attaquer nos besoins spécifiques.

Synchronisation entres les namespaces

Dans Kubernetes, un Deployment ne peut pas utiliser un secret qui se trouve dans un autre namespace. Nous avons donc dû trouver une solution pour partager des secrets entre namespaces à l’intérieur d’un même cluster.

Prenons l’exemple où nous devons copier le secret my-secret du namespace foo vers bar.

Création d’un ClusterSecretStore

Nous devons utiliser un ClusterSecretStore pour pointer vers le namespace source :

apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
 name: foo-secret-store
spec:
 provider:
   kubernetes:
     remoteNamespace: foo
     server:
       caProvider:
         type: ConfigMap
         name: kube-root-ca.crt
         key: ca.crt
         namespace: foo
     auth:
       serviceAccount:
         name: external-secrets
         namespace: argocd

Explications :

  • remoteNamespace - Namespace source du secret.
  • server.caProvider - Certificat du cluster. Chaque namespace possède un ConfigMap kube-root-ca.crt qui contient le certificat du serveur interne.
  • auth.serviceAccount - Référence un service account pour récupérer le secret. Par  simplicité nous utilisons ici un service account automatiquement créé lors d’installation de ESO, qui a tous les droits nécessaires (Note: notre ESO est installé dans le namespace argocd).

Création d’un ExternalSecret

Nous créons ensuite un ExternalSecret dans un namespace de destination.

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
 name: pull-my-secret
 namespace: bar
spec:
 refreshInterval: 1h
 secretStoreRef:
   name: foo-secret-store
   kind: ClusterSecretStore
 target:
   name: my-secret
 dataFrom:
   - extract:
       key: my-secret

Explications :

  • refreshInterval - La fréquence à laquelle l'opérateur vérifie les mises à jour des secrets dans la source externe.
  • secretStoreRef - Référence un secret store. Notez que le `kind` est ClusterSecretStore
  • target.name - le nom de secret cible.
  • dataFrom.extract.key - le nom de secret source.

Avec cette configuration, my-secret est désormais synchronisé entre les namespaces foo et bar.

Synchronisation entres les clusters

Pour partager des secrets entre différents clusters (ex. Platform → Dev), deux stratégies sont possibles :

  • Mode pull : Chaque cluster récupère les secrets depuis le cluster Platform.
  • Mode push : Le cluster Platform envoie les secrets aux clusters cibles.

Nous avons opté pour le mode push afin d’éviter que les clusters Dev et Prod dépendent de la disponibilité du cluster Platform.

Utilisation de PushSecret

Contrairement à ExternalSecret, qui récupère les secrets depuis des fournisseurs et crée une ressource de type Secret dans votre cluster, PushSecret lit un Secret local et envoie son contenu vers un SecretStore.

Étape 1 : Création d’un ServiceAccount et de ses permissions dans le cluster cible (Dev).

apiVersion: v1
kind: ServiceAccount
metadata:
  name: eso-service-account
  namespace: foo

---

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: foo
  name: eso-role
rules:
- apiGroups: [""]
  resources:
  - secrets
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - delete
  - patch
- apiGroups:
  - authorization.k8s.io
  resources:
  - selfsubjectrulesreviews
  verbs:
  - create

---

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: eso-role-binding
  namespace: foo
subjects:
  - kind: ServiceAccount
    name: eso-service-account
    namespace: foo
roleRef:
  kind: Role
  name: eso-role
  apiGroup: rbac.authorization.k8s.io

---

apiVersion: v1
kind: Secret
metadata:
 name: eso-token
 namespace: foo
 annotations:
   kubernetes.io/service-account.name: "eso-service-account"
type: kubernetes.io/service-account-token

Notez la présence de Secret eso-token. Kubernetes va automatiquement remplir ce Secret avec le token JWT et ca.crt pour s'authentifier auprès de l'API Kubernetes en tant que eso-service-account.

Nous le récupérons et le copions manuellement dans notre cluster source (Platform) sans oublier de changer son type en Opaque.

Étape 2 : Création d’un SecretStore et d’un PushSecret dans le cluster source (Platform)

apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
 name: foo-secret-store-dev
spec:
 provider:
   kubernetes:
     remoteNamespace: foo
     server:
       url: https://<url du cluster dev>:6443
       caProvider:
         type: Secret
         name: eso-token
         key: ca.crt
     auth:
       token:
         bearerToken:
           name: eso-token
           key: token

---

apiVersion: external-secrets.io/v1alpha1
kind: PushSecret
metadata:
 name: push-my-secret-to-dev
 namespace: foo
spec:
 updatePolicy: Replace
 deletionPolicy: None
 refreshInterval: 1h
 secretStoreRefs:
   - name: foo-secret-store-dev
     kind: SecretStore
 selector:
   secret:
     name: my-secret
 data:
   - match:
       remoteRef:
         remoteKey: my-secret

Une fois cette configuration appliquée, my-secret est automatiquement synchronisé vers le cluster Dev.

Conclusion

External Secrets s’avère être un outil puissant pour gérer la synchronisation des secrets dans Kubernetes, que ce soit entre namespaces ou entre clusters. Grâce aux ressources comme ClusterSecretStore et PushSecret, il est possible d’automatiser ces échanges tout en garantissant sécurité et scalabilité. En expérimentant ces approches, vous pourrez adapter External Secrets à vos propres besoins et renforcer la fiabilité de votre plateforme.