MAQPNADocs

Hyperscaler interop

Push MAQPNA policies into AWS Bedrock AgentCore Policy, and pull AWS CloudTrail, OpenAI and Anthropic audit events into a ledger as evidence of what ran outside the gateway.

The MAQPNA gateway governs every call that passes through it. Some agent traffic does not: an agent that calls Bedrock directly, AgentCore's own Code Interpreter, or an admin who changes API keys in a provider console. The gateway refuses provider-hosted tools (reasons provider_hosted_tool and provider_hosted_mcp), because they run at the provider, outside its egress, data loss prevention (DLP) and audit checks. MAQPNA covers the rest from both sides:

  • Push. maqpna policy push --to agentcore writes your MAQPNA policies into an AWS Bedrock AgentCore policy engine and keeps them reconciled. AgentCore then enforces the same decisions on traffic MAQPNA never sees.
  • Pull. maqpna audit import reads the providers' own audit events (AWS CloudTrail, the OpenAI organization audit log, the Anthropic Compliance API) into a ledger as evidence. Events that show a provider-hosted tool in use are reported as unmediated.
flowchart LR
    P["MAQPNA policies<br/>ToolPolicy / bundle"] --> C["maqpna policy push<br/>--to agentcore"]
    C -->|"Create / Update / DeletePolicy"| E["AgentCore<br/>policy engine"]
    E --> G["AgentCore gateway<br/>enforces"]
    CT["CloudTrail"] --> I["maqpna audit import"]
    OA["OpenAI audit log"] --> I
    AN["Anthropic Compliance API"] --> I
    I --> L["imports ledger"]
    L --> EV["maqpna evidence generate<br/>--imports"]

What is supported#

Platform Push policy Pull audit Model calls through the gateway
AWS Bedrock AgentCore Yes, AgentCore Policy (Cedar) Yes, CloudTrail Yes, Bedrock route
OpenAI No Yes, organization audit log Yes
Anthropic No Yes, Compliance API activity feed Yes
Azure (OpenAI, Foundry) No No Yes, Azure OpenAI route
Google (Vertex AI, Gemini) No No Yes, Vertex AI route

MAQPNA has no push or pull integration for the Azure or Google agent platforms. Route their model calls through the gateway instead: see Connect model providers.

Prerequisites#

  • The maqpna CLI.
  • Your policies as ToolPolicy files or a policies.json bundle. See Write and test policies.
  • For the push: an AgentCore gateway and policy engine, and a gateway manifest (step 1).
  • AWS credentials in the environment, in this order: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (development), IRSA (AWS_ROLE_ARN and AWS_WEB_IDENTITY_TOKEN_FILE, with AWS_REGION), or EKS Pod Identity or ECS container credentials (AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI). Shared profiles (AWS_PROFILE, ~/.aws/config) are not read.
  • For OpenAI imports: an admin key. For Anthropic imports: a Compliance Access Key, or an Admin API key with read:compliance_activities.

Push policy to AgentCore#

Step 1: Write the gateway manifest#

AgentCore knows tools by gateway target, not by MAQPNA server. The manifest maps each MAQPNA server to an AgentCore target, with each tool's input schema. This is the start of examples/integrations/agentcore/gateway-manifest.json:

{
  "gatewayArn": "arn:aws:bedrock-agentcore:eu-west-1:123456789012:gateway/maqpna-coder",
  "approvalAsDeny": true,
  "principal": {"namespaceTag": "maqpna_ns", "agentTag": "maqpna_agent", "groupsTag": "maqpna_groups"},
  "targets": [
    {"server": "github", "target": "GitHub", "tools": [
      {"name": "get_file_contents", "inputSchema": {"type": "object",
        "properties": {"owner": {"type": "string"}, "repo": {"type": "string"}, "path": {"type": "string"}},
        "required": ["owner", "repo", "path"]}}
    ]}
  ]
}

AgentCore has no approvals. approvalAsDeny: true compiles require_approval rules as denials; without it they are refused. The full manifest format is in Policy export.

Step 2: Compile and read the plan#

The push compiles your policies exactly as maqpna policy compile --to agentcore does: one Cedar statement per AgentCore policy, or an error naming the rule AgentCore cannot express (session taints, the substrate, when, schedule and others). Without --apply, the push is a dry run:

