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.
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.
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.
En résumé : ExternalSecret définit ce qu’il faut récupérer, SecretStore définit comment y accéder.
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.
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.
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
.
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 :
argocd
).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 :
Avec cette configuration, my-secret
est désormais synchronisé entre les namespaces foo
et bar
.
Pour partager des secrets entre différents clusters (ex. Platform → Dev), deux stratégies sont possibles :
Nous avons opté pour le mode push afin d’éviter que les clusters Dev et Prod dépendent de la disponibilité du cluster Platform.
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.
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.