Repository navigation
Migrate secrets from sops/age to Doppler with per-env R2 and Mongo access - #141
Conversation
…cess Secrets now live in Doppler project api-server (configs dev/prd) instead of a sops/age-encrypted .env.enc: - Container runs `doppler run -- java` (CLI baked into the image); compose feeds DOPPLER_TOKEN from /opt/api-server/doppler.env written by ansible - Playbook fetches the keystore password + nginx proxy secret from Doppler (service token in CI, logged-in CLI on laptops); sops/age tasks removed - CI ships no .env.enc and passes DOPPLER_TOKEN instead of AGE/TLS secrets - Dev and prod use separate Mongo users/databases and bucket-scoped R2 keys (api-server-dev bucket has a 7-day object retention rule) - @value keys renamed to kebab-case so UPPER_SNAKE env vars bind cleanly - hosts.ini pins ansible_python_interpreter to the distro python (3.14 discovery breaks the apt cryptography stack needed by openssl_pkcs12) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Migrates secret management and deployment flow from sops/age-encrypted .env.enc to Doppler (dev/prd), updating runtime, Ansible, and CI/CD to fetch/inject secrets via DOPPLER_TOKEN, and aligning Spring property keys with env-var-friendly naming.
Changes:
- Replaces
.env.enc/sops/age usage with Doppler-driven secret injection in container startup (doppler run) and Ansible secret retrieval (API token in CI vs CLI locally). - Updates Spring
@Valuekeys to kebab-case for Cloudflare DNS/R2 settings and removes.envimport + hard-coded Mongo DB name. - Removes sops/age tooling and artifacts from hooks, templates, Docker build, and GitHub Actions deploy payload.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| templates/.sops.yaml.template | Removes sops template (no longer needed with Doppler). |
| src/main/resources/application.properties | Drops .env import; documents Doppler-provided env secrets. |
| src/main/java/com/chencraft/common/service/api/CloudflareWebClient.java | Renames Cloudflare DNS property keys to kebab-case. |
| src/main/java/com/chencraft/common/config/S3Config.java | Renames Cloudflare R2 property keys to kebab-case. |
| scripts/age_keygen.sh | Removes age keygen + .sops.yaml generation script. |
| requirements.yml | Removes community.sops collection dependency. |
| README.md | Updates local/dev/prod secret workflow documentation for Doppler. |
| playbook.yml | Replaces sops decrypt flow with Doppler API/CLI fetch; writes /opt/api-server/doppler.env for compose. |
| hosts.ini | Pins ansible_python_interpreter to /usr/bin/python3 for the local target. |
| entrypoint.sh | Switches container startup to doppler run -- java -jar .... |
| doppler.yaml | Adds committed Doppler repo binding for dev config. |
| Dockerfile | Removes sops stage; bundles Doppler CLI into runtime image. |
| docker-compose.yml | Adds env_file pointing to /opt/api-server/doppler.env for DOPPLER_TOKEN. |
| CLAUDE.md | Updates contributor/dev notes to use doppler run. |
| .sops.yaml | Removes sops rules file. |
| .github/workflows/maven.yml | Removes sops assets/steps; switches deploy secret to DOPPLER_TOKEN. |
| .githooks/pre-commit | Removes auto-encrypt .env → .env.enc logic. |
| .githooks/post-checkout | Removes auto-decrypt/install sops/age; nudges Doppler setup instead. |
| .env.enc | Removes encrypted env payload from repo and deploy. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Inject secrets from Doppler (project/config implied by DOPPLER_TOKEN service token). | ||
| # --fallback keeps restarts working if api.doppler.com is briefly unreachable. | ||
| exec doppler run --fallback /opt/api-server/doppler-fallback.json -- java -jar api-server.jar |
There was a problem hiding this comment.
Verified locally with doppler CLI v3.76.0: doppler run --fallback <path> creates (and refreshes) the encrypted fallback file itself on every successful secrets fetch — it doesn't need to pre-exist, and a missing file doesn't block startup while api.doppler.com is reachable. The file only gets read when the API is unreachable, in which case a prior successful start has already written it. So no playbook/image task is needed; first boot creates it on the mounted /opt/api-server volume. Pushed a clarifying comment to entrypoint.sh.
Qodana for JVMIt seems all right 👌 No new problems were found according to the checks applied 💡 Qodana analysis was run in the pull request mode: only the changed files were checked Contact Qodana teamContact us at qodana-support@jetbrains.com
|
Addresses PR #141 review comment: the fallback file is auto-created by doppler run on each successful fetch and need not pre-exist. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Summary
Replaces the sops/age-encrypted
.env.encpipeline with Doppler (projectapi-server, configsdev/prd), and splits Cloudflare R2 and MongoDB access per environment.entrypoint.shis nowdoppler run -- java -jar(with an encrypted--fallbackfile for restart resilience). Compose feedsDOPPLER_TOKENfrom/opt/api-server/doppler.env.dopplerCLI on laptop runs (dev/prd config picked by install mode). All sops/age tasks, the age key prompt, andcommunity.sopsare gone..env.enc/.sops.yaml;DOPPLER_TOKENreplacesAGE_PRIVATE_KEY+TLS_KEYSTORE_PASSWORD; docker job drops the sops build stage.api-server-devAtlas user/database and a bucket-scoped key for the newapi-server-devR2 bucket (7-day object retention); prod gets its own bucket-scoped key and areadWrite-on-api-server-only Atlas user. DNS key stays shared.@Valuekeys renamed to kebab-case (cloudflare.r2.account-id, …) soUPPER_SNAKEenv vars bind via Spring relaxed binding;spring.config.importof.envand the hard-coded Mongo database name removed.hosts.inipinsansible_python_interpreter=/usr/bin/python3— interpreter discovery picked python3.14, which panics importing the apt cryptography stack needed byopenssl_pkcs12.Verification
doppler run -- mvn spring-boot:runboots the dev profile; actuator health shows Mongo + mail UPapi-server-devand isAccessDeniedon the prod bucket; prd key lists the prod bucket; dev Mongo user writes toapi-server-dev; prd user readsapi-server./install-dev.shconverges via the laptop Doppler path; nginxX-Proxy-Secrethash-matches the dev configPost-merge
Tag deploy will use the
DOPPLER_TOKENrepo secret (already set). After a healthy prod deploy: delete the old shared Atlas user + account-wide R2 keys, and remove theAGE_PRIVATE_KEY/TLS_KEYSTORE_PASSWORDGitHub secrets.🤖 Generated with Claude Code