Skip to content

Latest commit

 

History

History
887 lines (693 loc) · 22.5 KB

File metadata and controls

887 lines (693 loc) · 22.5 KB
name gh-aw-firewall
description Network egress control for AI agents with domain whitelisting, Squid proxy, iptables enforcement, and secure credential management
license Apache-2.0
version 2.0.1
last_updated 2026-04-13
tags
github-agentic-workflows
network-security
firewall
squid
domain-whitelisting
egress-control

🔥 GitHub Agentic Workflows - Firewall Skill

🔴 AI FIRST Quality Principle

Apply the AI FIRST principle: never accept first-pass quality. Minimum 2 iterations. Read all output, improve every section. No shortcuts.

📋 Purpose

Master the Agentic Workflow Firewall (AWF) - a network firewall for agentic workflows providing L7 (HTTP/HTTPS) egress control using Squid proxy and Docker containers. This skill provides comprehensive expertise in restricting network access to a whitelist of approved domains for AI agents and their MCP servers.

🎯 Core Concepts

What is AWF?

AWF (Agentic Workflow Firewall) is a network security layer that restricts AI agent network access to explicitly approved domains, preventing data exfiltration and unauthorized external communication.

Key Features:

  • 🌐 L7 Domain Whitelisting: HTTP/HTTPS traffic control at application layer
  • 🔒 Host-Level Enforcement: iptables DOCKER-USER chain for all containers
  • 📦 Chroot Mode: Host binaries with network isolation
  • 🔑 API Proxy Sidecar: Secure LLM credential management
  • Transparent: Works with existing containers

Security Model

┌────────────────────────────────────────────────┐
│          AI Agent Container                     │
│  ┌──────────────────────────────────────┐     │
│  │   Application Code                    │     │
│  │   (Read-only filesystem)              │     │
│  └───────────────┬──────────────────────┘     │
│                  │ Network Request             │
│                  ▼                              │
│  ┌──────────────────────────────────────┐     │
│  │   iptables DOCKER-USER Chain         │     │
│  │   (Force all traffic through Squid)  │     │
│  └───────────────┬──────────────────────┘     │
└──────────────────┼──────────────────────────────┘
                   │
                   ▼
   ┌───────────────────────────────┐
   │      Squid Proxy               │
   │  ┌─────────────────────────┐  │
   │  │  Domain Whitelist       │  │
   │  │  - github.com ✅        │  │
   │  │  - api.github.com ✅    │  │
   │  │  - evil.com ❌          │  │
   │  └─────────────────────────┘  │
   │                                │
   │  ┌─────────────────────────┐  │
   │  │  SSL Bump (HTTPS)       │  │
   │  │  (Content Inspection)   │  │
   │  └─────────────────────────┘  │
   └────────────┬──────────────────┘
                │
                ▼
         External Network
       (Allowed domains only)

🏗️ Architecture

Three Operating Modes

1. Standard Mode (Default)

awf --allow-domains github.com,api.github.com -- docker run myapp

How it works:

  • Launches Squid proxy with domain whitelist
  • Creates iptables rules in DOCKER-USER chain
  • Runs command in Docker container
  • All HTTP/HTTPS traffic forced through Squid
  • Unauthorized domains blocked

2. Chroot Mode

awf --chroot --allow-domains github.com -- python3 script.py

How it works:

  • Uses host binaries (Python, Node.js, Go)
  • Transparent network isolation
  • No Docker container overhead
  • Squid proxy still enforces whitelist

Use Cases:

  • Faster startup (no container pull)
  • Access to host tools
  • Still network-isolated

3. API Proxy Sidecar

awf --api-proxy --allow-domains api.openai.com,api.anthropic.com -- node agent.js

How it works:

  • Node.js proxy for LLM API calls
  • Credentials injected securely
  • Tokens never exposed to AI agent
  • All calls routed through Squid

🔧 Configuration

CLI Usage

Basic Command Structure:

awf [firewall-options] -- [command-to-run]

The -- separator divides firewall configuration from the command to execute.

Domain Allowlisting

Single Domain:

awf --allow-domains github.com -- curl https://api.github.com

Multiple Domains:

awf --allow-domains github.com,api.openai.com,anthropic.com -- python agent.py

Wildcard Subdomains:

awf --allow-domains '*.github.com' -- npm install

Domain File:

# domains.txt
github.com
api.github.com
*.githubusercontent.com

awf --allow-domains-file domains.txt -- git clone https://github.com/repo

Environment Variables

Passing Variables to Container:

awf --env API_KEY --env DEBUG -- node app.js

With Values:

awf --env API_KEY=secret123 -- python script.py

From File:

# .env file
API_KEY=secret123
DEBUG=true

awf --env-file .env -- npm start

Installation

Quick Install:

curl -sSL https://raw.githubusercontent.com/github/gh-aw-firewall/main/install.sh | sudo bash

Manual Install:

npm install -g gh-aw-firewall

Verify:

awf --version
awf --help

🔐 API Proxy Sidecar

Secure Credential Management

The API proxy sidecar provides secure credential management for LLM APIs (OpenAI, Anthropic) without exposing tokens to AI agents.

Architecture:

┌──────────────────────────────────────┐
│      AI Agent Container               │
│  ┌────────────────────────────┐      │
│  │  Code makes API call       │      │
│  │  http://localhost:8080/v1  │      │
│  │  (No API key in code)      │      │
│  └──────────────┬─────────────┘      │
└─────────────────┼────────────────────┘
                  │
                  ▼
    ┌─────────────────────────────┐
    │   API Proxy Sidecar         │
    │  ┌──────────────────────┐   │
    │  │ Inject Credentials   │   │
    │  │ Authorization: sk-xx │   │
    │  └──────────────────────┘   │
    │           │                  │
    │           ▼                  │
    │  ┌──────────────────────┐   │
    │  │  Route via Squid     │   │
    │  └──────────────────────┘   │
    └───────────┬─────────────────┘
                │
                ▼
         ┌─────────────┐
         │ Squid Proxy │
         │ (Whitelist) │
         └──────┬──────┘
                │
                ▼
        External API
     (api.openai.com)

Configuration:

# Export credentials (not visible to agent)
export OPENAI_API_KEY=sk-xxx
export ANTHROPIC_API_KEY=sk-ant-xxx

# Start with API proxy
awf --api-proxy \
    --allow-domains api.openai.com,api.anthropic.com \
    -- node agent.js

Agent Code:

// Agent makes calls without credentials
fetch('http://localhost:8080/v1/chat/completions', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    model: 'gpt-4',
    messages: [...]
  })
});

// API proxy automatically injects:
// Authorization: Bearer sk-xxx

Benefits:

  • ✅ Credentials never in agent code
  • ✅ Tokens isolated in proxy
  • ✅ All traffic still goes through Squid
  • ✅ Domain whitelist enforced
  • ✅ Logging and monitoring

Implementation Example

Go Proxy Server:

package main

import (
    "net/http"
    "net/http/httputil"
    "net/url"
    "os"
)

func main() {
    // Read credentials from environment
    openaiKey := os.Getenv("OPENAI_API_KEY")
    anthropicKey := os.Getenv("ANTHROPIC_API_KEY")
    
    // Squid proxy URL
    squidURL, _ := url.Parse("http://squid:3128")
    
    // Create reverse proxy
    proxy := httputil.NewSingleHostReverseProxy(squidURL)
    
    // Modify request to inject credentials
    director := proxy.Director
    proxy.Director = func(req *http.Request) {
        director(req)
        
        // Inject appropriate credential
        if req.Host == "api.openai.com" {
            req.Header.Set("Authorization", "Bearer "+openaiKey)
        } else if req.Host == "api.anthropic.com" {
            req.Header.Set("x-api-key", anthropicKey)
        }
        
        // Route through Squid
        req.URL.Host = req.Host
        req.URL.Scheme = "https"
    }
    
    http.ListenAndServe(":8080", proxy)
}

🌐 SSL Bump (HTTPS Inspection)

Content Inspection

