Data Masking
Mask sensitive production data with the GoMask CLI
Data Masking Guide
Learn how to mask sensitive production data for safe use in testing environments.
Overview
Data masking transforms sensitive data (PII, financial data, etc.) into realistic but anonymized values, enabling you to:
- Use production-like data in test environments
- Comply with GDPR, HIPAA, and other regulations
- Protect customer privacy
- Maintain data relationships and formats
Quick Start
Using the Setup Wizard
gomask setup
Select masking when prompted for routine type. The wizard uses AI to:
- Detect sensitive columns (emails, SSNs, names, etc.)
- Suggest appropriate masking functions
- Generate a ready-to-run configuration
Manual Configuration
routine:
name: "Mask Customer PII"
type: masking
connector_id: 1 # Your connector ID
tables:
- table_name: customers
schema_name: public
columns:
- column_name: email
masking_function: mask_email_domain
- column_name: ssn
masking_function: mask_ssn
- column_name: phone
masking_function: mask_phone_partial
Run it:
gomask run mask-customer-pii.yaml --watch
Masking Strategies
Partial Masking
Show some characters, hide others:
columns:
# SSN: 123-45-6789 → ***-**-6789
- column_name: ssn
masking_function: mask_ssn
# Credit card: 4111-1111-1111-1111 → ****-****-****-1111
- column_name: credit_card
masking_function: mask_credit_card
# Phone: (555) 123-4567 → (555) ***-4567
- column_name: phone
masking_function: mask_phone_partial
# Generic: show last 4 characters
- column_name: account_number
masking_function: mask_partial
masking_config:
- name: visible_chars
value: 4
- name: mask_char
value: "*"
Replacement Masking
Replace with realistic fake data:
columns:
# Replace with fake email (same format)
- column_name: email
masking_function: mask_email_domain
# Replace first name with initial
- column_name: full_name
masking_function: initial_last_name
# Scramble name characters
- column_name: first_name
masking_function: scramble_name
# Replace city with region
- column_name: city
masking_function: city_to_region
Date Masking
Preserve patterns while obscuring exact dates:
columns:
# Shift by random days (within ±30 days)
- column_name: birthdate
masking_function: shift_date_random
masking_config:
- name: days_range
value: 30
# Keep month/year, randomize day
- column_name: transaction_date
masking_function: preserve_month_year
Numeric Masking
Add noise or round to ranges:
columns:
# Add ±10% noise
- column_name: salary
masking_function: add_noise_percentage
masking_config:
- name: noise_percent
value: 10
# Round to ranges: 47 → "40-50"
- column_name: age
masking_function: round_to_range
masking_config:
- name: range_size
value: 10
Complete Anonymization
Remove data entirely:
columns:
# Set to NULL
- column_name: notes
masking_function: nullify
# Hash (irreversible)
- column_name: customer_id
masking_function: hash_sha256
masking_config:
- name: salt
value: "my-secret-salt"
# Generic anonymization
- column_name: sensitive_field
masking_function: anonymize
masking_config:
- name: strategy
value: hash # hash, random, mask, null
- name: preserve_type
value: true
Common Masking Patterns
Customer Table
tables:
- table_name: customers
schema_name: public
columns:
- column_name: first_name
masking_function: scramble_name
- column_name: last_name
masking_function: scramble_name
- column_name: email
masking_function: mask_email_domain
- column_name: phone
masking_function: mask_phone_partial
- column_name: ssn
masking_function: mask_ssn
- column_name: birthdate
masking_function: shift_date_random
masking_config:
- name: days_range
value: 30
- column_name: address
masking_function: mask_street_number
Financial Records
tables:
- table_name: transactions
schema_name: public
columns:
- column_name: account_number
masking_function: mask_partial
masking_config:
- name: visible_chars
value: 4
- column_name: card_number
masking_function: mask_credit_card
- column_name: amount
masking_function: add_noise_percentage
masking_config:
- name: noise_percent
value: 5
- column_name: description
masking_function: nullify
Healthcare Data
tables:
- table_name: patients
schema_name: public
columns:
- column_name: mrn
masking_function: hash_consistent
masking_config:
- name: salt
value: "patient-salt"
- column_name: name
masking_function: scramble_name
- column_name: ssn
masking_function: mask_ssn
- column_name: dob
masking_function: preserve_month_year
- column_name: diagnosis
masking_function: nullify
Deterministic Masking
For consistent masking across runs (same input = same output):
columns:
- column_name: customer_id
masking_function: hash_consistent
masking_config:
- name: salt
value: "my-secret-salt"
This ensures:
- Same customer ID always maps to same masked value
- Relationships between tables are preserved
- Different environments get consistent data
Preserving Format
Keep original format structure:
columns:
# Preserves format: ABC-123 → XXX-999
- column_name: reference_number
masking_function: preserve_format
masking_config:
- name: replacement_char
value: "X"
YAML Configuration
Full Structure
routine:
name: "Display Name"
description: "Optional description"
type: masking
connector_id: 1 # Your connector ID
settings:
batch_size: 1000
parallel_workers: 4
audit_reporting_enabled: true
tables:
- table_name: table_name
schema_name: public
columns:
- column_name: column_name
masking_function: masking_function
masking_config:
- name: key
value: value
Multiple Tables
tables:
- table_name: customers
schema_name: public
columns:
- column_name: email
masking_function: mask_email_domain
- table_name: orders
schema_name: public
columns:
- column_name: customer_email
masking_function: mask_email_domain
- column_name: shipping_address
masking_function: mask_street_number
Validation
# Validate configuration
gomask validate masking-routine.yaml --detailed
# Preview what will be masked
gomask run masking-routine.yaml --dry-run
Available Masking Functions
Contact Data
| Function | Description |
|---|---|
mask_email_domain | Mask email, replace domain |
mask_phone_partial | Show first 3, last 4 digits |
Identity Data
| Function | Description |
|---|---|
mask_ssn | Show only last 4 digits |
mask_credit_card | Show only last 4 digits |
scramble_name | Randomize characters |
initial_last_name | First initial + last name |
Location Data
| Function | Description |
|---|---|
mask_street_number | Replace street numbers |
city_to_region | Replace city with state |
Date/Time
| Function | Description |
|---|---|
shift_date_random | Shift by random days |
preserve_month_year | Keep month/year only |
Numeric
| Function | Description |
|---|---|
add_noise_percentage | Add random ±% |
round_to_range | Round to ranges |
Generic
| Function | Description |
|---|---|
mask_partial | Show last N chars |
nullify | Set to NULL |
hash_sha256 | Irreversible hash |
hash_consistent | Deterministic hash |
anonymize | Multiple strategies |
Compliance Considerations
GDPR
- Use irreversible functions (
hash_sha256,nullify) for right-to-erasure compliance - Document masking applied for accountability
- Consider pseudonymization vs anonymization requirements
HIPAA
- Protected Health Information (PHI) requires de-identification
- 18 HIPAA identifiers must be addressed
- Use
nullifyor strong masking for direct identifiers
PCI-DSS
- Credit card numbers must be masked showing only last 4 digits
- Use
mask_credit_cardfor compliant masking - Consider tokenization for production systems
Best Practices
- Map sensitive columns - Identify all PII before starting
- Use consistent salt - Same salt = same masked values
- Test thoroughly - Validate masked data meets requirements
- Document approach - Record masking decisions for compliance
- Preserve relationships - Use deterministic masking for foreign keys
- Validate output - Check masked data works for testing
Next Steps
- Function Reference - All masking functions
- Synthetic Data - Generate new data instead
- CI/CD Integration - Automate masking