Repository navigation
feat(proxy): expose the kamal-proxy run flag surface and a run.flags escape hatch - #92
Merged
Merged
Conversation
…escape hatch
kamal-proxy run accepts 29 flags; run_command_options emitted three, and there
was no passthrough either -- proxy.run.options goes to `docker run`, not to
`kamal-proxy run`. Fourteen named keys and the escape hatch close that.
proxy:
exclude_metrics_paths: [ /up ]
run:
log_format: text
trace_context: generate
min_tls: "1.3"
http3: true
reuse_port: true
ignore_restore_errors: true
proxy_protocol: true
proxy_protocol_allow_ips: [ 10.0.0.0/8 ]
metrics_allow_ips: [ 10.0.0.0/8 ]
read_header_timeout: 10
read_timeout: 30
write_timeout: 30
idle_timeout: 60
shutdown_timeout: 15
flags:
some-new-flag: value
This empties R7_BACKLOG. Every flag kamal-proxy accepts is now either emitted
from a deploy.yml key or waived with a reason, which is what the coverage test
defines as "R7 is done".
That makes the escape hatch a hazard for the canary, so the fixture's flags:
entry is a name kamal-proxy will never have. run.flags forwards anything, so
putting a real new flag there would turn the check green while leaving the flag
unreachable by name -- exactly the silence the test exists to break. The
R7_BACKLOG comment now says so.
The collision check lives in Proxy::Run#initialize rather than the validator:
whether a passthrough key duplicates a named one is only knowable once the named
options are built, and only Proxy::Run builds them. It raises with the same
proxy/run context the validator uses.
exclude_metrics_paths sits at proxy.exclude_metrics_paths, not under run. The
issue groups it with metrics config, but it is a deploy flag -- under run it
would be a key that looks proxy-wide feeding a per-service flag, and a
config_digest that moves when nothing about the container changed.
log_format, trace_context and min_tls are validated because kamal-proxy checks
them in preRun: a typo does not fail the deploy, it stops the container from
booting. min_tls accepts the spellings normalizeTLSVersion reduces (tls1_2 and
friends) and gives 1.0/1.1 their own message -- the flag narrows what the
listener negotiates and was never a way to widen it.
proxy_protocol without proxy_protocol_allow_ips warns. The header rewrites the
connecting address that allow_ips, rate_limit and the access log all key on, so
honouring it from any peer that can reach the port hands that address to whoever
asks. A warning rather than an error: a proxy on a private network with no other
route in is legitimate.
The issue also lists --data-dir as unreachable. It is not -- it is in
NEVER_EXPOSED because the kamal-proxy-config volume mount fixes it, and exposing
it would let an operator point the proxy's state outside the volume that
persists it. Left waived.
Closes #81
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
kamal-proxy runaccepts 29 flags;run_command_optionsemitted three, and there was no passthrough either —proxy.run.optionsgoes todocker run, not tokamal-proxy run. Fourteen named keys plus an escape hatch close the gap.Closes #81
🎉 This empties
R7_BACKLOGEvery flag kamal-proxy accepts is now either emitted from a
deploy.ymlkey or waived with a stated reason — whichtest/proxy_flag_coverage_test.rbdefines as "R7 is done". A future proxy release that adds a flag fails the build at theMINIMUM_VERSIONbump, the one moment anyone is thinking about gem/proxy compatibility.The escape hatch is a hazard for exactly that check, so the fixture's
flags:entry isnot-a-real-kamal-proxy-flag.run.flagsforwards anything, so dropping a genuinely new proxy flag in there would turn the canary green while leaving the flag unreachable by name — precisely the silence the test exists to break. TheR7_BACKLOGcomment now says so in as many words.Test plan
bundle exec rubocop --parallel— clean, 216 filesbuilder_test/build_test, identical on pristinedashHEAD (host-arch dependent, pass in CI)--exclude-metrics-pathon the deploy commandlog_format: textand confirm the access log switches to logfmtmin_tls: "1.3"and confirm a TLS 1.2 client is refusedhttp3: trueand confirm HTTP/3 negotiates (needs UDP open on the HTTPS port)proxy_protocol+proxy_protocol_allow_ipspreserves client addresses in the access logAutomated coverage
every new run key moves config_digestrun.flags are optionized onto the run command/is distinct from run.optionsdocker runa run.flags key colliding with a named key is rejected(+ the always-emitted case)proxy_protocol without an allow list warns(+ negative case)no new keys leave the run command byte-identicalbooleans left false emit nothingan explicit zero timeout reaches the proxylogfmt,tls1_2and the 1.0/1.1 messageexclude_metrics_paths lands on the deploy commandevery kamal-proxy deploy/run flag is exposed or waivedDeviations & judgment calls
Deviations
--data-diras unreachable. It is not — it sits inNEVER_EXPOSEDbecause thekamal-proxy-configvolume mount fixes it, and exposing it would let an operator point the proxy's state outside the volume that persists it. Left waived with the existing reason.proxy_protocol_allow_ipsandmetrics_allow_ipsare plural, matchingallow_ipsfrom Expose rate limiting, IP allow lists and client-IP identification in deploy.yml #77 rather than the singular flag names.Judgment calls
exclude_metrics_pathssits atproxy.exclude_metrics_paths, not underrun. The issue groups it with metrics config, but it is a deploy flag — underrunit would be a key that looks proxy-wide feeding a per-service flag, and aconfig_digestthat moves when nothing about the container changed. The docs cross-referencerun.metrics_portandrun.metrics_allow_ipsinstead.run.flagscollision check lives inProxy::Run#initialize, not the validator. Whether a passthrough key duplicates a named one is only knowable once the named options are built, and onlyProxy::Runbuilds them. It raises aKamal::ConfigurationErrorwith the sameproxy/runcontext, so an operator cannot tell the difference.run.flagsvalues are forwarded exactly as written —truerenders a bare flag, anything else--flag value. No guessing at Go duration or list syntax: the point of an escape hatch is that the gem holds no opinion about the flag it is passing.proxy_protocolwithout an allow list warns rather than errors. It is a real spoofing hole — the header rewrites the connecting address thatallow_ips,rate_limitand the access log all key on — but a proxy on a private network with no other route in is a legitimate configuration.flagsneeded the proxy validator'svalidate_key_override!arm, alongsideheadersfrom Expose header rules, redirects, rewrites and error interception in deploy.yml #78 — the example's key is an illustration, so the unknown-key check would reject every real use.