NATS Weekly #27

NATS Weekly #27

Week of May 16 - 22, 2022

🗞 Announcements, writings, and projects

A short list of  announcements, blog posts, projects updates and other news.

⚡ Releases

Official releases from NATS repos and others in the ecosystem.

⚙️ Projects️

Open Source and commercial projects (or products) that use or extends NATS.

  • bruth/rita - Toolkit for event-centric and reactive patterns leveraging NATS. This package has started as a result of the series Implementing an event store on NATS. Part II is coming out this week with the first set of design decisions for this package.

📖 Articles

Blog posts, tutorials, or any other text-based content about NATS.

💬 Discussions

Github Discussions from various NATS repositories.

💡 Recently asked questions

Questions sourced from Slack, Twitter, or individuals. Responses and examples are in my own words, unless otherwise noted.

How are decentralized users and account JWTs managed? What is special about the SYS account? How can I rotate keys?

Since there are a few points to unpack, I am going to do a quick walkthrough of the decentralized authentication setup and call out points of interest.

To bootstrap the decentralized authentication model, we must first create an operator. Each server in your cluster (with any topology) needs to be configured with the operator to be in the same authentication domain. Leaf nodes are the exception since they may provide their own authentication boundary, but they still need to rely on user credentials of the remote operator to authenticate the leaf node connection.

The nsc tool should be used to create the operator, the SYS account, and signing keys.

nsc add operator --generate-signing-key --sys --name local

nsc edit operator --require-signing-keys --account-jwt-server-url nats://127.0.0.1:4222

This will create the operator, called local, with a signing key (more on this in a bit) and the SYS account and sys user automatically. The follow-up edit requires signing keys to be used for account and user creation which is a best practice. The service URL config binds the operator to a specific server for pushing/pulling account JWTs, via nsc push or nsc pull.

Now we can use the following command to generate the config for the server relevent to configuring this auth model.

nsc generate config --nats-resolver --sys-account SYS

Which will generate something that looks like this (generated comments for brevity).

operator: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJCVVAzUFNRUkFaNUtJTjVIR1FPUVg2WkZDVElIMzdJU1NEREZRUUNEUFhRSUZNTVNHU1FBIiwiaWF0IjoxNjUzMDQ0MDAwLCJpc3MiOiJPQktDNEhRT0RXSFI0NFlBTDYzR0NNUzNFWkZJT0gyWkFGNlpRTFEyWURENEJUNUZVS1JJVjYzUyIsIm5hbWUiOiJsb2NhbCIsInN1YiI6Ik9CS0M0SFFPRFdIUjQ0WUFMNjNHQ01TM0VaRklPSDJaQUY2WlFMUTJZREQ0QlQ1RlVLUklWNjNTIiwibmF0cyI6eyJzaWduaW5nX2tleXMiOlsiT0FNS1FQM1dXRzYyUVpCUEtGQjNTUzRTWlVWVUw3VVdIVEdUUktJRk8yMlM2SDZYRTZVQ1o0VUMiXSwic3lzdGVtX2FjY291bnQiOiJBQ1BUUkUzNURYUEhBNDczU1pIVk9LUFdHWEhTNlBBUVRYSVdYR042VEFMSDNCQ1JJTEZBSUNWSSIsInR5cGUiOiJvcGVyYXRvciIsInZlcnNpb24iOjJ9fQ.hRtCCVbx_wCLd5wE-m6I4mKHdGarn99H4zZmDpiEjze1puMNyaKCZDYqkThvSsvGhQMHW8q89Q_3AWIQ2bSlAQ

system_account: ACPTRE35DXPHA473SZHVOKPWGXHS6PAQTXIWXGN6TALH3BCRILFAICVI

resolver {

type: full

dir: './jwt'

allow_delete: false

interval: "2m"

timeout: "1.9s"

}

