Fix HostAuthorization blocking internal k8s cluster traffic #239
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/host-authorization-internal-ips"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
/upfrom HostAuthorization, fixing health probes — but all other internal cluster requests arrive withHost: <pod-ip>and get 403'dBlocked hosts: 10.42.0.127:3000, triggering AlertManagerCloses #238
Changes
config/environments/production.rb: Broadenhost_authorizationexclude lambda to also skip requests where the Host header is an IP address (matches\d+.\d+.\d+.\d+pattern)Test Plan
Blocked hostslog spam stopslandscaping-assistant.tail5b443a.ts.netReview Checklist
Related Notes
ldraney/landscaping-assistant #238— HostAuthorization blocks internal k8s cluster trafficlandscaping-assistant— projectPR #239 Review
DOMAIN REVIEW
Stack: Ruby on Rails 8.1 (production config), k8s infrastructure concern.
Regex correctness:
The regex
/\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/is well-anchored (\A/\zprevent partial matching) and applied torequest.host, which Rails strips of the port component. This means10.42.0.127:3000resolves to10.42.0.127before matching -- correct behavior.Minor note: the regex does not validate octets are 0-255 (e.g.,
999.999.999.999would match). This is acceptable -- no legitimate HTTP client sends impossible IPs as Host headers, and the security boundary here is Tailscale Funnel, not the regex itself.Security analysis -- DNS rebinding protection:
The key question is whether excluding IP-based Host headers weakens DNS rebinding protection. Answer: no. Per
docs/networking.md, all external traffic arrives through Tailscale Funnel, which always sets proper hostname-based Host headers (landscaping-assistant.tail5b443a.ts.net, etc.). The only source of IP-based Host headers is internal k8s traffic (kubelet probes, service-to-pod, pod-to-pod). Excluding these is safe because they never originate from the public internet.Lambda structure:
Clean short-circuit evaluation. The
/uppath check runs first (cheapest), IP regex only evaluates if needed. Good.BLOCKERS
None.
NITS
docs/networking.md line 92 is now stale. It currently reads: "The
/uphealth check endpoint is excluded from host authorization so k8s liveness/readiness probes always pass, even when kubelet sends requests using the pod IP as the Host header." This should be updated to reflect that ALL requests with IP-based Host headers are now excluded, not just/up. The current wording implies/upis the only exclusion, which is no longer true after this PR.Regex precision (non-blocking, informational only): If you ever wanted stricter validation, you could match RFC 1918 ranges specifically (
/\A(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/). But the current approach is simpler and just as safe given the Tailscale boundary. Not recommending a change -- just noting the option.SOP COMPLIANCE
PROCESS OBSERVATIONS
/upbut missed other internal traffic. The pattern of incremental fixes is fine for a production-impacting bug (wall-to-wall log spam triggering AlertManager), but the docs gap (nit #1) should be addressed to prevent a third iteration.VERDICT: APPROVED