Aller au contenu principal

Gouvernez et masquez les traces dans Unity Catalog

Le stockage des traces dans Unity Catalog sert également de couche de conformité. Les traces atterrissent sous forme de tables Delta régies, de sorte qu’elles héritent des mêmes contrôles RBAC, masquage de colonnes, filtres de lignes, politiques de rétention et journaux d’audit que vous appliquez à tout autre data asset Unity Catalog, sans outil supplémentaire. Deux approches vous permettent ensuite de traiter spécifiquement les données PII :

  • Rédaction avant l’exportation (côté client) : filtrez les entrées et sorties de la portée dans votre agent avant que MLflow ne les transmette au backend. Les PII brutes ne quittent jamais votre environnement.
  • Redaction des traces stockees (cote serveur) : appliquez ai_mask via un LakeFlow Pipelines aux portees OTel deja stockees dans Unity Catalog, puis restreignez l'acces aux tables brutes. Aucune modification de votre code d'agent n'est requise.

Utilisez le masquage côté client lorsque vous devez garantir que les valeurs sensibles ne sont jamais transmises ni conservées. Utilisez l’approche de pipeline côté serveur lorsque les traces sont déjà stockées dans Unity Catalog et que vous préférez ne pas modifier votre agent.

remarque

La suppression des informations sensibles par MLflow affecte uniquement ce qui est enregistré dans la trace — l'agent lui-même continue de recevoir et de renvoyer le contenu d'origine, non expurgé. Pour empêcher que des données personnelles identifiables (PII) n'atteignent un service d'IA enregistré dans Unity Catalog ou pour appliquer une politique centrale à l'échelle de votre organisation, utilisez les stratégies de service.

Redact PII before export

Les processeurs de portée implémentent la rédaction côté client. Chaque processeur reçoit une portée, la modifie sur place et ne renvoie rien. Enregistrez un ou plusieurs processeurs auprès de mlflow.tracing.configure, et MLflow les applique à chaque portée avant l’exportation.

Python
from mlflow.entities.span import Span

def filter_function(span: Span) -> None:
# Read span.inputs / span.outputs, redact, then write back.
span.set_inputs(...)
span.set_outputs(...)

mlflow.tracing.configure(span_processors=[filter_function])

Comportement de la clé :

  • Le filtrage s’effectue côté client — le backend de trace ne reçoit jamais de données non caviardées.
  • Plusieurs processeurs s’exécutent dans l’ordre où vous les enregistrez, chacun recevant l’étendue après que le processeur précédent l’a modifiée.
  • Les processeurs s'appliquent à chaque étendue d'une trace, y compris celles créées par les intégrations de frameworks telles que LangChain et LangGraph.
  • Utilisez span.span_type pour appliquer une logique différente à différents types de portées : LLM, TOOL ou AGENT.

Prérequis

  • MLflow Tracing configuré pour votre agent. Voir Présentation du traçage.

  • Si vous stockez des traces dans le Unity Catalog, créez d’abord l’expérimentation avec un emplacement de trace Unity Catalog. Consultez Configuration : Créer une Experimentation avec un emplacement de trace Unity Catalog.

  • Installez les packages requis :

    Bash
    pip install --upgrade "mlflow-skinny[databricks]>=3.14" databricks-sdk "databricks-langchain>=0.19.0" "langgraph>=1.1.0"

    Pour un tracing de production léger, l’installation recommandée est mlflow-tracing. Ces exemples utilisent mlflow-skinny[databricks] car ils exploitent également le SDK Unity Catalog et les intégrations LangChain et LangGraph.

    Pour l'exemple Microsoft Presidio, installez également :

    Bash
    pip install presidio_analyzer presidio_anonymizer
    python -m spacy download en_core_web_lg

Rédiger avec une regex

L’exemple suivant recherche des adresses e-mail dans les entrées de portée à l’aide d’une expression régulière et les remplace par [REDACTED].

Python
import re
import mlflow
from mlflow.entities.span import Span

# mlflow.set_experiment(experiment_id=experiment_id)

@mlflow.trace
def predict(text: str):
return "Answer"

EMAIL_PATTERN = r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"

def redact_email(span: Span) -> None:
raw_input = span.inputs.get("text")
redacted_input = re.sub(EMAIL_PATTERN, "[REDACTED]", raw_input)
span.set_inputs({"text": redacted_input})

