Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ jobs:
proxy_mode: audit
test_dockerfile: test/Dockerfile.audit
assert_script: ./test/assert-audit-mode.sh
endpoint_port: 1234
builder_name: buildcage-audit
- mode: restrict
proxy_mode: restrict
test_dockerfile: test/Dockerfile.restrict
assert_script: ./test/assert-restrict-mode.sh
endpoint_port: 1235
builder_name: buildcage-restrict

name: test (${{ matrix.mode }})

Expand All @@ -59,14 +59,14 @@ jobs:
- name: Start containers
env:
PROXY_MODE: ${{ matrix.proxy_mode }}
PORT: ${{ matrix.endpoint_port }}
BUILDER_NAME: ${{ matrix.builder_name }}
run: docker compose up -d --wait

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
with:
driver: remote
endpoint: tcp://localhost:${{ matrix.endpoint_port }}
endpoint: docker-container://${{ matrix.builder_name }}

- name: Build test image
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
Expand All @@ -84,11 +84,16 @@ jobs:

- name: Show logs
if: always()
env:
BUILDER_NAME: ${{ matrix.builder_name }}
INPUT_BUILDER_NAME: ${{ matrix.builder_name }}
run: node report/main.mjs ./compose.yml || true

- name: Run assertions
run: ${{ matrix.assert_script }}

- name: Cleanup
if: always()
env:
BUILDER_NAME: ${{ matrix.builder_name }}
run: docker compose down -v --rmi all 2>/dev/null || true
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ run_audit_mode: ## Start in audit mode
@echo "Creating buildx builder..."
@docker buildx create --bootstrap \
--name buildcage \
--driver remote tcp://localhost:1234
--driver remote docker-container://buildcage

.PHONY: run_restrict_mode
run_restrict_mode: ## Start in restrict mode
Expand All @@ -36,7 +36,7 @@ run_restrict_mode: ## Start in restrict mode
@echo "Creating buildx builder..."
@docker buildx create --bootstrap \
--name buildcage \
--driver remote tcp://localhost:1234
--driver remote docker-container://buildcage

.PHONY: test_restrict_mode
test_restrict_mode: ## Run restrict mode tests
Expand Down
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ jobs:
uses: docker/setup-buildx-action@v3
with:
driver: remote
endpoint: tcp://localhost:${{ steps.buildcage.outputs.port }}
endpoint: docker-container://buildcage

- name: Build and discover dependencies
uses: docker/build-push-action@v6
Expand Down Expand Up @@ -150,7 +150,7 @@ jobs:
uses: docker/setup-buildx-action@v3
with:
driver: remote
endpoint: tcp://localhost:${{ steps.buildcage.outputs.port }}
endpoint: docker-container://buildcage

- name: Build with protection
uses: docker/build-push-action@v6
Expand Down Expand Up @@ -189,11 +189,11 @@ Starts the Buildcage builder container.
|-----------|----------|---------|-------------|
| `buildcage_image` | No | `ghcr.io/<owner>/<repo>` | Docker image name |
| `buildcage_version` | No | `1` | Image tag |
| `builder_name` | No | `buildcage` | Name of the builder container |
| `proxy_mode` | No | `restrict` | Operation mode (`audit` / `restrict`) |
| `allowed_https_rules` | No | empty | HTTPS allow rules (wildcard or regex, port required) |
| `allowed_http_rules` | No | empty | HTTP allow rules (wildcard or regex, port required) |
| `allowed_ip_rules` | No | empty | IP address allow rules (wildcard or regex, port required) |
| `port` | No | `1234` | BuildKit endpoint port on localhost |

**Rule syntax**

