Before start to integration helm-secrets with ArgoCD, consider using age over gpg. It's recommended to use age over GPG, if possible.
helm-secrets 3.9.x or higher
An Argo CD Application can use the downloader plugin syntax to use encrypted value files. There are two methods how to use an encrypted value file.
- Method 1: Mount the private key from a kubernetes secret as volume
- Method 2: Fetch the private key directly from a kubernetes secret
Please refer to the configuration section of the corresponding method for further instructions.
apiVersion: argoproj.io/v1alpha1
kind: Application
...
spec:
source:
helm:
valueFiles:
# Method 1: Mount the gpg/age key from a kubernetes secret as volume
# secrets+gpg-import://<key-volume-mount>/<key-name>.asc?<relative/path/to/the/encrypted/secrets.yaml>
# secrets+age-import://<key-volume-mount>/<key-name>.txt?<relative/path/to/the/encrypted/secrets.yaml>
# Example Method 1: (Assumptions: key-volume-mount=/helm-secrets-private-keys, key-name=app, secret.yaml is in the root folder)
- secrets+gpg-import:///helm-secrets-private-keys/key.asc?secrets.yaml
# ### Method 2: Fetch the gpg/age key from kubernetes secret
# secrets+gpg-import-kubernetes://<namespace>/<secret-name>#<key-name>.asc?<relative/path/to/the/encrypted/secrets.yaml>
# secrets+age-import-kubernetes://<namespace>/<secret-name>#<key-name>.txt?<relative/path/to/the/encrypted/secrets.yaml>
# Example Method 2: (Assumptions: namespace=argocd, secret-name=helm-secrets-private-keys, key-name=app, secret.yaml is in the root folder)
- secrets+gpg-import-kubernetes://argocd/helm-secrets-private-keys#key.asc?secrets.yaml
Helm will call helm-secrets because helm-secrets is registered as downloader plugin.
Before using helm secrets, we are required to install helm-secrets and sops on the ArgoCD Repo Server. There are two methods to do this. Either create your custom ArgoCD Docker Image or install them via init container.
Integrating helm-secrets
with Argo CD can be achieved by building a custom Argo CD Server image.
Below is an example Dockerfile
which incorporates sops
and helm-secrets
into the Argo CD image:
ARG ARGOCD_VERSION="v2.1.2"
FROM argoproj/argocd:$ARGOCD_VERSION
ARG SOPS_VERSION="3.7.1"
ARG HELM_SECRETS_VERSION="3.9.0"
ARG KUBECTL_VERSION="1.22.0"
USER root
RUN apt-get update && \
apt-get install -y \
curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN curl -fSSL https://github.com/mozilla/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux \
-o /usr/local/bin/sops && chmod +x /usr/local/bin/sops
RUN curl -fSSL https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl \
-o /usr/local/bin/kubectl && chmod +x /usr/local/bin/kubectl
USER argocd
ENV HELM_PLUGINS="/home/argocd/.local/share/helm/plugins/"
RUN helm plugin install --version ${HELM_SECRETS_VERSION} https://github.com/jkroepke/helm-secrets
Make sure to specify your custom image when deploying Argo CD.
install sops or vals and helm-secret through an init container.
This is an example values file for the ArgoCD Server Helm chart.
repoServer:
env:
- name: HELM_PLUGINS
value: /custom-tools/helm-plugins/
- name: HELM_SECRETS_SOPS_PATH
value: /custom-tools/sops
- name: HELM_SECRETS_KUBECTL_PATH
value: /custom-tools/kubectl
volumes:
- name: custom-tools
emptyDir: {}
volumeMounts:
- mountPath: /custom-tools
name: custom-tools
initContainers:
- name: download-tools
image: alpine:latest
command: [sh, -ec]
env:
- name: HELM_SECRETS_VERSION
value: "3.9.0"
- name: SOPS_VERSION
value: "3.7.1"
- name: KUBECTL_VERSION
value: "1.22.0"
args:
- |
mkdir -p /custom-tools/helm-plugins
wget -qO- https://github.com/jkroepke/helm-secrets/releases/download/v${HELM_SECRETS_VERSION}/helm-secrets.tar.gz | tar -C /custom-tools/helm-plugins -xzf-;
wget -qO /custom-tools/sops https://github.com/mozilla/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux
wget -qO /custom-tools/kubectl https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl
chmod +x /custom-tools/*
volumeMounts:
- mountPath: /custom-tools
name: custom-tools
It is required to configure ArgoCD so that it has access to the private key to decrypt the encrypted value file. There are two ways to achieve this. Either mount the gpg key from secret as volume or access the fetch the private key directly from a kubernetes secret. Both methods depend on a secret holding the key in asci format.
gpg --full-generate-key --rfc4880
When asked to enter a password you need to omit it.
Please also note that currently it is recommended to use the --rfc4880. This prevents you from running into a compatibility issue between gpg 2.2 and gpg 2.3. (Related Issue: Encryption with GnuPG 2.3 (RFC4880bis) causes compatibility issues with GnuPG 2.2)
gpg --armor --export-key <key-id> > key.asc
The key-id can be found in the output of the generate-key command. It looks something like this:
gpg: key 1234567890987654321 marked as ultimately trusted
age-keygen -o key.txt
The public key can be found in the output of the generate-key command. Unlike gpg, age does not have an agent. To encrypt the key with sops, set the environment variables
SOPS_AGE_KEY_FILE="path/age/key.txt"
SOPS_AGE_RECIPIENTS=public-key
before running sops. Define SOPS_AGE_RECIPIENTS
is only required on initial encryption of a plain file.
kubectl create secret generic helm-secrets-private-keys --from-file=key.asc
To use the secrets+gpg-import / secrets+age-import syntax, we need to mount the key on the ArgoCD Repo Server.
This is an example values file for the ArgoCD Server Helm chart.
repoServer:
volumes:
- name: helm-secrets-private-keys
secret:
secretName: helm-secrets-private-keys
volumeMounts:
- mountPath: /helm-secrets-private-keys/
name: helm-secrets-private-keys
Once mounted, your Argo CD Application should look similar to this:
apiVersion: argoproj.io/v1alpha1
kind: Application
...
spec:
source:
helm:
valueFiles:
# Method 1: Mount the gpg key from a kubernetes secret as volume
# secrets+gpg-import://<key-volume-mount>/<key-name>.asc?<relative/path/to/the/encrypted/secrets.yaml>
# secrets+age-import://<key-volume-mount>/<key-name>.txt?<relative/path/to/the/encrypted/secrets.yaml>
# Example Method 1: (Assumptions: key-volume-mount=/helm-secrets-private-keys, key-name=app, secret.yaml is in the root folder)
- secrets+gpg-import:///helm-secrets-private-keys/key.asc?secrets.yaml
To use the secrets+gpg-import-kubernetes / secrets+age-import-kubernetes syntax, we need Argo CD's service account to be able to access the secret. To achieve this we use the RBAC Permissions.
This is an example values file for the ArgoCD Server Helm chart.
# This allows to read secrets in the same namespace
repoServer:
serviceAccount:
create: true
name: argocd-repo-server
rbac:
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
- watch
RBAC permissions can be verified by executing the command below:
kubectl auth can-i get secrets --namespace argo-cd --as system:serviceaccount:$NAMESPACE:argo-cd-argocd-repo-server
Once granted access, your Argo CD Application should look similar to this:
apiVersion: argoproj.io/v1alpha1
kind: Application
...
spec:
source:
helm:
valueFiles:
# ### Method 2: Fetch the gpg key from kubernetes secret
# secrets+gpg-import-kubernetes://<namespace>/<secret-name>#<key-name>.asc?<relative/path/to/the/encrypted/secrets.yaml>
# secrets+age-import-kubernetes://<namespace>/<secret-name>#<key-name>.txt?<relative/path/to/the/encrypted/secrets.yaml>
# Example Method 2: (Assumptions: namespace=argocd, secret-name=helm-secrets-private-keys, key-name=app, secret.yaml is in the root folder)
- secrets+gpg-import-kubernetes://argocd/helm-secrets-private-keys#key.asc?secrets.yaml
Please note that it is not possible to use helm secrets in Argo CD for external Charts. Please take a look at this issue for more information.
As workaround, you can fetch additional values from remote locations:
apiVersion: argoproj.io/v1alpha1
kind: Application
...
spec:
source:
helm:
valueFiles:
- secrets+gpg-import:///helm-secrets-private-keys/key.asc?https://raw.githubusercontent.com/jkroepke/helm-secrets/main/tests/assets/values/sops/values.yaml
- secrets+gpg-import-kubernetes://argocd/helm-secrets-private-keys#key.asc?https://raw.githubusercontent.com/jkroepke/helm-secrets/main/tests/assets/values/sops/values.yaml
# Using https://github.com/aslafy-z/helm-git
- secrets+gpg-import-kubernetes://argocd/helm-secrets-private-keys#key.asc?git+https://github.com/jkroepke/helm-secrets@tests/assets/values/sops/secrets.yaml?ref=main"
Error:
Error decrypting tree: Error walking tree: Could not decrypt value: crypto/aes: invalid key size 0