Files
presidio/docs/samples/docker/aisix.md
T

5.0 KiB

Protect LLM requests with Presidio and AISIX AI Gateway

AISIX can call a self-hosted Presidio Analyzer and Anonymizer as an input guardrail before forwarding a request to an LLM provider. This sample configures two outcomes:

  • email addresses are replaced with an entity placeholder;
  • US Social Security numbers are blocked before the provider is called.
Application --> AISIX --> LLM provider
                  |
                  +--> Presidio Analyzer --> Presidio Anonymizer

Prerequisites

  • Docker
  • an OpenAI API key, or an OpenAI-compatible endpoint and matching AISIX provider configuration
  • curl

The commands below use AISIX 1.2.0 and Presidio 2.2.364.

Start Presidio

Create a private Docker network and run both Presidio services:

docker network create aisix-presidio

docker run -d --name presidio-analyzer --network aisix-presidio \
  -p 127.0.0.1:5002:3000 \
  ghcr.io/data-privacy-stack/presidio-analyzer:2.2.364

docker run -d --name presidio-anonymizer --network aisix-presidio \
  -p 127.0.0.1:5001:3000 \
  ghcr.io/data-privacy-stack/presidio-anonymizer:2.2.364

These services do not authenticate callers. Keep them on a private network in production instead of publishing their ports.

Wait for both services to report healthy before continuing:

until curl -fsS http://127.0.0.1:5002/health >/dev/null; do sleep 5; done
until curl -fsS http://127.0.0.1:5001/health >/dev/null; do sleep 2; done

Confirm that the Analyzer detects an email address:

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

The response includes an EMAIL_ADDRESS result with its character offsets and confidence score.

Configure AISIX

Create config.yaml:

resources_file: /etc/aisix/resources.yaml

proxy:
  addr: "0.0.0.0:3000"

admin:
  enabled: false

Create resources.yaml:

_format_version: "1"

provider_keys:
  - display_name: openai-main
    provider: openai
    api_key: ${OPENAI_API_KEY}

models:
  - display_name: presidio-demo
    provider: openai
    model_name: gpt-4o-mini
    provider_key: openai-main

api_keys:
  - display_name: local-demo
    key_env: CALLER_API_KEY
    allowed_models: ["presidio-demo"]

guardrails:
  - name: presidio-pii-policy
    enabled: true
    hook_point: input
    enforcement_mode: block
    fail_open: false
    kind: presidio
    analyzer_url: http://presidio-analyzer:3000
    anonymizer_url: http://presidio-anonymizer:3000
    entities:
      - type: EMAIL_ADDRESS
        action: mask
      - type: US_SSN
        action: block
    default_action: mask
    operator: replace
    language: en

guardrail_attachments:
  - guardrail_id: presidio-pii-policy
    scope_type: env
    priority: 100

Export credentials and start the gateway on the same Docker network:

export OPENAI_API_KEY="YOUR_PROVIDER_KEY"
export CALLER_API_KEY="sk-local-presidio-demo"

docker run -d --name aisix-presidio-gateway \
  --platform linux/amd64 \
  --network aisix-presidio \
  -v "$(pwd)/config.yaml:/etc/aisix/config.yaml:ro" \
  -v "$(pwd)/resources.yaml:/etc/aisix/resources.yaml:ro" \
  -e OPENAI_API_KEY -e CALLER_API_KEY \
  -p 127.0.0.1:3000:3000 \
  ghcr.io/api7/aisix:1.2.0

The guardrail must have an attachment. A configured guardrail with no matching attachment does not inspect traffic.

Verify masking and blocking

Send a request containing an email address:

curl -sS -X POST http://127.0.0.1:3000/v1/chat/completions \
  -H "Authorization: Bearer ${CALLER_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "presidio-demo",
    "messages": [
      {"role": "user", "content": "Contact alice@example.com about the order"}
    ]
  }'

AISIX asks the Analyzer to locate the email and the Anonymizer to replace it. The provider receives Contact <EMAIL_ADDRESS> about the order; the model's response remains provider-dependent.

Now send a value configured with the block action:

curl -sSi -X POST http://127.0.0.1:3000/v1/chat/completions \
  -H "Authorization: Bearer ${CALLER_API_KEY}" \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "presidio-demo",
    "messages": [
      {"role": "user", "content": "My SSN is 987-65-4321"}
    ]
  }'

The request returns 422 Unprocessable Entity with a content_filter error, and AISIX does not call the model provider.

This example is fail-closed. If the Analyzer is unavailable, AISIX returns a 422 guardrail_unavailable error instead of forwarding uninspected content. Set fail_open: true only when availability is more important than preventing unscreened text from reaching the provider.

Clean up

docker rm -f aisix-presidio-gateway presidio-analyzer presidio-anonymizer
docker network rm aisix-presidio

For entity selection, anonymization operators, output guardrails, streaming behavior, and deployment guidance, see the AISIX Presidio guardrail documentation.