NATS subjects are not just strings; they’re the fundamental mechanism for routing messages, and their structure dictates security.
Let’s see NATS permissions in action. Imagine two services: publisher and subscriber.
# publisher.conf
listen: ":4222"
authorization {
type: "token"
token: "pub-token-123"
}
# subscriber.conf
listen: ":4222"
authorization {
type: "token"
token: "sub-token-456"
}
Now, let’s define permissions in a separate JetStream authorization file, say auth.conf:
# auth.conf
acl {
user: "pub-token-123" {
permissions: {
publish: [ "data.>" ]
}
}
user: "sub-token-456" {
permissions: {
subscribe: [ "data.>" ]
}
}
}
To make this work, you’d start the NATS server with the -a flag pointing to this authorization file:
nats-server -a auth.conf
A client configured with pub-token-123 can publish to data.events.new but not internal.config. A client with sub-token-456 can subscribe to data.> but not data.sensitive.
NATS subjects are hierarchical, using dots (.) as separators. Wildcards (* and >) are crucial for defining flexible permission rules. A * matches any single token, while > matches zero or more tokens.
The core problem NATS subject permissions solve is granular control over message flow in a distributed system. Without them, any connected client could send or receive any message, leading to chaos or security breaches. NATS ACLs allow administrators to define precisely who can talk to whom, on which subjects.
Here’s how it breaks down internally:
- Client Connection: When a client connects, it presents its credentials (like a token).
- Authentication: The NATS server verifies these credentials. If using tokens, it checks if the token exists and is valid.
- Authorization Lookup: If authentication succeeds, the server consults the ACL configuration (
auth.confin our example) based on the authenticated identity (the token). - Permission Check:
- When a client attempts to
PUBLISHto a subject, the server checks thepublishpermissions for that user. It iterates through the allowed patterns. If the subject matches any pattern, the publish is allowed. - When a client attempts to
SUBSCRIBEto a subject, the server checks thesubscribepermissions. If the subject matches any pattern, the subscribe is allowed.
- When a client attempts to
- Action: If permissions are granted, the message is routed or the subscription is established. Otherwise, the operation is rejected with an authorization error.
The > wildcard is particularly powerful. data.> means a client can publish/subscribe to data.events, data.events.new, data.logs, data.logs.audit, and so on. It grants access to any subject that starts with data.. The * wildcard is more restrictive, matching only a single segment. For example, data.*.status would allow data.events.status and data.logs.status, but not data.status or data.events.new.status.
The system uses a trie-like data structure internally to efficiently match subjects against permission rules, especially when wildcards are involved. This allows for very fast lookups even with thousands of subjects and complex ACLs. When a publish or subscribe request comes in, the server traverses this structure to find the most specific matching rule.
A common misconception is that permissions are applied per-user. While you can define permissions for specific users (identified by their tokens or usernames), the power of NATS permissions comes from applying them to groups of users or using wildcard patterns that cover broad categories of subjects. This allows for a scalable permission model that doesn’t require individual configuration for every single client. You define a role (e.g., "metrics-publisher") with specific subject permissions, and then assign multiple users or services to that role.
The next step in mastering NATS security is understanding JetStream’s more advanced authorization mechanisms, including JWTs and account-based access control.