From d654e6df906cabe1f868bd2bc916689e18a5f1f1 Mon Sep 17 00:00:00 2001 From: ginnoir Date: Wed, 24 Jun 2026 01:45:11 -0500 Subject: [PATCH] fix(proxy): use parse-time {$SHARE_KEY} in share_gate instead of runtime placeholder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit {env.SHARE_KEY} is not resolved by Caddy's query matcher or CEL expression at request time — the literal placeholder string was compared against the URL key, causing every external request to fall through to 403. {$SHARE_KEY} is substituted by the Caddyfile adapter at reload/start, baking the literal key value into the compiled config. Co-Authored-By: Claude Sonnet 4.6 --- Caddyfile | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Caddyfile b/Caddyfile index aa2f4bd..a0d8e59 100644 --- a/Caddyfile +++ b/Caddyfile @@ -36,22 +36,27 @@ remote_ip 192.168.1.0/24 172.16.0.0/12 100.64.0.0/10 127.0.0.1 } -# Shared-link gate — external users visit ?k={$SHARE_KEY} once to get a 30-day cookie. +# Shared-link gate — external users visit ?k= once to get a 30-day cookie. # Internal IPs and tailnet clients pass through unconditionally. # Usage: import share_gate (replaces import internal_only on shared services) +# Uses {$SHARE_KEY} (parse-time substitution) — baked in at caddy reload/start when the +# env var is set. Rotate: update SHARE_KEY in stack.env, push → Portainer redeploys → key changes. (share_gate) { - route { - @has_key query k={$SHARE_KEY} - handle @has_key { - header Set-Cookie "share_access={$SHARE_KEY}; Path=/; Max-Age=2592000; HttpOnly; Secure; SameSite=Strict" - redir {http.request.uri.path} 302 + @external not remote_ip 192.168.1.0/24 172.16.0.0/12 100.64.0.0/10 127.0.0.1 + handle @external { + route { + @has_key query k={$SHARE_KEY} + handle @has_key { + header Set-Cookie "share_access={$SHARE_KEY}; Path=/; Max-Age=2592000; HttpOnly; Secure; SameSite=Strict" + redir {http.request.uri.path} 302 + } + @has_cookie expression `{http.request.cookie.share_access} == "{$SHARE_KEY}"` + handle @has_cookie { + } + handle { + respond "Access denied" 403 + } } - - @deny_external { - not remote_ip 192.168.1.0/24 172.16.0.0/12 100.64.0.0/10 127.0.0.1 - not expression `{http.request.cookie.share_access} == "{$SHARE_KEY}"` - } - respond @deny_external "Access denied" 403 } }