CRD data model#
MAQPNA's declarative API is the Kubernetes API group maqpna.com, version v1alpha1 (api/v1alpha1/). Every kind has a status subresource. The operator reads these objects and produces two kinds of output: sandboxes, tokens and NetworkPolicies for sessions, and rendered files (ConfigMaps and Secrets in the gateway namespace) that the gateway hot-reloads. The gateway never reads the CRDs for decisions; it reads only the rendered files.
The kinds#
| Kind | Scope | Short name | Status highlights |
|---|---|---|---|
TrustTier |
Cluster | tier |
warmPoolReady; conditions RuntimeClassAvailable, SandboxTemplateReady, WarmPoolReady, Ready |
Agent |
Namespaced | mqagent |
activeSessions; conditions TierFound, PolicyFound, SovereigntyCompliant, ModelCredentialsReady, Ready |
AgentSession |
Namespaced | asess |
phase (Pending, Provisioning, Running, Suspended, Completed, Failed), outcome.result (Succeeded, Failed, Expired, Revoked, Cancelled), spiffeID, principal, attestation, bootstrap, fork, readyIn |
AgentSessionSnapshot |
Namespaced | asnap |
phase (Pending, Capturing, Ready, Failed), source, forks; condition SnapshotReady |
ToolPolicy |
Namespaced | tp |
condition Ready (Published or InvalidPolicy) |
MCPServer |
Namespaced | mcps |
gatewayKey, observedTools, driftedTools, lastSeen; conditions Ready, SovereigntyCompliant, Pinned |
A2APeer |
Namespaced | a2ap |
gatewayPath; conditions Ready, SovereigntyCompliant |
AgentRevocation |
Namespaced | arev |
affectedSessions, appliedAt; condition Ready (Published, Expired, Invalid) |
BudgetPolicy |
Cluster | bp |
condition Ready (Published) |
Tenant |
Cluster | tn |
keyId, trustDomain, budgetPolicy, isolationViolations; conditions NamespacesOwned, KeyReady, Isolated, Ready |
SovereigntyPolicy |
Cluster | sovpol |
violations, lastEvaluated; conditions Active, Compliant, RetentionBelowAIAct |
MemoryStore |
Namespaced | mem |
gatewayKey; conditions Ready, ResidencyCompliant |
ConnectedAccount |
Namespaced | conn |
phase (Connected, ReauthRequired, Revoked), grant, scopes, token timestamps |
How the kinds relate#
classDiagram
direction LR
class TrustTier {
runtimeClassName
isolation gvisor|microvm|confidential
sandboxTemplateName
warmPoolSize
jurisdiction
egress gateway-only|deny-all
attestationRequired
maxSessionTTL
}
class Agent {
image
tier
model
tools[]
policyRef
scopes[]
budget
a2a
profile
}
class AgentSession {
agentRef
user
scopes[]
ttl
suspend
input
fork
status.phase
}
class AgentSessionSnapshot {
sessionRef
strategy
status.forks
}
class ToolPolicy {
agents[]
defaultAction
rules[]
toolPins[]
toolLabels[]
cedar
}
class MCPServer {
url
trust
dataClass
auth
shared
toolPins
dlpProfile
}
class A2APeer {
url
cardKeys
allowedCallers[]
skills[]
}
class AgentRevocation {
match
action block|suspend|terminate
expiresAt
}
class BudgetPolicy {
namespaces
users
onExceed
}
class Tenant {
namespaces[]
trustDomain
signingKeySecretRef
quotas
}
class SovereigntyPolicy {
allowedJurisdictions
allowedRegistries
allowedEgressHosts
requireAttestationFor
enforcement
}
class MemoryStore {
agents[]
backend
jurisdiction
}
class ConnectedAccount {
user
provider
status.phase
}
class Sandbox {
upstream agents.x-k8s.io
}
class SandboxClaim {
upstream extensions.agents.x-k8s.io
}
class SandboxWarmPool {
upstream maqpna-tier
}
AgentSession --> Agent : spec.agentRef
Agent --> TrustTier : spec.tier
Agent --> ToolPolicy : spec.policyRef
ToolPolicy ..> Agent : spec.agents globs
Agent --> MCPServer : tools[].serverRef
AgentSession --> AgentSessionSnapshot : spec.fork.fromSnapshot
AgentSessionSnapshot --> AgentSession : spec.sessionRef
AgentSession *-- Sandbox : owns (direct mode)
AgentSession *-- SandboxClaim : owns (warm pool)
SandboxClaim --> SandboxWarmPool : warmPoolRef
TrustTier *-- SandboxWarmPool : creates maqpna-tier
MemoryStore --> Agent : spec.agents
Tenant *-- BudgetPolicy : creates tenant-name
AgentRevocation ..> AgentSession : match sessions, agents, users
A2APeer ..> Agent : allowedCallers
SovereigntyPolicy ..> Agent : checked on reconcile
Reading the diagram:
- A session names its agent (
spec.agentRef, same namespace). Its scopes must be a subset of the agent's. - An agent names a cluster-scoped trust tier (
spec.tier) and aToolPolicyin its namespace (spec.policyRef). A policy separately selects agents byspec.agentsglobs; both must line up for the policy to apply at the gateway. - An agent's
tools[].serverRefpoints to anMCPServerin its own namespace, or in another namespace that shares it (shared,allowedNamespaces). - A session owns exactly one upstream
Sandbox(direct mode) orSandboxClaim(when the tier setssandboxTemplateName). The trust tier creates theSandboxWarmPoolnamedmaqpna-<tier>. - A fork names a snapshot (
spec.fork.fromSnapshot) or a session (spec.fork.fromSession, which makes the operator create a snapshot<session>-fork). - A
Tenantlabels its namespacesmaqpna.com/tenant=<name>and owns a generatedBudgetPolicytenant-<name>built from itsquotas. AgentRevocationobjects match sessions by name, agent, user or token ID; in the gateway namespace (maqpna-systemby default) they are cluster-wide.ConnectedAccountobjects are written by the gateway's token vault (status only); no operator reconciler manages them.- The
SovereigntyPolicydefaultis consulted by the Agent, AgentSession, MCPServer, A2A, model-route and MemoryStore reconcilers.
From CRDs to gateway files#
flowchart LR
TP[ToolPolicy] --> P["ConfigMap maqpna-policies<br/>policies.json"]
AG[Agent] --> M["ConfigMap maqpna-models<br/>models.json"]
AG --> MC["Secret maqpna-model-credentials<br/>route.key"]
MS[MCPServer] --> U["ConfigMap maqpna-upstreams<br/>upstreams.json"]
AG --> U
MS --> UC["Secret maqpna-upstream-credentials<br/>ns.name.token and others"]
AG --> A2["ConfigMap maqpna-a2a<br/>a2a.json"]
PEER[A2APeer] --> A2
REV[AgentRevocation] --> R["ConfigMap maqpna-revocations<br/>revocations.json"]
AG --> B["ConfigMap maqpna-budgets<br/>budgets.json"]
BP[BudgetPolicy] --> B
MEM[MemoryStore] --> ME["ConfigMap maqpna-memory<br/>memory.json"]
TN[Tenant] --> T["ConfigMap maqpna-tenants<br/>tenants.json"]
TN --> TK["Secret maqpna-tenant-keys<br/>tenant.pem"]
TN --> BP
P & M & MC & U & UC & A2 & R & B & ME & T --> GW(["maqpna-gateway"])
T & TK --> IB(["maqpna-identity"])
Every rendered ConfigMap is compact JSON with sorted keys, written by one reconciler that re-renders the whole document on any change. Secrets are written before the ConfigMap that references them. Invalid objects are left out of the document and get Ready=False, so one bad object never takes the others down. The operator exports the size of each rendered ConfigMap as maqpna_rendered_configmap_bytes{name} (ConfigMaps are limited to 1 MiB).
What you see#
kubectl get columns come from the CRD printer columns (api/v1alpha1/agentsession_types.go; values illustrative); maqpna explain documents any kind or field:
$ kubectl get asess -n team-a
NAME PHASE AGENT USER OUTCOME READY-IN AGE
fix-4790 Completed coder bob@acme.eu Succeeded 2.43s 118m
fix-4821 Running coder alice@acme.eu 1.71s 3m
See maqpna explain, maqpna init and maqpna validate.