Skip to content

Commit 7a422ef

Browse files
committed
chore(secrets): remove all hardcoded secrets from HEAD
Replace leaked passwords and AWS access key ID with placeholders / env-var references across k8s overlays, docs, tests, CI workflow, and docker-compose. Delete generated interweb-*.yaml manifests that embedded full credentials. Add .env.example and k8s/SECRET-EXPOSURE-AUDIT.md documenting the cleanup. Companion to a follow-up history rewrite that scrubs the same values from all reachable commits.
1 parent 8926ff3 commit 7a422ef

31 files changed

Lines changed: 156 additions & 3413 deletions

.env.example

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copy this file to .env and fill in real values.
2+
# .env is gitignored and must never be committed.
3+
4+
# PostgreSQL superuser password used by docker-compose and local k8s overlays.
5+
# Choose a strong unique value per environment.
6+
POSTGRES_PASSWORD=changeme-set-a-strong-password
7+
8+
# pgAdmin login password (only used by k8s overlays that deploy pgAdmin).
9+
PGADMIN_DEFAULT_PASSWORD=changeme-set-a-strong-password
10+
11+
# MinIO root credentials (S3-compatible local storage).
12+
MINIO_ROOT_USER=changeme-set-a-username
13+
MINIO_ROOT_PASSWORD=changeme-set-a-strong-password
14+
15+
# Mailgun (only required if EMAIL_SEND_USE_SMTP is false in dev).
16+
MAILGUN_API_KEY=
17+
MAILGUN_KEY=
18+
MAILGUN_DOMAIN=
19+
20+
# AWS Route53 access key ID for cert-manager DNS01 challenges (per-environment).
21+
ROUTE53_ACCESS_KEY_ID=
22+
ROUTE53_HOSTED_ZONE_ID=

.github/workflows/test-k8s-deployment.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,18 @@ jobs:
121121
echo "GHCR_USERNAME/GHCR_TOKEN not set; assuming images are public."
122122
fi
123123
124+
- name: Generate per-run postgres password
125+
# k8s overlay secrets use REPLACE_WITH_POSTGRES_PASSWORD placeholders; substitute
126+
# a fresh per-run value before Skaffold applies them so deploys + e2e share it.
127+
run: |
128+
PG_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=' | cut -c1-24)
129+
echo "PG_PASSWORD=$PG_PASSWORD" >> "$GITHUB_ENV"
130+
echo "::add-mask::$PG_PASSWORD"
131+
# Substitute into all kustomize secret files for the local-simple overlay.
132+
find k8s/overlays/local-simple -type f \( -name '*.yaml' -o -name '*.yml' \) \
133+
-exec sed -i.bak "s|REPLACE_WITH_POSTGRES_PASSWORD|${PG_PASSWORD}|g" {} \;
134+
find k8s/overlays/local-simple -name '*.bak' -delete
135+
124136
- name: Deploy with Skaffold (per-function profile)
125137
run: skaffold run -p ${{ matrix.name }}
126138

@@ -149,7 +161,7 @@ jobs:
149161
PGHOST: localhost
150162
PGPORT: "5432"
151163
PGUSER: postgres
152-
PGPASSWORD: "postgres123!"
164+
PGPASSWORD: ${{ env.PG_PASSWORD }}
153165
PGDATABASE: constructive
154166
run: |
155167
kubectl port-forward -n constructive-functions svc/postgres 5432:5432 &

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,7 @@ vite.config.ts.timestamp-*
140140

