BROKABROKA
Sign inDownload CommunityRequest a demo
Documentation112 pages
Guides

Data masking

Updated 6 October 2026 · applies to 1.0.1 · Commercial

Data masking hides chosen fields of message and value contents in what BROKA shows, for people who may read the contents but not those fields. Rules are defined in one place, Settings ▸ Data masking, and apply on every screen and every answer that carries contents.

A rule names the resources it covers, the fields it hides in them, and how each field is hidden. Someone who needs those fields as they are is given a permission of its own, and every read they make with it is recorded.

What masking is not

The settings screen says it under its header: Masking governs what Broka shows. It does not change the data in the broker, does not stop a client reading it directly, and does not encrypt anything at rest.

A client with its own credentials to the broker reads what the broker holds; no rule here changes that. To keep contents from someone altogether, leave Read message contents (messages.read) out of their role. Masking is for people who need the contents, but not every field in them.

Where it applies

Every place BROKA hands out contents passes through the rules:

  • Kafka — a record's value, key and headers on a topic's Messages tab, in the decoded form and the raw one.
  • RabbitMQ — a message read from a queue or from a stream.
  • Apache Artemis — a message browsed on a queue's Messages tab, and the messages on its Scheduled and In flight tabs.
  • Redis — a key's value: a string, a JSON document, a hash's fields, the members of a list, set or sorted set; a stream's entries, its live tail and the entries a claim hands back; Pub/Sub messages, whose channels are matched against the rule's key patterns; search index documents.
  • Memcached — an item's value.
  • The MCP server — its tools read through the same routes as the console, so an assistant is handed the masked contents, and a filter or a write that is refused here is refused there, with the same reason.

Two diagnostic reads of Redis carry values too: the slow log, and the call of a running function. When a rule masks any key on the connection for you, each entry keeps its command and — for a command known to take a key or a channel first — that name, and every other argument reads ••••. The script given to EVAL, the text given to ECHO, and any command not known to take a key first are masked whole.

Names are never masked. A topic, queue, key or channel name, a field or header name and a stream entry's id are how something is addressed; masking them would make it unaddressable.

No screen exports message contents as a file. A Redis key's Export — Redis's serialized form, the value byte for byte — is refused for a key a rule covers rather than handed over masked.

Where and when masking happens

Masking runs in the broker service, before contents leave it. The console and the MCP server only ever receive the masked rendition, so no screen, route or tool can forget to apply it. A value encoded through Schema Registry — Avro, Protobuf or JSON Schema — is decoded to JSON first and masked after, so a rule's JSON path reaches inside it.

A change to a rule needs no restart. It applies from the next read — within half a minute everywhere, as the confirmations say. A read that keeps going — a Kafka read that keeps listening, a Redis stream's live tail, a Pub/Sub subscription — looks at the rules again as they change, so a rule added while it runs applies from then on.

The list

Settings ▸ Data masking lists the rules, with New rule in the header and the line on what masking is not beneath it. Above the table: a Search rules… box, and filters by Platform, Scope — any environment or connection — State, enabled or disabled, and Tag — a compliance tag, an information kind or a risk level.

Column What it shows
Rule The rule's name; it opens the rule. Names are unique
Platform Kafka, RabbitMQ, Apache Artemis, Redis or Memcached
Scope The environment or the connection the rule applies on
Resources Its patterns
Fields All fields, All fields, except N kept apart, or the fields it masks — their number and the first two when there are more than two
Methods Redact, Partial, or both
Tags Its compliance tags, information kind and risk level
Unmasked readers How many people hold the permission to read unmasked where the rule applies
State enabled or disabled
Last changed When, and by whom

The list opens on Rule, Platform, Scope, Resources, Fields, State and Methods; Description, Tags, Unmasked readers and Last changed are added from the columns menu, and the layout can be kept as a view, as on the other lists.

Each row's menu has Edit, Duplicate — a new rule with the same settings, named (copy) — Disable or Enable, and Delete. Each asks first and says what changes: a disabled or deleted rule's fields are shown as they are from the next read on, an enabled one's are masked, and deleting adds that the audit trail keeps every change made to the rule.