maqpna policy push --to agentcore --manifest gateway-manifest.json \
  --engine <policy-engine-id> policies/

The push lists every policy in the engine, then plans create, update, delete, unchanged or conflict for each, with the SHA-256 of each statement. It also reads the AgentCore gateway named in the manifest and warns if its policy engine configuration does not name your engine. Policies in an unassociated engine are stored but not enforced.

Flag Default What it does
--to — Target. Only agentcore.
--manifest — The gateway manifest.
--engine — The AgentCore policy engine ID.
--owner default Owner label. Several installations can share one engine with different owners.
--apply off Execute the plan.
--wait off With --apply: wait for each phase to be ACTIVE or deleted.
--wait-timeout 5m With --wait: time allowed per phase.
--ledger FILE — With --apply: append one audit record per change.
--enforcement-mode AgentCore's (ACTIVE) ACTIVE or LOG_ONLY for the pushed policies.
--region the gateway ARN's, then AWS_REGION AWS region.
--endpoint https://bedrock-agentcore-control.<region>.amazonaws.com Control-plane URL.
--namespace default Namespace of ToolPolicies without metadata.namespace.

The full flag list is on maqpna policy push.

Step 3: Apply#

maqpna policy push --to agentcore --manifest gateway-manifest.json \
  --engine <policy-engine-id> policies/ --apply --wait --ledger push-ledger.jsonl

The push runs four phases, tightening first, so the engine is never looser part-way through than both the old and the new policy set:

  1. New and changed forbid statements.
  2. Removed permit statements.
  3. New and changed permit statements.
  4. Removed forbid statements.

Every change in a phase is attempted. If any fails, the later phases are skipped and the command exits non-zero. Throttling (429) and server errors (5xx) are retried with backoff.

The AWS identity needs bedrock-agentcore:ListPolicies, GetPolicy, CreatePolicy, UpdatePolicy, DeletePolicy and GetGateway. The push never changes the gateway itself. Associate the engine with the gateway yourself, in the AWS console or with the AWS CLI.

Step 4: Verify#

Run the same push again. Every policy is unchanged:

maqpna policy push --to agentcore --manifest gateway-manifest.json --engine <policy-engine-id> policies/ -o json

With -o json you get the plan (each change with statementSha256 and previousSha256), the outcomes, the gateway association and the warnings. With --ledger, each change is an audit record: server policy-push/agentcore, tool create, update or delete, decision observe, and the ext fields agentcoreEngine, agentcorePolicy, agentcorePolicyId and pushResult.

How ownership works#

The push only changes policies it owns. A policy belongs to an owner when its name starts with maqpna_ and its description starts with the owner's marker:

[maqpna owner=default sha256=<statement sha256>] coder-policy/github-read: Reads are fine.

Every other policy in the engine is foreign: it is counted and never updated or deleted. A wanted name already taken by a foreign policy is a conflict. So is a MAQPNA policy in CREATE_FAILED, UPDATE_FAILED or DELETING.

A name is maqpna_, the <policy>/<rule> ID cut to 32 characters, then 8 hex digits of a SHA-256 over owner and ID: at most 48 characters. Reordering rules does not rename the others.

Pull provider audit events#

Step 1: Import#

Use a dedicated imports ledger. Only one process may append to a ledger file, so never point it at a ledger a running gateway writes.

# LookupEvents API, region from AWS_REGION or --region
maqpna audit import --source cloudtrail --ledger imports.jsonl

# CloudTrail log files synced from S3 (.json, .json.gz), including data events
maqpna audit import --source cloudtrail --ledger imports.jsonl ./AWSLogs/
export OPENAI_ADMIN_KEY=<your-openai-admin-key>
maqpna audit import --source openai --ledger imports.jsonl
export ANTHROPIC_COMPLIANCE_ACCESS_KEY=<your-compliance-key>
maqpna audit import --source anthropic --ledger imports.jsonl
Source API What it shows
cloudtrail LookupEvents, one request per event source (default bedrock.amazonaws.com and bedrock-agentcore.amazonaws.com) Management events of the last 90 days in one region
cloudtrail with files CloudTrail log files ({"Records": [...]}) Everything the trail logs, including data events. --event-source '*' imports every source.
openai GET /v1/organization/audit_logs User actions and configuration changes (API keys, projects, members). Not model calls.
anthropic Compliance API GET /v1/compliance/activities Authentication, chat, file, project, administrative and platform activity