Expand All @@ -210,20 +210,16 @@ IP address rules (e.g., `192.168.1.1:443`) use the same syntax but go in `allowe

For detailed syntax, see [Rule Syntax](./docs/rules.md).

#### Outputs
#### Connecting Buildx

| Name | Description |
|------|-------------|
| `port` | BuildKit endpoint port |

Pass this port to [`docker/setup-buildx-action`](https://github.com/docker/setup-buildx-action) to use Buildcage as a remote builder:
Pass the container name to [`docker/setup-buildx-action`](https://github.com/docker/setup-buildx-action) to use Buildcage as a remote builder. The `endpoint` must match the `builder_name` parameter (default: `buildcage`):

```yaml
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
driver: remote
endpoint: tcp://localhost:${{ steps.buildcage.outputs.port }}
endpoint: docker-container://buildcage
```

#### Operation Modes
Expand Down Expand Up @@ -286,6 +282,7 @@ In restrict mode, the report step fails if blocked connections are detected, cau

| Parameter | Required | Default | Description |
|-----------|----------|---------|-------------|
| `builder_name` | No | `buildcage` | Name of the builder container |
| `fail_on_blocked` | No | `true` | Fail the step if blocked connections are detected (restrict mode only; ignored in audit mode) |

---
Expand Down
5 changes: 2 additions & 3 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
services:
builder:
container_name: ${BUILDER_NAME:-buildcage}
build:
context: docker
dockerfile: Dockerfile
Expand All @@ -25,8 +26,6 @@ services:
cgroup: host
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
ports:
- "${PORT:-1234}:1234"
environment:
- PROXY_MODE=${PROXY_MODE:-restrict}
- ALLOWED_HTTPS_RULES=${ALLOWED_HTTPS_RULES:-}
Expand All @@ -35,7 +34,7 @@ services:
- EXTERNAL_RESOLVER=${EXTERNAL_RESOLVER:-1.1.1.1,8.8.8.8}
restart: unless-stopped
healthcheck:
test: ["CMD", "sh", "-c", "curl -sf --unix-socket /var/run/haproxy-health.sock http://localhost/health && nc -z 127.0.0.1 1234"]
test: ["CMD", "sh", "-c", "curl -sf --unix-socket /var/run/haproxy-health.sock http://localhost/health"]
interval: 30s
timeout: 5s
retries: 10
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@ RUN chmod +x /etc/s6-overlay/scripts/* && \
chmod +x /etc/s6-overlay/s6-rc.d/haproxy-log/run

ENTRYPOINT ["/init"]
CMD ["buildkitd", "--oci-worker-net=cni", "--addr", "tcp://0.0.0.0:1234"]
CMD ["buildkitd", "--oci-worker-net=cni"]
4 changes: 0 additions & 4 deletions docker/files/s6-scripts/init-iptables
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,3 @@ iptables -t nat -A PREROUTING -i buildkit0 -p tcp \
iptables -A FORWARD -i buildkit0 -j DROP
ip6tables -A FORWARD -i buildkit0 -j DROP
echo "init-iptables: REDIRECT configured, FORWARD from buildkit0 blocked (IPv4/IPv6)"

iptables -A INPUT -i buildkit0 -p tcp --dport 1234 -j DROP
ip6tables -A INPUT -i buildkit0 -p tcp --dport 1234 -j DROP
echo "init-iptables: INPUT to buildkitd API from buildkit0 blocked (IPv4/IPv6)"
4 changes: 4 additions & 0 deletions report/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name: Report
description: Show proxy communication logs and fail if blocked connections detected

inputs:
builder_name:
description: "Name of the builder container"
required: false
default: 'buildcage'
fail_on_blocked:
description: "Fail the step if blocked connections are detected"
required: false
Expand Down
8 changes: 6 additions & 2 deletions report/main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ const __dirname = dirname(fileURLToPath(import.meta.url));

// 1. Get structured report from container via QuickJS
const composeFile = process.argv[2] || join(__dirname, "..", "setup", "compose.yml");
const composeEnv = {
...process.env,
BUILDER_NAME: process.env.INPUT_BUILDER_NAME || "buildcage",
};

let jsonOutput;
try {
jsonOutput = execFileSync(
"docker",
["compose", "-f", composeFile, "exec", "builder", "qjs", "/opt/buildcage/tools/report.mjs"],
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], env: composeEnv }
);
} catch (e) {
console.log("Failed to get report from container:", e.message);
Expand All @@ -29,7 +33,7 @@ try {
const rawLog = execFileSync(
"docker",
["compose", "-f", composeFile, "exec", "builder", "cat", "/var/log/haproxy/current"],
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], env: composeEnv }
);
process.stdout.write(rawLog);
} catch {
Expand Down
12 changes: 4 additions & 8 deletions setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ inputs:
buildcage_version:
description: "Image tag"
required: false
builder_name:
description: "Name of the builder container"
required: false
default: 'buildcage'
proxy_mode:
description: "audit or restrict"
required: false
Expand Down Expand Up @@ -41,14 +45,6 @@ inputs:
description: "Deprecated: specify port per rule in allowed_https_rules (e.g., 'example.com:8443')"
required: false
default: '443'
port:
description: "BuildKit endpoint port on localhost"
required: false
default: '1234'

outputs:
port:
description: "BuildKit endpoint port"

runs:
using: node24
Expand Down
5 changes: 2 additions & 3 deletions setup/compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
services:
builder:
container_name: ${BUILDER_NAME:-buildcage}
image: ${BUILDCAGE_IMAGE}:${BUILDCAGE_VERSION:-1}
# Instead of privileged: true, grant only the minimum privileges required
# to run BuildKit and iptables. This avoids granting full device access
Expand All @@ -23,8 +24,6 @@ services:
cgroup: host
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
ports:
- "${PORT:-1234}:1234"
environment:
- PROXY_MODE=${PROXY_MODE:-restrict}
- ALLOWED_HTTPS_RULES=${ALLOWED_HTTPS_RULES:-}
Expand All @@ -33,7 +32,7 @@ services:
- EXTERNAL_RESOLVER=${EXTERNAL_RESOLVER:-1.1.1.1,8.8.8.8}
restart: unless-stopped
healthcheck:
test: ["CMD", "sh", "-c", "curl -sf --unix-socket /var/run/haproxy-health.sock http://localhost/health && nc -z 127.0.0.1 1234"]
test: ["CMD", "sh", "-c", "curl -sf --unix-socket /var/run/haproxy-health.sock http://localhost/health"]
interval: 30s
timeout: 5s
retries: 10
Expand Down
6 changes: 1 addition & 5 deletions setup/main.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { execFileSync } from "node:child_process";
import { appendFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { buildLegacyRules } from "./lib/legacy-rules.mjs";
Expand Down Expand Up @@ -43,13 +42,13 @@ function main() {

const composeEnv = {
...env,
BUILDER_NAME: env.INPUT_BUILDER_NAME || "buildcage",
PROXY_MODE: env.INPUT_PROXY_MODE || "restrict",
ALLOWED_HTTPS_RULES: rules.httpsRules.join('\n'),
ALLOWED_HTTP_RULES: rules.httpRules.join('\n'),
ALLOWED_IP_RULES: rules.ipRules.join('\n'),
BUILDCAGE_IMAGE: image.repository,
BUILDCAGE_VERSION: image.tag,
PORT: env.INPUT_PORT || "1234",
};

execFileSync(
Expand All @@ -68,9 +67,6 @@ function main() {
{ stdio: "inherit", env: composeEnv }
);

// Set action output
const port = env.INPUT_PORT || "1234";
appendFileSync(env.GITHUB_OUTPUT, `port=${port}\n`);
}

/**
Expand Down
8 changes: 7 additions & 1 deletion setup/post.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,11 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
execFileSync(
"docker",
["compose", "-f", join(__dirname, "compose.yml"), "down"],
{ stdio: "inherit" }
{
stdio: "inherit",
env: {
...process.env,
BUILDER_NAME: env.INPUT_BUILDER_NAME || "buildcage",
},
}
);
Loading