Masking
Not every caller who reaches a field through Kafka Gateway is authorized to see the same thing. disclosure is the transforms entry that decides what a caller gets back on retrieval when they don't hold the role authorized for the real value: a masked, hashed, redacted, or omitted substitute, rather than the plaintext or an empty value.
topics:
- name: my-kafka-topic
value:
model: json
catalog:
my_catalog:
- strategy: topic
transforms:
- select:
- type: structure
fields:
- tagged:
- x-kind: pii
guarded:
my-guard:
- card:full
disclosure:
action: mask
pattern: "XX***@***XX"Anyone holding the card:full role gets the real value back on retrieval; everyone else gets the masked pattern instead.
topics[].name also accepts a wildcard * to match every topic on the binding, so the same disclosure rule applies uniformly instead of being repeated per topic.
How It Works
A transforms entry on a schema-backed model pairs a select (which fields it applies to), a guarded (which roles get the real value back), and a disclosure (what everyone else's retrieval degrades to instead). With no guarded at all on a rule, nobody ever gets the real value back: retrieval always degrades to the disclosure substitute, or to an empty/zero value if no disclosure is configured either.
disclosure needs no encryption configured at all: a field can be stored in Kafka as plain, unencrypted JSON, Avro, or Protobuf, and still have its real value withheld from callers who don't hold the right role. Its natural place, though, is downstream of encryption, on the same rule: together they say what an unauthorized caller gets back instead of the empty value encryption alone would leave them with.
Selecting which fields a rule applies to works the same way encryption selects them — see Selecting Which Fields to Protect.
Degrees of Retrieval
| Degree | Result |
|---|---|
| (full plaintext) | Governed by guarded; no disclosure needed. The caller gets the real value back. |
mask | The field is replaced per a pattern template such as "XX***@***XX": a reveal character (X by default, overridable via reveal) marks positions kept from the original value, a mask character (* by default, overridable via mask) marks positions hidden, and any other character is a literal anchor (like @ above) that must occur in the actual value at that position. If an anchor can't be found in the value, the whole value is masked as a fail-safe rather than risk revealing more than intended. |
hash | The field is replaced with a deterministic digest of its real value (SHA-256 by default, or HMAC-SHA256 keyed by a configured secret), rendered as hex. The same input always hashes the same, which supports joins or deduplication downstream without exposing the plaintext. |
redact | The field is replaced with a fixed, type-appropriate blank: "" for strings, 0 for numbers, false for booleans. |
omit | The field is nulled out entirely (legal only where the schema allows a null there). |
topics:
- name: my-kafka-topic
value:
model: json
catalog:
my_catalog:
- strategy: topic
transforms:
- select:
- type: structure
fields:
- tagged:
- x-kind: pii-hash
disclosure:
action: hash
secret: my-hmac-secretMasking a Field
mask is the only degree that keeps part of the original value legible, which makes it the right choice when a caller still needs to recognize or partially verify a value, such as the last four digits of a card number or the domain of an email address, without seeing the whole thing.
reveal and mask default to X and *, but either can be overridden to fit a pattern that reads more naturally for a given field:
disclosure:
action: mask
pattern: "RR-MMMM"
reveal: "R"
mask: "M"Any character in pattern other than the current reveal or mask character is treated as a literal anchor that must occur in the real value at that exact position; a value that doesn't match every anchor is masked in full instead, so a misconfigured or unexpectedly-shaped value never reveals more than intended.
Combining with Encryption
When a rule pairs disclosure with encryption, an authorized caller — matching guarded, or encryption.guarded if that's set — decrypts and gets the real value straight off. For anyone else, decrypt is skipped outright: never attempted, never charged against the vault. disclosure then decides what they see in its place. hash and mask never run against ciphertext bytes they can't read, so a denied decrypt can never leak a hash or masked fragment derived from real ciphertext. See Authorization and Decrypt for the full decrypt flow.
Editions
| Component | Community | Plus |
|---|---|---|
disclosure transform | — | ✓ |
Next Steps
- Encryption covers keeping a protected field unreadable at rest, and how disclosure interacts with decrypt.
- Schema Enforcement covers the model types disclosure layers onto.

