diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 879382e472..be8d1d88c8 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ iptables \ ipset \ iproute2 \ + dnsmasq \ dnsutils \ unzip \ wget \ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6f9b5492e5..81c0e3b3e9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "Onyx Dev Sandbox", - "image": "onyxdotapp/onyx-devcontainer@sha256:4986c9252289b660ce772b45f0488b938fe425d8114245e96ef64b273b3fcee4", + "image": "onyxdotapp/onyx-devcontainer@sha256:9aedd9b6e127c7e23c57eb05bbe14f466dec3093d26bfdb82c3299b275211419", "runArgs": [ "--cap-add=NET_ADMIN", "--cap-add=NET_RAW", diff --git a/.devcontainer/dnsmasq.conf b/.devcontainer/dnsmasq.conf new file mode 100644 index 0000000000..cac089388f --- /dev/null +++ b/.devcontainer/dnsmasq.conf @@ -0,0 +1,32 @@ +# Local resolver for the devcontainer. init-firewall.sh launches dnsmasq with +# this config and points /etc/resolv.conf at 127.0.0.1. +# +# The `ipset=` directives are the reason this exists: every A record dnsmasq +# returns for a listed domain is added to the `allowed-domains` ipset that +# iptables matches on. This keeps the allowlist correct as CDN IPs rotate +# (Fastly, Cloudflare, etc.) — the one-shot getent-at-boot approach in +# init-firewall.sh cannot do that. + +no-resolv +no-hosts + +# Forward upstream to Docker's embedded resolver. +server=127.0.0.11 + +# Only answer on loopback. +listen-address=127.0.0.1 +bind-interfaces + +cache-size=1000 + +# Domains whose resolved IPs should be added to the firewall allowlist. +# Keep in sync with ALLOWED_DOMAINS in init-firewall.sh. +ipset=/github.com/api.github.com/allowed-domains +ipset=/registry.npmjs.org/deb.nodesource.com/allowed-domains +ipset=/api.anthropic.com/api-staging.anthropic.com/files.anthropic.com/allowed-domains +ipset=/sentry.io/update.code.visualstudio.com/allowed-domains +ipset=/pypi.org/files.pythonhosted.org/allowed-domains +ipset=/go.dev/proxy.golang.org/sum.golang.org/allowed-domains +ipset=/storage.googleapis.com/dl.google.com/allowed-domains +ipset=/static.rust-lang.org/index.crates.io/static.crates.io/allowed-domains +ipset=/archive.ubuntu.com/security.ubuntu.com/allowed-domains diff --git a/.devcontainer/init-firewall.sh b/.devcontainer/init-firewall.sh index 283ff1c741..ea59c56ee4 100755 --- a/.devcontainer/init-firewall.sh +++ b/.devcontainer/init-firewall.sh @@ -121,4 +121,16 @@ if ! timeout 5 curl -s https://api.github.com/meta > /dev/null; then echo "Warning: GitHub API is not accessible" fi +# Start dnsmasq and point the container resolver at it. dnsmasq's ipset= +# directives add every resolved A record for allowlisted domains into the +# `allowed-domains` ipset at resolve time, keeping the firewall in step with +# CDN IP rotation. +pkill -x dnsmasq 2>/dev/null || true +dnsmasq -C /workspace/.devcontainer/dnsmasq.conf + +cat > /etc/resolv.conf <