fix(ssh): tunnel ssh through pipelock so agents on --internal can reach git remotes
The agent container is on an --internal Docker network with no default route — only the pipelock sidecar is reachable. HTTPS_PROXY routes HTTP through pipelock, but raw TCP (e.g. SSH on port 30009) had no egress path, so `git fetch` against any bottle.ssh entry failed with "Network is unreachable". Fix: tunnel SSH through pipelock's HTTP CONNECT proxy. - lib/ssh.sh injects `ProxyCommand socat - PROXY:<pipelock>:%h:%p,proxyport=<n>` into each Host block in the in-container ~/.ssh/config. socat is already in the image (apt-installed for the ssh-agent forwarder). - lib/pipelock.sh auto-adds each bottle.ssh[].Hostname to the effective allowlist so pipelock permits the CONNECT. - cli.sh threads the pipelock host:port into ssh_setup. Note: works for SSH hosts pipelock's SSRF layer doesn't block. CGNAT (100.64.0.0/10) and other non-RFC1918 ranges should pass; if a future host gets blocked, expose pipelock's trusted_domains as a follow-up. Assisted-by: Claude Code
This commit is contained in:
+33
-4
@@ -108,6 +108,17 @@ pipelock_proxy_url() {
|
||||
printf 'http://%s:%s' "$name" "$CLAUDE_BOTTLE_PIPELOCK_PORT"
|
||||
}
|
||||
|
||||
# pipelock_proxy_host_port <slug> — prints <sidecar>:<port> (no scheme),
|
||||
# suitable for socat's PROXY: directive in an SSH ProxyCommand. The
|
||||
# agent's --internal network has no default route, so SSH (and any other
|
||||
# raw TCP) must tunnel via pipelock's HTTP CONNECT.
|
||||
pipelock_proxy_host_port() {
|
||||
local slug="${1:?pipelock_proxy_host_port: missing slug}"
|
||||
local name
|
||||
name="$(pipelock_container_name "$slug")"
|
||||
printf '%s:%s' "$name" "$CLAUDE_BOTTLE_PIPELOCK_PORT"
|
||||
}
|
||||
|
||||
# --- Allowlist resolution --------------------------------------------------
|
||||
|
||||
# pipelock_bottle_allowlist <manifest_file> <bottle_name>
|
||||
@@ -139,12 +150,29 @@ pipelock_bottle_allowlist() {
|
||||
' "$manifest_file"
|
||||
}
|
||||
|
||||
# pipelock_bottle_ssh_hostnames <manifest_file> <bottle_name>
|
||||
#
|
||||
# Prints one hostname per line for each entry in bottles[<name>].ssh[].Hostname.
|
||||
# These need to reach pipelock's allowlist so the agent can tunnel SSH
|
||||
# through pipelock via HTTP CONNECT (see ssh_setup's ProxyCommand
|
||||
# wiring). Empty output if the bottle has no ssh entries.
|
||||
pipelock_bottle_ssh_hostnames() {
|
||||
local manifest_file="${1:?pipelock_bottle_ssh_hostnames: missing manifest file}"
|
||||
local bottle_name="${2:?pipelock_bottle_ssh_hostnames: missing bottle name}"
|
||||
|
||||
jq -r --arg b "$bottle_name" '
|
||||
.bottles[$b].ssh // [] | .[] | .Hostname // empty
|
||||
' "$manifest_file"
|
||||
}
|
||||
|
||||
# pipelock_effective_allowlist <manifest_file> <bottle_name>
|
||||
#
|
||||
# Prints the deduplicated union of the baked-in default allowlist and
|
||||
# the bottle's declared allowlist, one hostname per line, sorted for
|
||||
# stability. This is the single source of truth callers should use for
|
||||
# both YAML generation and the preflight summary.
|
||||
# Prints the deduplicated union of: the baked-in default allowlist, the
|
||||
# bottle's declared egress.allowlist, and any bottle.ssh[].Hostname
|
||||
# entries (so SSH tunneling through pipelock is permitted by the same
|
||||
# allowlist check that gates HTTP CONNECT). One hostname per line,
|
||||
# sorted for stability. This is the single source of truth callers
|
||||
# should use for both YAML generation and the preflight summary.
|
||||
pipelock_effective_allowlist() {
|
||||
local manifest_file="${1:?pipelock_effective_allowlist: missing manifest file}"
|
||||
local bottle_name="${2:?pipelock_effective_allowlist: missing bottle name}"
|
||||
@@ -152,6 +180,7 @@ pipelock_effective_allowlist() {
|
||||
{
|
||||
printf '%s\n' "$CLAUDE_BOTTLE_PIPELOCK_DEFAULT_ALLOWLIST"
|
||||
pipelock_bottle_allowlist "$manifest_file" "$bottle_name"
|
||||
pipelock_bottle_ssh_hostnames "$manifest_file" "$bottle_name"
|
||||
} | awk 'NF && !seen[$0]++' | LC_ALL=C sort
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user