Provide app secrets via environment variables / Kubernetes secrets (DOT_{APP_KEY}_{HOSTNAME}_{APP_VALUE_KEY})
A pull request for this has already been merged.
- #35860 by @wezell — merged
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Parent
User Story / Enhancement
Problem
dotCMS app secrets (the Apps framework, com.dotcms.security.apps) can today only be fully configured through the UI / stored secrets store. There is an existing env-var hook (AppsUtil.guessEnvVar → APP_{APP_KEY}_PARAM_{APP_VALUE_KEY}), but it:
- is not host-aware (one var overrides a param for every site),
- only enriches an existing stored blob — it cannot provision an app on a host that has no stored config,
- has override semantics that aren't expressed as a clear precedence model.
This blocks headless / IaC / Kubernetes deployments where secrets should be injected at the platform level.
Proposal
Add per-host environment-variable / Kubernetes-secret provisioning for all apps using the pattern:
DOT_{APP_KEY}_{HOSTNAME}_{APP_VALUE_KEY}
plus a global System Host form DOT_{APP_KEY}_SYSTEM_HOST_{APP_VALUE_KEY}.
Resolution is per-param, specificity-first (highest → lowest):
- host-specific env —
DOT_{APP_KEY}_{HOSTNAME}_{APP_VALUE_KEY}(locks the UI field) - host-specific stored / UI value
- System Host env —
DOT_{APP_KEY}_SYSTEM_HOST_{APP_VALUE_KEY} - legacy global env —
APP_{APP_KEY}_PARAM_{APP_VALUE_KEY}(deprecated, throttled warning) - System Host stored value
Behavior
- Full provisioning: an app with no stored blob is usable purely from env vars (partial provisioning returns only env-backed params).
- Normalization: env var names use
Config.envKey()only (uppercase, dots/dashes → underscores,DOT_prefix) — no parallel normalization; construct-and-lookup fromAppDescriptor.getParams()(never parses arbitrary env vars). A registered descriptor is required. - Editability: only tier-1 (host-specific env) locks the field read-only; global tiers stay editable so a deliberate per-host stored value still wins.
fromEnv: exposed on the JavaSecretobject and the RESTSecretView(boolean; no tier enum).- Listing/presence:
listAppKeys,appKeysByHost,filterSitesForAppKeyreport env-only apps as configured (lazy detection; System Host/legacy tiers mirror the stored System Host cascade). fallbackOnSystemHost=falsesuppresses both System Host tiers (3 and 5).- Masking follows the descriptor param type regardless of source; env values are returned raw (no coercion).
Out of scope
Live/hot secret rotation without restart (env vars are process-static), file-mounted-secret watching, type coercion, startup index, tier-enum REST field.
Backward-compatibility note
The legacy APP_..._PARAM_... pattern keeps working as tier-4 (with a deprecation warning), but precedence becomes specificity-first: a host-specific stored value now wins over the legacy global env var (previously legacy env overrode stored). Existing integration tests asserting the old override semantics will need to be updated.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with AppsUtil.guessEnvVar and the app resolution paths, then inspect AppDescriptor.getParams() and Config.envKey() for environment-name construction. Review the Java Secret and REST SecretView representations, app-key listing methods, and integration tests covering legacy override semantics. Done means the specified precedence, provisioning, masking, presence, and fallback behavior are covered by tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, kubernetes
- Domain
- api, backend, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100