How I Used HashiCorp Vault and External Secrets Operator
When building a Kubernetes deployment for an application using MySQL, I initially considered using a ConfigMap
to store my database connection details. However, I quickly ran into a problem: ConfigMaps are not designed for sensitive data like passwords, and more importantly, I was using Argo CD for GitOps.
With Argo CD, all Kubernetes manifests-including ConfigMaps-are stored in Git. This meant that if I put my MySQL password in a ConfigMap, it would end up in my Git repository. Even with a private repo, this felt risky and against best practices for secret management.
Instead, I turned to a solution combining HashiCorp Vault and the External Secrets Operator. Here’s how I set it up:
Storing the MySQL Password in Vault#
First, I stored my MySQL password securely in Vault:
vault kv put bacula/config @config.php
Creating an ExternalSecret Resource#
Next, I defined an ExternalSecret
resource that tells the External Secrets Operator to fetch the password from Vault and create a Kubernetes Secret:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: bacula
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-secret-store
kind: ClusterSecretStore
target:
name: bacula-config-secret # The name of the resulting Kubernetes Secret
creationPolicy: Owner
data:
- secretKey: config.php # The key in the resulting Kubernetes Secret
remoteRef:
key: bacula/config # The path in Vault
property: config # The property within the Vault secret to use
Mounting the Secret in My Application Pod#
Finally, I mounted the secret as a file in my application’s pod:
spec:
volumes:
- name: bacula-config-volume
secret:
secretName: bacula-config-secret
items:
- key: config.php
path: config.php
...
containers:
- name: bacula
image: baculaweb/bacula-web:latest
resources:
limits:
cpu: "200m"
memory: "256M"
volumeMounts:
- name: bacula-config-volume
mountPath: /var/www/html/application/config/config.php
subPath: config.php
Conclusion#
By using HashiCorp Vault and the External Secrets Operator, I was able to avoid exposing my MySQL password in Git while still automating my deployments with Argo CD. This approach kept my secrets secure and out of version control, while still letting my applications access them at runtime.