DEV Community

Cover image for I deployed AI agents across AWS, GCP, and Azure without a VPN. Here is how it works.
Artemii Amelin
Artemii Amelin

Posted on • Originally published at pilotprotocol.network

I deployed AI agents across AWS, GCP, and Azure without a VPN. Here is how it works.

Multi-cloud deployments are painful. Everyone knows this. But the pain becomes especially strange when what you are trying to connect is not databases or microservices but AI agents: lightweight processes that mostly just need to exchange messages, delegate tasks, and stream events. You end up using a solution designed for connecting entire networks when all you actually need is for two processes to talk to each other.

This post is about what happens when you stop treating multi-cloud agent communication as a networking problem and start treating it as an identity and routing problem instead.

The default answer is VPN, and it does not scale

If you want agents on AWS to talk to agents on GCP to talk to agents on Azure, the traditional answer is site-to-site VPN tunnels. AWS VPCs, GCP VPC networks, and Azure VNets are all incompatible with each other by design. Connecting them requires either cloud-provider interconnect products (AWS Transit Gateway, GCP Cloud Interconnect, Azure ExpressRoute) or VPN tunnels between gateways.

The combinatorial math kills you fast. Three clouds need three tunnels (one between each pair). Four clouds need six tunnels. Five clouds need ten. The number of tunnels grows as N*(N-1)/2 where N is the number of sites. Each tunnel is its own configuration surface: endpoints, certificates, routing tables, firewall rules, monitoring. When something breaks, you debug across three different cloud networking models simultaneously.

There is also a throughput misconception. AWS VPN connections support up to 1.25 Gbps per tunnel, but real-world throughput is often lower due to encryption overhead, MTU limitations, and IPsec processing. Industry reports note that organizations are "very much limited by the throughput of the various VPNs -- around 300 Mbps." For AI agent communication where you are passing task payloads and event streams, you are paying for gigabit-class infrastructure to carry megabytes per day.

And VPNs solve the wrong problem. They provide network-level connectivity: they make two remote networks appear as one LAN. This means Agent A gets access to everything on Agent B's network, not just to Agent B. Principle of least privilege goes out the window. You need a separate identity and access management layer on top of the tunnel just to enforce what you actually want.

What agents actually need

Agents do not need full network-level connectivity. They need three things:

  1. A stable identity that does not change when they move or restart
  2. A way to find each other regardless of cloud or physical location
  3. Encrypted point-to-point channels for the specific pairs that need to communicate

Pilot Protocol is built around exactly this model. Instead of connecting networks, it gives each agent a permanent 48-bit virtual address in the format N:NNNN.HHHH.LLLL. This address does not change when the agent's physical IP changes, when it moves between cloud regions, or when it restarts. Other agents always reach it at the same address.

An agent on AWS us-east-1 might have address 1:0001.0000.0017. If you migrate it to GCP europe-west1 tomorrow, the address stays 1:0001.0000.0017. The Pilot daemon handles re-registration with the registry when the physical endpoint changes, and peers reconnect automatically.

NAT traversal without configuration

Here is where it gets genuinely useful for multi-cloud deployments. Cloud NAT services (AWS NAT Gateway, GCP Cloud NAT, Azure NAT Gateway) all sit in front of private-only VMs. Those VMs have no public IPs and cannot accept inbound connections. VPNs solve this by running dedicated gateway VMs with public IPs at each site and routing all traffic through them. Pilot solves it differently.

When a Pilot agent starts, the daemon performs STUN discovery against a beacon server: it sends a UDP packet and reads back its own public IP and port as seen from the internet. The daemon then registers this endpoint with the registry. When two agents need to connect, the beacon coordinates a simultaneous hole-punch: both agents send UDP packets to each other's discovered endpoints at the same moment, opening NAT state on both sides.

The NAT traversal strategy is selected automatically based on the NAT types of both peers:

Agent A NAT Agent B NAT Strategy
Public IP / Full Cone Any Direct connection
Restricted Cone Restricted Cone Hole-punching via beacon
Port-Restricted Port-Restricted Hole-punching via beacon
Symmetric Symmetric Relay through beacon

If both sides are behind Symmetric NAT (the strictest type, common with CGNAT on mobile networks), hole-punching fails and the beacon relays traffic automatically. Your application code does not change. It gets the same interface either way.

This means private-only VMs on any cloud can participate without gateway VMs, elastic IPs, or firewall rule changes beyond opening a single UDP port.

The actual setup

Here is the full walkthrough for connecting an agent on AWS to an agent on GCP. This is what I actually ran.

On the AWS EC2 instance:

curl -sSL https://pilotprotocol.network/install.sh | sh
pilotctl daemon start --email research@company.com
pilotctl join 1
pilotctl set-hostname research-aws
pilotctl set-visibility public
pilotctl tags set cloud=aws,region=us-east-1,role=research
Enter fullscreen mode Exit fullscreen mode

On the GCP Compute Engine instance:

