Back to News & Insights
Cloud & Infrastructure August 10, 2026 · 10 min read

Three Clouds, Three Native Agents

What is this project trying to do? Three AI agents, each built with a different vendor's...

Three Clouds, Three Native Agents

Three AI agents, each built with a different vendor's framework, each running on that vendor's own hosting, all answering the same question at the same time: Google — an ADK agent on Cloud Run AWS — a Strands agent on Bedrock AgentCore Runtime Azure — an Agent Framework agent on Container Apps

One coordinator calls all three over A2A v1.0 and takes the median of their answers. And there is no long-lived credential stored anywhere in the running system — every call is authenticated with a token minted at the moment it is needed.

Everything is here: github.com/xbill9/multicloud-adk-a2a-currency. You can run the whole mesh on a laptop in about a minute; instructions are below.

The surprise wasn't the protocol. A2A worked. The surprise was that almost every decision that mattered was made before a single A2A call happened.

You have an agent on one cloud. Someone asks you to have it call an agent on another.

The reflex is to create a service account key, drop it in a secret manager, and move on. That works. It also means you now own a credential forever — rotating it, scoping it, auditing it, and eventually explaining to somebody why production contains a static key.

There is another way, and the interesting part is that it isn't harder. It is just decided earlier.

Every agent you want to call can consume an external token. AWS IAM has OIDC identity providers. Entra has Federated Identity Credentials. AgentCore accepts a CUSTOM_JWT. All three will trust a token minted somewhere else, provided you set the trust up correctly.

But only some runtimes can mint one. A runtime that can produce a workload OIDC token — for an audience you choose — can federate outward to any of them. A runtime that cannot is back to storing a credential.

So "where does my coordinator run?" is really "how many secrets will this system have?"

| Coordinator host | Legs it makes | Long-lived secrets | | :--- | :--- | :--- | | Cloud Run | GCP→AWS, GCP→Azure, GCP→GCP | potentially zero | | AgentCore | AWS→Azure, AWS→GCP | at least one | | Foundry | Azure→AWS, Azure→GCP | one or two, both unproven |

Cloud Run wins here because its metadata server hands you an ID token for any audience you name, which is exactly what the other two clouds' trust policies want to see. Whether AgentCore can do the same is unconfirmed — I did not test it. So "zero secrets" is a property of this topology, not a law about cross-cloud agents.

One leg stops being cross-cloud. The coordinator runs on Cloud Run, so the GCP leg is Google calling Google. Two vendor boundaries get crossed, not three. That belongs in the results, not in a footnote.

You cannot run it locally. A user credential cannot mint an arbitrary-audience ID token at all — gcloud auth print-identity-token --audiences=... refuses outright, telling you it requires a service account. There is no laptop version of this path. Once you choose federation, the only place the system works is the place it is deployed.

The legs do not look alike: GCP → GCP — an ID token whose audience is the target service's URL, plus roles/run.invoker. GCP → AWS — mint that token, hand it to STS AssumeRoleWithWebIdentity, get temporary credentials back, sign the request with SigV4. GCP → Azure — mint that token, present it to Entra as a client assertion against a Federated Identity Credential, get an access token back.

The move that made the rest tractable was putting all three behind one interface: httpx.Auth. To httpx, a bearer header and a signature over the request body are the same kind of object. All three vendor SDKs accept an httpx.AsyncClient. So the credential attaches once, and everything through that client carries it.

Build that seam before your second cloud, not after your third. Get one leg working with inline code and promise to generalise later, and you end up with three error-handling styles and three places a token gets cached.

Worth noticing: an agent's card lives at /.well-known/agent-card.json, and it sits behind the same authorization as the agent itself. Attach your credential to the request instead of the client and discovery 403s while the actual call would have worked. You get a protocol error pointing nowhere near auth. Attaching to the client makes that impossible by construction.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation