Repository navigation
feat(proxy): redact basic-auth and move the cache store off the command line (#93 workstream C) - #95
Merged
Merged
Conversation
…nd line ## Summary Workstream C of the v3.0.0 release gate (#93): nothing knowingly leaky ships under a 3.0 banner. C1: the basic-auth credential is wrapped in Kamal::Utils.sensitive (registry- login precedent), and Utils.optionize gains a Sensitive passthrough so the rendered --basic-auth option keeps the real value for execution and a [REDACTED] form for anything kamal prints - at :info verbosity it used to land in plain text. C2: the cache store URL never touches the docker run command line. kamal-proxy reads CACHE_STORE from its environment as the --cache-store default, so the URL travels in the proxy secrets env file - the acme.env mechanism generalized to .kamal/proxy/secrets.env (0600), carrying ACME credentials and the store together, on proxy hosts and the loadbalancer host alike. The drift digest hashes the secret *names*, never values: adding/removing the store reboots the proxy, rotating the URL needs an explicit `kamal proxy reboot` (same contract as acme credentials, now documented; the docs caveat that documented the leak is gone). --cache-store joins the flag-coverage waivers with the reason. C3: a host keeps no secrets it no longer needs - boot and reboot (proxy hosts and the LB host) remove .kamal/proxy/secrets.env when the config no longer calls for one. ## Test Coverage - raw argv keeps the credential, redacted form never contains it (app, loadbalancer, configuration levels) - store lands in secrets.env and never in run_command, docker options, printed boot output, or digest inputs; acme + store share one env file - digest moves on store presence, not value - CLI boot uploads CACHE_STORE 0600 and removes a stale secrets.env ## Verification - [x] bundle exec rubocop --parallel passes - [x] unit suite passes (builder failures are the known host-arch artifacts) Refs #93
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.
Summary
Workstream C of the v3.0.0 release gate (#93) — secrets & redaction. Builds on B's LB run surface (#94).
Proxy#basic_auth_credentialreturns aKamal::Utils.sensitivevalue (registry-login precedent), andUtils.optionizegains a Sensitive passthrough: the rendered--basic-auth="admin:s3cr3t"keeps the real value for execution and prints as--basic-auth=[REDACTED]everywhere SSHKit logs — at:infoverbosity it used to land in plain text.CACHE_STOREfrom its environment as the--cache-storedefault (run.go:50, verified against the published image), so the URL now travels in the proxy secrets env file —acme.envgeneralized to.kamal/proxy/secrets.env(0600), carrying ACME credentials and the store together, uploaded to proxy hosts and the LB host alike (the LB owns the cache after feat(proxy): explicit loadbalancer layering contract + LB run plumbing (#93 workstream B) #94). The drift digest hashes secret names, never values: adding/removing the store reboots the proxy; rotating the URL's value needs an explicitkamal proxy reboot— same contract as ACME credentials, now documented. The docs caveat that documented the leak is gone;--cache-storejoins the flag-coverage waivers with the reason..kamal/proxy/secrets.envwhen the config no longer needs one — a host keeps no secrets it no longer needs.Refs #93 (workstream C — D–G continue in follow-up PRs)
Test plan
Kamal::Utils.redactedform never contains it (app, loadbalancer, configuration, accessory levels)secrets.envand never inrun_command, docker options, printed boot output, or digest inputs; acme + store share one env filememory↔ redis URL is digest-identical)CACHE_STORE0600, never prints the URL; stalesecrets.envremoved when config gonebundle exec rubocop --parallelclean; unit suite green (builder failures are the known Apple-Silicon artifacts)Deviations & judgment calls
--basic-auth=[REDACTED]— username included, matching the registry-login precedent (-u [REDACTED]), rather thanadmin:[REDACTED].optionizepasses through caller-markedSensitivevalues per-value instead of growing a blanketsensitive:kwarg likeargumentize— only one of a command's options is secret here, and per-value marking keeps the rest of the argv readable in logs.acme.env→secrets.env(free — nothing since 2.12.0 is released). A host booted from a pre-release dash build with ACME keeps a staleacme.env; harmless (nothing references it,kamal proxy removedeletes the directory), so no migration code.store: memory→store: redis://…does not auto-reboot — the operator runskamal proxy reboot, as documented. If you'd rather drift on a credential-stripped form of the URL (scheme+host, no userinfo), it's a two-line change tosecret_names.CACHE_STOREgoes through the env file even when the value is the non-secretmemory— uniform delivery beats a special case, and kamal-proxy treats the env var identically.rm(withraise_on_non_zero_exit: false) on every boot/reboot when no secrets are configured — one extra no-op exec per host, mirroring the upload branches as v3.0.0 release gate: LB layering discipline, secret redaction, surface freeze, port_holder, docs tiering #93 specified.