With no rules yet, the table says so: Until there is one, Broka shows contents as they are.

Settings ▸ Data masking: New rule in the header and the line on what masking is not beneath it, the search box and the Platform, Scope, State and Tag filters, then five rules on four platforms — card numbers in payments and customer contact details on Kafka, a customer's e-mail in RabbitMQ order headers, payroll messages on Apache Artemis switched off, and session tokens on Redis — each with its scope, patterns, fields, state and methods.
A rule names fields, never a topic's or a key's name: the names stay readable so the resource can still be found.

Writing a rule

New rule, or a rule's name, opens the rule's sheet. It starts with the rule's Name, Description and an Enabled switch, then five sections.

Where. The Platform; the Scope — an Environment, which takes in the platform's connections in it, or one Connection; and one or more Resource patterns, each a glob in which * matches any run of characters and ? one. What a pattern names depends on the platform:

Platform A pattern matches
Kafka Topic
RabbitMQ Queue, or Queues bound from exchange — every queue bound from an exchange whose name matches, read through the bindings as they are when the contents are read
Apache Artemis Queue, or Address
Redis Key
Memcached Key

Under the patterns, the sheet shows what they match now: N topics on M connections, with the names, up to fifty on each connection. A pattern that matches nothing is allowed — Matches nothing yet. That is allowed: the rule applies to what is created later.

The masking rule sheet for Card numbers in payments: its name, description and Enabled switch, then Where — Kafka, scoped to the Production environment, the pattern payments.* and beneath it 5 topics on 1 connection, named — and the start of What, with $.card.number kept to its last four characters and $.card.holder redacted.
What the patterns match is read live from the brokers, so a rule is checked against the estate before it is saved.

What. Mask all fields redacts every value inside, keeping its type. Then one row per field to mask, each with its kind, its name or path, its own method, and a remove button; Add field adds a row. At least one field, or Mask all fields, is needed.

Kind What it masks Offered on
JSON path A path into a JSON value Every platform
Header A header, by name. On RabbitMQ a message property too, such as correlation_id; on Apache Artemis a message property, with the user id as userID Kafka, RabbitMQ, Apache Artemis
Record key The record's key Kafka
Whole value The whole value Every platform
Hash or stream field One field of a hash or of a stream entry, by name Redis

A JSON path is checked as you type, and takes a deliberate subset: $ followed by .name, ['name'], .* or [*], and ..name — $.customer.email, $.cards[*].number, $..iban. Array positions and filter expressions are not part of it. $ alone is the whole value, so it is refused in favour of Whole value; $..* would mask everything, so it is refused in favour of Mask all fields.

On Redis, a string or a JSON document is the value, and each member of a list, set or sorted set is a value of its own. A hash's fields and a stream entry's fields are masked by name with Hash or stream field; the other kinds apply to each field's value as they would to a value.

When another enabled rule covers the same resource and field, a warning under the fields names it and says which method wins: … also covers … Redact by … wins.

Classification. Compliance takes any number of tags, with the tags already used on other rules offered beside it; Information kind is chosen from the kinds already used or typed; Risk level is Low, Medium, High, Critical or not set. BROKA ships no tags of its own. They change nothing about what is masked: they filter the list, and they are written into the audit trail with every change to the rule and every unmasked read under it.

Preview. The rule as it stands — saved or not — applied to Pasted text, up to 1 MiB, or to the Latest record of a resource its patterns match now. Before and After sit side by side, each masked run highlighted with its rule named on hover, and each masked field listed beneath with its method; a value the rule cannot read shows as it would be read, Masked whole — with the reason. For a record, Before is what you may see of it now and After adds this rule. Reading a record for a preview takes Read message contents where the record is. On RabbitMQ only a stream's latest message can be previewed: reading one from a classic or quorum queue would take it.

The same sheet at Preview: a payment pasted as the sample, Before showing the card number, holder and expiry as they are and After showing the number as dots ending 1111 and the holder and expiry as ••••, each masked run highlighted, the three masked fields listed with their method and rule, and Who sees it unmasked reading Nobody.
The preview applies the rule as it stands in the sheet, saved or not.

Who sees it unmasked. Read-only: the people holding the permission to read unmasked on the rule's scope, each with where they hold it and through which role, team or grant, a disabled account marked as such — or Nobody: everyone sees the masked rendition. The permission is granted in Roles, Users and Teams, never here. The list, and the Unmasked readers count, take in every unmasked-reading grant on the platform within the scope without comparing its pattern with the rule's, so they can name too many people, never too few.

Create rule or Save changes saves it.

How a field is masked

Redact hides a value and its length, and keeps a JSON value's type:

The value Reads
a string ••••
a number 0
a boolean false
null null
an object or an array under the path every value inside it, redacted the same way

Outside JSON — a header, a record key, a whole value that is not JSON, a Redis string — redact gives ••••.

Partial keeps the first and the last characters you ask for, up to 64 at each end, and puts • in place of the rest: a card's last four digits, an e-mail address's first letter. It always yields text, a number's digits included. A value no longer than the characters it keeps is masked whole, as ••••.

A redacted number reads 0 and a redacted boolean false, so the screens that show contents mark what was masked: a masked badge beside the item, whose hover names each masked field, its method and the rule — or, for a value masked whole, the reason. Someone allowed to read it unmasked sees shown unmasked instead, whose hover names the rules that would have masked it and says the read is in the audit trail. It is never ambiguous which of the two you are looking at.

A payments.authorised record opened from the topic's Messages tab, its value as JSON with the masked badge: the card number reads as dots ending 1111, the holder and expiry as ••••, and the badge's hover names each — value $.card.number, partial, and $.card.holder and $.card.expiry, redact — by the rule Card numbers in payments. Re-publish is not offered.
The amounts and ids are untouched: a rule masks the fields it names and nothing beside them.

When rules meet. Inside one rule, Mask all fields and a field listed below it: the field keeps its own method — so all fields, with $.card.number partial keeping the last four, shows those four digits and nothing else. Across rules, the stricter method wins: redact over partial, and of two partials the one that keeps fewer characters.

When a rule cannot read a value

Masking fails closed. A value a rule covers that cannot be read the way the rule expects — not JSON for a rule that looks inside it, bytes rather than text, a schema-encoded record that could not be decoded — is masked whole, with the reason shown: masked: not JSON. A rule never lets content through because it could not find its field.

Until the broker service has read the rules for the first time — its database unreachable as it starts, say — every value it returns is masked whole, attributed to the masking rules, which could not be read. Once it has read them, a refresh that fails keeps the rules it already holds.

Reading unmasked

Read masked contents unmasked (messages.read.unmasked) shows the fields a rule covers as they are. It is in no built-in role, Admin included: it is granted deliberately, to a role, a team or a person — across the installation, on an environment or on a connection, or as a resource grant on a pattern of topics on Kafka, queues on RabbitMQ and Apache Artemis, or keys on Redis and Memcached, which lifts the rules on the resources it matches and nowhere else. A deny wins, as everywhere in the permission model; see Roles and permissions.

It sits beside Read message contents, never in place of it: reading contents still takes messages.read. An API token limited to named permissions reads masked contents unless messages.read.unmasked is one of them.

Every unmasked read is recorded, whatever the installation's setting for recording reads — one entry per resource, naming the rules that were skipped and their tags, so who read tagged data unmasked is one search of the audit trail. A read that streams is recorded when it begins. Contents are shown unmasked only when the read can be recorded: a Pub/Sub channel first heard partway through a pattern subscription is shown masked, even to someone allowed to see it.

On a read that keeps going, unmasked reading lapses after ten minutes. The permission was checked when the read began and cannot be checked again while it runs, so after ten minutes every rule applies; starting the read again asks again. A rule added during such a read applies at once.

A filter cannot reveal a masked field

