Skip to content

Instantly share code, notes, and snippets.

@ColinSullivan1
Last active July 16, 2019 18:54
Show Gist options
  • Save ColinSullivan1/2580ec042e63d5772e5fe9da17895e1e to your computer and use it in GitHub Desktop.
Save ColinSullivan1/2580ec042e63d5772e5fe9da17895e1e to your computer and use it in GitHub Desktop.
NATS 2.0 Install

Setting up NATS 2.0 Security - DRAFT/WIP

Install the tools

nats-server

go get github.com/nats-io/nats-server

nsc

curl -L https://raw.githubusercontent.com/nats-io/nsc/master/install.py | python

Setup the Operator JWT

$ nsc add operator -n AcmeOperator
Generated operator key - private key stored "~/.nkeys/AcmeOperator/AcmeOperator.nk"
Success! - added operator "AcmeOperator"

Save the generated NKEY (*.nk file) someplace very safe.

You'll need to reference the operator's JWT, so save that someplace accessible by the nats-account-server.

Setup the NATS server

This is all you need! Reference the operator JWT, and the resolver. In this case, we'll use the directory store, which is mutable, so operators can add and remove users and accounts.

operator: $HOME/.nsc/nats/AcmeOperator/AcmeOperator.jwt
resolver: URL(http://localhost:9090/jwt/v1/accounts/)

Setup the NATS account server

http: {
  host: "localhost",
  port: 9090,
  readtimeout: 5000,
  writetimeout: 5000,
}

# Reference the operator JWT.
OperatorJWTPath: /Users/colinsullivan/.nsc/nats/AcmeOperator/AcmeOperator.jwt

# This is the location of the store, where public account JWTs will be
# uploaded.
store: {
    dir: /Users/colinsullivan/setup-jwt-security/jwts
}

Create an account JWT

This would be done by the operator, or administrator.

$ nsc add account -n Acme
Generated account key - private key stored "~/.nkeys/AcmeOperator/accounts/Acme/Acme.nk"
Success! - added account "Acme"

Find the public NKEY of the account

$ nsc describe jwt -W -f ~/.nsc/nats/AcmeOperator/accounts/Acme/Acme.jwt | grep "Account ID"
│ Account ID                │ AAHC5D6GVMRI753MOVEIEV2LVR3C7GUCYLAOHQH5DL5V7M6CXSYGWZRK │

Upload the account JWT to the account server

You must use curl to upload the JWT to the account server. You could copy the JWT and rename it <Public NKEY>.jwt, but might not take advantage of sharding if configured.

 $ curl -i -X POST localhost:9090/jwt/v1/accounts/AAHC5D6GVMRI753MOVEIEV2LVR3C7GUCYLAOHQH5DL5V7M6CXSYGWZRK --data-binary @/Users/colinsullivan/.nsc/nats/AcmeOperator/accounts/Acme/Acme.jwt -H "Content-Type: text/text"
HTTP/1.1 200 OK
Vary: Origin
Date: Mon, 13 May 2019 20:54:22 GMT
Content-Length: 0

Create a user for your connecting applications

$ nsc add user -n Colin
Generated user key - private key stored "~/.nkeys/AcmeOperator/accounts/Acme/users/Colin.nk"
Generated user creds file "~/.nkeys/AcmeOperator/accounts/Acme/users/Colin.creds"
Success! - added user "Colin" to "Acme"

Test the user:

$ nats-pub -creds ~/.nkeys/AcmeOperator/accounts/Acme/users/Colin.creds foo bar
Published [foo] : 'bar'

Advanced

NATS Alerts

To enable NATS alerts, create a user to connect to NATS and publish alerts. In this case, we've created a user account-user.

Setup NATS connectivity in the NATS account server by adding the following stanza:

nats: {
  Servers: ["localhost:4222"],
  ConnectTimeout: 5000,
  MaxReconnects: 5,
  ReconnectWait: 5000,
  UserCredentials: /Users/colinsullivan/.nkeys/AcmeOperator/accounts/Acme/users/account-server.creds
}

The account server will connect to the NATS server to publish account related events. You'll see statements like this:

2019/05/13 17:39:31.905301 [ERR] failed to connect to NATS, nats: no servers available for connection
2019/05/13 17:39:31.905319 [ERR] will try to connect again in 5000 milliseconds
2019/05/13 17:39:36.908554 [INF] connecting to NATS for notifications

System Account

You can create a system account for generating alearts, usage, etc. It's simply a user you define.

$ nsc add account -n SYS
Generated account key - private key stored "~/.nkeys/AcmeOperator/accounts/SYS/SYS.nk"
Success! - added account "SYS"
$ nsc add user -n SYSU
Generated user key - private key stored "~/.nkeys/AcmeOperator/accounts/SYS/users/SYSU.nk"
Generated user creds file "~/.nkeys/AcmeOperator/accounts/SYS/users/SYSU.creds"
Success! - added user "SYSU" to "SYS"

Now upload the account. We'll need to add the system jwt, and to do that we need the public NKey. Obtain it through:

 $ ngs describe jwt -W -f /Users/colinsullivan/.nsc/nats/AcmeOperator/accounts/SYS/SYS.jwt | grep "Account ID"
│ Account ID               │ AALMWQBL3A3IPZUHRS22BXAMJDXI5MBOKTDNEZ4YAOFJIGSKQCZ2GOQZ │

Upload the JWT.

curl -i -X POST localhost:9090/jwt/v1/accounts/AALMWQBL3A3IPZUHRS22BXAMJDXI5MBOKTDNEZ4YAOFJIGSKQCZ2GOQZ --data-binary @/Users/colinsullivan/.nsc/nats/AcmeOperator/accounts/SYS/SYS.jwt -H "Content-Type: text/text"

TODO: is this necessary after having to upload the account? Add the system account to the NATS server and account server. In your account server configuration add:

SystemAccountJWTPath: /Users/colinsullivan/.nsc/nats/AcmeOperator/accounts/SYS/SYS.jwt

In the NATS server configuration, add:

system: AALMWQBL3A3IPZUHRS22BXAMJDXI5MBOKTDNEZ4YAOFJIGSKQCZ2GOQZ

Reload or bounce the NATS server.

At this point, you can import the sys account into other accounts, or use the system account credentials to listen:

 nats-sub -creds ~/.nkeys/AcmeOperator/accounts/SYS/users/SYSU.creds ">"
Listening on [>]
[#1] Received on [$SYS.SERVER.NAMJJH7VO4ZZRP2BIVCE2MFZGXH3BH5HVUS2Y7XM55QWZMPHJ6S57BDL.STATSZ]: '{
  "server": {
    "host": "0.0.0.0",
    "id": "NAMJJH7VO4ZZRP2BIVCE2MFZGXH3BH5HVUS2Y7XM55QWZMPHJ6S57BDL",
    "ver": "2.0.0-RC12",
    "seq": 13,
    "time": "2019-05-13T18:58:44.729401-06:00"
  },
  "statsz": {
    "start": "2019-05-13T18:54:14.681899-06:00",
    "mem": 10383360,
    "cores": 8,
    "cpu": 0,
    "connections": 2,
    "total_connections": 2,
    "active_accounts": 2,
    "subscriptions": 9,
    "sent": {
      "msgs": 0,
      "bytes": 0
    },
    "received": {
      "msgs": 0,
      "bytes": 0
    },
    "slow_consumers": 0
  }
}'

Importing and exporting data

Let's import some of the data from the SYS account into our Acme account.

First create and upload another account:

nsc create account -n PublicServices

Upload the account as you would the others with curl. Next create a user for the application.

nsc create user -n PublicServiceUser

Export a service from the PublicServices account

Note that we are already working on the PublicServices account.

 $ nsc add import --name "TicketService" --subject "generate.ticket" --service
Success! - added public service export "TicketService"

You've locally updated your account to have a public TicketService exposed on subject generate.ticket. The changes are local, so now upload it with curl. First we'll need the account ID.

 $  nsc describe jwt -W -f ~/.nsc/nats/AcmeOperator/accounts/PublicServices/PublicServices.jwt | grep "Account ID"
│ Account ID                │ ACOAYG5E4EWOE3VJ26RTQFD3QNOL2JA5EMEWHVM5RDKHYQAOEAIO35PS │
curl -i -X POST localhost:9090/jwt/v1/accounts/ACOAYG5E4EWOE3VJ26RTQFD3QNOL2JA5EMEWHVM5RDKHYQAOEAIO35PS --data-binary @/Users/colinsullivan/.nsc/nats/AcmeOperator/accounts/PublicService/PublicService.jwt -H "Content-Type: text/text"

Import the service from the Acme account

Let's change the account we're working on:

 $ nsc env -a Acme
 $

Now we'll add an import to the account:

Get the account ID from the list the accounts:

$ nsc describe jwt -W -f ~/.nsc/nats/AcmeOperator/accounts/Acme/Acme.jwt | grep "Account ID"
│ Account ID                │ AAHC5D6GVMRI753MOVEIEV2LVR3C7GUCYLAOHQH5DL5V7M6CXSYGWZRK │

Now add the import.

$ nsc add import --src-account ACOAYG5E4EWOE3VJ26RTQFD3QNOL2JA5EMEWHVM5RDKHYQAOEAIO35PS --name TicketService --remote-subject generate.ticket --service
Success! - added service import "generate.ticket"

Now upload your account changes:

curl -i -X POST localhost:9090/jwt/v1/accounts/AAHC5D6GVMRI753MOVEIEV2LVR3C7GUCYLAOHQH5DL5V7M6CXSYGWZRK --data-binary @/Users/colinsullivan/.nsc/nats/AcmeOperator/accounts/Acme/Acme.jwt -H "Content-Type: text/text"

Restart the NATS server.

Test your service

 $ ./nats-rply --creds ~/.nkeys/AcmeOperator/accounts/PublicServices/users/PublicServiceUser.creds "generate.ticket" "A ticket for you"
Listening on [generate.ticket]
[#1] Received on [generate.ticket]: '1234'

Make the request:

 $ nats-req -creds ~/.nkeys/AcmeOperator/accounts/Acme/users/Colin.creds generate.ticket 1234
Published [generate.ticket] : '1234'
Received  [_INBOX.uwUhiGebcjQeLsLg30O4oU.V0ZUziqZ] : 'A ticket for you'
@cgebe
Copy link

cgebe commented Jul 16, 2019

Hi Colin,

Thanks for the detailed guide!

I have data i want to publish per user on my platform on a dedicated channel, e.g. api.user.12345.orders where 12345 is the user id.
Lets say the account is api.user. My question is, do i have to create and hold generated nkeys for each user when he/she registers on our platform in order to sign JWTs later on? Or can the account sign the respective JWTs? Where do i specifically define the pub / sub rights, e.g. sub: api.user.12345.>.

Thank you!

@ColinSullivan1
Copy link
Author

No problem - Thank you for using NATS!

This is a little out of date, I'd suggest visiting the official doc. There's another step here I didn't include, which are generating signing keys. Signing keys are additional keys you provide your operators so you don't need to ever use your private key to sign - you can more easily replace your signing key. You can create an account signing key, and use that to sign the user's jwt. You can assign user pub/sub permissions by editing the user JWT, described here.

e.g.
nsc add user --name username --allow-pub "_INBOX.>" --allow-sub "req.a"

You can also edit existing users:
nsc edit user -n username --deny-sub "baz"

@cgebe
Copy link

cgebe commented Jul 16, 2019

Ahh that makes sense! Thank you for your answer. I follow up on the official doc articles.
NATS is awesome, appreciate your work!

Best regards,
Chris

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment