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.
- Container starts with temporary sudo access to iptables
- Entrypoint script configures iptables to redirect traffic to the proxy
- Entrypoint removes sudo access, locking in the rules
- Container user runs without privilege—cannot modify iptables
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"]#!/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 "$@"#!/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 ;;
esacdocker run -it --cap-add=NET_ADMIN your-imageThe --cap-add=NET_ADMIN capability is required for iptables.
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-certificatesSome 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