a2a cloud
whitepaper

v1.0 · 2026

Zero-Trust Whitepaper

A reference for security, platform, and infrastructure leaders evaluating a2a cloud. This page describes boundaries visible in the repository, the paths that enforce them, and the limitations that remain configuration or operator responsibilities.

section 1

Threat model

The design model distinguishes the human or service caller, the hosted agent process, peer agents, workspace and sandbox services, external tools, and the platform operator. The implementation does not turn every external tool into a platform principal: agent code can still use ordinary libraries and network clients. Assurance therefore depends on which adapter and authentication path a call uses.

Hosted ingress supports agent-selected authentication, including platform-user auth, custom resolvers, an API key, or no auth. The repository does not install one universal per-agent rate limiter. Platform handoff and workspace paths can carry Ed25519-signed grants; the receiving adapter must verify the token and enforce its own audience, bucket, and scope checks. Explicit code execution through ctx.sandbox uses the separate microsandbox service.

The threat model treats LLM output, peer-agent behavior, and tool side effects as untrusted. Grants and sandbox APIs can reduce the authority available on supported paths, but the code does not prove that compromise can never escalate. Agent application code, dependencies, deployment policy, cluster controls, and trusted signing services remain part of the security boundary.

section 2

Runtime authorization boundaries

Hosted user agents run as Knative Services by default; always-on agents use a Kubernetes Deployment. Generated pod specs disable service-account-token automounting and service links. They can, however, receive an optional per-agent Kubernetes Secret throughenvFrom, and agent code can read its own container filesystem and make network calls allowed by cluster policy. The implementation therefore does not support a blanket “no ambient credentials” claim.

The SDK grant schema scopes workspace access by audience, bucket, mode, allow/deny patterns, write prefixes, and expiry. It can also carry LLM model, budget, and rate limits plus source-agent scope.delegate_grant mechanically prevents a child from widening the parent's supported workspace, LLM, source, TTL, or delegation-depth limits.

verify_grant checks Ed25519 signature, payload shape, and expiry. It does not enforce audience or issued_at; the server adapter layers audience checks on top. The hosted ASGI adapter checks the agent audience before installing a WorkspaceClient. The sandbox service accepts either a trusted platform bearer token or a signed grant; on the grant path it verifies the token, matches the requested bucket, and forwards workspace policy labels. These are path-specific controls, not a universal signed envelope around every tool or network call.

section 3

Hosted service and sandbox boundaries

A hosted agent request executes in the agent's Knative container, not in a newly created libkrun VM. Ordinary user services default to Knative minimum scale zero and may reuse one pod for multiple requests up to configured concurrency. A warm lifecycle or an approved always-on deployment keeps at least one replica. The repository does not claim per-invocation process or memory disposal for this hosted path.

Explicit sandbox calls use a host-side microsandbox/libkrun service. On the signed-grant path, the requested bucket must match the grant and path/write policy is passed to the MinIO-backed/workspace mount. A trusted bearer-token path also exists and does not derive workspace restrictions from a grant. Network disabling is opt-in on the current HTTP API—its default is false. When requested, the runtime attempts to apply the restriction inside the guest and fails the command if setup cannot be established. Declarative agent egress metadata is not rendered into a Kubernetes NetworkPolicy by the deployer shown in this repository.

Sandbox lifecycle depends on the endpoint. One-shotrun_shell and run_python calls create and execute a sandbox, then stop it in a cleanup path. Named /sandboxes sessions intentionally persist across commands until a deletion request or service shutdown stops them. The guest also has the selected OCI image filesystem, and the runtime can copy changed guest-root files into outputs/rootfs-captures; those references are not automatically receipt artifacts or file-operation evidence. Microsandbox places tool code behind a separate virtualization boundary instead of running it directly in the agent container. Its production daemon is a privileged, host-integrated component with KVM and FUSE access and belongs to the trusted computing base. This repository does not establish an absolute no-escape, no-side-channel, or cross-tenant security guarantee.