SSL Bump allows Squid to inspect HTTPS traffic for URL path filtering and content validation.

Configuration:

# Enable SSL Bump
http_port 3128 ssl-bump \
    cert=/etc/squid/certs/squid-ca-cert.pem \
    key=/etc/squid/certs/squid-ca-key.pem

# SSL Bump rules
acl step1 at_step SslBump1
ssl_bump peek step1
ssl_bump bump all

# URL path filtering
acl allowed_paths url_regex ^https://api\.github\.com/repos/
http_access allow allowed_paths
http_access deny all

Use Cases:

  • ✅ Block specific URL paths
  • ✅ Content validation
  • ✅ Deep packet inspection
  • ✅ Logging HTTPS requests

Security Considerations:

  • ⚠️ Requires CA certificate in agent
  • ⚠️ Man-in-the-middle by design
  • ✅ Transparent to agent code
  • ✅ Logs include HTTPS details

🔄 GitHub Actions Integration

Basic Workflow

name: Agentic Workflow with Firewall

on: pull_request

jobs:
  agent:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install AWF
        run: |
          curl -sSL https://raw.githubusercontent.com/github/gh-aw-firewall/main/install.sh | sudo bash
      
      - name: Run Agent with Firewall
        run: |
          awf --allow-domains github.com,api.github.com \
              -- node agent.js
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

MCP Server Configuration

- name: Run MCP Server with Firewall
  run: |
    awf --allow-domains github.com,api.githubcopilot.com \
        --env GITHUB_TOKEN \
        -- docker run -i \
        -e GITHUB_TOKEN \
        ghcr.io/github/github-mcp-server:latest
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Multi-Stage Pipeline

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build with NPM Registry
        run: |
          awf --allow-domains registry.npmjs.org \
              -- npm install
      
      - name: Test with External APIs
        run: |
          awf --allow-domains api.github.com,api.openai.com \
              --api-proxy \
              -- npm test
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      
      - name: Deploy (No Network)
        run: |
          awf --allow-domains '' \
              -- npm run build

📊 Logging & Monitoring

Log Files

Squid Access Log:

# Location
/var/log/squid/access.log

# Format
timestamp ip method url status bytes

# View recent
tail -f /var/log/squid/access.log

# Filter blocked requests
grep "TCP_DENIED" /var/log/squid/access.log

Squid Cache Log:

# Location
/var/log/squid/cache.log

# Contains
- Squid startup/shutdown
- Configuration errors
- Domain whitelist violations

# Monitor
tail -f /var/log/squid/cache.log

Quick Reference

View All Traffic:

awf --log-level debug --allow-domains github.com -- curl https://api.github.com

Filter by Domain:

grep "github.com" /var/log/squid/access.log

Count Requests:

awk '{print $7}' /var/log/squid/access.log | sort | uniq -c | sort -rn

Blocked Requests:

grep "TCP_DENIED" /var/log/squid/access.log | awk '{print $7}' | sort | uniq

Monitoring Metrics

Prometheus Exporter:

# docker-compose.yml
services:
  squid-exporter:
    image: boynux/squid-exporter
    ports:
      - "9301:9301"
    environment:
      - SQUID_HOSTNAME=squid
      - SQUID_PORT=3128

Grafana Dashboard:

  • Total requests
  • Allowed vs denied
  • Top domains
  • Response times
  • Cache hit rate

🔧 Troubleshooting

Common Issues

1. Connection Refused

Symptom:

Error: connect ECONNREFUSED 127.0.0.1:3128

Diagnosis:

# Check Squid is running
ps aux | grep squid

# Check Squid port
netstat -tlnp | grep 3128

# Check Squid logs
tail /var/log/squid/cache.log

Solutions:

  • Ensure Squid container is running
  • Verify iptables rules are applied
  • Check Squid configuration syntax

2. Domain Not Whitelisted

Symptom:

HTTP 403 Forbidden
TCP_DENIED/403

Diagnosis:

# Check domain in whitelist
grep "example.com" /etc/squid/allowed-domains.txt

