Securing Cloud Run Deployments with GitOps, SOPS, and Config Connector
Introduction
In cloud-native environments, securely managing secrets while adhering to GitOps principles presents a significant challenge. How can we reconcile the GitOps philosophy (where everything is declarative and versioned in Git) with the need to protect sensitive information? This guide demonstrates a comprehensive and secure approach to deploying Cloud Run services with encrypted secrets using GitOps.
This demonstration integrates three key technologies:
FluxCD - For GitOps automation
SOPS - For secret encryption
Config Connector - For declarative GCP resource management
This guide focuses primarily on the Kustomize integration. For FluxCD and Config Connector installation, please refer to their respective documentation.
Create the kustomize folder tree
SOPS
Create a age key for SOPS
We follow this setup
We committed the Private key in this repo: of course it’s wrong, you must never do that, it is just to give you the ability to decrypt the secrets of this repo.
sops encryption we chose for this demo to use age since it is the more simpler integration. Of course pick the appropriate KMS solution regarding your integration.
export the age key in your env
Create SOPS configuration files in overlays
See official SOPS documentation
Notice we will use the same encryption key for both dev and prod environnement for simplicity. This is not the good way to achieve segregation of concern between environnements. I ALWAYS use distincts keys accross environnement.
Create a SOPS secret
I edit and replace everything by
Save and quit
Now check:
We definitely can find the bar value in : “ENC[AES256_GCM,data:Pz9E,iv:r7juY6vZJ/R0eg4Tqz0vXfKp/fsS6dsla4+o1NLO+Jk=,tag:7uiexLFfyG/ko8GCMBEKZg==,type:str]”
Notice if you have exported in your shell environnement the SOPS_AGE_KEY previously, the repetition of environnement variable is useless here.
Generate a Kubernetes Secret with Kustomize
We have a secret un git, now we will create a secret in kubernetes, we will use kustomize for that:
Great! We have a SOPS encrypted secret! Notice the name of the secret is suffixed with a hash. This hash will change whenever the secret value changes, which is a critical feature for our implementation.
Generate a SecretManager Secret
Cloud Run only supports secrets from SecretManager sources, so we need to create both a SecretManagerSecret and a SecretManagerSecretVersion. Since these declarations will be shared across environments, we’ll add them to the base folder.
And now we check:
And… it fails! In the SecretManagerSecretVersion, the secretKeyRef.name is “foo”, but it should be “foo-d9225dh699” to match the generated Kubernetes Secret.
Fortunately, Kustomize can help us with the Name reference transformer:
Next, edit kustomization.yaml and add:
Let’s check the result of the kustomization again:
Perfect! With the name reference transformer, the SecretManagerSecretVersion now correctly follows the Kubernetes Secret definition. When the secret content changes, both the Kubernetes Secret and the SecretManagerSecretVersion will be updated with new hash suffixes.
Add the CloudRun Service
See Config Connector reference for CloudRun Service
And now check:
Success! The Secret Version reference in the Cloud Run service is correctly configured.
Feel free to change the value of the secret to see how the entire system automatically updates.
Key Benefits of This Architecture
Security: Secrets are always encrypted in Git
GitOps Compliance: FluxCD detects changes and triggers deployments
Atomicity: Any secret change generates a new hash, forcing a complete update
Audit Trail: Git history provides a complete audit trail of changes
Environment Consistency: Single workflow for all environments
By combining FluxCD, SOPS, Kustomize, and Config Connector, we’ve created a complete GitOps pipeline that meets security requirements while maintaining the benefits of declarative infrastructure.
Entire sources of this demo are available here: https://gitlab.com/mialon.pg/gitops-secrets-cloudrun
Software Engineer at Quartz
2mo1Password... 😁
Comment ferais-tu la décryptation du SOPS par rapport à FluxCD ? J'utilisais généralement les hooks Skaffold, une extension SOPS Kustomize ou un shell script en amont, mais dans un contexte GitOps j'ai souvent fini avec SealedSecret ou un "day 1 script".