Skip to content

Compliance & PII Masking

Protect sensitive data throughout the reconciliation pipeline with PII masking, audit trails, and automated retention enforcement.

Overview

Healthcare, financial, and global organizations need identity resolution that respects data privacy regulations. Kanoniv's compliance system lets you declare which fields contain PII, whether audit trails are mandatory, and how long data should be retained. The engine enforces these settings at runtime.

Cloud Feature

Compliance configuration requires the Cloud tier.

Spec Configuration

Add a compliance block to your entity definition:

yaml
entity:
  name: patient
  description: Healthcare patient identity
  compliance:
    frameworks:
      - hipaa
      - gdpr
    pii_fields:
      - email
      - phone
      - ssn
      - date_of_birth
    audit_required: true
    retention_days: 2555  # 7 years

Fields

FieldTypeRequiredRuntime Behavior
pii_fieldsstring[]NoFields listed here are masked with *** in audit logs, match results, and API responses for non-admin callers
audit_requiredboolNoWhen true, forces audit trail logging for every match decision (overrides audit.log_all_comparisons)
retention_daysintNoCleanup pipeline deletes external entities older than this many days
frameworksstring[]NoDeclarative tags stored in the compiled plan. Not enforced at runtime; see below

The frameworks field

The frameworks field accepts an array of strings (e.g., hipaa, gdpr, soc2, ccpa) that are compiled into the identity plan and stored alongside your configuration. However, these values are never read or acted upon by any runtime code path. No framework-specific enforcement logic exists. There is no automatic mapping from hipaa to stricter retention, from gdpr to right-to-erasure behavior, or from soc2 to additional access controls.

The frameworks field is useful for:

  • Audit log filtering: query which identity plans operate under a given regulatory framework
  • Organizational documentation: declare intent so that teams reviewing specs understand which regulations apply
  • CI/CD policy enforcement: external tooling (linters, policy-as-code) can read the compiled plan and validate that pii_fields, audit_required, and retention_days are configured appropriately for the declared frameworks

All actual runtime enforcement comes from the other three fields: pii_fields, audit_required, and retention_days. If you need HIPAA-grade protection, you must explicitly configure those fields yourself.

What Each Field Does at Runtime

pii_fields: PII Masking

Fields listed in pii_fields are masked in two places:

1. Audit logs and match results (pipeline)

During reconciliation, the worker collects PII field names from both the entity-level compliance.pii_fields list and any source-level pii_fields declarations. Before persisting match results and audit records, field values that match a PII field name are replaced with ***. Raw values are used in-memory for matching but never written to storage unmasked.

2. API responses (canonical entity reads)

When a non-admin caller reads a canonical entity through the API, any keys in canonical_data that match a declared PII field are replaced with ***. Admin callers see the full unmasked data.

python
import httpx

# Admin key -- sees full data
resp = httpx.get(
    "https://api.kanoniv.com/v1/entities/ent_123",
    headers={"X-API-Key": "kn_admin_..."},
)
entity = resp.json()
print(entity["canonical_data"]["email"])
# -> "[email protected]"

# Regular key -- PII is masked
resp = httpx.get(
    "https://api.kanoniv.com/v1/entities/ent_123",
    headers={"X-API-Key": "kn_readonly_..."},
)
entity = resp.json()
print(entity["canonical_data"]["email"])
# -> "***"
bash
# Admin key -- full data
curl "https://api.kanoniv.com/v1/entities/ent_123" \
  -H "X-API-Key: kn_admin_..."
# -> { "canonical_data": { "email": "[email protected]", ... } }

# Non-admin key -- masked PII
curl "https://api.kanoniv.com/v1/entities/ent_123" \
  -H "X-API-Key: kn_readonly_..."
# -> { "canonical_data": { "email": "***", ... } }

audit_required: Forced Audit Trail

When audit_required is set to true, the pipeline logs an audit record for every match decision, including NoMerge outcomes that would otherwise be skipped. This overrides the per-decision filtering controlled by audit.log_decisions and audit.log_all_comparisons.

Without audit_required, audit logging follows the settings in the decision.audit block:

yaml
decision:
  audit:
    log_all_comparisons: false  # Only logs non-NoMerge decisions by default
    log_decisions: true

With compliance.audit_required: true, every comparison is logged regardless of those settings.

retention_days: Automated Data Cleanup

When retention_days is set, the cleanup pipeline (which runs periodically) deletes external entities older than the specified number of days:

sql
DELETE FROM external_entities
WHERE tenant_id = $1
  AND entity_type = $2
  AND created_at < NOW() - '<retention_days> days'::interval

Deletions are logged with the tenant ID, entity type, retention period, and count of removed records.

Schema-Level PII Declaration

In addition to the entity-level pii_fields list, you can declare PII at the source schema level:

yaml
sources:
  - name: crm
    adapter: postgres
    location: public.contacts
    primary_key: id
    schema:
      email:
        type: string
        pii: true
      ssn:
        type: string
        pii: true
      name:
        type: string
        nullable: true

Fields marked pii: true in the schema are automatically included in compliance masking, even if not listed in pii_fields. At runtime, the pipeline merges both sets before applying masking.

WARNING

If a source declares PII fields in its schema but no compliance block exists on the entity, the validator will emit a warning. Always pair PII declarations with a compliance config.

Full Example

yaml
api_version: kanoniv/v2
identity_version: patient_v2

metadata:
  name: Patient Identity Resolution
  owner: data-engineering
  tags:
    - healthcare
    - production

entity:
  name: patient
  description: Cross-system patient matching
  compliance:
    frameworks:
      - hipaa
    pii_fields:
      - email
      - phone
      - ssn
      - date_of_birth
    audit_required: true
    retention_days: 2555

sources:
  - name: ehr
    adapter: postgres
    location: clinical.patients
    primary_key: patient_id
    schema:
      email:
        type: string
        pii: true
      phone:
        type: string
        pii: true
      ssn:
        type: string
        pii: true
      date_of_birth:
        type: date
        pii: true
      name:
        type: string
    attributes:
      email: email_address
      phone: phone_number
      name: full_name

  - name: claims
    adapter: snowflake
    location: warehouse.claims.members
    primary_key: member_id
    attributes:
      email: member_email
      phone: contact_phone
      name: member_name

rules:
  - type: exact
    name: email_match
    field: email
    weight: 1.0
  - type: similarity
    name: name_match
    field: name
    algorithm: jaro_winkler
    threshold: 0.88
    weight: 0.7

decision:
  thresholds:
    match: 0.9
    review: 0.7
  audit:
    log_all_comparisons: true
    log_decisions: true
    log_conflicts: true

In this example:

  • pii_fields ensures that email, phone, ssn, and date_of_birth are masked in all persisted match results, audit logs, and non-admin API responses
  • audit_required: true guarantees every comparison is logged, even NoMerge decisions
  • retention_days: 2555 causes the cleanup pipeline to delete entities older than ~7 years
  • frameworks: [hipaa] is stored as a declarative tag but does not trigger any automatic behavior

Next Steps

The identity and delegation layer for AI agents.