Goal this serves — Protecting the credentials that control donation infrastructure
Why this matters
The Kubernetes secret manifest is committed with empty placeholder values and a comment explaining that real values should come from an external provider or be created out of band. That comment is the entire mechanism. Nothing implements the external path, nothing rotates a credential, and nothing detects a credential that has been in use far too long.
These credentials protect the database holding donation records and the accounts that submit transactions. The current arrangement depends on every operator reading a comment and doing the right thing manually.
Evidence
# k8s/secret.yaml
# the Helm chart with secrets.provider=external (External Secrets Operator).
stringData:
POSTGRES_PASSWORD: ""
RESEND_API_KEY: ""
AWS_SECRET_ACCESS_KEY: ""
The Helm chart references an external provider option, so the intent exists. No External Secrets Operator resources are defined anywhere, no rotation procedure is documented, and nothing checks credential age.
The committed file contains no real credentials, which is correct — the gap is that no supported path exists for supplying them safely.
Why this is hard
Rotation without downtime needs overlap. A database password cannot be changed instantaneously across running pods, so the design must support two valid credentials during a rotation window — that dual-validity period is where most rotation designs fail.
Stellar keys are different. A key controlling an account cannot simply be replaced; rotation means moving authority on-chain, which is a different operation with its own risk.
Provider choice affects everyone. Whichever backing store is chosen must be workable for a solo maintainer and a larger deployment alike.
Local development must stay easy. A secrets architecture that makes running the project locally painful will be bypassed.
Compromise response is part of this. Knowing which credential leaked, what it could reach, and how quickly it can be revoked is as important as rotation.
Suggested approach
Implement the external provider path the chart already anticipates, with a documented local development story that does not require it.
Support rotation with an overlap window so a credential can be replaced without downtime, and document the distinct procedure for Stellar account authority.
Track credential age and surface anything overdue. Write the compromise runbook alongside the mechanism rather than after an incident.
Acceptance criteria
Scope
Roughly 5,000–7,000 lines, including tests.
Relevant files
k8s/secret.yaml
helm/greenpay/values.yaml
k8s/backend.yaml
docs/runbooks/
Why this matters
The Kubernetes secret manifest is committed with empty placeholder values and a comment explaining that real values should come from an external provider or be created out of band. That comment is the entire mechanism. Nothing implements the external path, nothing rotates a credential, and nothing detects a credential that has been in use far too long.
These credentials protect the database holding donation records and the accounts that submit transactions. The current arrangement depends on every operator reading a comment and doing the right thing manually.
Evidence
The Helm chart references an external provider option, so the intent exists. No External Secrets Operator resources are defined anywhere, no rotation procedure is documented, and nothing checks credential age.
The committed file contains no real credentials, which is correct — the gap is that no supported path exists for supplying them safely.
Why this is hard
Rotation without downtime needs overlap. A database password cannot be changed instantaneously across running pods, so the design must support two valid credentials during a rotation window — that dual-validity period is where most rotation designs fail.
Stellar keys are different. A key controlling an account cannot simply be replaced; rotation means moving authority on-chain, which is a different operation with its own risk.
Provider choice affects everyone. Whichever backing store is chosen must be workable for a solo maintainer and a larger deployment alike.
Local development must stay easy. A secrets architecture that makes running the project locally painful will be bypassed.
Compromise response is part of this. Knowing which credential leaked, what it could reach, and how quickly it can be revoked is as important as rotation.
Suggested approach
Implement the external provider path the chart already anticipates, with a documented local development story that does not require it.
Support rotation with an overlap window so a credential can be replaced without downtime, and document the distinct procedure for Stellar account authority.
Track credential age and surface anything overdue. Write the compromise runbook alongside the mechanism rather than after an incident.
Acceptance criteria
Scope
Roughly 5,000–7,000 lines, including tests.
Relevant files
k8s/secret.yamlhelm/greenpay/values.yamlk8s/backend.yamldocs/runbooks/