For someone who may not read the resource unmasked:

  • Kafka — a JSONPath filter or a condition whose path reaches a masked field, and a condition on a masked key or header, is refused before anything is read, naming the rule: The filter reads …, which the masking rule "…" covers, so it would reveal what is masked. Filter on a field you can see, or search the text, which runs on what you can see. Contains, Regex and a Script run on the masked rendition, so they can match only what you can see.
  • Apache Artemis — a selector naming a masked property is refused by the browse, by the count, by the count by original address and by every bulk action, because the messages it matches, and how many, would say what the property holds.
  • Redis — a search index query naming a masked field is refused, and so is finding the positions of a value in a list a rule covers.

Writes and copies

A masked item cannot be written back, and its contents cannot be carried to a place the rule may not reach. For someone who may not read the resource unmasked:

  • Kafka — Re-publish is disabled on a masked record, with the reason: writing it back would overwrite the hidden values with the masks.
  • Redis — setting a masked string, hash field, list item or JSON document is refused, and the sheet's editors are read-only for it, saying why. Renaming, copying and exporting a key a rule covers are refused.
  • Memcached — Set, Replace, Append and Prepend over a key a rule covers, and adjusting it as a counter, are refused; for the item it has just read, the console disables Store, Increment and Decrement, with the reason. Add, which stores only where nothing is, goes ahead.
  • Apache Artemis — moving, copying, retrying, expiring or dead-lettering a masked message, one at a time or by a filter, is refused, and the message's dialog disables those buttons with the reason. The address a retry or an expiry sends a message to is the broker's choice, message by message, so it is refused rather than compared.
  • RabbitMQ — Move messages on a queue a rule masks is refused.

Configuration that keeps copying is refused on the same terms: a RabbitMQ shovel or federation upstream, an Apache Artemis divert or a replay of retained messages, and a Kafka Connect connector that reads topics. Only a source named plainly is compared with the rules by name — a shovel's source queue or exchange, an upstream's queue or exchange, a topic name in a connector's topics — and it is refused when a rule masks it. On RabbitMQ a queue source is also refused while a rule on exchanges masks anything, and an exchange source while a rule on queues does, because the virtual host and the bindings behind a source cannot be read reliably here. Every other way of naming a source — an AMQP 1.0 address, a value that is not text, an upstream that names neither, a MirrorMaker connector's topics, a topic pattern or regular expression — and every divert and replay is refused while any rule of that kind masks anything for you. A federation upstream is checked whatever host its URI names, because whether that host is this broker cannot be told from the URI.

Producing a new message, adding a new key or member and deleting stay governed by their own permissions; none of them shows what is masked. A count such a write returns — how many members were added, how many were removed — still says whether a member was there.

Someone allowed to read the resource unmasked does all of this as before.

Permissions

  • masking.manage — Manage data masking: opening Settings ▸ Data masking, and creating, changing and deleting rules. It is in the built-in Admin role.
  • messages.read.unmasked — Read masked contents unmasked: as above, in no built-in role.

What is recorded

Creating, changing and deleting a rule are each recorded — configuration.masking-rule.create, .update and .delete — with the rule's tags in the entry. Every unmasked read is recorded as broker.message.read-unmasked, naming the rules that were skipped and their tags.

Edition and licence

Data masking is BROKA Commercial: the rules, this screen and the permission to read unmasked are compiled only into the Commercial images. In Community, Data Masking keeps its place under Settings, tagged Commercial, and opens a page saying it is Available in Broka Commercial; nothing is masked.

An expired licence never turns masking off. Every rule stays applied, whatever the licence's state — a protection that lapses with a payment is not one. Only creating, changing or deleting a rule follows the licence: while it withholds Commercial changes, a change is refused with The licence withholds Commercial changes, so masking rules cannot be changed now. Every rule stays applied.

What it costs

Measured on a development machine with ten rules on one JSON value: 0.87 ms for a 1 KiB value, 4.5 ms for 64 KiB, 42.5 ms for 1 MiB. A read of a topic a rule covers pays that for each record, before the read's filter runs; a resource no rule covers pays only a pattern lookup.

← PreviousMCP toolsNext →Clusters