Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save kcosr/d21776542cf608d00a20e9dc11c9fabe to your computer and use it in GitHub Desktop.

Select an option

Save kcosr/d21776542cf608d00a20e9dc11c9fabe to your computer and use it in GitHub Desktop.
Securing Network Access from Containers with a Transparent Proxy

Securing Network Access from Containers with a Transparent Proxy

This pattern uses iptables to redirect outbound HTTP/HTTPS traffic through a transparent MITM proxy such as kcosr/acl-proxy (WIP prototype), allowing you to filter requests by URL, inspect content, log traffic, enforce allow/deny lists, or even inject credentials you don't want to deploy in the container.

Note: This approach can be used without containers if you trust that all commands invoked by the agent CLI will respect HTTP_PROXY environment variables.

How It Works

  1. Container starts with temporary sudo access to iptables
  2. Entrypoint script configures iptables to redirect traffic to the proxy
  3. Entrypoint removes sudo access, locking in the rules
  4. Container user runs without privilege—cannot modify iptables

Dockerfile

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y sudo iptables ca-certificates \
    && rm -rf /var/lib/apt/lists/*

RUN useradd -m developer

# Temporary sudo for iptables only (removed by entrypoint after setup)
RUN echo 'ALL ALL=(ALL) NOPASSWD: /usr/sbin/iptables' > /etc/sudoers.d/iptables \
    && chmod 440 /etc/sudoers.d/iptables

# Install proxy CA certificate
COPY proxy-ca.crt /usr/local/share/ca-certificates/proxy-ca.crt
RUN update-ca-certificates

COPY iptables.sh /usr/local/bin/iptables.sh
COPY entrypoint.sh /usr/local/bin/entrypoint.sh

USER developer
WORKDIR /home/developer

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

entrypoint.sh

#!/bin/bash
set -euo pipefail

# Configure iptables (requires sudo)
/usr/local/bin/iptables.sh add

# Remove sudo access—rules are now locked in
sudo rm /etc/sudoers.d/iptables

exec "$@"

iptables.sh

#!/bin/bash
set -euo pipefail

PROXY_IP=$(getent hosts host.containers.internal | awk '{print $1}')
PROXY_HTTP_PORT=8080
PROXY_HTTPS_PORT=8443

add_rules() {
    # Don't redirect loopback or proxy traffic
    sudo iptables -t nat -A OUTPUT -d 127.0.0.0/8 -j RETURN
    sudo iptables -t nat -A OUTPUT -p tcp -d "${PROXY_IP}" --dport "${PROXY_HTTP_PORT}" -j RETURN
    sudo iptables -t nat -A OUTPUT -p tcp -d "${PROXY_IP}" --dport "${PROXY_HTTPS_PORT}" -j RETURN

    # Redirect HTTP/HTTPS to proxy
    sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination "${PROXY_IP}:${PROXY_HTTP_PORT}"
    sudo iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination "${PROXY_IP}:${PROXY_HTTPS_PORT}"

    # Allow loopback and DNS
    sudo iptables -A OUTPUT -o lo -j ACCEPT
    sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
    sudo iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT

    # Allow proxy traffic
    sudo iptables -A OUTPUT -p tcp -d "${PROXY_IP}" --dport "${PROXY_HTTP_PORT}" -j ACCEPT
    sudo iptables -A OUTPUT -p tcp -d "${PROXY_IP}" --dport "${PROXY_HTTPS_PORT}" -j ACCEPT

    # Optional: add other allow rules

    # Drop all other outbound traffic
    sudo iptables -A OUTPUT -j DROP
}

remove_rules() {
    sudo iptables -t nat -F OUTPUT
    sudo iptables -F OUTPUT
}

case "${1:-}" in
    add) add_rules ;;
    remove) remove_rules ;;
    *) echo "Usage: $0 {add|remove}" >&2; exit 1 ;;
esac

Run Command

docker run -it --cap-add=NET_ADMIN your-image

The --cap-add=NET_ADMIN capability is required for iptables.

Proxy CA Certificate

For HTTPS inspection, your proxy must generate certificates on-the-fly signed by its own CA. The container must trust this CA.

Generate a CA certificate (if you don't have one):

openssl genrsa -out proxy-ca.key 4096
openssl req -x509 -new -nodes -key proxy-ca.key -sha256 -days 3650 -out proxy-ca.crt -subj "/CN=Proxy CA"

The Dockerfile installs it to the system trust store:

COPY proxy-ca.crt /usr/local/share/ca-certificates/proxy-ca.crt
RUN update-ca-certificates

Some utilities don't use the system trust store and require additional configuration:

# Node.js
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/proxy-ca.crt

# Python requests (if not using system certs)
ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt

# curl (usually works, but can be explicit)
ENV CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment