MAQPNADocs

Cloud profiles

Per-cloud Helm profiles for EKS, GKE, AKS, OpenShift and RKE2, cloud-native WORM and SIEM sinks, FQDN egress policies, and the CERT-In, DPDP and EU AI Act compliance profiles.

The chart ships one values profile per platform. Each profile maps the trust tiers to the RuntimeClass names the platform really ships, holds placeholders for cloud workload identity, puts the audit ledger on the platform's default storage class, and shows the cloud's own WORM and SIEM sinks. Layer a profile after values-production.yaml:

helm upgrade --install maqpna deploy/helm/maqpna -n maqpna-system --create-namespace \
  -f deploy/helm/maqpna/values-production.yaml -f deploy/helm/maqpna/values-gke.yaml
maqpna values validate -f deploy/helm/maqpna/values-production.yaml -f deploy/helm/maqpna/values-gke.yaml --profile production
Profile tier-0 tier-1 tier-2 Storage class FQDN egress
values-eks.yaml gvisor (chart RuntimeClass, gVisor node group) kata-qemu (kata-deploy on C8i/M8i/R8i nested virtualization) not created gp3 eks
values-gke.yaml gvisor (GKE Sandbox) kata-qemu (kata-deploy, not supported by Google) not created standard-rwo gke
values-aks.yaml kata-vm-isolation (Pod Sandboxing) kata-vm-isolation not created managed-csi cilium (ACNS)
values-openshift.yaml kata (sandboxed containers) kata kata-remote, commented cluster default none (OVN NetworkPolicy)
values-rke2.yaml gvisor (chart RuntimeClass) kata-qemu (kata-deploy) opt-in cluster default cilium (with RKE2's Cilium)

Sandbox runtimes per cloud#

  • AKS. Pod Sandboxing runs each pod in a Kata VM on Cloud Hypervisor, on Azure Linux node pools created with --workload-runtime KataVmIsolation. Pods opt in with runtimeClassName: kata-vm-isolation. Each pod VM gets memory equal to its limit and whole vCPUs, Arm64 and FIPS pools cannot run Kata, and Defender for Containers does not assess Kata pods. Confidential Containers (kata-cc-isolation) are still preview, and their Azure Linux 2.0 images are removed on 2026-10-31. Confidential VM node pools are GA since 2026-06-19, but protect the node, not the pod, so the profile creates no tier-2.
  • EKS. EC2 nested virtualization on C8i, M8i and R8i is GA since 2026-02-16, so Kata no longer needs *.metal instances. gVisor still needs a node group whose launch template or AMI installs runsc. Fargate cannot host sandboxes.
  • GKE. GKE Sandbox and GKE Agent Sandbox create the gvisor RuntimeClass, and MAQPNA renders sessions into the same upstream Sandbox objects. For pod snapshots set operator.sandboxSnapshotApi: podsnapshot.gke.io/v1.
  • OpenShift. OpenShift sandboxed containers provide kata (and kata-remote for peer pods); confidential containers with the Red Hat build of Trustee back tier-2 (maqpna-attest --verifier trustee).
  • RKE2. RKE2 ships neither runtime: install runsc through RKE2's containerd template and Kata with kata-deploy.

Workload identity#

Every component's ServiceAccount takes annotations, and every pod takes extra labels:

Cloud Mechanism Values
EKS Pod Identity (default) none: create a pod identity association for maqpna-gateway
EKS IRSA (AWS Marketplace metering, Fargate, hybrid nodes) gateway.serviceAccount.annotations: {eks.amazonaws.com/role-arn: arn:aws:iam::<account>:role/<role>}
GKE Workload Identity Federation none for a direct principal:// IAM binding, or iam.gke.io/gcp-service-account: <gsa>@<project>.iam.gserviceaccount.com
AKS Entra Workload ID gateway.serviceAccount.annotations: {azure.workload.identity/client-id: <uuid>} and gateway.podLabels: {azure.workload.identity/use: "true"}

The keys are gateway, identity and operator .serviceAccount.annotations, and .podLabels on those plus attestation. The identity broker's ServiceAccount exists when identity.bootstrap.enabled (the default).

The gateway exchanges this identity for cloud credentials itself (pkg/cloudcreds; see Cloud identity & keys). With audit.worm.credentials: aws|gcp|azure the WORM sink, with credentials: aws|azure|gcp a CloudWatch, Sentinel or SecOps SIEM sink, and with no explicit credential a Bedrock, Vertex AI, Azure OpenAI or OCI Generative AI model route use it, and no Secret is mounted. gateway.cloudCredentials tunes the providers (region, IMDS fallback, partition DNS suffix, metadata host).

WORM audit storage#

audit.sink: worm ships sealed ledger segments to a write-once store. audit.worm.provider picks it:

Provider Store Immutability the gateway requires at startup Credentials
s3 S3 Object Lock (AWS, MinIO, Ceph RGW, Scaleway, OVHcloud) GetObjectLockConfiguration returns ObjectLockEnabled: Enabled; every object is written in COMPLIANCE mode with its own retain-until date credentials: aws (EKS Pod Identity / IRSA), or credentialsSecret: access-key, secret-key, optional session-token
gcs Google Cloud Storage a locked retention policy at least as long as the retention (Bucket Lock), or Object Retention Lock (then every object gets a Locked retention) credentials: gcp (GKE Workload Identity Federation), or tokenSecret: OAuth token (devstorage.read_write)
azure Azure Blob Storage version-level immutability support on the container (x-ms-immutable-storage-with-versioning-enabled); every blob gets a Locked x-ms-immutability-policy-until-date credentials: azure (Entra Workload ID), or tokenSecret (Entra token for https://storage.azure.com/.default) or sasSecret

When the check fails the gateway does not start (fail closed). Uploads never replace an object: GCS writes use ifGenerationMatch=0 and Azure writes If-None-Match: *; a crashed leader's identical re-upload is recognised by its MD5 and accepted. audit.worm.objectLockDays sets the retention (default: sovereignty.auditRetentionDays).

# AWS: a bucket with Object Lock
aws s3api create-bucket --bucket acme-maqpna-audit --region eu-central-1 \
  --create-bucket-configuration LocationConstraint=eu-central-1 --object-lock-enabled-for-bucket
# Google Cloud: Bucket Lock (locking is irreversible)
gcloud storage buckets create gs://acme-maqpna-audit --location=europe-west3 --retention-period=3650d
gcloud storage buckets update gs://acme-maqpna-audit --lock-retention-period
# Azure: a container with version-level immutability support
az storage container-rm create --storage-account acmeaudit -n maqpna-audit --enable-vlw

SIEM sinks#

audit.sinks adds cloud-native types next to syslog, http and jsonl:

Type Destination Required fields
cloudwatch CloudWatch Logs PutLogEvents (OCSF messages by default) region, logGroup, optional logStream (created if missing), credentials: aws or awsCredentialsSecret
sentinel Microsoft Sentinel through the Azure Monitor Logs Ingestion API url (data collection endpoint), dcrImmutableId, streamName (Custom-<Table>), credentials: azure or tokenSecret
chronicle Google SecOps: unstructured logs:import or UDM events:import url (instance URL), chronicleMode (logs with logType, or udm), credentials: gcp or tokenSecret
splunk-hec Splunk HTTP Event Collector url (HEC base URL; must be https://, http:// only to a loopback collector, since the HEC token is sent in the Authorization header), tokenSecret, optional index, source, sourceType

Batches are split at each collector's byte and count limits. Authentication errors, throttling (Retry-After) and server errors are retried with exponential backoff without dropping anything; records the collector rejects as malformed or out of range go to <auditPath>.sinks/<name>.deadletter.jsonl (bounded by deadLetterMaxBytes, 64 MiB by default; when it is full, delivery stops instead). maqpna_gateway_audit_sink_dead_lettered_total{sink} counts them.

Amazon Security Lake. MAQPNA does not write Parquet itself. Ship OCSF to CloudWatch Logs with the cloudwatch sink, then add a subscription filter to an Amazon Data Firehose stream that converts the records to Parquet into a Security Lake custom source (OCSF class 6003, API Activity). This keeps the gateway free of a columnar writer and lets Security Lake own partitioning and retention.

Microsoft Sentinel. Create a custom table (for example MaqpnaAudit_CL) and a data collection rule whose stream declares the columns of the json record (TimeGenerated, seq, time, session, namespace, agent, user, server, tool, decision, rule, reason, hash, ext) and grant the identity Monitoring Metrics Publisher on the DCR.

FQDN egress policies#

The gateway is the only component that calls tools, models, WORM and SIEM endpoints; agent sandboxes reach only the gateway. networkPolicy.fqdnEgress mirrors the gateway's own allowlist (sovereignty.allowedEgressHosts and allowedEgressCIDRs, plus extraHosts) into the CNI, so a host the gateway refuses is also dropped in the kernel:

provider Objects Clusters
cilium CiliumNetworkPolicy with toFQDNs (DNS proxy on kube-dns, the whole cluster and the API server allowed) AKS with ACNS, RKE2 with Cilium, any Cilium cluster
gke FQDNNetworkPolicy plus a base NetworkPolicy (DNS, cluster pods, clusterCIDRs) GKE Dataplane V2
eks ApplicationNetworkPolicy with domainNames plus the same base NetworkPolicy EKS Auto Mode, or VPC CNI 1.21.1+ with network policies

In-cluster names (*.svc, *.cluster.local) are skipped because they resolve to cluster IPs. On gke and eks the gateway's egress becomes default-deny, so clusterCIDRs must list the API server endpoint (the chart refuses to render without it while gateway.configSync or gateway.activity is on). Cilium's *.example.com matches one label; list deeper subdomains explicitly.

OpenShift: restricted-v2#

values-openshift.yaml removes the pinned UID/GID/fsGroup 65532 from every pod and sets operator.sandboxRunAsUID: -1 (operator flag --sandbox-run-as-uid=-1), so OpenShift assigns UIDs from the namespace range and every pod, sandboxes included, runs under the default restricted-v2 SCC. No nonroot-v2 grant is needed.

RKE2 and FIPS#

RKE2 can run FIPS 140-3 validated Kubernetes components, but MAQPNA's images are not FIPS builds and contain no validated cryptographic module; in a FIPS cluster record MAQPNA as a non-FIPS workload. ingress-nginx in RKE2 reached end of life in March 2026; the chart creates no Ingress.

Compliance profiles#

compliance.profiles declares the regulatory profiles an installation is meant to meet. The chart refuses to render when a profile's retention floor is not met, maqpna values validate --profile <name> reports the same rules plus warnings, and every pod carries the annotation maqpna.com/compliance-profiles. These are configuration checks, not legal advice.

Profile Checks
cert-in sovereignty.auditRetentionDays and audit.worm.objectLockDays of at least 180 days; a ledger that outlives the pod (WORM, a persistent volume or a SIEM sink); warnings for the time sources and a non-Indian jurisdiction
dpdp sovereignty enabled; a warning below 365 days of retention
eu-ai-act at least 183 days (six months, Art. 19 and 26(6)); values-sovereign-eu.yaml declares it

values-cert-in.yaml is a ready India profile: jurisdiction IN, 365 days, S3 Object Lock in ap-south-1.

CERT-In. The Directions of 28 April 2022 require incident reports within 6 hours, ICT logs kept for 180 days, and clocks synchronised to the NTP servers of NIC or NPL. MAQPNA timestamps every ledger record with the gateway's clock in UTC, so synchronise the nodes: point chrony or systemd-timesyncd at samay1.nic.in, samay2.nic.in and time.nplindia.org (or sources traceable to them) and declare them in compliance.timeSources. For the 6-hour report, export the timeline:

maqpna incident export --gateway "$GW" --since 6h --detected 2026-10-10T07:45:00Z --format md --out incident.md

The export verifies the hash chain over the window, lists denials, approvals, kill-switch and revocation events, DLP and taint hits, and maps them to the fields of the CERT-In report with the deadline. See maqpna incident export.

DPDP. maqpna memory erase --user <subject> deletes a person's entries from every memory store of the gateway's memory backend (the file store, or the PostgreSQL state backend with HA) and returns a signed erasure certificate anchored in the ledger. It does not reach the PostgreSQL/pgvector and OpenSearch memory adapters (documented stubs that store nothing today), the audit ledger itself (records hold the subject identifier and argument hashes, not argument values, and stay immutable by design), copies already shipped to WORM or SIEM, data inside sandboxes or upstream tools, or prompts sent to model providers. Cover those in your retention and erasure procedures.

Reference clusters and the smoke test#

hack/cloud/{eks,gke,aks} are OpenTofu modules for small test clusters with the sandbox node pools, a NetworkPolicy dataplane and workload identity wired to the gateway's ServiceAccount. hack/cloud-smoke.sh <eks|gke|aks> installs MAQPNA with the matching profile and checks that the gateway pod gets cloud credentials with no Secret mounted, that a delete in the WORM bucket is refused by the provider, and that egress to a host outside the allowlist is blocked.