MAQPNADocs

Security hardening checklist

Every posture check maqpna doctor runs, what it protects against and the value that fixes it, plus the hardening steps outside the checks.

maqpna doctor and the gateway's GET /v1/posture report every item below as pass, warn, fail, info, skip or accepted. An installation made from the prod profile (values-production.yaml), with every CHANGE-ME replaced, has no failed check. Work through this page before you let agents act on production systems.

flowchart LR
  A[maqpna doctor --offline<br/>--config gateway.json] --> B[Fix values]
  B --> C[maqpna values validate<br/>--profile production]
  C --> D[maqpna upgrade]
  D --> E[maqpna doctor --strict]
  E -->|warn or fail| B
  E -->|pass| F[Record accepted risks]

Goal#

maqpna doctor --strict exits 0, and every accepted risk is written down with a reason.

Prerequisites#

  • An installation, or the gateway configuration you plan to deploy.
  • An admin or auditor token for GET /v1/posture (doctor's gateway checks).

Steps#

1. Check a configuration before you deploy it#

maqpna doctor --offline evaluates a gateway configuration file without a gateway or a cluster. Real output for a minimal configuration with static admin token, file state and no DLP:

$ maqpna doctor --offline --config gateway.json
STATUS  CHECK                     COMPONENT  DETAIL
FAIL    admin-auth-mode           gateway    adminAuth.mode=token
          fix:                               set adminAuth.mode: oidc (Helm adminAuth.mode) so approvers come from verified tokens; the static token is for dev/bootstrap only
WARN    audit-failure-policy      audit      auditFailurePolicy=open
          fix:                               set auditFailurePolicy: closed (Helm gateway.auditFailurePolicy: closed)
WARN    state-backend             state      stateBackend.type=file
          fix:                               set state.backend: postgres and gateway.replicas >= 2 for HA (docs/state-backend.md)
WARN    audit-signed-checkpoints  audit      no auditCheckpointKey (MAQPNA_AUDIT_HMAC_KEY unknown offline)
          fix:                               set audit.checkpointSigning.enabled: true with a Secret holding audit-signing.pem (Ed25519)
WARN    dlp-default-profile       gateway    dlp.defaultProfile=(unset)
          fix:                               define a profile under dlp.profiles and set dlp.defaultProfile
WARN    admin-listen              gateway    adminListen=(unset: admin API on the agent-facing listener)
          fix:                               set gateway.config.adminListen (e.g. ":9090") and expose it only to operators
WARN    tls-svid                  gateway    tls off, svidMode=off
          fix:                               enable spire and gateway.tls with svidMode: required so a stolen token is useless outside its sandbox
WARN    static-upstreams          gateway    static upstreams: echo
          fix:                               register MCP servers as MCPServer objects (per namespace, hot-reloaded) and remove gateway.config.upstreams
INFO    guards-fail-mode          gateway    no injection classifier guards configured
          fix:                               configure gateway.guards (F-29) for tool results from untrusted sources
INFO    sovereignty-policy        gateway    no SovereigntyPolicy: upstream egress is not residency-checked
          fix:                               enable sovereignty (Helm sovereignty.enabled) when data residency matters
PASS    otel-residency            gateway    span export off (propagation only)
PASS    budget-currency           gateway    currency USD
SKIP    admin-break-glass-token   gateway    covered by admin-auth-mode
SKIP    audit-worm-sink           audit      MAQPNA_AUDIT_SINK unknown (offline)
SKIP    cedar-engine              gateway    unknown offline
SKIP    capture-key-custody       gateway    captureArgs disabled
SKIP    token-vault-issuers       identity   tokenVault disabled
SKIP    license                   license    licence state unknown (offline config)

score 26/100: 1 fail, 7 warn, 2 pass, 2 info, 6 skip, 0 accepted

It exits 3 because a check failed. maqpna config validate gateway.json --strict checks the same file's syntax, references and gateway rules.

2. Validate the Helm values#

maqpna values validate --chart ./maqpna -f my-values.yaml --profile production

The production rules make these errors: the echo test MCP server enabled, identity.key.mode: generate, and attestation.verifier: sample.

3. Check the running installation#

maqpna doctor -n maqpna-system --strict

--strict exits 3 on warnings too. Accept a known risk with --accept ID,... for one run, or permanently for gateway checks with gateway.config.posture.accept: [<id>].

The checklist#

Severity is the impact when the check does not pass: fail blocks production, warn is weaker than the production profile, info is advisory.

Admin access and approvals#

Check Severity Fix
admin-auth-mode: admin API authenticated with OIDC fail adminAuth.mode: oidc, so approvers come from verified tokens.
admin-break-glass-token: static admin token only as audited break-glass warn Keep the break-glass token sealed and rotated, or set adminAuth.breakGlassToken.enabled: false.
admin-listen: admin API on a separate listener warn gateway.config.adminListen: ":9090", reachable only by operators.

Audit ledger#

Check Severity Fix
audit-failure-policy: calls refused when the audit record cannot be written fail gateway.auditFailurePolicy: closed.
audit-signed-checkpoints: checkpoints signed with a customer-held key fail audit.checkpointSigning.enabled: true (Ed25519) and keep audit.hmacCheckpoints: true.
audit-worm-sink: ledger shipped to write-once storage (WORM) warn audit.sink: worm with audit.worm.endpoint, bucket, credentialsSecret (needs sovereignty.enabled).

State and availability#

Check Severity Fix
state-backend: shared state backend for HA replicas fail state.backend: postgres, or one gateway replica.
gateway-replicas-state: gateway replicas share state fail Same as above (cluster check).

Data protection and injection#

Check Severity Fix
dlp-default-profile: a DLP default profile applies to all traffic warn Define a profile under dlp.profiles and set dlp.defaultProfile.
guards-fail-mode: injection guards fail closed warn failOpen: false on every gateway.guards[] entry.
capture-key-custody: argument-capture key in a KMS or HSM warn gateway.captureArgs.keyURI with kms:// or pkcs11:.
token-vault-issuers: token vault bound to verified users of one identity provider fail Keep delegation.tokenVault.allowUnverifiedPrincipal: false; use a kms:// or pkcs11: key.

Identity and workload binding#

Check Severity Fix
identity-key-mode: identity signing key persistent and customer-held fail identity.key.mode: existingSecret (synced from your HSM or KMS) or helm.
tls-svid: agent tokens bound to workload certificates (mTLS) warn spire.enabled: true and gateway.tls with svidMode: required, so a stolen token is useless outside its sandbox.

Policies, MCP servers and engines#

Check Severity Fix
cedar-engine: Cedar policies have an engine fail Use the release images (built with Cedar) or remove spec.cedar.
static-upstreams: no deprecated static upstreams warn Register MCP servers as MCPServer objects and remove gateway.config.upstreams.
budget-currency: budgets and metering use one currency fail Set budgetCurrency to the pricing table's currency.

Sovereignty and residency#

Check Severity Fix
sovereignty-policy: sovereignty policy enforced at the gateway warn sovereignty.enforcement: enforce.
cluster-sovereignty-policy: sovereignty policy enforced at admission warn sovereignty.enforcement: enforce.
otel-residency: trace export stays in jurisdiction warn Export only to collectors in sovereignty.telemetryEndpoints, or an in-cluster collector.

Cluster and sandboxes#

Check Severity Fix
crd-installed: MAQPNA CRDs installed and served fail Apply the chart's CRDs (maqpna upgrade does it).
crd-schema-current: installed CRDs match this release fail Same. Helm never upgrades CRDs.
runtimeclass-per-tier: every trust tier has its RuntimeClass fail Install the node runtime and enable its RuntimeClass, or remove the tier.
networkpolicy-default-deny: agent namespaces are default-deny warn networkPolicy.agentNamespaces.enabled, label agent namespaces maqpna.com/agent-namespace=true, use an enforcing CNI.

Attestation (tier-2)#

Check Severity Fix
attest-verifier: attestation uses a hardware verifier fail attestation.verifier: trustee. The sample verifier accepts forgeable dev evidence.
attest-response-signing: attestation responses are signed fail attestation.responseSigning.enabled: true with a Secret holding key.pem and pub.pem.

Licence#

Check Severity Fix
license: commercial licence warn maqpna license install FILE -n <namespace>. A licence never blocks agent traffic.
license-node-limit: billable nodes within the licence limit warn Extend the licence's node limit, or run sandboxes on fewer nodes.

Hardening outside the checks#

  • Pin images by digest (image.digest) after you verify them (Verify releases).
  • Keep the hardened pod defaults. Every pod runs as UID 65532, non-root, read-only root filesystem, no capabilities, RuntimeDefault seccomp. Override per component only if you know why.
  • Bind session principals. principalBinding.mode: requester makes spec.user equal to the Kubernetes user who created the session, unless that user is a trusted creator (for example a portal ServiceAccount).
  • Map roles to stable identifiers. Role mapping uses claims such as username and email; prefer user:<sub> entries and a separate identity provider per tenant on shared installations.
  • Limit approval previews. approvals.preview.mode: redacted (the default) masks obvious secrets; hash or none shows approvers less.
  • Narrow egress allow-lists. The egress proxy sees only the CONNECT host; avoid shared-CDN host names in sovereignty.allowedEgressHosts and browser allow-lists.
  • Rate-limit public routes at your ingress, in particular /v1/connect/* (consent flows for connected accounts).
  • Raise maxScanBytes deliberately. DLP denies content over maxScanBytes by default when the direction redacts or denies; set onOversize: audit only when you accept unscanned content.
  • Back up and rotate keys on a schedule (Backup, restore and DR).

Troubleshooting#

Symptom Cause Fix
doctor: no admin token: GET /v1/posture needs the auditor or admin role No admin credential for the gateway checks maqpna login, or pass --oidc-token-file.
doctor reports skip for many checks Offline mode cannot see Secrets or environment variables Run doctor against the installation for the final check.
cedar-engine fails A gateway image built without Cedar Use the release images; a build without Cedar denies Cedar policies (fail closed).

Next steps#