docs: reframe POLICY_SETUP as a Fusion de-id policy

Position /tokenize + /restore as the transform backend of an inline request/
response policy on the route to the AgentCore agent, with Fusion as the
non-bypassable enforcement + audit point — rather than a manual HTTP
orchestrator. Adds an honest Fusion-vs-/demo governance note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 18:26:18 +10:00
parent acaf145903
commit 2443e0e6f3

View File

@@ -1,55 +1,89 @@
# Fusion (shared SaaS) policy setup (steps 2, 3-route, 8) # Fusion (shared SaaS) policy setup — de-identification as a gateway policy
Fusion is a **shared SaaS instance** configured in the Amplify AI Gateway Fusion (Axway Amplify AI Gateway) is a **shared SaaS instance**, configured in the
console, not deployed by this repo. Because it's SaaS it **cannot reach private console not deployed by this repo. Here it is the **enforcement plane** in front
VPC resources or use local AWS creds**, so it does not call Presidio or DynamoDB of the AgentCore agent: de-identification is a **policy on the route**, not
directly. Instead it calls two **public HTTPS endpoints** this repo exposes application code. `/tokenize` and `/restore` are the policy's **transform backend**
(built in `gateway_api/`, tasks T1/T2), which do the detection, minting, vault (they hold the detector + vault on-prem); Fusion applies them inline to traffic.
writes, and restore on the AWS side. Fusion owns the orchestration and routing.
## Endpoints Fusion calls > **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
- `TOKENIZE_URL` = `https://<api-id>.execute-api.<region>.amazonaws.com/tokenize` - `TOKENIZE_URL` = `https://<api-id>.execute-api.<region>.amazonaws.com/tokenize`
(ingress: detect + mint + vault-write + splice). Get the live value with `terraform -chdir=terraform output -raw tokenize_url`
`terraform -chdir=terraform output -raw tokenize_url`. - `RESTORE_URL` = `https://<...>/restore``terraform ... output -raw restore_url`
- `RESTORE_URL` = `https://<...>/restore` (egress: vault lookup + re-attach identity — T2) - `AGENT_RUNTIME_ARN` (the route's upstream) = printed by `scripts/agentcore_setup.sh`
- `AGENT_RUNTIME_ARN` (or its HTTPS invoke endpoint) = printed by `scripts/agentcore_setup.sh` - **Auth:** public API Gateway HTTP API; send the shared secret in the **`x-api-key`**
- **Auth (T1, live):** the endpoint is a public API Gateway HTTP API; it requires a header (`Authorization: Bearer <secret>` also works). The secret is the Terraform
shared secret in the **`x-api-key`** header (a `Authorization: Bearer <secret>` `tokenize_api_key` var (gitignored `terraform/local.auto.tfvars`, never committed) —
header also works). Configure Fusion's outbound request to send it. The secret is hand it to the console operator out of band.
the Terraform `tokenize_api_key` var (kept in gitignored `terraform/local.auto.tfvars`,
never committed) — hand it to the Fusion console operator out of band.
- *Note:* a Lambda Function URL was the first choice, but this account's SCP blocks - *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 instead. unauthenticated Function URLs, so the public front door is API Gateway.
## Ingress policy (advisor request → cloud) ## Request policy — ingress (prompt bound for the agent)
1. **Authenticate** the advisor; apply the RBAC / business-purpose check. Applied to every request on the route; the app cannot skip it.
2. **Tokenize**: POST `{ query }` to `TOKENIZE_URL`. Receive 1. **AuthN / RBAC / business-purpose** check (Fusion native).
`{ deidentified_prompt, session_id }`. (The endpoint runs detect → mint → 2. **Tokenize transform:** `POST { query }``TOKENIZE_URL` → `{ deidentified_prompt,
vault-write → splice; detection returns typed findings, never a redacted blob.) session_id }`. The endpoint runs detect → mint → vault-write → splice (typed
3. **Route**: invoke the agent with `{ "prompt": deidentified_prompt }`. findings, never a redacted blob). **Replace** the outbound prompt with
4. **Trace**: log the **tokenized** payload only — never the raw query. `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.
## Egress policy (cloud response → advisor) ## Response policy — egress (agent's answer)
1. Receive the agent's de-identified result. Applied to every response on the route.
2. **Restore**: POST `{ session_id, text }` to `RESTORE_URL`; receive `{ final }`. 1. **Restore transform:** `POST { session_id, text }` → `RESTORE_URL` → `{ final }`
3. Return `{ "final": ..., "deidentified_prompt": ... }` so the UI shows the split view. (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 /tokenize) ## Vault item shape (DynamoDB, written by the tokenize transform)
One row per detected entity. `value` is the original PII (so `/restore` can put it 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 back); a resolvable PERSON also gets a `customer_id` so the RAG tool can turn the
token into a de-identified evidence package. token into a de-identified evidence package.
``` ```
{ "token": "CUST_863651", "type": "PERSON", "value": "王小明", { "token": "CUST_863651", "type": "PERSON", "value": "王小明",
"session_id": "<conv id>", "expires_at": <epoch+ttl>, "customer_id": "cust-0001" } "session_id": "<session>", "expires_at": <epoch+ttl>, "customer_id": "cust-0001" }
{ "token": "TW_683250", "type": "TW_ROC_ID", "value": "A123456789", { "token": "TW_683250", "type": "TW_ROC_ID", "value": "A123456789",
"session_id": "<conv id>", "expires_at": <epoch+ttl> } "session_id": "<session>", "expires_at": <epoch+ttl> }
``` ```
(The seed's `--with-demo-token` writes a different `type=CUSTOMER, value=cust-0001` (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 `/tokenize` mints.) row; that's only a standalone RAG test aid, not what the tokenize transform mints.)
## Why this split ## Fusion vs. the `/demo` orchestrator (be honest on camera)
Keeping detection, minting, and the vault behind `/tokenize` and `/restore` means `gateway_api/orchestrator/` (`/demo`) runs the *identical* tokenize → agent →
the only things exposed to the SaaS gateway are two authenticated HTTPS endpoints — restore mechanics over plain HTTP, so the Fusion-less demo works end to end. Show
no AWS creds or private resources leave the account, and Fusion stays a pure that to prove the data-flow. Then make the governance point: only Fusion turns
orchestration/routing layer. That is also the cleanest story on camera: the those mechanics into a **mandatory, audited policy** across all AI traffic — the
gateway owns the flow; the cloud only ever sees tokens. 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.