Allow db creds declared in Cfn to be secrets - #21
Open
nicklathe wants to merge 1 commit into
Open
Conversation
Signed-off-by: Nick Lathe <nick.lathe@code.org>
carl-codeorg
approved these changes
Aug 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds db secrets declared in a Cloud Formation Stack to be propagated to the cluster secrets so they are available in a Deployment/Pod
Why
Currently, we're not able to connect to the MySQL database from our cluster. Root cause is a gap between how dashboard declares its database configuration and what we sync into Kubernetes.
dashboard's DB endpoints and credentials —
db_endpoint_proxy_reporting,db_credential_reader, and ten sibling keys — are declared!StackSecretin code-dot-org'sconfig.yml.erb. A!StackSecretresolves to the AWS Secrets Manager pathCfnStack/<stack-name>/<key>, where the stack name is discovered by reading theaws:cloudformation:stack-nametag off the EC2 instance the process is running on.There is no EC2 instance in Kubernetes. So that resolution cannot work, and the config loader falls back to a live
GetSecretValuecall at boot. That call has no credentials to sign with: no workload manifest setsserviceAccountName(no IRSA), and the worker explicitly setsAWS_EC2_METADATA_DISABLED=true.The existing ExternalSecret syncs only
<env>/cdo/*, which supplies the URL-style keys (db_writer,db_reader,reporting_db_reader, …) but none of the CloudFormation-provisioned ones. Confirmed in the staging namespace:No
CDO_db_endpoint_*, noCDO_db_credential_*.What
Add a second
dataFrom.findto the per-namespaceExternalSecretsoCfnStack/<env>/*is synced intocdo external-secretsalongside<env>/cdo/*, with the same prefix-stripping rewrite.Once those keys arrive as
CDO_*environment variables, they win the config loader's precedence (env is source #1, and the merge keeps the first writer), so the!StackSecretplaceholder is never constructed and no Secrets Manager callhappens at boot. No code-dot-org change is required.
This also fixes
bin/mysql-client-dashboard-readerin-cluster, which needsCDO.db_endpoint_proxy_readerandCDO.db_credential_readerfor the same reason.Scope
Single-namespace env types only — staging, test, levelbuilder, production.
The adhoc
ClusterExternalSecretis deliberately unchanged: adhoc deployments get one CloudFormation stack each, so there is noCfnStack/adhoc/*path to sync, and the multi-namespace IAM policy does not grant one. Adhoc namespaces still need either the in-cluster mysql component or a code-dot-org-side change.Why this is low risk
apps/infra/standard-envtypes/chart/templates/aws/single-namespace-envtypes-iam.yamlalready grants the ESO service accountsecret:CfnStack/{{ $env }}/*. The permission was provisioned in anticipation of exactly this.bootstrap/codeai-k8s/cluster-infra-argocd/test/test-external-secrets.yamlfetchesCfnStack/staging/db_endpoint_proxy_reader_portthrough the sameaws-secrets-manager-storeSecretStore.Verification
helm templateonstandard-envtypeswith all four single-namespace env types renders valid YAML, withdataFrompaths:After sync (allow one 5m
refreshInterval), confirm in the staging namespace:kubectl get secret cdo-external-secrets -n staging -o jsonpath='{.data}' | jq -r 'keys[]' | grep db_endpointkubectl rollout restart deploy/cdo-active-job-worker -n stagingenvFromvalues are injected once at container start, so the restart is required.Notes / follow-ups
apps/infra/standard-envtypes/chart/charts/eso-per-envtype-0.1.0.tgzis trackedand stale — the
_envtype.tplinside it still contains thecreationPolicy/deletionPolicy/conversionStrategy/decodingStrategyfields that 1021fbaremoved from source. If argocd-repo-server runs
helm dependency buildbeforetemplating (expected), the vendored copy is dead weight and should be untracked.
If it does not, that commit never took effect and neither will this one. Worth
confirming in the rendered diff on first sync.
environment_typeequals the CloudFormation stack name for these fourenv types. Same assumption the IAM template already makes; worth a spot-check for
production.
dataFromentries merge in order, so ordering is now load-bearing if the twopaths ever share a key name. They are disjoint today.
lib/cdo/secrets.rb:68mutates a frozen exception message and destroys the realerror;
StackSecret#keyinlib/cdo/secrets_config.rbshadowsSecret#keysothe environment-type fallback is unreachable and requests an empty secret id off
EC2; and
lib/cdo/mysql_console_helper.rb:23,31resolve StackSecrets in everyenvironment because the
rack_env?(:production)guard is last in the&&chain.🤖 Generated with Claude Code