fix(workspaces): exempt private peers from basic auth - #7
Conversation
- hairpinned in-network requests (bridge gateway peer) hit 401 - widen @external from loopback to RFC1918/ULA private ranges - bypass still keys on real TCP peer via remote_ip only - align image README, repo README and AGENTS auth contract docs
This comment has been minimized.
This comment has been minimized.
| # auth setup step; missing/invalid WORKSPACE_AUTH_* fails the container | ||
| # at start, so this block is always populated when Caddy runs. | ||
| @external not remote_ip 127.0.0.1 ::1 | ||
| @external not remote_ip 127.0.0.1 ::1 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 fc00::/7 |
There was a problem hiding this comment.
The @external matcher exempts the entire RFC1918/ULA address space (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7) from HTTP Basic Auth, allowing any co-located container or LAN/VPC host that can reach the published port to access the full WordPress backend without credentials — a boundary far broader than the stated need. Scope the auth bypass to the actual bridge/proxy CIDR via a build/deploy-time configurable env value pinned to the narrow bridge-gateway CIDR, so only in-deployment peers bypass auth while external hosts still require credentials.
# scope to the deployment's actual bridge/proxy CIDR (injected via env) instead of all RFC1918/ULA
@external not remote_ip 127.0.0.1 ::1 {$WORKSPACE_EXEMPT_CIDRS}Prompt for LLM
File images/php-caddy/Caddyfile:
Line 65:
The @external matcher exempts the entire RFC1918/ULA address space (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fc00::/7) from HTTP Basic Auth, allowing any co-located container or LAN/VPC host that can reach the published port to access the full WordPress backend without credentials — a boundary far broader than the stated need. Scope the auth bypass to the actual bridge/proxy CIDR via a build/deploy-time configurable env value pinned to the narrow bridge-gateway CIDR, so only in-deployment peers bypass auth while external hosts still require credentials.
Suggested Code:
# scope to the deployment's actual bridge/proxy CIDR (injected via env) instead of all RFC1918/ULA
@external not remote_ip 127.0.0.1 ::1 {$WORKSPACE_EXEMPT_CIDRS}
Talk to Kody by mentioning @kody
Was this suggestion helpful? React with 👍 or 👎 to help Kody learn from this interaction.
- host-published-peer requests are private-range now exempt, so the old external-401 assertions passed spuriously - attach web to a TEST-NET-1 (192.0.2.0/24) bridge and run the public-peer 401/401/200 cases from a container on that network - add private-network peer -> 200 no-credentials case - keep spoofed-XFF assertion, run from the public peer
Kody Review CompleteGreat news! 🎉 Keep up the excellent work! 🚀 Kody Guide: Usage and ConfigurationInteracting with Kody
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
Adds the RFC 1918 and ULA private ranges to the Caddy
@externalbypass so workspace Basic Auth applies only to public-address peers, matching the protect-from-the-internet threat model.A request hairpinned through the published port from inside the deployment's Docker network arrives with the bridge gateway as its TCP peer (
remote_ip 172.18.0.1) and previously got 401; exports that probe the workspace's public URL anonymously (Cast's export probe and capture) now reach the site without credentials. The bypass still keys on the real TCP peer viaremote_ip, never on spoofable forwarding headers. Matcher verified withcaddy validate/caddy adapt(2.11.4) to compile to a singlenot remote_ipmatcher with all ranges.fix(workspaces): exempt private peers from basic auth
Summary
This PR widens the HTTP Basic Auth bypass for the PHP-Caddy workspace image so that not only loopback traffic (
127.0.0.1,::1) but also private-network traffic (RFC 1918 / ULA ranges) is exempt from authentication.What changed
images/php-caddy/Caddyfile): the existing loopback-only bypass was extended to also cover private address ranges:10.0.0.0/8172.16.0.0/12192.168.0.0/16fc00::/7remote_ipmatcher — the real TCP peer — and does not trust spoofable forwarding headers.AGENTS.md,README.md,images/php-caddy/README.md) was updated to reflect the new "external vs. private-network" auth model and the rationale for the broader bypass.Purpose
The workspace often receives in-deployment traffic that arrives hairpinned through the published port with a private-network peer IP (for example, a service inside the Docker network calling the workspace's public URL via
wp_remote_get, such as Cast's anonymous export probe). Previously these requests were treated as "non-loopback" and required Basic Auth credentials, even though they originate from the deployment's own network.The intent is to keep the workspace protected from the public internet while allowing internal/private-network consumers to reach it without credentials. The comment in the Caddyfile clarifies the threat model: TLS and public ingress already terminate on a private-network peer (the Coolify proxy), so the auth boundary is "protect from the internet," not "protect from the deployment's own network."
Risk note
One critical review finding was raised: widening the bypass to the entire RFC1918/ULA private space means any LAN/VPC host that can reach the published port will bypass Basic Auth, not just the deployment's own bridge network. This is an intentional trade-off per the documented threat model, but it should be acknowledged when merging.