141141
# Generated function workspace packages (created by scripts/generate.ts)
142142
generated/
143+
144+
# Rendered Kubernetes manifests may include Secret objects. Regenerate locally
145+
# with k8s/Makefile targets instead of committing them.
146+
k8s/manifests/*.yaml

CLAUDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ pnpm test:integration # tests/integration/ — isolated component tests
4040
Requires Skaffold running (`make skaffold-dev`) or equivalent with port-forwards active.
4141

4242
```bash
43-
# With default credentials (postgres/postgres123! on localhost:5432)
43+
# With default credentials (postgres/$POSTGRES_PASSWORD on localhost:5432)
4444
pnpm test:e2e
4545

4646
# With explicit env vars
47-
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGPASSWORD='postgres123!' PGDATABASE=constructive pnpm test:e2e
47+
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGPASSWORD='$POSTGRES_PASSWORD' PGDATABASE=constructive pnpm test:e2e
4848
```
4949

5050
E2E tests insert jobs into `app_jobs.jobs` via SQL and verify the job service picks them up and the functions process them.

DEVELOPMENT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ pnpm test:e2e
327327
With explicit env vars:
328328

329329
```bash
330-
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGPASSWORD='postgres123!' PGDATABASE=constructive pnpm test:e2e
330+
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGPASSWORD="$POSTGRES_PASSWORD" PGDATABASE=constructive pnpm test:e2e
331331
```
332332

333333
### What's tested

docker-compose.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ services:
1414
environment:
1515
POSTGRES_DB: constructive
1616
POSTGRES_USER: postgres
17-
POSTGRES_PASSWORD: password
17+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set (see .env.example)}
1818
ports:
1919
- "5432:5432"
2020
volumes:
@@ -34,7 +34,7 @@ services:
3434
PGHOST: postgres
3535
PGPORT: "5432"
3636
PGUSER: postgres
37-
PGPASSWORD: password
37+
PGPASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set (see .env.example)}
3838
PGDATABASE: constructive
3939
entrypoint: ["bash", "-c"]
4040
command:
@@ -75,7 +75,7 @@ services:
7575
PGHOST: postgres
7676
PGPORT: "5432"
7777
PGUSER: postgres
78-
PGPASSWORD: password
78+
PGPASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set (see .env.example)}
7979
PGDATABASE: constructive
8080
# API configuration — header-based routing (X-Api-Name, X-Database-Id)
8181
API_ENABLE_SERVICES: "true"

docs/skills/local-dev-skaffold.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ To reproduce the CI e2e matrix locally:
215215
make skaffold-dev
216216

217217
# 2. In another terminal, run a specific function's e2e test
218-
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGPASSWORD='postgres123!' PGDATABASE=constructive \
218+
PGHOST=localhost PGPORT=5432 PGUSER=postgres PGPASSWORD="$POSTGRES_PASSWORD" PGDATABASE=constructive \
219219
pnpm jest tests/e2e/__tests__/simple-email.e2e.test.ts tests/e2e/__tests__/job-queue.test.ts
220220

221221
# Or run all e2e tests

k8s/ARCHITECTURE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ This is what `make skaffold-dev` deploys.
4444
- PgBouncer `Pooler postgres-pooler` for read‑write connections.
4545
- Access pattern:
4646
- Applications connect via `postgres-cluster-rw.postgres-db.svc.cluster.local:5432` (dev/staging) or `postgres` (local / local-simple overlays).
47-
- Credentials are provided via `base/cnpg/secret.yaml` and `base/constructive/pg-secret.yaml` (or per-overlay `pg-secret.yaml` for local).
47+
- Credentials are referenced by Secret name and must be created out-of-band
48+
with a secret manager, ExternalSecrets, SOPS, or `kubectl create secret`.
4849

4950
### Observations
5051

k8s/Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ kustomize-staging:
5959
$(KUBECTL) apply -n $(CONSTRUCTIVE_NS) -k $(K8S_DIR)/overlays/staging
6060

6161
# Render overlays to single YAML files (no apply).
62-
# Rendered manifests go under k8s/manifests to keep the k8s root clean.
62+
# Rendered manifests go under k8s/manifests, which is gitignored because
63+
# rendered output may contain Secret objects.
6364
MANIFESTS_DIR ?= $(K8S_DIR)/manifests
6465

6566
render-dev:
@@ -146,9 +147,9 @@ proxy-stop:
146147

147148
######## Helper commands ########
148149

149-
ZONE_ID=Z00381072B5MMXZMWY1JN # launchql.dev
150-
LB_IP=34.55.147.174 # Server Load Balancer IP of GCP
151-
AWS_PROFILE=webinc
150+
ZONE_ID ?= REPLACE_WITH_ROUTE53_ZONE_ID
151+
LB_IP ?= REPLACE_WITH_LOAD_BALANCER_IP
152+
AWS_PROFILE ?= default
152153

153154
aws-route53:
154155
aws route53 change-resource-record-sets \

k8s/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,5 @@ If pods show `ImagePullBackOff`, this secret is missing or the PAT has expired.
5656
## Notes
5757

5858
- Function deployments are not in the `local-simple` overlay — Skaffold consumes the per-function manifests generated under `generated/<name>/k8s/` directly. Run `pnpm generate` after editing any `handler.json`.
59-
- Secrets in `base/` (Postgres, Mailgun, server bucket) are development defaults; replace them via your secret manager before any non-local use.
59+
- Rendered manifests in `k8s/manifests/*.yaml` are gitignored because Kustomize output can include Kubernetes `Secret` objects. Regenerate them locally with `make render-*` when needed.
60+
- Tracked Secret manifests use explicit placeholder values only (e.g. `REPLACE_WITH_POSTGRES_PASSWORD`). Create real secrets through your secret manager, ExternalSecrets, SOPS, or `kubectl create secret`; do not commit rendered or environment-specific secret values.

0 commit comments

Comments
 (0)