# View denied requests
grep "TCP_DENIED" /var/log/squid/access.log | tail -20

Solutions:

  • Add domain to whitelist
  • Use subdomain wildcard sparingly: *.example.com (for known trusted organizations only)
  • Check for typos in domain name

⚠️ NEVER use TLD-level wildcards like *.com, *.org, *.se, *.io — these effectively disable the firewall by allowing all traffic to those TLDs. Always use explicit domain names (e.g., api.example.com, data.example.se) or scoped subdomain wildcards for trusted organizations only.

3. SSL Certificate Issues

Symptom:

Error: certificate verify failed

Diagnosis:

# Check CA certificate
ls -la /etc/squid/certs/

# Test SSL connection
openssl s_client -connect api.github.com:443 -proxy localhost:3128

Solutions:

  • Install Squid CA certificate in container
  • Disable SSL Bump if not needed
  • Use --insecure flag for testing (not production)

4. Performance Issues

Symptom:

  • Slow response times
  • High latency

Diagnosis:

# Check Squid CPU/memory
docker stats squid

# Monitor request timing
tail -f /var/log/squid/access.log | grep -o "TCP_[A-Z_]*"

Solutions:

  • Increase Squid cache size
  • Add more Squid workers
  • Use connection pooling
  • Enable HTTP/2

5. Docker Networking

Symptom:

Error: network unreachable

Diagnosis:

# Check Docker network
docker network ls
docker network inspect awf-network

# Check iptables
sudo iptables -L DOCKER-USER -n -v

Solutions:

  • Verify Docker network exists
  • Check iptables rules are applied
  • Restart Docker daemon

⚙️ Advanced Configuration

Custom Squid Configuration

squid.conf:

# Basic ACLs
acl localnet src 172.16.0.0/12
acl SSL_ports port 443
acl Safe_ports port 80
acl CONNECT method CONNECT

# Allowed domains from file
acl allowed_domains dstdomain "/etc/squid/allowed-domains.txt"

# Deny CONNECT to other than SSL ports
http_access deny CONNECT !SSL_ports

# Allow only safe ports
http_access deny !Safe_ports

# Allow localhost
http_access allow localnet

# Allow only whitelisted domains
http_access allow allowed_domains

# Deny everything else
http_access deny all

# Logging
access_log /var/log/squid/access.log squid
cache_log /var/log/squid/cache.log

# Performance
cache_mem 256 MB
maximum_object_size 50 MB
cache_dir ufs /var/spool/squid 1000 16 256

# DNS
dns_nameservers 8.8.8.8 8.8.4.4

Docker Compose Setup

version: '3.8'

services:
  squid:
    image: ubuntu/squid:latest
    container_name: awf-squid
    ports:
      - "3128:3128"
    volumes:
      - ./squid.conf:/etc/squid/squid.conf:ro
      - ./allowed-domains.txt:/etc/squid/allowed-domains.txt:ro
      - squid-cache:/var/spool/squid
      - squid-logs:/var/log/squid
    networks:
      - awf-network
    restart: unless-stopped

  agent:
    image: myagent:latest
    depends_on:
      - squid
    environment:
      - HTTP_PROXY=http://squid:3128
      - HTTPS_PROXY=http://squid:3128
    networks:
      - awf-network

networks:
  awf-network:
    driver: bridge

volumes:
  squid-cache:
  squid-logs:

iptables Rules

Automatic (via AWF):

awf --allow-domains github.com -- docker run myapp
# iptables rules applied automatically

Manual:

# Force all container traffic to Squid
sudo iptables -I DOCKER-USER -p tcp --dport 80 -j REDIRECT --to-port 3128
sudo iptables -I DOCKER-USER -p tcp --dport 443 -j REDIRECT --to-port 3128

# Verify rules
sudo iptables -L DOCKER-USER -n -v

🎯 Best Practices

1. Principle of Least Privilege

❌ DON'T: Allow all subdomains

awf --allow-domains '*' -- node agent.js

✅ DO: Specific domains only

awf --allow-domains api.github.com,api.openai.com -- node agent.js

