Managing Operator Hierarchies in NATS 2.0

Kevin Hoffman
4 min readApr 18, 2019
NATS 2.0 Security Hierarchy

In my previous blog post on NATS 2.0, I discussed some of the new concepts and basic primitives in its decentralized security system. In this post, I’ll be walking you through the creation of an operator hierarchy using available NATS command line tools.

To recap my previous post — NATS 2.0 includes a new security hierarchy that starts at the top with operators, which vouch for (via signing) accounts, which in turn vouch for users within those accounts. NATS configuration files can be set up to store accounts statically in memory, or via a remote HTTP account resolver.

The first thing you need to do if you want to follow along is install the nsc command line tool (which I believe stands for NATS Server Configuration). With this in place, you can start creating entities in your new secure system that will be stored in folders on your local disk.

For this tutorial, let’s assume that we’re going to create a highly available NATS cluster to provide the backbone for an online game called World of WasmCraft, a high fantasy game controlled entirely through WebAssembly modules.

To get started, we’ll create an entire operator hierarchy with the init command:

Initializing an Operator Hierarchy

If you ran the same command I did, you should see a nice box that shows you the names and locations of the entities you just created:

  • wasmcraft_operator — The root operator
  • gamecore —A single account, signed by the operator
  • coreuser — A single user, signed by the gamecore account. This user comes with a credentials file containing their JWT and the secret seed key.

The .nk files are nkey files, a more human-consumable version of Ed25519 keys. Everything in a .nk file is a secret and needs to be treated as such. With this one command we were able to create all of the entities necessary to start using a NATS server right away.

With everything created, go ahead and issue the following commands to take a look at what information is available for each of these entity types:

  • nsc describe operator
  • nsc describe account
  • nsc describe user

The information supporting these describe commands is coming from the public information in the JSON Web Token (JWT). As another fun experiment, take a look at the JWT files (you’ll find them in the ~/.nsc/nats/wasmcraft_operator directory). Copy the contents of any of the JWT files and paste it into jwt.io and you can see the data inside the encoded string. Here’s what my operator looks like (your public key will be different):

{
"jti": "TJ5A3HD3FPJW6BW7AQ2EB4AT6PFNTQVUGMTSLTYSYVMGRJROPOWA",
"iat": 1555599057,
"iss": "OATAMZNCE575N2KBCS7B74HONGVBEZFJPFRAPM47XWCCZG3LMSI6XLA4",
"name": "wasmcraft_operator",
"sub": "OATAMZNCE575N2KBCS7B74HONGVBEZFJPFRAPM47XWCCZG3LMSI6XLA4",
"type": "operator"
}

An interesting thing to point out here is that the iss field (issuer) and the sub field (subject) are identical. Think of this like a self-signed certificate — the operator issued (and signed) its own JWT. When you look at an account JWT, you’ll see that the issuer is the public key of the operator:

{
"jti": "FOPM6ZZQFQNZIEHCMFUJI32WNZQIFTYFDK2H6FK6ATC3HFSDQDMQ",
"iat": 1555599057,
"iss": "OATAMZNCE575N2KBCS7B74HONGVBEZFJPFRAPM47XWCCZG3LMSI6XLA4",
"name": "gamecore",
"sub": "ACFTXEBWFTAVV5OX4QAXOXJN3AZL54SWNFKTVBK7EXYMYBGP24G3LHDJ",
"type": "account",
"nats": {
"limits": {
"subs": -1,
"conn": -1,
"imports": -1,
"exports": -1,
"data": -1,
"payload": -1,
"wildcards": true
}
}
}

The JWTs you’ve seen so far are used for verification purposes by NATS 2.0 when operating in decentralized security mode. Users also present JWTs to NATS when they connect (users here shouldn’t be thought of as humans, rather they are logical units of authentication and authorization).

It’s worth paying special attention to the iss field, which is the key to establishing provenance of any user connecting to NATS. A valid account is the issuer of a user, and a valid operator is the issuer of an account.

The nsc command line tool helps you create and edit JWTs and the corresponding seed keys, but it doesn’t do anything to help you configure your NATS server to recognize them. For that, you’ll need to edit the configuration file manually.

Here’s an example configuration file that configures our root operator, sets the gamecore account as the system account (used for special NATS operations), and identifies the gamecore account as a valid account for user connections.

NATS 2.0 Configuration File for “Wasmcraft”

In this configuration, the NATS server will start up with a single operator and a single account (which is also the system account). Any user issued by the gamecore account should be able to connect to NATS and start publishing and subscribing on subjects contained within the gamecore account.

You can also set NATS up to use a remote HTTP account resolver, and I’ll talk about how to build that in another blog post. This gives you some more flexible control over the list of valid accounts without sacrificing the benefits of the decentralized security system.

With a configuration like this in place, account owners (those who possess the account seed key) can create as many users as they like, with whatever permissions they like, and NATS will automatically be able to verify and constrain those users all without the central server storing any secrets for accounts, users, or operators.

If you’ve ever tried to maintain your own messaging system in production, then you know how much of a pain it is to deal with changes to security, to users, and, in some cases, changes to queues and partitions and other fussy things that need constant attention. NATS 2.0 needs no such babysitting.

Hopefully this post inspired you to go play with the nsc tool and create accounts. In another blog post, I’ll show how you can use nsc to create imports and exports and control secure sharing between accounts with no operations overhead.

Until then, keep NATSing!

--

--

Kevin Hoffman

In relentless pursuit of elegant simplicity. Tinkerer, writer of tech, fantasy, and sci-fi. Converting napkin drawings into code for @CapitalOne