mlflow.tracing.configure(span_processors=[redact_email])

predict("My e-mail address is test@example.com")

Filtrer par type d’étendue

Utilisez span.span_type pour appliquer une logique de masquage différente à différents types d’étendues — LLM, TOOL, AGENT, et ainsi de suite. Cela vous permet de cibler la plage d'où provient une valeur sensible plutôt que de scanner chaque structure de charge utile qu'un framework peut produire.

L’exemple suivant supprime les numéros de compte bancaire d’un agent LangGraph. Le numéro de compte provient d’un outil. Par conséquent, le processeur remplace entièrement les sorties de portée TOOL et applique une expression régulière aux entrées et aux sorties de toutes les autres portées en guise de filet de sécurité.

Configurer l’agent :

Python
import mlflow
from langchain_core.tools import tool
from databricks_langchain import ChatDatabricks
from langchain.agents import create_agent

# autolog() registers a LangChain callback so MLflow automatically captures spans
# for every LLM call, tool invocation, and agent step.
mlflow.langchain.autolog()

@tool
def get_bank_account_number(user_name: str):
"""Return the bank account number for the given user name."""
return "1234567890"

llm = ChatDatabricks(model="databricks-llama-4-maverick", use_ai_gateway=True)
graph = create_agent(llm, [get_bank_account_number])

Définissez le processeur de spires :

Python
import re
from mlflow.entities.span import Span, SpanType

ACCOUNT_NUMBER_PATTERN = re.compile(r"\d{10}")

def filter_bank_account_number(span: Span) -> None:
# The tool returns the account number directly — redact its output entirely.
if span.span_type == SpanType.TOOL:
span.set_outputs("[REDACTED]")
return

# For all other spans, mask any account-number pattern in the inputs and outputs.
if span.inputs is not None:
span.set_inputs(ACCOUNT_NUMBER_PATTERN.sub("[REDACTED]", str(span.inputs)))
if span.outputs is not None:
span.set_outputs(ACCOUNT_NUMBER_PATTERN.sub("[REDACTED]", str(span.outputs)))

Enregistrez le processeur et appelez l’agent :

Python
mlflow.tracing.configure(span_processors=[filter_bank_account_number])

result = graph.invoke(
{"messages": [{"role": "user", "content": "What is the bank account number for John Doe?"}]}
)

Rédiger avec Microsoft Presidio

Pour une détection plus précise des données personnelles au-delà des expressions régulières, utilisez Microsoft Presidio. Un AnalyzerEngine détecte des entités telles que des noms, des cartes de crédit et des adresses e-mail, tandis qu’un AnonymizerEngine les réécrit.

Python
import mlflow
from mlflow.entities.span import Span, SpanType

@mlflow.trace(span_type=SpanType.AGENT)
def customer_support_agent(request: str):
return "Yes"

Initialisez Presidio et définissez le processeur d’étendue :

Python
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine

analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()

def filter_pii(span: Span) -> None:
text = span.inputs.get("request")
results = analyzer.analyze(
text=text,
entities=["PERSON", "CREDIT_CARD", "EMAIL_ADDRESS", "LOCATION", "DATE_TIME"],
language="en",
)
anonymized_text = anonymizer.anonymize(text=text, analyzer_results=results)
span.set_inputs({"request": anonymized_text.text})

Enregistrez le processeur et exécutez l’agent :

Python
mlflow.tracing.configure(span_processors=[filter_pii])

customer_support_agent(
"Please cancel my credit card effective September 19th. My name is John Doe and my credit "
"card number is 4095-2609-9393-4932. My email is john.doe@example.com and I live in Amsterdam."
)

Reset les processeurs de spans

Pour cesser de masquer des étendues, transmettez une liste vide afin d’effacer tous les processeurs enregistrés :

Python
mlflow.tracing.configure(span_processors=[])

Ou utilisez reset pour effacer toute la configuration de traçage :

Python
mlflow.tracing.reset()

Rédiger les données personnelles identifiables (PII) à partir des traces OTel stockées

Cette approche masque les informations personnelles identifiables (PII) dans les plages de traces OTel déjà stockées dans Unity Catalog, sans modifier votre agent. Un Lakeflow pipeline lit les nouvelles plages OTel de manière incrémentielle, applique ai_mask pour masquer les PII, et écrit les résultats dans un schéma distinct bénéficiant d'un accès plus large. Un job planifié gère le nettoyage optionnel de la rétention sur les tables brutes.

