Skip to main content

Microsoft Presidio Guardrails

The Presidio guardrail detects and anonymizes sensitive data with Microsoft Presidio, an open-source PII engine you run yourself. AISIX calls your Presidio analyzer for each request or response. Detected entities are either blocked or anonymized with an operator you choose, and anonymized traffic continues with the rewritten text.

Compared with the built-in PII guardrail, Presidio adds:

  • NER/ML entities a regex cannot express, such as PERSON, LOCATION, NRP, and the rest of Presidio's recognizer set.
  • Anonymization operators: replace with an entity placeholder, mask with asterisks, hash with SHA-256, or redact the span entirely.
  • Self-hosted analysis: content is analyzed inside your own network, with no vendor key.

In this guide, you will run Presidio locally, create a Presidio guardrail with per-entity actions, and verify anonymization and blocking.

Prerequisites

Before starting, prepare the following:

  • Review Guardrail Behavior for hook points, enforcement modes, and remote failure handling.
  • One of these configuration paths:
    • AISIX Cloud with an environment, an attached gateway, and a write-scoped admin token. For On-Premises, follow the AISIX Cloud Quickstart. To request Hybrid Cloud access, contact API7.
    • An open-source AISIX gateway that loads a declarative resources.yaml file.
  • A working model alias and caller API key that can send Chat Completions requests.
  • Docker, to run the Presidio analyzer and anonymizer containers used in this guide.
  • curl. The AISIX Cloud path also uses jq.

Start Presidio

For a local Docker evaluation, create a network and start the two Presidio services on it:

docker network create aisix-guardrails
docker run -d --name presidio-analyzer --network aisix-guardrails \
-p 5002:3000 mcr.microsoft.com/presidio-analyzer:latest
docker run -d --name presidio-anonymizer --network aisix-guardrails \
-p 5001:3000 mcr.microsoft.com/presidio-anonymizer:latest

Connect the gateway container to aisix-guardrails, or provide equivalent network reachability in your deployment. The open-source quickstart uses this command:

docker network connect aisix-guardrails aisix-quickstart

Confirm the analyzer responds from the host:

curl -sS -X POST "http://127.0.0.1:5002/analyze" \
-H "Content-Type: application/json" \
-d '{
"text": "my email is alice@example.com",
"language": "en"
}'

The response lists the detected EMAIL_ADDRESS entity with its offsets and score.

Create a Presidio Guardrail

The example below anonymizes emails and person names but blocks US Social Security Numbers on both hooks. Choose one configuration path, then use the shared verification procedure.

Export the gateway values used by both paths:

# AISIX_PROXY has no trailing slash or endpoint path.
# The local quickstarts use http://127.0.0.1:3000.
export AISIX_PROXY="YOUR_AISIX_GATEWAY_URL"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="gpt-4o-mini"

AISIX Cloud

Export the control-plane connection details:

# AISIX_CP includes /api and has no trailing slash.
# The local On-Premises quickstart uses http://localhost:8080/api.
export AISIX_CP="YOUR_AISIX_CLOUD_ADMIN_API_BASE_URL"
export AISIX_TOKEN="YOUR_ADMIN_TOKEN"
export ENV_ID="YOUR_ENVIRONMENT_ID"

Create the guardrail and capture its ID:

export GUARDRAIL_ID=$(curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/guardrails" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "presidio-pii-policy",
"enabled": false,
"hook_point": "both",
"fail_open": false,
"kind": "presidio",
"config": {
"analyzer_url": "http://presidio-analyzer:3000",
"anonymizer_url": "http://presidio-anonymizer:3000",
"entities": [
{
"type": "EMAIL_ADDRESS"
},
{
"type": "PERSON"
},
{
"type": "US_SSN",
"action": "block"
}
],
"default_action": "mask",
"operator": "replace",
"score_threshold": 0.5,
"language": "en"
}
}' | jq -r '.guardrail.id')

entities limits detection to the listed Presidio entities. An empty list analyzes with Presidio's full recognizer set.

default_action: "mask" anonymizes listed entities unless an entry overrides the action. This example blocks US Social Security Numbers with action: "block".

operator: "replace" substitutes masked values with entity placeholders such as <EMAIL_ADDRESS>. Use hash when downstream systems need a stable pseudonym instead of a placeholder.

score_threshold drops analyzer results below the given confidence. Omit it to accept every result the analyzer returns.

A guardrail runs only where it is attached. Attach it to the whole environment so it applies to all traffic:

curl -sS -X POST "$AISIX_CP/environments/$ENV_ID/guardrails/$GUARDRAIL_ID/attachments" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"scope_type": "env"
}'

The env scope applies the guardrail to all traffic in the environment and takes no scope_id. Use model, api_key, or team with a matching scope_id to narrow the attachment.

Enable the guardrail after its attachment exists:

curl -sS -X PATCH "$AISIX_CP/environments/$ENV_ID/guardrails/$GUARDRAIL_ID" \
-H "Authorization: Bearer $AISIX_TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'

The enabled configuration projects to attached gateways automatically.

Open-Source AISIX Gateway

Add the guardrail to the resources file that already defines the example model and caller API key:

resources.yaml
guardrails:
- name: presidio-pii-policy
enabled: true
hook_point: both
fail_open: false
kind: presidio
analyzer_url: http://presidio-analyzer:3000
anonymizer_url: http://presidio-anonymizer:3000
entities:
- type: EMAIL_ADDRESS
- type: PERSON
- type: US_SSN
action: block
default_action: mask
operator: replace
score_threshold: 0.5
language: en

The provider fields sit directly on the guardrail entry rather than under config. Use analyzer and anonymizer URLs that are reachable from the gateway process. Every enabled guardrail in the resources file applies to every request handled by that gateway.

Validate the complete file, then reload the gateway. See Reload a Resources File for the runnable Docker workflow.

Because this guardrail uses hook_point: both, AISIX applies the same anonymization to model responses before they reach the caller. Original request values do not reach the upstream model, and original response values do not reach the caller. For streamed model responses, see Streaming Output.

Matched values are also kept out of gateway logs and usage records. Usage records contain only per-entity mask counts with entity names.

Verify Anonymization

AISIX Cloud projection is asynchronous. If the first request does not reflect the guardrail, wait for the gateway to apply the latest revision and retry. See Resource Projection for convergence checks.

Send a prompt containing an email address:

curl -sSi -X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"model": "${AISIX_MODEL}",
"messages": [
{
"role": "user",
"content": "email alice@example.com about the order"
}
]
}
EOF

If the upstream model succeeds, the response starts with HTTP/1.1 200 OK. AISIX anonymizes the prompt before calling the upstream model, so the provider receives:

email <EMAIL_ADDRESS> about the order

Verify Blocking

A request containing a blocked entity is rejected:

curl -sSi -X POST "$AISIX_PROXY/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"model": "${AISIX_MODEL}",
"messages": [
{
"role": "user",
"content": "my ssn is 123-45-6789"
}
]
}
EOF

The response starts with HTTP/1.1 422 Unprocessable Entity and includes the standard content-filter error:

{
"error": {
"message": "request blocked by content policy (guardrail 'presidio-pii-policy')",
"type": "content_filter"
}
}

The matched value is not echoed back.

Rewrite Limits

On endpoints that cannot rewrite request text in place, such as audio, images, and passthrough, a maskable detection blocks instead. AISIX never releases content its policy says should have been anonymized. If the analyzer finds PII but the anonymizer call fails, the remote failure policy applies rather than releasing the un-anonymized text.

Next Steps

You have now configured Microsoft Presidio and verified anonymization and blocking. Use these guides to tune behavior or compare related guardrails: