Pseudonimizzazione e ripristino controllato di dati personali (PII), basato su Microsoft Presidio
10K+
Microservizio FastAPI per pseudonimizzazione e ripristino controllato di dati personali (PII), basato su Microsoft Presidio + vault PostgreSQL.
Il servizio riduce il rischio privacy quando un applicativo deve inviare testo a componenti esterni (es. LLM, servizi di classificazione, canali terzi), sostituendo i dati personali con token e consentendo il ripristino solo in ambiente controllato.
Questo microservizio supporta un approccio privacy-by-design e privacy-by-default:
art. 5(1)(c)): verso sistemi esterni transitano token, non valori personali in chiaro.art. 5(1)(f), art. 32): separazione tra testo tokenizzato e vault di mapping.art. 25): pseudonimizzazione integrata nel flusso applicativo.Nota importante: questa soluzione implementa pseudonimizzazione, non anonimizzazione irreversibile. I dati restano dati personali ai sensi GDPR se il mapping e la chiave sono disponibili. Per compliance totale è fondamentale garantire la cifratura del volume di PostgreSQL e limitare gli accessi esclusivamente midiante utenza applicativa.
POST /anonymize
conversation_idPERSON, PHONE*, EMAIL*, ecc.)POST /restore
conversation_id originalefull_name, name, phone, email)children)json.loads)ast.literal_eval) per payload con apici singoliPERSON: restituzione normalizzata in base alle componenti del tokenPHONE*: restituzione normalizzata (E.164 o forma normalizzata disponibile)/anonymizeconversation_id -> cifrato con chiave segreta (SCRUBBER_CRYPTO_KEY)token <-> valore per conversazione/restore usa token + masked_conversation_id per ripristinare valori e conversation idPOST /anonymizeRequest:
{
"conversation_id": "chat-123",
"raw_text": "Buongiorno, sono Mario Rossi. Chiamami al +39 333 123 4567"
}
Response (esempio):
{
"masked_conversation_id": "<encrypted-id>",
"masked_text": "Buongiorno, sono <PERSON_1:first_name last_name>. Chiamami al <PHONE_1>"
}
POST /restoreRequest:
{
"masked_conversation_id": "<encrypted-id>",
"masked_text": "Buongiorno, sono <PERSON_1:first_name last_name>. Chiamami al <PHONE_1>"
}
Response:
{
"conversation_id": "chat-123",
"raw_text": "Buongiorno, sono Mario Rossi. Chiamami al +393331234567"
}
OpenAPI: GET /openapi.json
SCRUBBER_CRYPTO_KEY (obbligatoria): chiave segreta per cifrare/decifrare conversation_idCONFIG_DIR (default /config in container): directory file YAMLDEFAULT_LANG (default en, consigliato it per uso italiano)LANGUAGES_CONFIG_FILE (default languages-config.yaml)RECOGNIZERS_CONFIG_FILE (opzionale, es. pattern-recognizers.yaml)SCRUBBER_APP_CONFIG_FILE (default scrubber-app-config.yaml)DB (se non usi DB_PII_SCRUBBER_URI):
DB_HOST, DB_PORTPOSTGRES_PASSWORD (admin setup)SCRUBBER_DB_USER, SCRUBBER_DB_PASSWORD, SCRUBBER_DB_NAMEconfig/languages-config.yamlConfigura NLP engine (spaCy), mapping label->entity Presidio, e labels_to_ignore.
Uso tipico:
it_core_news_lg)LOCATION)config/pattern-recognizers.yamlCustom recognizer regex/context-based.
Uso tipico:
full_name, phone, email) per aumentare precisione su payload strutturaticonfig/scrubber-app-config.yamlRegole applicative del microservizio:
denylist: termini da non mascherare (es. saluti)entity_priority: tie-break tra entita su overlapjson_key_primary_entity: semantica per masking JSON key/value (es. children: CHILD)Di seguito esempio di configurazione in yaml:
# Application-level scrubber behavior config
denylist:
- dotty
- buonasera
- buongiorno
- salve
- ciao
- grazie
- prego
- per favore
- scusi
- scusami
entity_priority:
PERSON: 100
PHONE: 90
PHONE_NUMBER: 90
EMAIL: 80
EMAIL_ADDRESS: 80
LOCATION: 70
json_key_primary_entity:
full_name: PERSON
name: PERSON
phone: PHONE
email: EMAIL_ADDRESS
children: CHILD
git clone <repo-url>
cd pii-scrubber
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp example.env .env
Genera chiave crypto:
python scripts/generate_key.py
# copia il valore in .env -> SCRUBBER_CRYPTO_KEY=...
Avvio servizio:
set -a
. ./.env
set +a
bash scripts/entrypoint.sh
Servizio disponibile su http://localhost:8080.
#!/usr/bin/env bash
set -euo pipefail
git fetch --all --tags
git pull --rebase
#!/usr/bin/env bash
set -euo pipefail
docker build -t pii_scrubber:latest .
#!/usr/bin/env bash
set -euo pipefail
docker run --rm -v "$PWD":/app -w /app python:3.13-slim python scripts/generate_key.py
Prerequisiti:
.env valorizzato (incluso SCRUBBER_CRYPTO_KEY)#!/usr/bin/env bash
set -euo pipefail
docker run --rm \
-p 8080:8080 \
--env-file .env \
-e CONFIG_DIR=/config \
-v "$PWD/config":/config \
-v "$PWD/data":/app/data \
--name pii_scrubber \
mariomastrorilli/pii_scrubber:latest
services:
pii_scrubber:
image: mariomastrorilli/pii_scrubber:latest
container_name: pii_scrubber
restart: unless-stopped
env_file:
- .env
environment:
CONFIG_DIR: /config
DB_HOST: db
DB_PORT: "5432"
# opzionale alternativa completa:
# DB_PII_SCRUBBER_URI: postgresql://pii_scrubber:pii_scrubber@db:5432/pii_scrubber
volumes:
- ./config:/config:ro
- ./data:/app/data
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
container_name: pii_scrubber_db
restart: unless-stopped
environment:
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 20
volumes:
db_data:
E2E (tutti):
./.venv/bin/python -m unittest discover -s test -p 'test*_e2e.py' -v
Include anche:
conversation_idchildren)Task VS Code:
Release PipelineScript:
bash scripts/release_pipeline.sh v1.2.3
La pipeline gestisce:
vX.Y.Z[-prerelease][+build])SCRUBBER_CRYPTO_KEY con strategia di migrazione./restore (authN/authZ, mTLS, allowlist).Created by Mario Mastrorilli
Content type
Image
Digest
sha256:879c04115…
Size
1.2 GB
Last updated
7 months ago
docker pull mariomastrorilli/pii_scrubber