Cette approche fonctionne avec toutes les traces OTel dans Unity Catalog, y compris les traces écrites par MLflow. Consultez Stocker des traces OpenTelemetry dans Unity Catalog.

Aperçu de la rédaction des PII avec OTel

Prérequis

download les ressources

download ces fichiers et importez-les dans votre Workspace :

Fichier

Description

deploy_notebook.py

Notebook de déploiement guidé — alternative interactive à deploy.sh.

deploy.sh

Script de déploiement CLI.

pii_redaction_pipeline.sql

Le pipeline — tables de streaming avec ai_mask.

unified_view.sql

Vue unifiée des traces regroupant les spans et les annotations.

setup_schema_and_grants.sql

Autorisations de création de schémas et de contrôle d’accès.

pipeline_config.json

Exemple de configuration de pipeline (référence).

send_pii_traces.py

Utilitaire d'infrastructure publique de test qui envoie des données de test PII sous forme de portées OTel.

pii_test_data.jsonl

50 lignes de donnees de test PII synthetiques.

Fichier

Description

deploy_notebook.py

Notebook de déploiement guidé — alternative interactive à deploy.sh.

deploy.sh

Script de déploiement CLI.

pii_redaction_pipeline.sql

Le pipeline — tables de streaming avec ai_mask.

unified_view.sql

Vue unifiée des traces regroupant les spans et les annotations.

setup_schema_and_grants.sql

Autorisations de création de schémas et de contrôle d’accès.

pipeline_config.json

Exemple de configuration de pipeline (référence).

send_pii_traces.py

Utilitaire d'infrastructure publique de test qui envoie des données de test PII sous forme de portées OTel.

pii_test_data.jsonl

50 lignes de donnees de test PII synthetiques.

Déployez la solution

Pour un déploiement étape par étape directement dans votre Workspace :

  1. Importez deploy_notebook.py dans votre workspace avec les autres assets téléchargés. Consultez les dossiers Git Databricks.
  2. Ouvrir deploy_notebook.py dans votre workspace.
  3. Renseignez les parameters du widget en haut : catalogue, schéma source, schéma cible et préfixe de table.
  4. Cliquez sur Run all . Chaque étape effectue une validation avant de continuer.

Cette approche utilise le SDK Python Databricks (aucun CLI requis), peut être réexécutée en toute sécurité et fournit un retour interactif à chaque étape.

Paramètres de déploiement

Transmettez chaque parameter en tant que valeur de widget dans deploy_notebook.py ou en tant qu'argument à deploy.sh.

parameter

Description

Par défaut

catalog

Catalogue Unity Catalog pour les tables brutes et masquées.

(obligatoire)

source_schema

Schéma contenant les tables OTel brutes.

(obligatoire)

target_schema

Schéma des tables de résultats charcutées.

(obligatoire)

table_prefix

Préfixe pour les noms de table OTel.

(obligatoire)

pii_categories

Types de PII à masquer, séparés par des virgules et entre guillemets simples.

'email','phone','ssn','credit_card','name','address'

pipeline_name

Nom du pipeline.

otel-pii-redaction

retention_days

Nombre de jours de conservation des données brutes avant suppression. Une valeur vide, 0 ou none désactive la suppression.

90

redaction_pipeline_mode

Mode d’exécution du pipeline : triggered ou continuous.

triggered

redaction_trigger_frequency

Fréquence d'exécution du pipeline (mode Trigger uniquement) : hourly, every 6 hours, daily ou weekly.

daily

parameter

Description

Par défaut

catalog

Catalogue Unity Catalog pour les tables brutes et masquées.

(obligatoire)

source_schema

Schéma contenant les tables OTel brutes.

(obligatoire)

target_schema

Schéma des tables de résultats charcutées.

(obligatoire)

table_prefix

Préfixe pour les noms de table OTel.

(obligatoire)

pii_categories

Types de PII à masquer, séparés par des virgules et entre guillemets simples.

'email','phone','ssn','credit_card','name','address'

pipeline_name

Nom du pipeline.

otel-pii-redaction

retention_days

Nombre de jours de conservation des données brutes avant suppression. Une valeur vide, 0 ou none désactive la suppression.

90

redaction_pipeline_mode

Mode d’exécution du pipeline : triggered ou continuous.

triggered

redaction_trigger_frequency

Fréquence d'exécution du pipeline (mode Trigger uniquement) : hourly, every 6 hours, daily ou weekly.

daily

Les tables sources suivent le modèle de nommage {catalog}.{source_schema}.{table_prefix}_otel_spans, {catalog}.{source_schema}.{table_prefix}_otel_logs et {catalog}.{source_schema}.{table_prefix}_otel_annotations.

Modes de pipeline :

  • triggered : crée un job planifié qui exécute le pipeline à la fréquence configurée. Le pipeline traite les nouvelles données à chaque exécution, puis s'arrête.
  • continuous : le pipeline s'exécute en continu et traite les nouvelles données dès leur arrivée. Coût de compute plus élevé que pour le mode Trigger, car le pipeline est toujours activé.

Paramètres de rédaction des PII

Ces parameter contrôlent les informations personnelles identifiables (PII) à charcuter et la manière de le faire. Transmettez pii_categories en tant que parameter de déploiement ; modifiez pii_redaction_pipeline.sql directement pour remplacer les autres.

parameter

Description

Exemple

pii_categories

Liste des types de PII à détecter et à rédiger. Valeurs prises en charge : email, phone, name, address, ssn, credit_card, ip_address, date_of_birth.

["email","phone","ssn","credit_card","name","address"]

redaction_mode

Comment masquer des PII : mask, hash ou remove.

mask

mask_character

Caractère utilisé lorsque redaction_mode est mask.

*

fields_to_redact

Champs OTel auxquels appliquer le masquage.

["attributes", "resource.attributes", "events"]

allowlisted_keys

Clés d'attributs pour ignorer le masquage, par exemple les métadonnées techniques qui ne comportent pas d'informations personnelles identifiables (PII).

["service.name", "http.method", "http.status_code"]

custom_patterns

Modèles regex pour les PII spécifiques à un domaine non couvert par ai_mask.

{"employee_id": "EMP-\\d{6}", "internal_account": "ACCT-[A-Z0-9]+"}

parameter

Description

Exemple

pii_categories

Liste des types de PII à détecter et à rédiger. Valeurs prises en charge : email, phone, name, address, ssn, credit_card, ip_address, date_of_birth.

["email","phone","ssn","credit_card","name","address"]

redaction_mode

Comment masquer des PII : mask, hash ou remove.

mask

mask_character

Caractère utilisé lorsque redaction_mode est mask.

*

fields_to_redact

Champs OTel auxquels appliquer le masquage.

["attributes", "resource.attributes", "events"]

allowlisted_keys

Clés d'attributs pour ignorer le masquage, par exemple les métadonnées techniques qui ne comportent pas d'informations personnelles identifiables (PII).

["service.name", "http.method", "http.status_code"]

custom_patterns

Modèles regex pour les PII spécifiques à un domaine non couvert par ai_mask.

{"employee_id": "EMP-\\d{6}", "internal_account": "ACCT-[A-Z0-9]+"}

Pour les motifs personnalisés tels que les identifiants d’employé (EMP-XXXXXX), appliquez regexp_replace avant ai_mask dans le SQL du pipeline.

Éléments masqués

Le pipeline applique ai_mask aux champs suivants :

Table

Champs occultés

Étendues

attributes, events, resource.attributes

Journaux

body, attributes, resource.attributes

Annotations

Transmission — aucune PII attendue

Table

Champs occultés

Étendues

attributes, events, resource.attributes

Journaux

body, attributes, resource.attributes

Annotations

Transmission — aucune PII attendue

Les champs ne contenant pas de PII restent inchangés : identifiants de trace, identifiants de portée, Timestamp, noms de service et codes d'état.

ai_mask est adossé à un LLM et prend en charge divers formats d'informations personnelles sans nécessiter de motif distinct par variation ; par exemple, les numéros de téléphone au format (555) 123-4567, 555.123.4567 ou +1 555-123-4567 sont tous reconnus.

Rétention et contrôle d’accès

Conservation des données brutes : le déploiement configure l'heure de suppression automatique sur les tables OTel brutes afin de supprimer les données de trace plus anciennes qu'un nombre de jours configurable (default : 90). Cette fonctionnalité prend en charge le GDPR et les réglementations pour la protection des données similaires. Définissez retention_days sur 0 ou none pour gérer la rétention séparément.

remarque

Le calendrier exact de suppression automatique basé sur le TTL n’est pas garanti. Il peut y avoir une mémoire tampon pouvant aller jusqu’à 6 jours entre l’expiration d’une ligne et sa suppression définitive, en plus de la durée de conservation des données (default de 7 jours). Si vos exigences de conformité imposent des délais de suppression stricts, utilisez plutôt un job planifié avec DELETE et VACUUM manuels.

Contrôle d’accès : les tables OTel brutes contiennent des PII non masquées et leur accès doit être restreint. Accordez l’accès au schéma source brut uniquement au service principal du pipeline et aux administrateurs qui en ont besoin pour le debugging ou la réponse aux incidents. Tous les flux de travail d’analytique et d’observabilité de routine doivent query les tables masquées. Le fichier setup_schema_and_grants.sql comprend des exemples d’attribution. Pour plus de détails sur les privilèges Unity Catalog, consultez la page Gérer les privilèges dans Unity Catalog.

Tester la suppression

Générez des étendues de test avec des informations PII connues pour valider le résultat :

Bash
pip install opentelemetry-exporter-otlp-proto-http

python send_pii_traces.py <WORKSPACE_HOST> <CATALOG.SCHEMA.PREFIX_otel_spans>

Cette opération envoie 50 traces de test contenant des e-mails, des numéros de téléphone, des numéros de sécurité sociale, des cartes de crédit, des noms et des adresses.

Après avoir exécuté le pipeline, comparez les étendues brutes et masquées :

SQL
SELECT
s.span_id,
CAST(s.attributes AS STRING) AS raw,
CAST(r.attributes AS STRING) AS redacted
FROM <source_catalog>.<source_schema>.<prefix>_otel_spans s
JOIN <target_catalog>.<target_schema>.redacted_spans r
ON s.trace_id = r.trace_id AND s.span_id = r.span_id
WHERE s.name = 'pii-test-interaction'
LIMIT 5;

Architecture de référence

Deux flux sont disponibles. Utilisez Flow 1 (batch pipeline) pour la plupart des déploiements de production : cette option pré-matérialise les tables masquées pour des queries rapides et prend en charge la rétention auto-TTL. Utilisez Flow 2 (view-based) comme option légère lorsque le coût de stockage est la principale préoccupation et que les queries sont rares.

Dimension

Flux 1 : batch pipeline

Flux 2 : basé sur les vues

Coûts de stockage