resolver_preload: {

ACPTRE35DXPHA473SZHVOKPWGXHS6PAQTXIWXGN6TALH3BCRILFAICVI: eyJ0eXAiOiJKV1QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJQV01QUk1JWU1SVkRPU0U0T0VIRE1INkQyRklPWlhaRkVVS0FRNVlFTUVEM0MzNldOUVZRIiwiaWF0IjoxNjUzMDQ0MDAwLCJpc3MiOiJPQU1LUVAzV1dHNjJRWkJQS0ZCM1NTNFNaVVZVTDdVV0hUR1RSS0lGTzIyUzZINlhFNlVDWjRVQyIsIm5hbWUiOiJTWVMiLCJzdWIiOiJBQ1BUUkUzNURYUEhBNDczU1pIVk9LUFdHWEhTNlBBUVRYSVdYR042VEFMSDNCQ1JJTEZBSUNWSSIsIm5hdHMiOnsiZXhwb3J0cyI6W3sibmFtZSI6ImFjY291bnQtbW9uaXRvcmluZy1zdHJlYW1zIiwic3ViamVjdCI6IiRTWVMuQUNDT1VOVC4qLlx1MDAzZSIsInR5cGUiOiJzdHJlYW0iLCJhY2NvdW50X3Rva2VuX3Bvc2l0aW9uIjozLCJkZXNjcmlwdGlvbiI6IkFjY291bnQgc3BlY2lmaWMgbW9uaXRvcmluZyBzdHJlYW0iLCJpbmZvX3VybCI6Imh0dHBzOi8vZG9jcy5uYXRzLmlvL25hdHMtc2VydmVyL2NvbmZpZ3VyYXRpb24vc3lzX2FjY291bnRzIn0seyJuYW1lIjoiYWNjb3VudC1tb25pdG9yaW5nLXNlcnZpY2VzIiwic3ViamVjdCI6IiRTWVMuUkVRLkFDQ09VTlQuKi4qIiwidHlwZSI6InNlcnZpY2UiLCJyZXNwb25zZV90eXBlIjoiU3RyZWFtIiwiYWNjb3VudF90b2tlbl9wb3NpdGlvbiI6NCwiZGVzY3JpcHRpb24iOiJSZXF1ZXN0IGFjY291bnQgc3BlY2lmaWMgbW9uaXRvcmluZyBzZXJ2aWNlcyBmb3I6IFNVQlNaLCBDT05OWiwgTEVBRlosIEpTWiBhbmQgSU5GTyIsImluZm9fdXJsIjoiaHR0cHM6Ly9kb2NzLm5hdHMuaW8vbmF0cy1zZXJ2ZXIvY29uZmlndXJhdGlvbi9zeXNfYWNjb3VudHMifV0sImxpbWl0cyI6eyJzdWJzIjotMSwiZGF0YSI6LTEsInBheWxvYWQiOi0xLCJpbXBvcnRzIjotMSwiZXhwb3J0cyI6LTEsIndpbGRjYXJkcyI6dHJ1ZSwiY29ubiI6LTEsImxlYWYiOi0xfSwic2lnbmluZ19rZXlzIjpbIkFCNUo0QU9BVU5UWExQNUZIQVBVTVhRSkxRSkpNT0xUMjRDN1NSVk1URTZTRk5GTUo1RlNKTUk1Il0sImRlZmF1bHRfcGVybWlzc2lvbnMiOnsicHViIjp7fSwic3ViIjp7fX0sInR5cGUiOiJhY2NvdW50IiwidmVyc2lvbiI6Mn19.hh2xIs1SvCMdHxgt5h4kXCAEIxTl4Tv-HbTsP1kVLPwCpskasx4blzCRVml3eFdyok4TBAtcF2FsHjABW-ENAw,

}

This inlines the operator JWT, declares the system account, preloads the system account JWT (since this is necessary to push and pull subsequent accounts via nsc), and configures the account resolver. Depending your environment, you may need to change the ./jwt directory path.

With this config alone, you can startup a NATS server.

nats-server -c auth.conf -a 127.0.0.1

In a different shell, you can configure the NATS context:

nats context save local-sys \

--server nats://127.0.0.1:4222 \

--nsc nsc://local/SYS/sys # notice the operator/account/user hierarchy

Now you can issue server related commands.

nats --context local-sys server info

What is special about the SYS account? It has special access to the $SYS.> subject so system account users can perform various system-related operations such as these.

To create a new account and user for use by our application, we can do the following.

nsc add account --operator local APP

nsc edit account APP --sk generate

nsc add user --account APP user

Note, if you want JetStream enabled for the account, you must add the following flags with whatever limits are appropriate, -1 denotes unlimited.

nsc edit account APP \

--js-streams -1 \

--js-consumer -1 \

--js-disk-storage -1 \

--js-ha-resources -1 \

--js-mem-storage -1

If there are additional changes required now or in the future, you can use nsc edit account or nsc edit user later to make changes.

Whenever new accounts are created or the SYS account has been edited, do a nsc push -A to latest account JWTs to the server.

For users, any time the permissions of a user changes, the new credentials must be provided to the clients connecting to the server. User JWTs are not pushed to the server, only the accounts.

For the last part of rotating keys, the general strategy would be to create a new account signing key and push it.

nsc edit account --sk generate

nsc push -A

Resign the users with the new signing key that was produced

nsc edit user --private-key "A..." --expiry 0

Note, specify the private key alone complains an ectual edit operation is required. --expiry 0 is simple default that can be used to force the operation.Distribute the new user creds and after some period of time, remove the old signing key and push.

nsc edit account --rm-sk 'A...'

nsc push -A

Any connections using credentials signed by the old key will be detected and an "Authorization violation" will be observed by the clients.