2. Use API Proxy for Credentials

❌ DON'T: Expose tokens to agent

const token = process.env.OPENAI_API_KEY;  // Visible to agent

✅ DO: Use API proxy

awf --api-proxy -- node agent.js  # Tokens in proxy only

3. Monitor and Audit

Enable comprehensive logging:

awf --log-level debug \
    --audit-log /var/log/awf/audit.log \
    --allow-domains github.com \
    -- python agent.py

Review logs regularly:

# Daily review
grep "TCP_DENIED" /var/log/squid/access.log | wc -l

# Alert on suspicious patterns
grep "evil.com" /var/log/squid/access.log && notify-admin

4. Test Firewall Rules

Verify blocking:

# Should succeed
awf --allow-domains github.com -- curl https://api.github.com

# Should fail
awf --allow-domains github.com -- curl https://evil.com

5. Performance Optimization

Enable caching:

cache_mem 512 MB
maximum_object_size 100 MB
cache_dir ufs /var/spool/squid 10000 16 256

Use connection pooling:

persistent_connection_timeout 60 seconds
client_persistent_connections on
server_persistent_connections on

6. Security Hardening

Disable unnecessary features:

# No FTP
acl FTP proto FTP
http_access deny FTP

# No HTTPS without SSL Bump
acl SSL_ports port 443
http_access deny CONNECT !SSL_ports

Regular updates:

# Update Squid
docker pull ubuntu/squid:latest

# Update AWF
npm update -g gh-aw-firewall

🔗 Related Skills

  • gh-aw-safe-outputs - Controlled write operations
  • gh-aw-mcp-gateway - MCP server routing
  • gh-aw-security-architecture - Overall security model
  • gh-aw-containerization - Docker patterns
  • gh-aw-authentication-credentials - Credential management

📚 References

🆕 AWF in the Five-Layer Security Model (v0.68.1)

The Agent Workflow Firewall (AWF) is Layer 3 of the five-layer security model:

Layer 1: Read-only tokens (agent can't write)
Layer 2: Zero secrets in agent (nothing to steal)
Layer 3: AWF Firewall (can't call unauthorized servers)  ← THIS SKILL
Layer 4: Safe outputs (structured, validated writes)
Layer 5: Threat detection (AI scans for malicious content)

How AWF Works

  1. Squid Proxy — All outbound HTTP/HTTPS traffic routed through Squid
  2. Domain Allowlist — Only explicitly allowed domains pass through
  3. iptables Enforcement — Kernel-level rules block all other traffic
  4. SSL Bump — HTTPS traffic can be inspected (optional)
  5. API Proxy Sidecar — Credential-bearing requests isolated from agent

Default Allowed Domains

The firewall allows essential domains:

  • api.github.com — GitHub API access
  • github.com — Repository content
  • api.githubcopilot.com — Copilot API
  • api.anthropic.com — Claude API (if using Claude engine)
  • api.openai.com — Codex API (if using Codex engine)

Custom domains can be added per workflow:

---
network:
  allowed:
    - api.example.com
    - data.government.se
---

✅ Remember

  • ✅ AWF is Layer 3 of five-layer security — prevents data exfiltration
  • ✅ Domain allowlist = explicit opt-in, everything else blocked
  • ✅ iptables enforces at kernel level — can't bypass from container
  • ✅ SSL Bump enables HTTPS content inspection
  • ✅ API proxy isolates credentials from agent process
  • ✅ Monitor firewall logs for security events
  • ✅ Principle of least privilege — minimize allowed domains
  • ✅ Test firewall rules before production
  • ✅ Compromised agent has no outbound escape route

Version: 2.0.0
Last Updated: 2026-04-02
Maintained by: Hack23 AB


🔗 Integration with Riksdagsmonitor agentic workflows

This gh-aw skill is applied by the 11 agentic news workflows in .github/workflows/news-*.md. Their domain contract (analysis-artifact product, gate, article contract) lives in:

Upstream gh-aw docs (v0.69.3): abridged · complete · agentic-workflows blog series · source repo · GitHub CLI manual.