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

HashiCorp Vault

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.