Operator#
The operator (maqpna-operator) is the Kubernetes controller of MAQPNA. It is built on controller-runtime and watches the maqpna.com/v1alpha1 kinds. It has two jobs:
- Run sessions. For each
AgentSessionit checks the request, gets credentials from the identity broker (or registers an attested release), creates the sandbox through the upstream agent-sandbox project and fences it with a NetworkPolicy. - Feed the gateway. It renders the cluster's policies, MCP servers, model routes, A2A routes, revocations, budgets, memory stores and tenants into ConfigMaps (and two credential Secrets) in the gateway namespace, which the gateway hot-reloads.
The operator never sits on the request path of a tool call. Running sessions keep working when it is down.
Code: cmd/maqpna-operator, internal/controller, api/v1alpha1.
Responsibilities and neighbours#
flowchart LR
K[("Kubernetes API<br/>maqpna.com/v1alpha1")] -- watch --> OP
subgraph OP["maqpna-operator"]
SR["AgentSession reconciler"]
AGG["Aggregating reconcilers:<br/>ToolPolicy, MCPServer, ModelRoute,<br/>A2A, AgentRevocation, Budget,<br/>MemoryStore, Tenant"]
OTH["Agent, TrustTier,<br/>SovereigntyPolicy, Snapshot"]
MET["Licence watcher,<br/>node counter"]
end
SR -- "POST /v1/token" --> IB["Identity broker"]
SR -- "POST /v1/releases" --> AT["Attestation service"]
SR -- "Sandbox / SandboxClaim,<br/>Secrets, NetworkPolicy" --> K
SR -- "POST /v1/usage/sandbox" --> GW["Gateway"]
AGG -- "ConfigMaps maqpna-*<br/>in maqpna-system" --> K
K -- "files, polled" --> GW
OTH -- "SandboxWarmPool maqpna-tier" --> K
Inputs and outputs#
| Input | Output |
|---|---|
AgentSession, Agent, TrustTier, SovereigntyPolicy, AgentRevocation |
Upstream Sandbox or SandboxClaim named after the session; Secrets <session>-maqpna-token and <session>-maqpna-input; NetworkPolicy <session>-maqpna; PVC <session>-maqpna-workspace; status (phase, conditions, spiffeID, expiresAt, readyIn, outcome) |
ToolPolicy |
ConfigMap maqpna-policies, key policies.json |
MCPServer, Agent.spec.tools |
ConfigMap maqpna-upstreams (upstreams.json), Secret maqpna-upstream-credentials |
Agent.spec.model |
ConfigMap maqpna-models (models.json), Secret maqpna-model-credentials |
Agent.spec.a2a, A2APeer |
ConfigMap maqpna-a2a (a2a.json) |
AgentRevocation |
ConfigMap maqpna-revocations (revocations.json) |
Agent.spec.budget, BudgetPolicy |
ConfigMap maqpna-budgets (budgets.json) |
MemoryStore |
ConfigMap maqpna-memory (memory.json) |
Tenant |
Namespace labels maqpna.com/tenant, Secret maqpna-tenant-keys, BudgetPolicy tenant-<name>, ConfigMap maqpna-tenants |
TrustTier with a template and warm pool size |
Upstream SandboxWarmPool maqpna-<tier> in each warm-pool namespace |
AgentSessionSnapshot |
GKE PodSnapshotManualTrigger or CSI VolumeSnapshot <snapshot>-maqpna |
Gateway annotations maqpna.com/last-activity, maqpna.com/result, maqpna.com/tool-pins, maqpna.com/taints |
Idle suspension, status.outcome, MCPServer pin status, snapshot taints |
Pods labelled maqpna.com/session (leader only) |
ConfigMap maqpna-usage-nodes, metric maqpna_billable_nodes |
Reconcilers are registered in this order: AgentSession, Agent, TrustTier, ToolPolicy, ModelRoute, MCPServer, A2A, AgentRevocation, Budget, AgentSessionSnapshot, MemoryStore, Tenant, SovereigntyPolicy. Every aggregating reconciler validates each object first: an invalid one is left out of the rendered document with Ready=False, so one bad object cannot make the gateway reject the whole bundle.
How a session is reconciled#
- On first sight the session becomes
Pendingand gets the finalizermaqpna.com/cleanup. - The operator loads the
Agentand theTrustTier(AgentNotFound,TierNotFoundfail the session). - It resolves the principal:
status.principal{user, groups, verifiedBy}from--principal-binding, or a verified OIDC ID token fromspec.userAssertionRef. - It checks the agent against the
defaultSovereigntyPolicy (SovereigntyViolationin enforce mode). - It checks that the requested scopes are a subset of the agent's (
ScopeEscalation), addingmodels:<route>when the agent has a model. - It clamps the TTL to the tier and agent maximums and computes
expiresAt; an expired session is torn down andCompleted. - It applies governance: a failed attestation (
AttestationFailed), a matching revocation (terminate, suspend or block) and concurrency quotas (QuotaExceeded, oldest first). - It validates
spec.inputand resolves a fork. - It gets credentials: an attested release (tier-2), nothing (warm-pool claim, the broker mints at bootstrap), or a token from
POST /v1/token, re-minted at 80% of its lifetime. - It creates the input Secret, workspace,
SandboxorSandboxClaim, then the NetworkPolicy, and sets the phase from the sandbox's conditions.
The full flow, with the state diagram, is in session lifecycle.
Configuration#
Flags of cmd/maqpna-operator (Helm sets them from operator.*, gateway.*, identity.* and attestation.*):
| Flag | Default | Purpose |
|---|---|---|
--broker-url |
http://maqpna-identity.maqpna-system.svc:8081 |
Identity broker |
--attest-url |
http://maqpna-attest.maqpna-system.svc:8082 |
Attestation service |
--attest-agent-image, --attest-response-pubkey-file, --attest-tsm-host-path |
ghcr.io/maqpna/maqpna-attest-agent:latest, —, off |
tier-2 init and renewer containers |
--gateway-url |
http://maqpna-gateway.maqpna-system.svc:8080 |
Injected into sandboxes as MAQPNA_GATEWAY_URL |
--gateway-namespace |
maqpna-system |
Where rendered ConfigMaps live; revocations there are cluster-wide |
--sandbox-api-version |
v1beta1 |
Upstream agent-sandbox API version |
--watch-sandboxes |
true |
Watch the upstream kinds |
--warmpool-namespace |
default |
Default namespace for warm pools |
--default-session-ttl, --token-ttl |
1h, 15m |
Session and token lifetimes |
--bootstrap-audience, --bootstrap-port |
maqpna-bootstrap, 8083 |
Warm-pool late binding |
--principal-binding |
off |
off, requester or trustedCreators |
--user-oidc-issuer, --user-oidc-audience, --user-oidc-jwks |
— | Verify spec.userAssertionRef ID tokens |
--mcpserver-shared-namespaces |
any | Namespaces whose MCPServers may be shared |
--upstream-credential-resync |
1m |
Re-read credential Secrets for rotation |
--spire-workload-registration, --spire-trust-domain |
false, — |
SPIRE ClusterSPIFFEID labels |
--sandbox-snapshot-api |
— | Pod snapshot API for forks |
--tenant-trust-domain-suffix |
maqpna.local |
Default tenant trust domain suffix |
--license-file, --node-count-interval |
—, 1m |
Licence reporting, billable node counting |
--usage-report-url, --usage-report-token-file |
—, /var/run/secrets/maqpna/usage/token |
Report sandbox time to the gateway |
--leader-elect |
false |
Lease maqpna-operator.maqpna.com |
--session-workers, --kube-api-qps, --kube-api-burst |
8, 50, 100 |
Throughput |
--metrics-bind-address, --health-probe-bind-address |
:8080, :8081 |
Metrics and probes |
Environment: MAQPNA_BROKER_TOKEN, the bearer for broker and attestation calls. The manager caches only operator-labelled Secrets and ConfigMaps in the gateway namespace; other Secrets (MCP server credentials, model API keys) are read uncached.
Failure modes#
| Failure | Effect |
|---|---|
| Operator down | Running sessions keep running and keep their tokens until expiry; new sessions wait; token re-minting at 80% stops, so tokens can expire before the session does; rendered ConfigMaps keep their last content |
| Identity broker unreachable | MintFailed event; the session stays Provisioning and is retried |
| Attestation service unreachable | Release registration retried; outages do not fail the session |
| agent-sandbox not installed | Sandbox creation fails; maqpna preflight checks for it (agent-sandbox) |
| RuntimeClass missing | RuntimeClassAvailable=False on the tier; maqpna doctor reports it |
Invalid ToolPolicy or MCPServer |
Left out of the rendered document with Ready=False (InvalidPolicy) or a specific reason |
| Rendered ConfigMap approaching 1 MiB | maqpna_rendered_configmap_bytes, alert MaqpnaConfigMapNearLimit |
Scaling#
- Leader election (
--leader-elect, added by the chart whenoperator.replicas > 1) makes one replica active;values-production.yamlruns two. --session-workers(8) sessions reconcile in parallel; quota admission stays serialised.- The licence watcher runs on every replica; the node counter runs on the leader only.
Metrics#
maqpna_session_ready_seconds{tier,mode}, maqpna_sessions{namespace,tier,phase}, maqpna_session_phase_transitions_total{from,to,reason}, maqpna_session_outcomes_total{tier,result}, maqpna_token_mint_seconds, maqpna_warm_pool_ready{tier}, maqpna_reconcile_errors_total{controller,reason}, maqpna_reconcile_duration_seconds{controller}, maqpna_rendered_configmap_bytes{name}, maqpna_billable_nodes{period}, maqpna_license_state, maqpna_license_days_left, maqpna_license_node_limit and maqpna_build_info. See observability.
What you see#
maqpna status shows the operator next to the other workloads (format from cmd/maqpna/status.go; values illustrative):
Release maqpna in maqpna-system: deployed, revision 2, chart maqpna-0.1.0, app 0.1.0, updated 2026-10-02T14:05:09Z
REVISION STATUS CHART APP UPDATED DESCRIPTION
1 superseded maqpna-0.1.0 0.1.0 2026-10-01T09:12:44Z maqpna install 0.1.0
2 deployed maqpna-0.1.0 0.1.0 2026-10-02T14:05:09Z Upgrade complete
WORKLOAD COMPONENT READY IMAGE
deployment/maqpna-gateway gateway 1/1 ghcr.io/maqpna/maqpna-gateway:0.1.0
deployment/maqpna-identity identity 1/1 ghcr.io/maqpna/maqpna-identity:0.1.0
deployment/maqpna-operator operator 1/1 ghcr.io/maqpna/maqpna-operator:0.1.0
CRDs: 13 maqpna.com Sessions: Completed=12 Running=4
Gateway http://127.0.0.1:8080: ready=true pendingApprovals=1 revocations=0 tainted=2 auditHead=4711 verified=true licence=valid
The line formats are fixed in the code; the values are illustrative. Session events (maqpna events SESSION) carry the operator's reasons: Accepted, TokenMinted, TokenRefreshed, ReleaseRegistered, SandboxCreated, TTLClamped, Suspending, Resumed, Expired, Completed, and the warnings ScopeEscalation, SovereigntyViolation, Revoked, QuotaExceeded, AttestationFailed. See maqpna status and maqpna events.