← Back to Blog
Architecture July 30, 2026 · 7 min read

How AI agents access private infrastructure securely

MCP servers, Docker agents, and CI/CD bots need to reach private databases and APIs. wzctl gives them an ephemeral WebSocket tunnel — no VPN client, no NET_ADMIN.

The problem

AI agents are moving beyond chat. Claude MCP servers query your production database to answer questions. GitHub Copilot agents run migrations against staging. Custom bots pull metrics from internal APIs. These agents need network access to private infrastructure — databases, REST APIs, Kubernetes clusters — that lives behind firewalls with no public endpoint.

The challenge: these agents run in ephemeral containers on shared infrastructure. They don't have persistent network configs. They spin up, do their job, and disappear.

Why traditional approaches fail

  • VPNs require NET_ADMIN — container runtimes (Docker, Kubernetes pods, cloud sandboxes) don't grant this capability. You can't create a WireGuard or OpenVPN interface inside a standard container.
  • Credentials leak — embedding database connection strings in agent configs means they persist in logs, memory, and potentially in the LLM's context window.
  • No time-bounding — a VPN config or SSH key gives permanent access. If an agent is compromised, the attacker has a persistent tunnel into your network.
  • No audit granularity — you can't tell which agent session accessed which resource, or revoke a single session without rotating shared credentials.

The solution: wzctl

wzctl is a userspace binary that creates an encrypted WebSocket tunnel to the WireZTNA broker. No kernel interface, no NET_ADMIN, no TUN device. It exposes a local TCP port that forwards to a specific host:port on the private network.

The flow:

  • Register via wzctl register (self-service, no portal)
  • Generate a publisher token with wzctl token --cidrs
  • Enroll the publisher on the private server
  • The agent runs wzctl connect --daemon to open a local port
  • When the TTL expires, the tunnel drops — no lingering access

Step 1: Set up (one-time)

Register and generate a publisher token:

# Register (free tier)
wzctl register --broker https://freetier.wireztna.com --email you@example.com --save

# Generate publisher token
wzctl token --broker https://freetier.wireztna.com --cidrs "10.0.2.0/24" --name my-db-server

# On the private server: enroll publisher
sudo ./wireztna-publisher install --token "<url_from_wzctl_token>"
sudo systemctl start wireztna-publisher

Step 2: Connect from the agent

Inside the agent container, run wzctl connect in daemon mode:

# Connect — opens localhost:5432 tunneled to 10.0.2.30:5432
wzctl connect --broker https://freetier.wireztna.com \
  --publisher <publisher_id> \
  --target 10.0.2.30 --port 5432 \
  --ttl 30m --local-port 5432 --daemon &

Now the agent can connect to localhost:5432 as if the database were local:

# From the agent's perspective, it's just a local PostgreSQL
psql -h localhost -p 5432 -U readonly -d analytics

Step 3: CI/Docker usage

For containerized agents or CI runners:

# In a GitHub Actions step
- name: Connect to private DB
  run: |
    curl -fsSL https://wireztna.com/dl/wzctl-linux-amd64 -o wzctl
    chmod +x wzctl
    ./wzctl connect --broker "$WIREZTNA_BROKER" \
      --publisher "$PUBLISHER_ID" \
      --target 10.0.2.30 --port 5432 \
      --ttl 10m --local-port 5432 --daemon &
    sleep 2
    psql -h localhost -p 5432 -U readonly -d analytics

No --privileged, no --cap-add NET_ADMIN, no host networking. It runs entirely in userspace.

Security model

  • Time-limited — passes expire after the configured TTL (default: 1 hour). The tunnel terminates automatically.
  • Scoped to host:port — a pass grants access to exactly one destination. The agent cannot pivot to other hosts on the private network.
  • Auto-revoked — if the orchestrator detects an issue, it can revoke the pass via API. The tunnel drops immediately.
  • Full audit — every connection is logged with the pass ID, agent label, source IP, bytes transferred, and duration. You know exactly which agent session touched your database.
  • No stored credentials — the pass token is ephemeral. It's not a password or a key — it's a one-time scoped authorization that can't be replayed after expiry.

Real-world patterns

Claude MCP server querying a database

Your MCP server starts, requests an access pass for the analytics DB, connects via wzctl, and serves queries to Claude. When the session ends, the pass expires and the tunnel closes.

GitHub Actions deploying to a private cluster

A workflow step mints a pass for the K8s API server (port 6443), connects via wzctl, runs kubectl apply, and the pass auto-revokes after the job completes.

Cron job pulling metrics

A scheduled agent requests a 5-minute pass to the Prometheus API, scrapes the data it needs, and disconnects. No lingering access between runs.

Summary

AI agents need network access to private infrastructure, but they run in environments where VPNs don't work. wzctl solves this with ephemeral, scoped, auditable tunnels that require no kernel privileges. Your agents get exactly the access they need, for exactly as long as they need it — and nothing more.

Learn more about wzctl →