The command prints how many events it imported, how many were already recorded and how many were malformed, then any unmediated events in a table with the columns SEQ, EVENT TIME, ACTION, TOOLS, ACTOR and REFUSED BY GATEWAY. The last column counts how often the gateway refused the same tool: the same thing, done outside the gateway.

Useful flags: --since and --until (RFC 3339, or a duration ago such as 72h), --dry-run, --namespace and --agent to attribute events to a MAQPNA system, --raw-dir DIR to keep each raw event as DIR/<source>/<sha256>.json, --type to filter OpenAI event or Anthropic activity types, and --key-env to read the key from another variable. See maqpna audit import.

Step 2: Run it on a schedule#

Imports are incremental and safe to repeat:

  • Dedupe by event ID. Events whose provider ID the ledger already holds are skipped.
  • Cursor. <ledger>.import-<source>.json (--state) records the end of the last complete window. The next window starts there minus --overlap (default 15 minutes). The first window is --lookback (default 24 hours). Log-file imports have no window and no cursor.
  • All or nothing per window. Every page is fetched before anything is appended. An error, or more than --max-events (default 50,000) events, appends nothing and leaves the cursor in place.

The gateway has no background importer. Run the command from cron or a Kubernetes CronJob.

Step 3: Use the imports as evidence#

maqpna evidence generate --framework eu-ai-act --system namespace:team-a --period 2026-Q4 \
  --ledger audit.jsonl --imports imports.jsonl --key <checkpoint-key-uri>

Imported records are never MAQPNA decisions. Each has decision observe, server import/<source>, reason imported:<source> (plus unmediated:<tools> when a hosted tool ran), and ext fields such as importedEventId, importedActor and importedRawSha256. Evidence packs list them only under External observations and in workpapers/external-observations.csv. They are left out of decision counts, approvals, tool inventory, AI-BOM, cost and FOCUS exports. See Generate a compliance evidence pack.

What counts as unmediated#

The import flags an event when its raw content shows what the gateway itself would refuse:

  • a tools entry whose type is a provider-hosted tool, such as web_search_20250305 or code_interpreter;
  • Gemini and Bedrock tool keys such as googleSearch, codeExecution and systemTool;
  • provider-hosted MCP (mcp_servers, or tools of type mcp or mcp_toolset);
  • for CloudTrail, AgentCore's built-in tools: StartCodeInterpreterSession and InvokeCodeInterpreter as code_interpreter, StartBrowserSession and ConnectBrowserAutomationStream as browser.

Limits#

  • AgentCore only for push. Only AgentCore Policy (Cedar). The push checks the gateway association but does not set it.
  • What providers log. Most providers log no request bodies, so a hosted tool used inside a model call shows up only where the log carries the request (for example CloudTrail data events).
  • CloudTrail is one region per run. Reading log files straight from S3 is not built: sync them first with aws s3 sync.
  • Late events. API imports miss events delivered later than --overlap.
  • Import time, not event time. An imported record falls in the evidence period it was imported in. The workpaper gives the provider's event time.

Troubleshooting#

Symptom Cause and fix
cloudcreds: no credentials found for AWS No AWS credentials found. Set IRSA, Pod Identity or the access-key variables.
IRSA needs AWS_REGION Set AWS_REGION for the regional STS endpoint.
Warning: gateway ... is not associated with policy engine The policies are stored but not enforced. Associate the engine with the AgentCore gateway.
Plan shows conflict A foreign policy holds the name, or a MAQPNA policy is in a failed or deleting state. Fix it in AgentCore, then push again.
ConflictException on apply Another request is changing the policy. Push again.
Compile error naming a rule AgentCore cannot express that rule. Change it, or set approvalAsDeny for approval rules.
audit import: set OPENAI_ADMIN_KEY ... The key variable is empty. Export it, or name another one with --key-env.
Window refused for too many events Narrow it with --until, or raise --max-events.

Next steps#