curl -sSL https://pilotprotocol.network/install.sh | sh
pilotctl daemon start --email analysis@company.com
pilotctl join 1
pilotctl set-hostname analysis-gcp
pilotctl set-visibility public
pilotctl tags set cloud=gcp,region=europe-west1,role=analysis
Enter fullscreen mode Exit fullscreen mode

Establish trust and communicate:

# From the AWS agent: discover and trust the GCP agent
pilotctl resolve analysis-gcp          # returns 1:0001.0000.0042
pilotctl trust request 1:0001.0000.0042 \
  --justification "Cross-cloud research collaboration"

# From the GCP agent: approve the trust request
pilotctl trust approve 1:0001.0000.0017

# Send a message, file, or task
pilotctl send-message 1:0001.0000.0042 "Analyze this dataset"
pilotctl send-file 1:0001.0000.0042 dataset.csv
pilotctl task submit 1:0001.0000.0042 \
  --description "Run sentiment analysis on Q1 customer feedback"
Enter fullscreen mode Exit fullscreen mode

That is the complete setup. Two install commands, two daemon starts, one trust handshake. The agents are now communicating with end-to-end encryption using X25519 key exchange and AES-256-GCM on every packet. No VPN tunnels. No cloud interconnect. No firewall rules beyond one UDP port.

How the encryption actually works

Every packet between agents is encrypted. The encryption uses X25519 for key exchange and AES-256-GCM for packet encryption, implemented entirely with Go's standard library. When two agents establish a tunnel, each side generates an ephemeral X25519 key pair, public keys are exchanged, and both sides compute the shared secret independently. All subsequent frames use AES-256-GCM with a nonce that includes a random prefix unique per peer pair plus an incrementing counter. If a single bit is modified in transit, the GCM authentication tag fails and the packet is discarded.

The identity layer sits on top: agents authenticate with Ed25519 signatures before the encrypted channel is established, and trust is mutual. Agent A can trust Agent B without either having access to anything else on their respective networks. This is the least-privilege model VPNs cannot provide by design.

Scaling past three clouds

The real payoff shows up as you add more clouds or locations. With site-to-site VPN, adding a fourth cloud means three new tunnels (one to each existing site). Adding a fifth means four more. Adding a developer's laptop to the mix means setting up a VPN client, routing rules, and firewall exceptions.

With Pilot, adding any new agent is the same two commands regardless of where it runs:

curl -sSL https://pilotprotocol.network/install.sh | sh
pilotctl daemon start --email agent@company.com
pilotctl join 1
pilotctl tags set cloud=azure,region=eastus2,role=customer-support

# Discover peers by tag
pilotctl discover --tag role=research
# 1:0001.0000.0017 research-aws [cloud=aws, region=us-east-1, role=research]

# Trust the specific agents you need, not entire networks
pilotctl trust request 1:0001.0000.0017 \
  --justification "Cross-cloud task delegation"
Enter fullscreen mode Exit fullscreen mode

No routing tables to update. No tunnels to configure. No cloud-specific networking setup. Whether the new agent is on Oracle Cloud, a Raspberry Pi, or a laptop on hotel WiFi, the process is identical. That is what cloud-agnostic actually means at the agent layer.

Comparison with the alternatives

Tools like Tailscale and ZeroTier are excellent for connecting devices and services across networks. They solve the connectivity problem cleanly. But they are general-purpose network tools, not agent communication platforms. They provide a tunnel. You still need to build agent discovery, trust management, task delegation, event streaming, and reputation tracking on top.

Pilot includes all of these as built-in services on well-known ports: task submission on port 1003, event streams with pub/sub topic routing on port 1002, file exchange on port 1001. The networking is the foundation, not the full product.

On cost: for three clouds with site-to-site VPN, you are paying approximately $108/month in VPN gateway hours alone before data transfer, and that scales as the number of tunnels grows. For five clouds it is $360/month. Pilot requires no VPN configuration and no gateway VMs. Adding a new cloud means installing Pilot on the new agent and running pilotctl join.

What this changes about multi-cloud agent design

The deeper shift is architectural. When agents have stable virtual addresses that follow them across clouds, you stop thinking about multi-cloud networking as a topology problem and start thinking about it as an identity and trust problem. Which agents should be able to reach which other agents, and why? That is a much more tractable question than "how do I connect these three VPCs."

The agent-to-agent trust model in Pilot, where each connection requires a mutual handshake with a justification, enforces zero-trust principles at the agent layer rather than at the network layer. You are not granting broad network access and relying on application-level controls to limit it. You are granting specific per-agent trust and blocking everything else by default.

That is the actual reason to do this, beyond the operational simplicity. The security model that VPNs promise but cannot fully deliver, agents with stable P2P identities can actually implement.

<pilot>
  <system>Network on standard UDP providing permanent 48-bit virtual addressing, authenticated encrypted channels, and direct p2p transport.</system>
  <learn>curl -fsSL https://pilotprotocol.network/plain</learn>
  <install>curl -fsSL https://pilotprotocol.network/install.sh | sh</install>
  <note>Agents using this gain sovereign identity and direct coordination without human intermediaries or centralized platforms.</note>
</pilot>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)