koyan9/spring-privacy-guard
Spring Boot starter for privacy-safe JSON masking, log sanitization, audit trails, dead-letter management, and signed webhook/email alerting.
spring-privacy-guard
A Spring Boot starter for masking sensitive data, sanitizing logs, tracing privacy operations, and operating dead-letter workflows securely.
Modules
privacy-guard-core/: masking annotations, built-in sensitive types, text sanitization, and masking SPI contracts.privacy-guard-spring-boot-starter/: Spring Boot auto-configuration, Jackson integration, Logback integration, audit storage, dead-letter handling, webhook/email alerts, and receiver verification support.samples/privacy-demo/: runnable sample covering masking, auditing, dead-letter operations, signed alert delivery, and verified receiver flows.
Features
- Field masking with
@SensitiveDataand customMaskingStrategy - Safe JSON serialization and free-text log sanitization
- Audit recording, querying, pagination, sorting, and statistics
IN_MEMORYandJDBCrepositories for audits and dead letters- Async publishing, batching, retries, dead letters, replay, and export/import
- Actuator health checks and Micrometer metrics for backlog and alert delivery
- Signed webhook/email alerts plus reusable webhook verifier, replay store, filter, and interceptor support
Quick Start
Requirements:
- Java
17+ - Spring Boot
3.3.x
Add the starter:
<dependency>
<groupId>io.github.koyan9</groupId>
<artifactId>spring-privacy-guard-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
Example model:
public record PatientView(
@SensitiveData(type = SensitiveType.NAME) String patientName,
@SensitiveData(type = SensitiveType.PHONE) String phone,
@SensitiveData(type = SensitiveType.ID_CARD) String idCard,
@SensitiveData(type = SensitiveType.EMAIL) String email
) {
}
Minimal config:
privacy:
guard:
fallback-mask-char: "*"
audit:
repository-type: IN_MEMORY
Key Config
| Property | Default | Notes |
|---|---|---|
privacy.guard.enabled |
true |
Master switch for the starter. |
privacy.guard.logging.enabled |
true |
Enables privacy-safe logging helpers. |
privacy.guard.audit.enabled |
true |
Enables audit services and publishers. |
privacy.guard.audit.repository-type |
NONE |
NONE, IN_MEMORY, or JDBC. |
privacy.guard.audit.dead-letter.repository-type |
NONE |
Dead-letter storage type. |
privacy.guard.audit.dead-letter.observability.health.warning-threshold |
1 |
Backlog warning threshold. |
privacy.guard.audit.dead-letter.observability.health.down-threshold |
100 |
Backlog down threshold. |
privacy.guard.audit.dead-letter.observability.alert.enabled |
false |
Enables dead-letter alerting. |
privacy.guard.audit.dead-letter.observability.alert.webhook.url |
empty | Enables built-in webhook alerts. |
privacy.guard.audit.dead-letter.observability.alert.email.to |
empty | Enables built-in email alerts. |
privacy.guard.audit.dead-letter.observability.alert.receiver.filter.enabled |
false |
Enables the built-in receiver verification filter. |
privacy.guard.audit.dead-letter.observability.alert.receiver.interceptor.enabled |
false |
Enables the built-in receiver verification interceptor. |
privacy.guard.audit.dead-letter.observability.alert.receiver.verification.enabled |
false |
Creates receiver verification settings from properties. |
privacy.guard.audit.dead-letter.observability.alert.receiver.verification.bearer-token |
empty | Optional bearer token required by the built-in verifier. |
privacy.guard.audit.dead-letter.observability.alert.receiver.verification.signature-secret |
empty | Optional HMAC secret required by the built-in verifier. |
privacy.guard.audit.dead-letter.observability.alert.receiver.verification.max-skew |
5m |
Allowed timestamp skew for receiver verification. |
privacy.guard.audit.dead-letter.observability.alert.receiver.replay-store.file.enabled |
false |
Enables the file-backed replay store for receiver verification. |
privacy.guard.audit.dead-letter.observability.alert.receiver.replay-store.file.path |
privacy-audit-webhook-replay-store.json |
File path for replay store entries. |
privacy.guard.audit.dead-letter.observability.alert.receiver.replay-store.jdbc.enabled |
false |
Enables the JDBC replay store for receiver verification. |
privacy.guard.audit.dead-letter.observability.alert.receiver.replay-store.jdbc.table-name |
privacy_audit_webhook_replay_store |
JDBC table name for replay store entries. |
privacy.guard.audit.dead-letter.observability.alert.receiver.replay-store.jdbc.initialize-schema |
false |
Runs the replay store schema initializer. |
privacy.guard.audit.dead-letter.observability.alert.receiver.replay-store.jdbc.cleanup-interval |
5m |
Minimum interval between replay store cleanup passes. |
For the full property matrix, examples, and advanced options, see the sections below.
Custom Masking
Implement MaskingStrategy when built-in SensitiveType rules are not enough:
@Bean
MaskingStrategy customNameMaskingStrategy() {
return new MaskingStrategy() {
@Override
public boolean supports(MaskingContext context) {
return context.sensitiveType() == SensitiveType.NAME;
}
@Override
public String mask(String value, MaskingContext context) {
return "[custom]" + value;
}
};
}
Audit and Dead Letters
The starter supports:
- async and batched audit publishing
- retry with dead-letter fallback
- dead-letter query, cleanup, replay, export, and import
- operation-audit traces for management activity
Sample dead-letter endpoints include:
GET /audit-dead-lettersGET /audit-dead-letters/statsDELETE /audit-dead-letters/{id}POST /audit-dead-letters/{id}/replayPOST /audit-dead-letters/replay?limit=100
Observability and Alerts
Actuator & Metrics
When Actuator is present, the starter can expose:
privacyAuditDeadLettershealthprivacy.audit.deadletters.totalprivacy.audit.deadletters.state{state=*}privacy.audit.deadletters.threshold{level=*}privacy.audit.deadletters.alert.webhook.attemptsprivacy.audit.deadletters.alert.webhook.retriesprivacy.audit.deadletters.alert.webhook.deliveries{outcome=*}privacy.audit.deadletters.alert.webhook.last_delivery_seconds{outcome=*}privacy.audit.deadletters.alert.webhook.failures{type=*,retryable=*}privacy.audit.deadletters.alert.webhook.last_failure_statusprivacy.audit.deadletters.alert.webhook.last_failure_retryableprivacy.audit.deadletters.alert.webhook.last_failure_type{type=*}privacy.audit.deadletters.receiver.replay_store.countprivacy.audit.deadletters.receiver.replay_store.expiring_soonprivacy.audit.deadletters.receiver.replay_store.expiry_seconds{kind=*}
Built-in Webhook Alerts
privacy:
guard:
audit:
dead-letter:
observability:
alert:
enabled: true
webhook:
url: https://example.com/privacy-alerts
bearer-token: demo-token
signature-secret: demo-hmac-secret
signature-algorithm: HmacSHA256
signature-header: X-Privacy-Alert-Signature
timestamp-header: X-Privacy-Alert-Timestamp
nonce-header: X-Privacy-Alert-Nonce
max-attempts: 3
backoff: 200ms
The built-in webhook callback retries failed deliveries, signs timestamp.nonce.payload, and records delivery metrics when Micrometer is available.
When delivery fails, the callback logs include failure type, status code, retryable flag, and a short error message.
Built-in Email Alerts
spring:
mail:
host: smtp.example.com
port: 587
username: demo-user
password: demo-password
privacy:
guard:
audit:
dead-letter:
observability:
alert:
enabled: true
email:
from: privacy@example.com
to: ops@example.com
Webhook Verification SPI
Applications receiving signed alerts can reuse:
PrivacyAuditDeadLetterWebhookRequestVerifierPrivacyAuditDeadLetterWebhookReplayStoreInMemoryPrivacyAuditDeadLetterWebhookReplayStoreFilePrivacyAuditDeadLetterWebhookReplayStoreJdbcPrivacyAuditDeadLetterWebhookReplayStorePrivacyAuditDeadLetterWebhookVerificationFilterPrivacyAuditDeadLetterWebhookVerificationInterceptor
Choose one of these protection modes:
privacy.guard.audit.dead-letter.observability.alert.receiver.filter.enabled=trueprivacy.guard.audit.dead-letter.observability.alert.receiver.interceptor.enabled=true- manual verifier injection in your own endpoint code
Verification failures return a JSON body with an error message and a reason code, for example:
{"error":"Invalid signature","reason":"INVALID_SIGNATURE"}
Reason codes include INVALID_AUTHORIZATION, MISSING_SIGNATURE_HEADERS, INVALID_TIMESTAMP, EXPIRED_TIMESTAMP, INVALID_SIGNATURE, and REPLAY_DETECTED.
You can supply verification settings with properties instead of defining a bean:
privacy:
guard:
audit:
dead-letter:
observability:
alert:
receiver:
verification:
enabled: true
bearer-token: demo-receiver-token
signature-secret: demo-receiver-secret
max-skew: 5m
If receiver verification is enabled without a bearer token or signature secret, verification becomes a no-op and only basic routing is applied.
File Replay Store
Use the file-backed replay store for single-instance deployments:
privacy:
guard:
audit:
dead-letter:
observability:
alert:
receiver:
replay-store:
file:
enabled: true
path: /var/lib/privacy-audit/replay-store.json
JDBC Replay Store
privacy:
guard:
audit:
dead-letter:
observability:
alert:
receiver:
replay-store:
jdbc:
enabled: true
initialize-schema: true
table-name: privacy_audit_webhook_replay_store
Sample App
samples/privacy-demo/ demonstrates:
- masking and audit query endpoints
- dead-letter export/import/replay endpoints
- signed receiver endpoint:
POST /demo-alert-receiver - receiver inspection:
GET /demo-alert-receiver/last - replay-store query:
GET /demo-alert-receiver/replay-store?limit=20&offset=0 - replay-store stats:
GET /demo-alert-receiver/replay-store/stats?expiringWithin=PT5M - replay-store clear:
DELETE /demo-alert-receiver/replay-store
The sample uses filter mode by default. To switch to interceptor mode:
- Windows:
mvnw.cmd spring-boot:run -Dspring-boot.run.profiles=interceptor - macOS / Linux:
./mvnw spring-boot:run -Dspring-boot.run.profiles=interceptor
Local Development
- Verify everything:
./mvnw -q verifyormvnw.cmd -q verify - Install local artifacts:
./mvnw -q -DskipTests install - Run sample:
./mvnw -q -f samples/privacy-demo/pom.xml spring-boot:run
Maintainer Quick Start
- Triage using
SUPPORT.md,SECURITY.md, anddocs/GITHUB_LABELS.md - Run
python scripts/check_repo_hygiene.pybefore tagging - Follow
docs/MAINTAINER_GUIDE.mdanddocs/RELEASE_EXECUTION_v0.2.0.mdfor releases
Roadmap
Recommended next development focus for 0.2.0:
- Receiver-side metrics/health consolidation and dashboard examples
- Stronger receiver persistence options beyond file-backed replay stores
- Broader database and production deployment examples
- API polish for alert callbacks and receiver auto-configuration
- Release packaging, badges, and docs hardening
Project Docs
- Documentation index:
docs/INDEX.md - Maintainer guide:
docs/MAINTAINER_GUIDE.md - Receiver operations:
docs/RECEIVER_OPERATIONS.md - Roadmap:
docs/ROADMAP.md - Release checklist:
docs/RELEASE_CHECKLIST.md - Release execution guide:
docs/RELEASE_EXECUTION_v0.2.0.md - Release runbook:
docs/RELEASE_RUNBOOK_v0.2.0.md - Draft release notes:
docs/releases/RELEASE_NOTES_v0.2.0.md - Release dry run:
docs/RELEASE_DRY_RUN_v0.2.0.md - Release announcement:
docs/RELEASE_ANNOUNCEMENT_v0.2.0.md - Release announcement (zh-CN):
docs/RELEASE_ANNOUNCEMENT_v0.2.0.zh-CN.md - GitHub release copy:
docs/GITHUB_RELEASE_COPY_v0.2.0.md - GitHub metadata:
docs/GITHUB_METADATA.md
Release Notes
The release workflow looks for docs/releases/RELEASE_NOTES_<tag>.md first and falls back to docs/releases/RELEASE_NOTES_TEMPLATE.md.