iron-proxy is a transparent forward proxy that intercepts all HTTP and HTTPS traffic from your CI job and enforces a domain allowlist. The ironsh/iron-proxy-action GitHub Action handles all the setup for you.
Add the action to your workflow before your build steps, and the summary step after:
steps:
- uses: actions/checkout@v4
- uses: ironsh/iron-proxy-action@v0.1.0
with:
egress-rules: egress-rules.yaml
warn: true # log denied requests without blocking
# Your build steps
- run: npm ci
- run: npm test
- uses: ironsh/iron-proxy-action/summary@v0.1.0
if: always()Create an egress-rules.yaml with the domains your build needs. You can use this repo's egress-rules.yaml as a starting point:
domains:
- "nodejs.org"
- "*.nodejs.org"
- "*.npmjs.org"Push with warn: true and check the job summary to see every domain your build contacted. Add those domains to egress-rules.yaml, remove warn: true, and push again. The proxy will now enforce the allowlist.
See this repository for a complete working example. Everything below explains what is happening under the hood.
Security note: GitHub Actions gives build jobs
sudoby default. The action revokessudofor subsequent steps (controlled by thedisable-sudoinput) so that build scripts cannot bypass the proxy. For stronger isolation, we recommend using self-hosted runners in VMs and performing egress enforcement at the hypervisor level.
The workflow uses the ironsh/iron-proxy-action action, which handles downloading iron-proxy, generating and trusting a TLS interception CA, configuring DNS, starting the proxy, and locking down outbound traffic with iptables — all in a single step:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ironsh/iron-proxy-action@v0.1.0
with:
egress-rules: egress-rules.yaml
# Your build steps (all traffic goes through iron-proxy)
- run: npm ci
- run: npm test
- uses: ironsh/iron-proxy-action/summary@v0.1.0
if: always()The summary step runs at the end (even on failure) and produces a job summary showing all allowed and denied requests.
| Input | Default | Description |
|---|---|---|
egress-rules |
egress-rules.yaml |
Path to your egress rules file |
version |
latest |
Iron proxy version to install |
warn |
false |
Log denied requests without blocking them |
disable-sudo |
true |
Revoke sudo so subsequent steps can't bypass the proxy |
disable-docker |
true |
Revoke Docker access so subsequent steps can't bypass the proxy |
upstream-resolver |
8.8.8.8:53 |
Upstream DNS resolver |
The egress rules live in egress-rules.yaml:
domains:
- "nodejs.org"
- "*.nodejs.org"
- "*.npmjs.org"domains lists hostnames (with optional wildcards) that are allowed through the proxy. Everything else is blocked.
iron-proxy sits between your CI job and the internet. It has four responsibilities:
- DNS interception. iron-proxy runs a DNS server on
127.0.0.1:53. When any process resolves a hostname, iron-proxy returns127.0.0.1, directing the connection back through itself. It forwards the real lookup to an upstream resolver (8.8.8.8by default) to connect to the actual destination. - TLS interception. For HTTPS, iron-proxy generates certificates on the fly for each destination host, signed by a short-lived CA that the action creates and trusts. Tools like
curl,npm, andaptaccept these certificates because the CA is in the system trust store. - Allowlist enforcement. Each request is checked against the domain list in
egress-rules.yaml. Requests to unlisted hosts are blocked and logged. - Network lockdown. iptables rules prevent any process from bypassing the proxy by connecting to an external IP directly. Only the proxy and already-established connections are allowed to make outbound connections. All other processes must go through loopback, where the proxy is listening.
- GitHub Actions gives build jobs
sudoby default. The action revokessudofor subsequent steps, but if you setdisable-sudo: false, attackers who detect the proxy could circumvent it. - Some runtimes ship their own certificate bundles and may need extra configuration to trust the interception CA. The action handles Node.js (
NODE_EXTRA_CA_CERTS) automatically; others like Python'srequests(REQUESTS_CA_BUNDLE) or Java (keytool) may need manual setup.
This example is provided under the MIT License.