2x (fenêtré dans le temps ; ~1x si auto-TTL s'applique)

1x — aucune duplication

Coût de compute

Une fois par enregistrement

Par query

Performances de la query

Rapide (pré-matérialisé)

Lent (recalcul sur chaque query)

Latence et disponibilité

Minutes (intervalle du pipeline)

Immédiatement

Déploiement des modifications de règles

refresh du pipeline

Instantané

Conformité GDPR

TTL automatique ou nettoyage planifié sur les tables brutes

TTL automatique ou nettoyage planifié sur les tables brutes

Idéal pour

Utilisation principale en production

Utilisation intermédiaire ou à faible volume de query

Dimension

Flux 1 : batch pipeline

Flux 2 : basé sur les vues

Coûts de stockage

2x (fenêtré dans le temps ; ~1x si auto-TTL s'applique)

1x — aucune duplication

Coût de compute

Une fois par enregistrement

Par query

Performances de la query

Rapide (pré-matérialisé)

Lent (recalcul sur chaque query)

Latence et disponibilité

Minutes (intervalle du pipeline)

Immédiatement

Déploiement des modifications de règles

refresh du pipeline

Instantané

Conformité GDPR

TTL automatique ou nettoyage planifié sur les tables brutes

TTL automatique ou nettoyage planifié sur les tables brutes

Idéal pour

Utilisation principale en production

Utilisation intermédiaire ou à faible volume de query

Flux 1 : pipeline de batch (recommandé)

Un Lakeflow pipeline matérialise les tables de streaming masquées à partir des tables OTel brutes. Les étendues OTel sont en écriture seule (append-only), ce qui les rend idéales pour l'ingestion par streaming incrémentielle.

Architecture de rédaction des PII OTel

Le code SQL suivant définit les tables de streaming masquées (pii_redaction_pipeline.sql) :

SQL
-- Streaming Table: Redacted Spans
CREATE OR REFRESH STREAMING TABLE redacted_spans
COMMENT 'PII-redacted OTel spans'
TBLPROPERTIES (
'quality' = 'gold',
'pipelines.autoOptimize.zOrderCols' = 'trace_id,date'
)
AS
SELECT
trace_id, span_id, parent_span_id, name, kind, start_time, end_time,
status, date, record_id, service_name, time, instrumentation_scope,

-- Redact span attributes
CASE
WHEN attributes IS NOT NULL THEN
ai_mask(CAST(attributes AS STRING), array(${pii_categories}))
ELSE attributes
END AS attributes,

-- Redact resource attributes
CASE
WHEN resource:attributes IS NOT NULL THEN
named_struct(
'attributes',
ai_mask(CAST(resource:attributes AS STRING), array(${pii_categories})),
'dropped_attributes_count', resource:dropped_attributes_count
)
ELSE resource
END AS resource,

-- Redact events (may contain exception messages with PII)
CASE
WHEN events IS NOT NULL THEN
ai_mask(CAST(events AS STRING), array(${pii_categories}))
ELSE events
END AS events,

-- Pass through links unchanged (typically just trace/span IDs)
links

FROM STREAM(${source_catalog}.${source_schema}.${table_prefix}_otel_spans);


-- Streaming Table: Redacted Logs
CREATE OR REFRESH STREAMING TABLE redacted_logs
COMMENT 'PII-redacted OTel logs'
AS
SELECT
trace_id, span_id, severity_number, severity_text, date, record_id,
service_name, time, instrumentation_scope,

CASE
WHEN body IS NOT NULL THEN
ai_mask(CAST(body AS STRING), array(${pii_categories}))
ELSE body
END AS body,

CASE
WHEN attributes IS NOT NULL THEN
ai_mask(CAST(attributes AS STRING), array(${pii_categories}))
ELSE attributes
END AS attributes,

CASE
WHEN resource:attributes IS NOT NULL THEN
named_struct(
'attributes',
ai_mask(CAST(resource:attributes AS STRING), array(${pii_categories})),
'dropped_attributes_count', resource:dropped_attributes_count
)
ELSE resource
END AS resource

FROM STREAM(${source_catalog}.${source_schema}.${table_prefix}_otel_logs);


-- Streaming Table: Annotations (passthrough — no PII expected)
CREATE OR REFRESH STREAMING TABLE redacted_annotations
COMMENT 'OTel annotations (passthrough, no PII redaction applied)'
AS SELECT * FROM STREAM(${source_catalog}.${source_schema}.${table_prefix}_otel_annotations);

Restreignez l’accès aux données brutes et autorisez l’accès aux tables masquées :

SQL
-- Lock down raw tables: grant only to the pipeline service principal
GRANT USE CATALOG ON CATALOG ${source_catalog} TO `pii_pipeline_sp`;
GRANT USE SCHEMA ON SCHEMA ${source_catalog}.${source_schema} TO `pii_pipeline_sp`;
GRANT SELECT ON TABLE ${source_catalog}.${source_schema}.${table_prefix}_otel_spans TO `pii_pipeline_sp`;
GRANT SELECT ON TABLE ${source_catalog}.${source_schema}.${table_prefix}_otel_logs TO `pii_pipeline_sp`;
REVOKE SELECT ON TABLE ${source_catalog}.${source_schema}.${table_prefix}_otel_spans FROM `data_team`;

-- Broad access to redacted tables only
GRANT USE CATALOG ON CATALOG ${target_catalog} TO `data_team`;
GRANT USE SCHEMA ON SCHEMA ${target_catalog}.${target_schema} TO `data_team`;
GRANT SELECT ON SCHEMA ${target_catalog}.${target_schema} TO `data_team`;

Configurez la conservation auto-TTL sur les tables brutes pour assurer la conformité au GDPR :

SQL
ALTER TABLE ${source_catalog}.${source_schema}.${table_prefix}_otel_spans
DELETE ROWS ${retention_days} DAYS AFTER time;

ALTER TABLE ${source_catalog}.${source_schema}.${table_prefix}_otel_logs
DELETE ROWS ${retention_days} DAYS AFTER time;

Créer la vue unifiée des traces pointant vers les tables masquées :

SQL
CREATE OR REPLACE VIEW ${target_catalog}.${target_schema}.${table_prefix}_trace_unified AS
SELECT
s.trace_id,
s.date,
min(s.start_time) AS request_time,
max(s.end_time) - min(s.start_time) AS execution_duration,
collect_list(
named_struct(
'span_id', s.span_id,
'parent_span_id', s.parent_span_id,
'name', s.name,
'kind', s.kind,
'start_time', s.start_time,
'end_time', s.end_time,
'status', s.status,
'attributes', s.attributes,
'events', s.events
)
) AS spans,
a.tags,
a.assessments
FROM ${target_catalog}.${target_schema}.redacted_spans s
LEFT JOIN ${target_catalog}.${target_schema}.redacted_annotations a
ON s.trace_id = a.target_id
GROUP BY s.trace_id, s.date, a.tags, a.assessments;

Template de configuration du pipeline (pipeline_config.json) :

JSON
{
"name": "otel-pii-redaction",
"catalog": "${target_catalog}",
"schema": "${target_schema}",
"serverless": true,
"continuous": false,
"channel": "CURRENT",
"configuration": {
"source_catalog": "<value>",
"source_schema": "<value>",
"table_prefix": "<value>",
"pii_categories": "'email','phone','ssn','credit_card','name','address'"
},
"libraries": [{ "file": { "path": "/Workspace/path/to/pii_redaction_pipeline.sql" } }]
}

Flux 2 : rédaction basée sur la vue

Ce flux applique ai_mask dans une vue Unity Catalog de sorte que la suppression s’effectue au moment de la lecture : aucune copie supprimée n’est stockée et aucun job de pipeline n’est requis.

Quand utiliser :

  • Le coût de stockage est une préoccupation majeure et une seconde copie des données de trace n'est pas acceptable.
  • Les données masquées font l'objet de requêtes peu fréquentes, de sorte que le coût de compute par requête lié à l'exécution de ai_mask est acceptable.
  • Vous souhaitez que les règles de rédaction prennent effet instantanément sans refresh du pipeline.

Rédaction basée sur la vue PII OTel

SQL
CREATE OR REPLACE VIEW ${target_catalog}.${target_schema}.${table_prefix}_otel_spans_redacted
AS
SELECT
trace_id, span_id, parent_span_id, name, kind, start_time, end_time,
status, date, service_name, time, instrumentation_scope, links,

ai_mask(CAST(attributes AS STRING), array(${pii_categories})) AS attributes,
ai_mask(CAST(events AS STRING), array(${pii_categories})) AS events,

named_struct(
'attributes',
ai_mask(CAST(resource:attributes AS STRING), array(${pii_categories})),
'dropped_attributes_count', resource:dropped_attributes_count
) AS resource

FROM ${source_catalog}.${source_schema}.${table_prefix}_otel_spans;

Compromis :

Aspect

Avantages

Inconvénients

Stockage

Aucune duplication.

Calculer

ai_mask s'exécute à chaque query, ce qui coûte cher à grande échelle.

Latence

Reflète immédiatement les nouvelles données.

Réponse de query plus lente.

Flexibilité

Les règles de rédaction sont mises à jour instantanément sans refresh du pipeline.

Aspect

Avantages

Inconvénients

Stockage

Aucune duplication.

Calculer

ai_mask s'exécute à chaque query, ce qui coûte cher à grande échelle.

Latence

Reflète immédiatement les nouvelles données.

Réponse de query plus lente.

Flexibilité

Les règles de rédaction sont mises à jour instantanément sans refresh du pipeline.

Liste de contrôle de mise en œuvre

Avant le déploiement en production :

  • Validez le comportement de ai_mask sur les colonnes VARIANT avec des données d’étendue OTel d’exemple.
  • Évaluez le throughput de ai_mask pour dimensionner l’intervalle de planification du pipeline.
  • Définissez les clés d’attributs listées dans la liste blanche qui doivent ignorer la rédaction.
  • Configurer les groupes de contrôle d’accès : accès brut ou accès masqué.
  • Configurez la durée de conservation automatique (auto-TTL) pour les tables brutes ou un job DELETE et VACUUM planifié pour des délais de suppression stricts.
  • Créer un tableau de bord de monitoring pour la santé du pipeline et la couverture du caviardage.

Ressources supplémentaires

Étape suivante : Exporter les traces MLflow vers OpenTelemetry