Files
hncb-fusion-deid-demo/fusion/POLICY_SETUP.md
Conan Scott b5de55d4a6 feat(net): custom domain for the Fusion-facing API
Fusion couldn't resolve the default *.execute-api.amazonaws.com endpoint, so front
the same HTTP API with hncb-deid.apim-apac-demo.com (ACM DNS-validated cert,
apigatewayv2 REGIONAL custom domain, root api mapping, Route53 A ALIAS). Callers
resolve our hostname straight to IPs and never touch an execute-api name; also
survives API-id churn. Point POLICY_SETUP + README demo at the custom URLs.

Verified live: resolves to IPs, 401 unauthenticated, tokenizes with the key.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 11:04:19 +10:00

5.4 KiB

Fusion (shared SaaS) policy setup — de-identification as a gateway policy

Fusion (Axway Amplify AI Gateway) is a shared SaaS instance, configured in the console — not deployed by this repo. Here it is the enforcement plane in front of the AgentCore agent: de-identification is a policy on the route, not application code. /tokenize and /restore are the policy's transform backend (they hold the detector + vault on-prem); Fusion applies them inline to traffic.

Why put Fusion in the path at all? Functionally, everything below is an HTTP call — the /demo orchestrator proves a plain client can do the same mechanics. That is the point: the mechanics are not the differentiator. Fusion adds what a plain call cannot:

  • Non-bypassable enforcement — de-id is applied at the gateway to all AI traffic, not trusted to each app to call /tokenize correctly.
  • Central audit — the gateway's own trace is the compliance artifact proving only tokens ever reached the model. (See the money-shot check in the README.)
  • Reuse — one policy governs every model/agent/app behind Fusion; routing, rate-limits, and guardrails come with it.

Drop Fusion and you lose enforcement and audit, not capability.

The policy model

Fusion fronts the AgentCore Runtime as a governed route. Two policies wrap it:

advisor ─▶ [ Fusion route to the agent ]
             │  request policy  (ingress) ── tokenize transform ─▶ /tokenize
             ▼
           AgentCore Runtime  (sees TOKENS only)
             │  response policy (egress)  ── restore transform ──▶ /restore
             ▼
advisor ◀────┘

The transforms run inside the policy boundary; the raw name never crosses it.

Backend the policy calls

Use the custom domain — Fusion could not resolve the default *.execute-api.ap-southeast-1.amazonaws.com endpoint, so the API is fronted by a Route53-aliased name that resolves straight to IPs (see terraform/custom_domain.tf).

  • TOKENIZE_URL = https://hncb-deid.apim-apac-demo.com/tokenizeterraform -chdir=terraform output -raw tokenize_url_custom
  • RESTORE_URL = https://hncb-deid.apim-apac-demo.com/restoreterraform -chdir=terraform output -raw restore_url_custom
  • AGENT_RUNTIME_ARN (the route's upstream) = printed by scripts/agentcore_setup.sh
  • Auth: public API Gateway HTTP API; send the shared secret in the x-api-key header (Authorization: Bearer <secret> also works). The secret is the Terraform tokenize_api_key var (gitignored terraform/local.auto.tfvars, never committed) — hand it to the console operator out of band.
    • Note: the raw …execute-api… URLs (output -raw tokenize_url / restore_url) still work for anything that can resolve them; Fusion should use the custom domain.
    • Note: a Lambda Function URL was the first choice, but this account's SCP blocks unauthenticated Function URLs, so the public front door is API Gateway.

Request policy — ingress (prompt bound for the agent)

Applied to every request on the route; the app cannot skip it.

  1. AuthN / RBAC / business-purpose check (Fusion native).
  2. Tokenize transform: POST { query }TOKENIZE_URL{ deidentified_prompt, session_id }. The endpoint runs detect → mint → vault-write → splice (typed findings, never a redacted blob). Replace the outbound prompt with deidentified_prompt; carry session_id as policy/session context.
  3. Forward to the AgentCore upstream with { "prompt": deidentified_prompt } — tokens only.
  4. Audit: record the tokenized payload; the raw query never leaves the policy.

Response policy — egress (agent's answer)

Applied to every response on the route.

  1. Restore transform: POST { session_id, text }RESTORE_URL{ final } (vault lookup scoped to this session; re-attaches identity at the envelope and swaps any inline tokens).
  2. Return { "final": ..., "deidentified_prompt": ... } so the UI renders the restored-vs-tokenized split view.

Vault item shape (DynamoDB, written by the tokenize transform)

One row per detected entity. value is the original PII (so restore can put it back); a resolvable PERSON also gets a customer_id so the RAG tool can turn the token into a de-identified evidence package.

{ "token": "CUST_863651", "type": "PERSON",    "value": "王小明",
  "session_id": "<session>", "expires_at": <epoch+ttl>, "customer_id": "cust-0001" }
{ "token": "TW_683250",   "type": "TW_ROC_ID", "value": "A123456789",
  "session_id": "<session>", "expires_at": <epoch+ttl> }

(The seed's --with-demo-token writes a different type=CUSTOMER, value=cust-0001 row; that's only a standalone RAG test aid, not what the tokenize transform mints.)

Fusion vs. the /demo orchestrator (be honest on camera)

gateway_api/orchestrator/ (/demo) runs the identical tokenize → agent → restore mechanics over plain HTTP, so the Fusion-less demo works end to end. Show that to prove the data-flow. Then make the governance point: only Fusion turns those mechanics into a mandatory, audited policy across all AI traffic — the enforcement boundary an app-level HTTP call can't guarantee.

Not automated here: Fusion is shared SaaS and configured by a human in the console. This file is the spec for that configuration.