-
Notifications
You must be signed in to change notification settings - Fork 28
feat: propagate host.docker.internal to child containers (#422) #1722
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,5 +1,18 @@ | ||||||
| #!/bin/bash | ||||||
| cat >&2 <<'EOF' | ||||||
| # SECURITY: Docker command interceptor for AWF (Agentic Workflow Firewall) | ||||||
| # | ||||||
| # When DinD is NOT enabled (default): blocks all Docker commands with a helpful error. | ||||||
| # When DinD IS enabled (AWF_DIND_ENABLED=1): intercepts docker run/create to force | ||||||
| # shared network namespace with the agent container, preventing proxy bypass. | ||||||
| # | ||||||
| # This ensures child containers inherit the agent's NAT rules and cannot make | ||||||
| # direct outbound requests that bypass the Squid proxy. | ||||||
|
|
||||||
| set -euo pipefail | ||||||
|
|
||||||
| # --- DinD disabled: block all Docker commands --- | ||||||
| if [ "${AWF_DIND_ENABLED:-}" != "1" ]; then | ||||||
| cat >&2 <<'EOF' | ||||||
| ERROR: Docker-in-Docker support was removed in AWF v0.9.1 | ||||||
|
|
||||||
| Docker commands are no longer available inside the firewall container. | ||||||
|
|
@@ -11,4 +24,102 @@ If you need to: | |||||
|
|
||||||
| See PR #205: https://github.com/github/gh-aw-firewall/pull/205 | ||||||
| EOF | ||||||
| exit 127 | ||||||
| exit 127 | ||||||
| fi | ||||||
|
|
||||||
| # --- DinD enabled: enforce shared network namespace --- | ||||||
|
|
||||||
| REAL_DOCKER="${AWF_REAL_DOCKER:-}" | ||||||
| if [ -z "$REAL_DOCKER" ] || [ ! -x "$REAL_DOCKER" ]; then | ||||||
| echo "ERROR: AWF_REAL_DOCKER is not set or not executable: '$REAL_DOCKER'" >&2 | ||||||
| exit 127 | ||||||
| fi | ||||||
|
|
||||||
| AGENT_CONTAINER="${AWF_AGENT_CONTAINER:-awf-agent}" | ||||||
|
|
||||||
| # Get the subcommand (first non-flag argument) | ||||||
| get_subcommand() { | ||||||
| for arg in "$@"; do | ||||||
| case "$arg" in | ||||||
| -*) continue ;; | ||||||
| *) echo "$arg"; return ;; | ||||||
| esac | ||||||
| done | ||||||
| } | ||||||
|
|
||||||
| SUBCOMMAND=$(get_subcommand "$@") | ||||||
|
|
||||||
| # Block commands that could attach containers to other networks | ||||||
| case "$SUBCOMMAND" in | ||||||
| "network") | ||||||
| # Check for 'docker network connect' which could bypass firewall | ||||||
| # Allow 'docker network ls', 'docker network inspect', etc. | ||||||
| shift # remove 'network' | ||||||
| NETWORK_SUBCMD=$(get_subcommand "$@") | ||||||
| if [ "$NETWORK_SUBCMD" = "connect" ]; then | ||||||
| echo "ERROR: 'docker network connect' is blocked by AWF firewall." >&2 | ||||||
| echo "Child containers must share the agent's network namespace for security." >&2 | ||||||
| exit 1 | ||||||
| fi | ||||||
| exec "$REAL_DOCKER" network "$@" | ||||||
| ;; | ||||||
|
|
||||||
| "run"|"create") | ||||||
| # Intercept 'docker run' and 'docker create' to enforce shared network namespace | ||||||
| # This ensures child containers use the agent's NAT rules (traffic -> Squid proxy) | ||||||
| CMD="$1" | ||||||
| shift # remove 'run' or 'create' | ||||||
|
|
||||||
| FILTERED_ARGS=() | ||||||
| SKIP_NEXT=false | ||||||
|
|
||||||
| for arg in "$@"; do | ||||||
| if [ "$SKIP_NEXT" = true ]; then | ||||||
| SKIP_NEXT=false | ||||||
| continue | ||||||
| fi | ||||||
|
|
||||||
| case "$arg" in | ||||||
| # Strip --network=* and --net=* (combined flag=value form) | ||||||
| --network=*|--net=*) | ||||||
| echo "WARNING: AWF stripped '$arg' — child containers must share agent's network namespace" >&2 | ||||||
| continue | ||||||
| ;; | ||||||
| # Strip --network and --net (separate flag value form) | ||||||
| --network|--net) | ||||||
| echo "WARNING: AWF stripped '$arg' — child containers must share agent's network namespace" >&2 | ||||||
| SKIP_NEXT=true | ||||||
| continue | ||||||
| ;; | ||||||
| *) | ||||||
| FILTERED_ARGS+=("$arg") | ||||||
| ;; | ||||||
| esac | ||||||
| done | ||||||
|
|
||||||
| # Build the extra flags to inject | ||||||
| INJECT_FLAGS=("--network" "container:${AGENT_CONTAINER}") | ||||||
|
|
||||||
| # Propagate host.docker.internal DNS to child containers when host access is enabled. | ||||||
| # The agent container gets this via Docker's extra_hosts in docker-compose.yml, | ||||||
| # but child containers spawned via 'docker run' don't inherit it automatically. | ||||||
| if [ "${AWF_ENABLE_HOST_ACCESS:-}" = "1" ]; then | ||||||
|
||||||
| if [ "${AWF_ENABLE_HOST_ACCESS:-}" = "1" ]; then | |
| if [ -n "${AWF_ENABLE_HOST_ACCESS:-}" ]; then |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,11 @@ | ||||||||||||||||||||||||||||||||||||||||
| #!/bin/bash | ||||||||||||||||||||||||||||||||||||||||
| set -e | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| # SECURITY: Lock down AWF control variables to prevent tampering by user code. | ||||||||||||||||||||||||||||||||||||||||
| # These are set by the Docker Compose environment and must not be modified. | ||||||||||||||||||||||||||||||||||||||||
| readonly AWF_ENABLE_HOST_ACCESS="${AWF_ENABLE_HOST_ACCESS:-}" | ||||||||||||||||||||||||||||||||||||||||
| export AWF_ENABLE_HOST_ACCESS | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+4
to
+12
|
||||||||||||||||||||||||||||||||||||||||
| # SECURITY: Lock down AWF control variables to prevent tampering by user code. | |
| # These are set by the Docker Compose environment and must not be modified. | |
| readonly AWF_ENABLE_HOST_ACCESS="${AWF_ENABLE_HOST_ACCESS:-}" | |
| export AWF_ENABLE_HOST_ACCESS | |
| # SECURITY: Do not use an exported environment variable as the enforcement source | |
| # for host-access enablement. A child shell can override exported variables even | |
| # if they were marked readonly in this shell. Persist the value in a root-owned | |
| # runtime file instead and expose only the file path to child processes. | |
| AWF_RUNTIME_DIR="/run/awf" | |
| AWF_ENABLE_HOST_ACCESS_FILE="$AWF_RUNTIME_DIR/enable_host_access" | |
| mkdir -p "$AWF_RUNTIME_DIR" | |
| chmod 0755 "$AWF_RUNTIME_DIR" | |
| printf '%s\n' "${AWF_ENABLE_HOST_ACCESS:-}" > "$AWF_ENABLE_HOST_ACCESS_FILE" | |
| chmod 0644 "$AWF_ENABLE_HOST_ACCESS_FILE" | |
| readonly AWF_RUNTIME_DIR | |
| readonly AWF_ENABLE_HOST_ACCESS_FILE | |
| export AWF_ENABLE_HOST_ACCESS_FILE | |
| unset AWF_ENABLE_HOST_ACCESS | |
| readonly AWF_ENABLE_HOST_ACCESS="" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
get_subcommand()parser treats any non-flag token as the subcommand, which breaks when Docker global options take a value (e.g.--context foo run ...,--config dir ps,-H tcp://... info). In those cases it will mis-detect the subcommand and skip the enforcement logic, allowingrun/createto pass through unmodified. Consider explicitly parsing Docker global flags (including those that consume the next arg) before determining the subcommand, or using a more robust subcommand detection approach.This issue also appears on line 67 of the same file.