├── .github └── workflows │ └── ghcr.yaml ├── Dockerfile ├── README.md └── argocd-repo-server-wrapper /.github/workflows/ghcr.yaml: -------------------------------------------------------------------------------- 1 | name: Build a Docker image and publish it to GHCR 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | build-and-push: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v3 15 | 16 | - name: Log in to the Container registry 17 | uses: docker/login-action@v2 18 | with: 19 | registry: ghcr.io 20 | username: ${{ github.actor }} 21 | password: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | - name: Set up QEMU 24 | uses: docker/setup-qemu-action@v3 25 | 26 | - name: Set up Docker Buildx 27 | uses: docker/setup-buildx-action@v3 28 | 29 | - name: Build and push Docker image 30 | uses: docker/build-push-action@v3 31 | with: 32 | context: . 33 | platforms: linux/amd64,linux/arm64 34 | push: true 35 | tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }} 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM docker.io/golang:1.24 as builder 2 | RUN git clone --branch=20250205-1 --depth=1 https://github.com/camptocamp/helm-sops && \ 3 | cd helm-sops && \ 4 | go build 5 | 6 | FROM quay.io/argoproj/argocd:v2.14.5 7 | USER root 8 | COPY argocd-repo-server-wrapper /usr/local/bin/ 9 | COPY --from=builder /go/helm-sops/helm-sops /usr/local/bin/ 10 | RUN cd /usr/local/bin && \ 11 | mv argocd-repo-server _argocd-repo-server && \ 12 | mv argocd-repo-server-wrapper argocd-repo-server && \ 13 | chmod 755 argocd-repo-server && \ 14 | mv helm _helm && \ 15 | mv helm-sops helm 16 | USER 999 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Argo CD Docker Image 2 | 3 | This Argo CD Docker Image contains the necessary tools to make use of Helm value files encrypted using Sops. 4 | 5 | The following tools have been added to the image: 6 | 7 | - GnuPG 8 | - [Helm Sops](https://github.com/camptocamp/helm-sops) 9 | 10 | Helm Sops is installed to transparently wrap Helm. This way, there is no need to configure a custom tool in Argo CD and native Helm functionalities can still be used (such as *valueFiles* or *values*). 11 | 12 | Argo CD repository server binary is wrapped by a shell script which can import a GPG private key if it exists. The key must be located at `/app/config/gpg/privkey.asc`. 13 | 14 | ## Usage 15 | 16 | ### Encrypting Helm value files 17 | 18 | Read [Helm Sops documentation](https://github.com/camptocamp/helm-sops) to start using Helm encrypted value files. 19 | 20 | ### Deploying Argo CD using the Helm chart 21 | 22 | #### Using the custom image 23 | 24 | To use this custom image when deploying Argo CD using the [Helm chart](https://github.com/argoproj/argo-helm/tree/master/charts/argo-cd), add the following lines to the chart value file: 25 | 26 | ```yaml 27 | global: 28 | image: 29 | repository: "camptocamp/argocd" 30 | tag: "v2.11.3_c2c.1" 31 | ``` 32 | 33 | #### Using Sops with a GPG key 34 | 35 | In order to use Sops with a GPG key, add the following lines to the chart value file: 36 | 37 | ```yaml 38 | global: 39 | securityContext: 40 | fsGroup: 2000 41 | 42 | repoServer: 43 | volumes: 44 | - name: "gpg-private-key" 45 | secret: 46 | secretName: "argocd-secret" 47 | items: 48 | - key: "gpg.privkey.asc" 49 | path: "privkey.asc" 50 | defaultMode: 0600 51 | volumeMounts: 52 | - name: "gpg-private-key" 53 | mountPath: "/app/config/gpg/privkey.asc" 54 | subPath: "privkey.asc" 55 | ``` 56 | 57 | and add the following lines to an encrypted value file (the GPG private key can be exported by running `gpg --export-secret-keys --armor `: 58 | 59 | ```yaml 60 | configs: 61 | secret: 62 | extra: 63 | gpg.privkey.asc: | 64 | -----BEGIN PGP PRIVATE KEY BLOCK----- 65 | 66 | ... 67 | -----END PGP PRIVATE KEY BLOCK----- 68 | ``` 69 | 70 | #### Using Sops with an AWS KMS key 71 | 72 | In order to use Sops with an AWS KMS key and if [instance profiles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2.html) cannot be used, add the following lines to the chart value file: 73 | 74 | ```yaml 75 | repoServer: 76 | env: 77 | - name: "AWS_ACCESS_KEY_ID" 78 | valueFrom: 79 | secretKeyRef: 80 | name: "argocd-secret" 81 | key: "aws.accessKeyId" 82 | - name: "AWS_SECRET_ACCESS_KEY" 83 | valueFrom: 84 | secretKeyRef: 85 | name: "argocd-secret" 86 | key: "aws.secretAccessKey" 87 | ``` 88 | 89 | and add the following lines to an encrypted value file (create a dedicated IAM Access Key): 90 | 91 | ```yaml 92 | configs: 93 | secret: 94 | extra: 95 | aws.accessKeyId: 96 | aws.secretAccessKey: 97 | ``` 98 | 99 | #### Using Sops with AGE key 100 | 101 | Install the Age tool and run the below command to generate a new key: 102 | 103 | ```bash 104 | age-keygen -o key.txt 105 | ``` 106 | 107 | In order to use Sops with a Age key, add the following lines to the chart value file: 108 | 109 | ```yaml 110 | repoServer: 111 | env: 112 | - name: SOPS_AGE_KEY_FILE 113 | value: /app/config/age/keys.txt 114 | volumeMounts: 115 | - mountPath: /app/config/age/keys.txt 116 | name: sops-age 117 | subPath: keys.txt 118 | volumes: 119 | - name: sops-age 120 | secret: 121 | defaultMode: 420 122 | items: 123 | - key: keys.txt 124 | path: keys.txt 125 | secretName: argocd-secret 126 | ``` 127 | 128 | and add the following lines to add key.txt (Add data of sops age key file): 129 | 130 | ```yaml 131 | configs: 132 | secret: 133 | extra: 134 | keys.txt: | 135 | ... 136 | 137 | ``` 138 | 139 | ## Example application 140 | 141 | An example application as well as an example Argo CD setup to deploy it can be found [here](https://github.com/camptocamp/argocd-helm-sops-example). 142 | -------------------------------------------------------------------------------- /argocd-repo-server-wrapper: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | GPG_PRIVATE_KEY_FILE='/app/config/gpg/privkey.asc' 4 | 5 | if [ -f "${GPG_PRIVATE_KEY_FILE}" ] 6 | then 7 | gpg --import "${GPG_PRIVATE_KEY_FILE}" 8 | fi 9 | 10 | ARGOCD_BINARY_NAME="$(basename "$0")" exec "$(dirname "$0")/_$(basename "$0")" "$@" 11 | --------------------------------------------------------------------------------