section 4

Grant signing

Grant tokens use Ed25519-only signing primitives. Trusted control- plane components hold A2A_GRANT_SIGNING_KEY; hosted user-agent, sandbox, and LLM workloads receive grant-verifying material rather than the platform private key. The issuer field is a claim covered by the platform signature, not a signature made by each deployed agent. There is no algorithm field or HMAC/shared-secret fallback in the grant module.

The wire format is two base64url segments joined by a dot: base64url(payload).base64url(sig). The SDK serializes the Pydantic model as compact JSON in model field order; it is not a separate standards-defined canonical-JSON format. The signature covers the exact emitted payload bytes. Implementation lives in a2a_pack/grants.py.

grant payload fields
grant_id
Identifier generated with secrets.token_hex(8).
issuer / audience
Claimed issuer and intended recipient. The consuming adapter, not verify_grant itself, must enforce the expected audience.
bucket / mode
Workspace bucket plus read-only, overlay-write, or direct-write mode.
allow_patterns / deny_patterns
Workspace path globs carried into grant-aware workspace and sandbox adapters.
outputs_prefix / write_prefixes
Optional prefixes that narrow where a grant-aware client may write.
llm_models / llm_max_budget_usd
Optional model and aggregate budget limits for grant-aware LLM paths.
llm_rpm_limit / llm_tpm_limit
Optional request-per-minute and token-per-minute limits carried in the grant.
source_grants[]
Optional source-agent access claims with read or write scope.
parent_grant_id / delegation_depth
Delegation lineage and depth; delegate_grant rejects child scope that exceeds its parent.
max_delegation_depth
Maximum permitted delegation depth. The SDK default is 40.
issued_at / expires_at
Issue and expiry timestamps. mint_grant defaults to a 300-second TTL; verify_grant rejects expired tokens.
nonce
Random token included in the signed payload. The SDK does not implement a nonce replay cache.

A token that fails signature, structural, or expiry validation raises GrantInvalid in the SDK verifier. Audience, bucket, and operation-specific decisions remain the responsibility of the consuming adapter. The SDK has no nonce replay cache and does not itself emit a security-audit row for every rejection.

section 5

Receipt provenance

The authenticated control-plane Agent API seals and persists an ExecutionReceipt. A trusted control-plane ingress gateway performs the same role for public /invoke and standard MCP tools/call executions, observing their arguments and terminal results at the proxy boundary. Hosted user workloads remain verifier-only; receipt and replay private keys stay in the control-plane namespace. The SDK can still seal conditionally when an operator explicitly configures its keys. Implementation lives in a2a_pack/receipts.py.

Authenticated Agent API receipts bind the platform caller as user:{id}. Direct gateway ingress cannot resolve arbitrary upstream auth to a platform user, so it records a conservative anonymous, credential-present, or verified grant-issuer classification. Direct gateway receipts record zero platform economics because those paths do not establish platform buyer binding or billing preflight.

The envelope uses the same wire format as grants: base64url(payload).base64url(sig). The signing and verification functions require their configured Ed25519 key material; the module has no HMAC fallback. Verification checks signature and schema but not freshness, because receipts are historical artifacts. The control-plane self-report ingestion path verifies and stores an incoming token without re-signing it. On that path, fields such as caller are signed claims from the submitting signer, not independently bound by receipt verification alone.

execution receipt fields
receipt_id / schema_version
Random receipt identifier and wire-schema version.
agent_name / agent_version
Reported agent identity and version supplied by the sealing path.
caller / task_id
Agent API binds user:{id}; gateway callers are anonymous, credential-present, or a verified grant issuer. Task assurance depends on the sealing path.
skill_name
Which skill on the agent card was executed.
input_hash
sha256 of inputs after sorted-key compact JSON serialization. Signed input-integrity evidence.
input_preview / result_preview
Truncated previews. They can still contain sensitive data and are not automatically redacted.
grant_ids[]
Grant identifiers supplied by the sealing path; references, not embedded grant payloads.
file_ops
Optional aggregate read/write counts, byte totals, and truncated path previews.
tool_calls[]
Optional name, args_hash, status, and elapsed_ms entries. Receipt tool arguments are not stored as payloads.
artifacts[]
Optional workspace artifact references: path, mime_type, and bytes.
handoffs[]
Optional callee, skill, grant_id, status, and elapsed_ms entries.
status / error_type
Status and error strings supplied by the sealing path; status is not a closed enum in the Pydantic model.
eval_score / reviewer
Optional non-negative score and reviewer string supplied by the sealing call site.
started_at / ended_at / elapsed_ms
Signed start, end, and elapsed timing for the recorded run.
nonce
Per-receipt random token sealed into the signature.

seal_receipt signs the observations supplied by its call site. Current sealing paths populate identity, input evidence, outcome, and timing, but optional file, tool, artifact, handoff, evaluation, and reviewer fields may be empty unless instrumentation supplies them. Tool-call arguments in a receipt are stored by args_hash, not by payload. Input and result previews are different: they are truncated strings and can expose sensitive data, so access control and upstream redaction remain required.

section 6

Audit + replay design

Execution receipts and ReplaySession tokens are distinct evidence schemas. The ingress gateway records a minimal ordered transport timeline for direct executions; it does not observe the SDK's full internal LLM, tool, workspace, or progress-event stream. Formal A2A message and task routes manage protocol state rather than execute a skill, so accepting one is not itself a receipt-producing run. A signed session is stored as a database header plus object-store JSONL. Automatic agent re-execution from a receipt is not shipped. Replay event payloads are free-form and the current recorder can include full validated arguments, so they require stricter access and retention treatment than receipt hashes and previews.

Receipt ingestion verifies the signature, checks the receipt's agent name against the route, and rejects duplicate receipt IDs. The organization compliance policy defaults to 180 days and theeu_ai_act option enforces a 180-day floor. The explicit retention-enforce endpoint blocks when legal hold is active and otherwise deletes old organization receipts and admin-audit rows; it does not purge platform-scoped grant audits or AgentSession rows. Receipts are retrievable by receipt_id and listed per agent with time pagination. The organization decision-record API filters by kind, agent, outcome, and time—not by every field present in the receipt schema.

A deterministic rerun is conditional: the runtime must replace external LLM and tool side effects with replay doubles, and the agent must use the injected random seed. Without those controls, the signed event session supports inspection of the original history rather than a promise to reproduce it.

section 7

Key management

Signing modules read role-specific Ed25519 key material from environment variables. Placement differs by trust role; user workloads are not platform signers.

A2A_GRANT_SIGNING_KEY
Ed25519 private key projected into trusted control-plane components that mint platform grants, not user workloads.
A2A_GRANT_VERIFYING_KEY
Ed25519 public key projected into hosted agent services and grant-aware sandbox/LLM services that verify grants.
A2A_RECEIPT_SIGNING_KEY
Ed25519 private key used by the authenticated control-plane Agent API and the gateway gateway. It is not projected into hosted user-agent workloads.
A2A_RECEIPT_VERIFYING_KEY
Ed25519 public key read by components that verify persisted or submitted execution receipts.
A2A_REPLAY_SIGNING_KEY
Ed25519 private key for trusted control-plane components, including the ingress gateway's minimal replay timeline. User-agent workloads do not receive it.
A2A_REPLAY_VERIFYING_KEY
Ed25519 public key used by the control-plane session ingestion path and other replay-token verifiers.

The code does not implement a quarterly or annual rotation schedule, a key identifier in the token, or a multi-key verifier. The repository runbook specifies manual verifier-first rotation: update grant verifiers before the grant signer and allow old short-lived grants to expire. Replacing a receipt or replay verifier can make historical tokens fail verification; preserving old public keys and implementing an archival verifier is required when long-term verification across rotations is a requirement.

Back to /security·Read the platform overview /platform·Contact security@a2acloud.io