1
0
mirror of https://github.com/taigrr/nats.docs synced 2025-01-18 04:03:23 -08:00

GitBook: [master] 326 pages and 16 assets modified

This commit is contained in:
Ginger Collison
2019-10-04 17:48:52 +00:00
committed by gitbook-bot
parent 8b7ba5c3bb
commit fb0d5c8355
203 changed files with 4640 additions and 3107 deletions

52
nats-tools/mkpasswd.md Normal file
View File

@@ -0,0 +1,52 @@
# mkpasswd
The server supports hashing of passwords and authentication tokens using `bcrypt`. To take advantage of this, simply replace the plaintext password in the configuration with its `bcrypt` hash, and the server will automatically utilize `bcrypt` as needed.
A utility for creating `bcrypt` hashes is included with the nats-server distribution \(`util/mkpasswd.go`\). Running it with no arguments will generate a new secure password along with the associated hash. This can be used for a password or a token in the configuration.
## Installing `mkpasswd`
If you have [go installed](https://golang.org/doc/install), you can easily install the `mkpasswd` tool by doing:
```text
> go get github.com/nats-server/util/mkpasswd
```
Alternatively, you can:
```text
> git clone git@github.com:nats-io/nats-server
> cd nats-server/util/mkpasswd
> go install mkpasswd.go
```
## Generating bcrypted passwords
With `mkpasswd` installed:
```text
> mkpasswd
pass: #IclkRPHUpsTmACWzmIGXr
bcrypt hash: $2a$11$3kIDaCxw.Glsl1.u5nKa6eUnNDLV5HV9tIuUp7EHhMt6Nm9myW1aS
```
If you already have a password selected, you can supply the `-p` flag on the command line, enter your desired password, and a `bcrypt` hash will be generated for it:
```text
> mkpasswd -p
Enter Password: *******
Reenter Password: ******
bcrypt hash: $2a$11$3kIDaCxw.Glsl1.u5nKa6eUnNDLV5HV9tIuUp7EHhMt6Nm9myW1aS
```
To use the password on the server, add the hash into the server configuration file's authorization section.
```text
authorization {
user: derek
password: $2a$11$3kIDaCxw.Glsl1.u5nKa6eUnNDLV5HV9tIuUp7EHhMt6Nm9myW1aS
}
```
Note the client will still have to provide the plain text version of the password, the server however will only store the hash to verify that the password is correct when supplied.

20
nats-tools/nas/README.md Normal file
View File

@@ -0,0 +1,20 @@
# nats-account-server
The [NATS Account Server](https://github.com/nats-io/nats-account-server) is an HTTP server that hosts and vends JWTs for nats-server 2.0 account authentication. The server supports an number of stores which enable it to serve JWTs from:
* a directory
* an [NSC](../nsc/nsc.md) directory
* memory \(for testing purposes\)
The server can operate in a _READ ONLY_ mode where it serves content from a directory, or in notification mode, where it can notify a NATS server that a JWT in the store has been modified, updating the NATS server with the updated JWT.
The server supports replica mode, which allows load balancing, fault tolerance and geographic distribution of servers. Replicas are read-only and copy JWTs from the primary based on cache invalidation or NATS notifications.
The account server can host activation tokens as well as account JWTs. These tokens are used when one account needs to give permission to another account to access a private export. Tokens can be configured as full tokens, or URLs. By hosting them in the account server you can avoid the copy/paste process of embedding tokens. They can also be updated more easily on expiration.
## Memory Resolver
For very simple installations, where JWTs are mostly static, the NATS server also supports a _Memory Resolver_ that can be configured statically in the server's configuration file.
You can learn more about how to configure the [memory resolver here](mem_resolver.md).

102
nats-tools/nas/dir_store.md Normal file
View File

@@ -0,0 +1,102 @@
# Directory Store
## NATS Account Server Configuration
```text
OperatorJWTPath: "/users/synadia/.nsc/nats/AAA/AAA.jwt",
http {
port: 9090
},
store {
dir: "/tmp/as_store",
readonly: false,
shard: true
}
```
The server configuration specifies the `OperatorJWTPath` which is used to validate accounts submitted to the server. If an account is not signed by the specified operator, the update is rejected.
Starting the server:
```text
> nats-account-server -c nas.conf
2019/05/31 12:35:23.430128 [INF] loading configuration from "/Users/synadia/Desktop/nats_jwt_doc/as_dir/nas.conf"
2019/05/31 12:35:23.430417 [INF] starting NATS Account server, version 0.0-dev
2019/05/31 12:35:23.430434 [INF] server time is Fri May 31 12:35:23 CDT 2019
2019/05/31 12:35:23.430462 [INF] loading operator from /users/synadia/.nsc/nats/AAA/AAA.jwt
2019/05/31 12:35:23.430919 [INF] creating a store at /tmp/as_store
2019/05/31 12:35:23.430948 [INF] NATS is not configured, server will not fire notifications on update
2019/05/31 12:35:23.437938 [INF] http listening on port 9090
2019/05/31 12:35:23.437953 [INF] nats-account-server is running
2019/05/31 12:35:23.437956 [INF] configure the nats-server with:
2019/05/31 12:35:23.437966 [INF] resolver: URL(http://localhost:9090/jwt/v1/accounts/)
```
On a new store, the server doesn't have any JWTs. This means that any nats-server that attempts to resolve accounts will fail. To add JWTs to the server, you can use a tool like [`curl` to post request](dir_store.md#add/using-curl-to-add-or-update-accounts). But it is much easier if you use `nsc` to update the nats-account-server.
## Using NSC to And or Update Accounts
The `nsc` tool has built-in facilities to `push` JWTs related to an operator. The tool also performs validation of your JWTs to ensure that you push JWTs that will validate correctly.
If your operator doesn't have any entities, now it is a good time to add some:
```text
> nsc add account -n A
Generated account key - private key stored "~/.nkeys/AAA/accounts/A/A.nk"
Success! - added account "A"
> nsc add user -n u1
Generated user key - private key stored "~/.nkeys/AAA/accounts/A/users/u1.nk"
Generated user creds file "~/.nkeys/AAA/accounts/A/users/u1.creds"
Success! - added user "u1" to "A"
> nsc add user -n u2
Generated user key - private key stored "~/.nkeys/AAA/accounts/A/users/u2.nk"
Generated user creds file "~/.nkeys/AAA/accounts/A/users/u2.creds"
Success! - added user "u2" to "A"
> nsc add account -n B
Generated account key - private key stored "~/.nkeys/AAA/accounts/B/B.nk"
Success! - added account "B"
```
With the account and a couple of users in place, let's push all the accounts to the nats-account-server:
```text
> nsc push -A
successfully pushed all accounts [A,B]
```
Quick checking of the store directory, shows that the JWTs have been sharded by their public keys:
```text
> tree as_store
as_store
├── 27
│ └── ACVEO3LPVRGE5W262FCYF3OMGQFJIW252AX75FEE6BUY752BFVDADN27.jwt
└── TY
└── ADDVBX4VPWSNEDLWH5Y6ITASMXS3QY3L6KRNZ6VIQJ6Q3FRGR43NFHTY.jwt
```
Quick check on nsc to verify the ids of the accounts on nsc, match the files:
```text
> nsc list accounts -W
╭─────────────────────────────────────────────────────────────────╮
│ Accounts │
├──────┬──────────────────────────────────────────────────────────┤
│ Name │ Public Key │
├──────┼──────────────────────────────────────────────────────────┤
│ A │ ACVEO3LPVRGE5W262FCYF3OMGQFJIW252AX75FEE6BUY752BFVDADN27 │
│ B │ ADDVBX4VPWSNEDLWH5Y6ITASMXS3QY3L6KRNZ6VIQJ6Q3FRGR43NFHTY │
╰──────┴──────────────────────────────────────────────────────────╯
```
## Using Curl to Add or Update Accounts
```text
> curl -i -X POST localhost:9090/jwt/v1/accounts/AC7PO3MREV26U3LFZFP5BN3HAI32X3PKLBRVMPAETLEHWPQEUG7EJY4H --data-binary @/Users/synadia/.nsc/nats/Test/accounts/TestAccount/TestAccount.jwt -H "Content-Type: text/text"
```
Note that the `@` before the file name is required for `curl` to read the specified file, and use it as the payload. Otherwise, it will simply post the path specified, which will result in an update error.

View File

@@ -0,0 +1,39 @@
# Inspecting JWTs
Lets say that you know the account for a stream that you are interested in, but you don't know all the details for creating an import. If you know and have access to a nats-account-server, you can help yourself. The nats-account-server can decode a JWT and give you human readable values that you can use.
The endpoint for retrieving an account JWT is: `/jwt/v1/accounts/<account_id>`. To decode a JWT add the query string `?decode=true`.
```javascript
> curl http://localhost:9090/jwt/v1/accounts/AC7PO3MREV26U3LFZFP5BN3HAI32X3PKLBRVMPAETLEHWPQEUG7EJY4H\?decode=true
{
"typ": "jwt",
"alg": "ed25519"
}
{
"jti": "5YMRO4KNMYWQDMRAHVTT4KX63CA2L3M6F4VM3S7NNGPMCCATORXQ",
"iat": 1556229062 (2019-04-25),
"iss": "OAYI3YUZSWDNMERD2IN3HZSIP3JA2E3VDTXSTEVOIII273XL2NABJP64",
"name": "TestAccount",
"sub": "AC7PO3MREV26U3LFZFP5BN3HAI32X3PKLBRVMPAETLEHWPQEUG7EJY4H",
"type": "account",
"nats": {
"exports": [
{
"name": "abc",
"subject": "a.b.c.>",
"type": "stream"
}
],
```
As you can see from above, the JWT is decoded. The standard JWT claim field abbreviated names may be a little terse, so here's a list of the more important ones:
* `jti` is the _JWT ID_. All JWTs have one and they are unique.
* `iat` is _Issued At_ - the UNIX date \(number of seconds since 1970\) when the JWT was issued.
* `iss` is the _Issuer_. For NATS JWTs it is the public key of the issuer. In the example above the entity is an account, so the issuer will be an operator. Thus the id will always start with the letter `O`.
* `sub` is the _Subject_ of the claim. In NATS JWTs it is the public key of the entity of the claim is for. In the example above, it is an Account, so the issuer will always start with the letter `A`.
On the example above, we see that there is one export in this account, it is public \(`token_req` is `false` or not set\), and it is a `stream`. So this account exports a public stream. With that information you can create an import on the public stream.

View File

@@ -0,0 +1,118 @@
# Memory Resolver
The `MEMORY` resolver is a built-in resolver for JWTs. It is mostly used by test setups but can be used to test the simplest of environments where there is one or very few accounts, and the account JWTs don't change often.
The basic configuration for the server requires:
* The operator JWT
* `resolver` set to `MEMORY`
* `resolver_preload` set to an object where account public keys are mapped to account JWTs.
## Create Required Entities
Let's create the setup:
```text
> nsc add operator -n memory
Generated operator key - private key stored "~/.nkeys/memory/memory.nk"
Success! - added operator "memory"
> nsc add account --name A
Generated account key - private key stored "~/.nkeys/memory/accounts/A/A.nk"
Success! - added account "A"
> nsc describe account -W
╭──────────────────────────────────────────────────────────────────────────────────────╮
│ Account Details │
├───────────────────────────┬──────────────────────────────────────────────────────────┤
│ Name │ A │
│ Account ID │ ACSU3Q6LTLBVLGAQUONAGXJHVNWGSKKAUA7IY5TB4Z7PLEKSR5O6JTGR │
│ Issuer ID │ ODWZJ2KAPF76WOWMPCJF6BY4QIPLTUIY4JIBLU4K3YDG3GHIWBVWBHUZ │
│ Issued │ 2019-04-30 20:21:34 UTC │
│ Expires │ │
├───────────────────────────┼──────────────────────────────────────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Leaf Node Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├───────────────────────────┼──────────────────────────────────────────────────────────┤
│ Imports │ None │
│ Exports │ None │
╰───────────────────────────┴──────────────────────────────────────────────────────────╯
> nsc add user --name TA
Generated user key - private key stored "~/.nkeys/memory/accounts/A/users/TA.nk"
Generated user creds file "~/.nkeys/memory/accounts/A/users/TA.creds"
Success! - added user "TA" to "A"
```
## Create the Server Config
The `nsc` tool can generate a configuration file automatically. You provide a path to the server configuration and operator jwt. The `nsc` tool will copy the operator JWT to the file specified, and generate the server config for you:
```text
> nsc generate config --mem-resolver --config-file /tmp/server.conf --operator-jwt /tmp/memory.jwt
Success!! - generated "/tmp/server.conf"
generated "/tmp/memory.jwt"
```
If you require additional settings, you may want to consider using [`include`](../../nats-server/configuration/#include-directive) in your main configuration, to reference the generated files. Otherwise, you can start a server and reference the generated configuration:
```text
> nats-server -c /tmp/server.conf
```
You can then [test it](mem_resolver.md#testing-the-configuration).
## Manual Server Config
While generating a configuration file is easy, you may want to craft one by hand to know the details. With the entities created, and a standard location for the `.nsc` directory. You can reference the operator JWT and the account JWT in a server configuration. Remember that your configuration will be in `$NSC_HOME/nats/<operator_name>/<operator_name>.jwt` for the operator. The account JWT will be in `$NSC_HOME/nats/<operator_name>/accounts/<account_name>/<account_name>.jwt`
For the configuration you'll need:
* The path to the operator JWT
* A copy of the contents of the account JWT file
The format of the file is:
```text
operator: <path to the operator jwt>
resolver: MEMORY
resolver_preload: {
<public key for an account>: <contents of the account jwt>
### add as many accounts as you want
...
}
```
In this example this translates to:
```text
operator: /Users/synadia/.nsc/nats/memory/memory.jwt
resolver: MEMORY
resolver_preload: {
ACSU3Q6LTLBVLGAQUONAGXJHVNWGSKKAUA7IY5TB4Z7PLEKSR5O6JTGR: eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5In0.eyJqdGkiOiJPRFhJSVI2Wlg1Q1AzMlFJTFczWFBENEtTSDYzUFNNSEZHUkpaT05DR1RLVVBISlRLQ0JBIiwiaWF0IjoxNTU2NjU1Njk0LCJpc3MiOiJPRFdaSjJLQVBGNzZXT1dNUENKRjZCWTRRSVBMVFVJWTRKSUJMVTRLM1lERzNHSElXQlZXQkhVWiIsIm5hbWUiOiJBIiwic3ViIjoiQUNTVTNRNkxUTEJWTEdBUVVPTkFHWEpIVk5XR1NLS0FVQTdJWTVUQjRaN1BMRUtTUjVPNkpUR1IiLCJ0eXBlIjoiYWNjb3VudCIsIm5hdHMiOnsibGltaXRzIjp7InN1YnMiOi0xLCJjb25uIjotMSwibGVhZiI6LTEsImltcG9ydHMiOi0xLCJleHBvcnRzIjotMSwiZGF0YSI6LTEsInBheWxvYWQiOi0xLCJ3aWxkY2FyZHMiOnRydWV9fX0._WW5C1triCh8a4jhyBxEZZP8RJ17pINS8qLzz-01o6zbz1uZfTOJGvwSTS6Yv2_849B9iUXSd-8kp1iMXHdoBA
}
```
Save the config at server.conf and start the server:
```text
> nats-server -c server.conf
```
You can then [test it](mem_resolver.md#testing-the-configuration).
## Testing the Configuration
To test the configuration, simply use one of the standard tools:
```text
> nats-pub -creds ~/.nkeys/memory/accounts/A/users/TA.creds hello world
Published [hello] : 'world'
```

158
nats-tools/nas/nas_conf.md Normal file
View File

@@ -0,0 +1,158 @@
# Basics
Basic configuration revolves around 4 settings:
* The store to read JWTs from
* The HTTP/S configuration
* NATS \(for cases where updates are enabled\)
* Logging
For complete information on please refer to the project's [Github](https://github.com/nats-io/nats-account-server).
## `nsc` Configuration
For a basic usage of the server you can specify the `-nsc` flag, and specify the path to an operator in your environment.
> If you have not yet created an operator or accounts, you'll need to do so before continuing. See [NSC](../nsc/)
You can easily locate the path by running `nsc env` to print your `nsc` settings:
```text
> nsc env
╭──────────────────────────────────────────╮
│ NSC Environment │
├──────────────────┬─────┬─────────────────┤
│ Setting │ Set │ Effective Value │
├──────────────────┼─────┼─────────────────┤
│ $NKEYS_PATH │ No │ ~/.nkeys │
│ $NSC_HOME │ No │ ~/.nsc │
│ Config │ │ ~/.nsc/nsc.json │
├──────────────────┼─────┼─────────────────┤
│ Stores Dir │ │ ~/.nsc/nats │
│ Default Operator │ │ Test │
│ Default Account │ │ TestAccount │
│ Default Cluster │ │ │
╰──────────────────┴─────┴─────────────────╯
```
The path you are interested in the `Stores Dir`. This is the root of all operators, you'll also need the name of your operator. If your current operator is not listed, you can list all your available operators by doing:
```text
> nsc list operators
```
To start the `nats-account-server` with the operator `Test`:
```text
> nats-account-server -nsc ~/.nsc/nats/Test
2019/05/10 11:22:41.845148 [INF] starting NATS Account server, version 0.0-dev
2019/05/10 11:22:41.845241 [INF] server time is Fri May 10 11:22:41 CDT 2019
2019/05/10 11:22:41.845245 [INF] loading operator from /Users/synadia/.nsc/nats/Test/Test.jwt
2019/05/10 11:22:41.846367 [INF] creating a read-only store for the NSC folder at /Users/synadia/.nsc/nats/Test
2019/05/10 11:22:41.846459 [INF] NATS is not configured, server will not fire notifications on update
2019/05/10 11:22:41.855291 [INF] http listening on port 9090
2019/05/10 11:22:41.855301 [INF] nats-account-server is running
2019/05/10 11:22:41.855303 [INF] configure the nats-server with:
2019/05/10 11:22:41.855306 [INF] resolver: URL(http://localhost:9090/jwt/v1/accounts/)
```
By default the server will serve JWTs on the localhost at port 9090. The last line in the shown in the printout is important, that is the resolver URL you'll have to provide on your NATS server configuration. You'll also need the matching operator JWT which is on `~/.nsc/nats/Test/Test.jwt` if you are following the example above. On the server configuration you'll need to expand the `~` as necessary. Here's what my NATS server configuration looks like:
```text
operator: /Users/synadia/.nsc/nats/Test/Test.jwt
resolver: URL(http://localhost:9090/jwt/v1/accounts/)
```
Note that servers you create with the `-nsc` option \(or store option\) are read-only. This means that the server will not accept POST requests to update the JWT store.
## Directory Configuration
You can start a server using a plain directory. In this case you'll be responsible for adding any JWT that you want resolved.
> The server looks for account JWTs by using the public key of the account as the file name followed by the extension `.jwt`. The server will not introspect the JWTs, so if you don't name the files correctly, it will fail to find them or serve a JWT that doesn't match the requested account.
```text
> mkdir /tmp/jwts
nats-account-server -dir /tmp/jwts
2019/05/10 11:33:40.501305 [INF] starting NATS Account server, version 0.0-dev
2019/05/10 11:33:40.501383 [INF] server time is Fri May 10 11:33:40 CDT 2019
2019/05/10 11:33:40.501404 [INF] creating a store at /tmp/jwts
2019/05/10 11:33:40.501430 [INF] NATS is not configured, server will not fire notifications on update
2019/05/10 11:33:40.510273 [INF] http listening on port 9090
2019/05/10 11:33:40.510283 [INF] nats-account-server is running
2019/05/10 11:33:40.510285 [INF] configure the nats-server with:
2019/05/10 11:33:40.510291 [INF] resolver: URL(http://localhost:9090/jwt/v1/accounts/)
```
Configuration for the NATS server is the same as in the previous example:
```text
operator: /Users/synadia/.nsc/nats/Test/Test.jwt
resolver: URL(http://localhost:9090/jwt/v1/accounts/)
```
## Configuration File
While the `-nsc` and `-dir` store flags are sufficient for some very simple developer setups, any production or non-read-only server will require a configuration file.
Let's take a look at the configuration options:
### Configuration Options
| Option | Description |
| :--- | :--- |
| `http` | An `http` configuration block specifying HTTP options. |
| `logging` | A `logging` configuration block specifying server logging options. |
| `nats` | A `nats` configuration block specifying NATS connection information for the account server to push JWT changes to a NATS server. |
| `operatorjwtpath` | The path to an operator JWT. Required for non-read-only servers. Only JWTs signed by the operator \(or one of it's signing keys\) are accepted. |
| `store` | A `store` configuration block specifying store options. |
| `systemaccountjwtpath` | Path to an Account JWT that should be returned as the system account. |
| `primary` | URL for the primary, `protocol://host:port`. |
| `replicationtimeout` | Timeout, in milliseconds, used by the replica when talking to the primary, defaults to `5000`. |
### `store` Configuration
| Option | Description |
| :--- | :--- |
| `dir` | Configures a directory as a store. |
| `nsc` | Configures an nsc read-only store. The value should be the path to an operator _directory_. Option is mutually exlusive with `dir`. |
| `readonly` | If `true`, the store will not accept POST requests. Note that to receive requests, the store must also have `operatorjwtpath` specified as a root option. |
| `shard` | If `true`, JWTs are sharded in the store directory. |
## `logging` Options
| Option | Description |
| :--- | :--- |
| `time` | If `true`, a timestamp is added to log messages. |
| `debug` | If `true`, debug messages are logged. |
| `trace` | If `true`, trace messages are logged. |
| `colors` | If `true`, messages are logged using ANSI color escape sequences. |
| `pid` | If `true`, the process id for the server is added to log messages. |
## `http` Options
| Option | Description |
| :--- | :--- |
| `host` | Interface to listen for requests on. |
| `port` | Port to listen for requests on. |
| `readtimeout` | Max amount of time in milliseconds to wait for a http read operation to complete. |
| `writetimeout` | Max amount of time in milliseconds to wait for a http write operation to complete. |
## `nats` Options
| Option | Description |
| :--- | :--- |
| `servers` | List of NATS servers for the account server to use when connecting to a NATS server to publish updates. |
| `connecttimeout` | Max amount of time in milliseconds to wait for a NATS connection. |
| `reconnecttimewait` | Amount of time in milliseconds to between NATS server reconnect attempts. |
| `tls` | A `tls` configuration block. |
| `usercredentials` | A credentials _creds_ file for connecting to the NATS server. Account must be a member of a system account. |
## `tls` Options
| Option | Description |
| :--- | :--- |
| `root` | filepath to the CA certificate. |
| `cert` | filepath to the certificate. |
| `cert` | filepath to the certificate key. |

View File

@@ -0,0 +1,106 @@
# Update Notifications
The `nats-account-server` can notify a nats-server about JWT updates, enabling the NATS server to update itself to the newly updated JWT.
To push notifications, the nats-account-server makes use of [system accounts](../../nats-server/nats_admin/sys_accounts/).
Here's a nats-account-server configuration with updates enabled:
```text
operatorjwtpath: "/users/synadia/.nsc/nats/AAA/AAA.jwt",
systemaccountjwtpath: "/users/synadia/.nsc/nats/AAA/accounts/SYS/SYS.jwt"
http {
port: 9090
},
store {
dir: "/tmp/as_store",
readonly: false,
shard: true
}
nats {
servers: [nats://localhost:4222]
usercredentials: "/Users/synadia/.nkeys/AAA/accounts/SYS/users/sys.creds"
}
```
The above configuration:
* Sets the `operatorjwtpath` to verify pushed JWTs are signed by the operator
* Sets the `systemaccountjwtpath` so that the `nats-server` can ask for the system account \(which the nats-account-server will trigger when it connects to the nats-server\)
The `nats` section:
* Sets the `servers` with a list of NATS urls
* Sets `usercredentials` to the credentials file for the system account user that issues notifications.
When the account server starts:
* It makes a connection to the NATS server using the `usercredentials` of the system account.
The NATS server configuration looks like:
```text
operator: /users/synadia/.nsc/nats/AAA/AAA.jwt
resolver: URL(http://localhost:9090/jwt/v1/accounts/)
system_account: AAUR7CJU5WTR2RROXOJJFTJFJQPZ6B4VF2NOX6OQ6SQMPIKLQYQ7T37U
```
It specifies:
* The `operator` JWT
* The `resolver` URL where the nats-account-server will create requests. Note the nats-account-server log prints the exact value you should provide for this setting:
```text
...
2019/05/31 16:47:50.519361 [INF] configure the nats-server with:
2019/05/31 16:47:50.519368 [INF] resolver: URL(http://localhost:9090/jwt/v1/accounts/)
...
```
The nats-account-server has to be running before that nats-server starts, as currently, the nats-server will verify that it can connect to the resolver on startup.
```text
> nats-account-server -c nas_not.conf
2019/05/31 18:00:26.327583 [INF] loading configuration from "/Users/synadia/Desktop/nats_jwt_doc/as_dir/nas_not.conf"
2019/05/31 18:00:26.327833 [INF] starting NATS Account server, version 0.0-dev
2019/05/31 18:00:26.327852 [INF] server time is Fri May 31 18:00:26 CDT 2019
2019/05/31 18:00:26.327862 [INF] loading operator from /users/synadia/.nsc/nats/AAA/AAA.jwt
2019/05/31 18:00:26.328278 [INF] loading system account from /users/synadia/.nsc/nats/AAA/accounts/SYS/SYS.jwt
2019/05/31 18:00:26.328590 [INF] creating a store at /tmp/as_store
2019/05/31 18:00:26.328619 [INF] connecting to NATS for notifications
2019/05/31 18:00:26.329875 [ERR] failed to connect to NATS, nats: no servers available for connection
2019/05/31 18:00:26.329884 [ERR] will try to connect again in 1000 milliseconds
2019/05/31 18:00:26.330541 [INF] http listening on port 9090
2019/05/31 18:00:26.330548 [INF] nats-account-server is running
2019/05/31 18:00:26.330551 [INF] configure the nats-server with:
2019/05/31 18:00:26.330557 [INF] resolver: URL(http://localhost:9090/jwt/v1/accounts/)
2019/05/31 18:00:27.330103 [INF] connecting to NATS for notifications
2019/05/31 18:00:27.331215 [ERR] failed to connect to NATS, nats: no servers available for connection
2019/05/31 18:00:27.331223 [ERR] will try to connect again in 1000 milliseconds
```
Then start the NATS server:
```text
> nats-server -c /tmp/server.conf
[57440] 2019/05/31 18:01:29.940149 [INF] Starting nats-server version 1.4.1
[57440] 2019/05/31 18:01:29.940234 [INF] Git commit [not set]
[57440] 2019/05/31 18:01:29.940468 [INF] Listening for client connections on 0.0.0.0:4222
[57440] 2019/05/31 18:01:29.940476 [INF] Server is ready
```
At this point, you have both servers running. You can submit updates to the nats-account-server using `nsc`:
```text
> nsc push -A
successfully pushed all accounts [A, B, SYS]
```
The account server should show the updates in its log:
```text
2019/05/31 18:02:29.702044 [INF] updated JWT for account - ACVEO3LPVRGE - GSO7ZQPXXNTBBEEGXFFLFXZLCGOA5ABUOADZBPASYGCDIEJ6QQPQ
2019/05/31 18:02:29.702988 [INF] updated JWT for account - ADDVBX4VPWSN - VPBI4OHVJ7ITKX6S2RWHHJ3BB6JFZ7NPJN33JH6L752T2YI2QJKA
2019/05/31 18:02:29.703745 [INF] updated JWT for account - AAUR7CJU5WTR - NHEPTVMURCQEURAWHX6LUUMO4KCQUAP4JCLIQANP3JTNPMG3IFWQ
```

View File

@@ -0,0 +1,84 @@
# nats-top
## NATS TOP
[nats-top](https://github.com/nats-io/nats-top) is a [top](http://man7.org/linux/man-pages/man1/top.1.html)-like tool for monitoring nats-server servers.
The nats-top tool provides a dynamic real-time view of a NATS server. nats-top can display a variety of system summary information about the NATS server, such as subscription, pending bytes, number of messages, and more, in real time. For example:
```bash
nats-top
nats-server version 0.6.4 (uptime: 31m42s)
Server:
Load: CPU: 0.8% Memory: 5.9M Slow Consumers: 0
In: Msgs: 34.2K Bytes: 3.0M Msgs/Sec: 37.9 Bytes/Sec: 3389.7
Out: Msgs: 68.3K Bytes: 6.0M Msgs/Sec: 75.8 Bytes/Sec: 6779.4
Connections: 4
HOST CID SUBS PENDING MSGS_TO MSGS_FROM BYTES_TO BYTES_FROM LANG VERSION SUBSCRIPTIONS
127.0.0.1:56134 2 5 0 11.6K 11.6K 1.1M 905.1K go 1.1.0 foo, hello
127.0.1.1:56138 3 1 0 34.2K 0 3.0M 0 go 1.1.0 _INBOX.a96f3f6853616154d23d1b5072
127.0.0.1:56144 4 5 0 11.2K 11.1K 873.5K 1.1M go 1.1.0 foo, hello
127.0.0.1:56151 5 8 0 11.4K 11.5K 1014.6K 1.0M go 1.1.0 foo, hello
```
## Installation
nats-top can be installed using `go get`. For example:
```bash
go get github.com/nats-io/nats-top
```
NOTE: You may have to run the above command as user `sudo` depending on your setup. If you receive an error that you cannot install nats-top because your $GOPATH is not set, when in fact it is set, use command `sudo -E go get github.com/nats-io/nats-top` to install nats-top. The `-E` flag tells sudo to preserve the current user's environment.
## Usage
Once installed, nats-top can be run with the command `nats-top` and optional arguments.
```bash
nats-top [-s server] [-m monitor] [-n num_connections] [-d delay_in_secs] [-sort by]
```
## Options
Optional arguments inclde the following:
| Option | Description |
| :--- | :--- |
| `-m monitor` | Monitoring http port from nats-server. |
| `-n num_connections` | Limit the connections requested to the server \(default 1024\). |
| `-d delay_in_secs` | Screen refresh interval \(default 1 second\). |
| `-sort by` | Field to use for sorting the connections \(see below\). |
## Commands
While in nats-top view, you can use the following commands.
### option
Use the `o<option>` command to set the primary sort key to the `<option>` value. The option value can be one of the following: `cid`, `subs`, `pending`, `msgs_to`, `msgs_from`, `bytes_to`, `bytes_from`, `lang`, `version`.
You can also set the sort option on the command line using the `-sort` flag. For example: `nats-top -sort bytes_to`.
### limit
Use the `n<limit>` command to set the sample size of connections to request from the server.
You can also set this on the command line using the `-n num_connections` flag. For example: `nats-top -n 1`.
Note that if `n<limit>` is used in conjunction with `-sort`, the server will respect both options allowing queries such as the following: Query for the connection with largest number of subscriptions: `nats-top -n 1 -sort subs`.
### s, ? and q Commands
Use the `s` command to toggle displaying connection subscriptions.
Use the `?` command to show help message with options.
Use the `q` command to quit nats-top.
### Tutorial
For a walkthrough with `nats-top` check out the [tutorial](https://github.com/nats-io/nats.docs/tree/51fc56e3090645f7cedb242415e2d5361e1807e7/nats_tools/nats_top/tutorial.md).

View File

@@ -0,0 +1,138 @@
# Tutorial
You can use [nats-top](https://github.com/nats-io/nats-top) to monitor in realtime NATS server connections and message statistics.
## Prerequisites
* [Set up your Go environment](https://golang.org/doc/install)
* [Installed the NATS server](../../nats-server/installation.md)
## 1. Install nats-top
```bash
% go get github.com/nats-io/nats-top
```
You may need to run the following instead:
```bash
% sudo -E go get github.com/nats-io/nats-top
```
## 2. Start the NATS server with monitoring enabled
```bash
% nats-server -m 8222
```
## 3. Start nats-top
```bash
% nats-top
```
Result:
```bash
nats-server version 0.6.6 (uptime: 2m2s)
Server:
Load: CPU: 0.0% Memory: 6.3M Slow Consumers: 0
In: Msgs: 0 Bytes: 0 Msgs/Sec: 0.0 Bytes/Sec: 0
Out: Msgs: 0 Bytes: 0 Msgs/Sec: 0.0 Bytes/Sec: 0
Connections: 0
HOST CID SUBS PENDING MSGS_TO MSGS_FROM BYTES_TO BYTES_FROM LANG VERSION
```
## 4. Run NATS client programs
Run some NATS client programs and exchange messages.
For the best experience, you will want to run multiple subscribers, at least 2 or 3. Refer to the [example pub-sub clients](../../nats-server/clients.md).
## 5. Check nats-top for statistics
```bash
nats-server version 0.6.6 (uptime: 30m51s)
Server:
Load: CPU: 0.0% Memory: 10.3M Slow Consumers: 0
In: Msgs: 56 Bytes: 302 Msgs/Sec: 0.0 Bytes/Sec: 0
Out: Msgs: 98 Bytes: 512 Msgs/Sec: 0.0 Bytes/Sec: 0
Connections: 3
HOST CID SUBS PENDING MSGS_TO MSGS_FROM BYTES_TO BYTES_FROM LANG VERSION
::1:58651 6 1 0 52 0 260 0 go 1.1.0
::1:58922 38 1 0 21 0 105 0 go 1.1.0
::1:58953 39 1 0 21 0 105 0 go 1.1.0
```
## 6. Sort nats-top statistics
In nats-top, enter the command `o` followed by the option, such as `bytes_to`. You see that nats-top sorts the BYTES\_TO column in ascending order.
```bash
nats-server version 0.6.6 (uptime: 45m40s)
Server:
Load: CPU: 0.0% Memory: 10.4M Slow Consumers: 0
In: Msgs: 81 Bytes: 427 Msgs/Sec: 0.0 Bytes/Sec: 0
Out: Msgs: 154 Bytes: 792 Msgs/Sec: 0.0 Bytes/Sec: 0
sort by [bytes_to]:
Connections: 3
HOST CID SUBS PENDING MSGS_TO MSGS_FROM BYTES_TO BYTES_FROM LANG VERSION
::1:59259 83 1 0 4 0 20 0 go 1.1.0
::1:59349 91 1 0 2 0 10 0 go 1.1.0
::1:59342 90 1 0 0 0 0 0 go 1.1.0
```
## 7. Use different sort options
Use some different sort options to explore nats-top, such as:
`cid`, `subs`, `pending`, `msgs_to`, `msgs_from`, `bytes_to`, `bytes_from`, `lang`, `version`
You can also set the sort option on the command line using the `-sort` flag. For example: `nats-top -sort bytes_to`.
## 8. Display the registered subscriptions.
In nats-top, enter the command `s` to toggle displaying connection subscriptions. When enabled, you see the subscription subject in nats-top table:
```bash
nats-server version 0.6.6 (uptime: 1h2m23s)
Server:
Load: CPU: 0.0% Memory: 10.4M Slow Consumers: 0
In: Msgs: 108 Bytes: 643 Msgs/Sec: 0.0 Bytes/Sec: 0
Out: Msgs: 185 Bytes: 1.0K Msgs/Sec: 0.0 Bytes/Sec: 0
Connections: 3
HOST CID SUBS PENDING MSGS_TO MSGS_FROM BYTES_TO BYTES_FROM LANG VERSION SUBSCRIPTIONS
::1:59708 115 1 0 6 0 48 0 go 1.1.0 foo.bar
::1:59758 122 1 0 1 0 8 0 go 1.1.0 foo
::1:59817 124 1 0 0 0 0 0 go 1.1.0 foo
```
## 9. Quit nats-top
Use the `q` command to quit nats-top.
## 10. Restart nats-top with a specified query
For example, to query for the connection with largest number of subscriptions:
```bash
% nats-top -n 1 -sort subs
```
Result: nats-top displays only the client connection with the largest number of subscriptions:
```bash
nats-server version 0.6.6 (uptime: 1h7m0s)
Server:
Load: CPU: 0.0% Memory: 10.4M Slow Consumers: 0
In: Msgs: 109 Bytes: 651 Msgs/Sec: 0.0 Bytes/Sec: 0
Out: Msgs: 187 Bytes: 1.0K Msgs/Sec: 0.0 Bytes/Sec: 0
Connections: 3
HOST CID SUBS PENDING MSGS_TO MSGS_FROM BYTES_TO BYTES_FROM LANG VERSION
::1:59708 115 1 0 6 0 48 0 go 1.1.0
```

151
nats-tools/natsbench.md Normal file
View File

@@ -0,0 +1,151 @@
# nats-bench
NATS is fast and lightweight and places a priority on performance. NATS provides tools for measuring performance. In this tutorial you learn how to benchmark and tune NATS on your systems and environment.
## Prerequisites
* [Set up your Go environment](https://golang.org/doc/install)
* [Install the NATS server](../nats-server/installation.md)
## Start the NATS server with monitoring enabled
```bash
% nats-server -m 8222
```
Verify that the NATS server starts successfully, as well as the HTTP monitor:
```bash
[18541] 2016/10/31 13:26:32.037819 [INF] Starting nats-server version 0.9.4
[18541] 2016/10/31 13:26:32.037912 [INF] Starting http monitor on 0.0.0.0:8222
[18541] 2016/10/31 13:26:32.037997 [INF] Listening for client connections on 0.0.0.0:4222
[18541] 2016/10/31 13:26:32.038020 [INF] Server is ready
```
## Installing and running the benchmark utility
The NATS benchmark can be installed and run via Go. Ensure your golang environment is setup.
There are two approaches; you can either install the `nats-bench` utility in the directory specified in your `GOBIN` environment variable:
```bash
% go install $GOPATH/src/github.com/nats-io/nats.go/examples/nats-bench/main.go
```
... or you can simply run it via `go run`:
```bash
% go run $GOPATH/src/github.com/nats-io/nats.go/examples/nats-bench/main.go
```
_On windows use the % environment variable syntax, replacing `$GOPATH` with `%GOPATH%`._
For the purpose of this tutorial, we'll assume that you chose the first option, and that you've added the `GOBIN` environment variable to your `PATH`.
The `nats-bench` utility is straightforward to use. The options are as follows:
```bash
% nats-bench -h
Usage: nats-bench [-s server (nats://localhost:4222)] [--tls] [-np NUM_PUBLISHERS] [-ns NUM_SUBSCRIBERS] [-n NUM_MSGS] [-ms MESSAGE_SIZE] [-csv csvfile] <subject>
```
The options are self-explanatory. Each publisher or subscriber runs in its own go routine with its own NATS connection.
## Run a publisher throughput test
Let's run a test to see how fast a single publisher can publish one million 16 byte messages to the NATS server.
```bash
% nats-bench -np 1 -n 100000 -ms 16 foo
```
The output tells you the number of messages and the number of payload bytes that the client was able to publish per second:
```bash
Starting benchmark [msgs=100000, msgsize=16, pubs=1, subs=0]
Pub stats: 7,055,644 msgs/sec ~ 107.66 MB/sec
```
Now increase the number of messages published:
```bash
% nats-bench -np 1 -n 10000000 -ms 16 foo
Starting benchmark [msgs=10000000, msgsize=16, pubs=1, subs=0]
Pub stats: 7,671,570 msgs/sec ~ 117.06 MB/sec
```
## Run a publish/subscribe throughput test
When using both publishers and subscribers, `nats-bench` reports aggregate, as well as individual publish and subscribe throughput performance.
Let's look at throughput for a single publisher with a single subscriber:
```bash
% nats-bench -np 1 -ns 1 -n 100000 -ms 16 foo
```
Note that the output shows the aggregate throughput as well as the individual publisher and subscriber performance:
```bash
Starting benchmark [msgs=100000, msgsize=16, pubs=1, subs=1]
NATS Pub/Sub stats: 2,009,230 msgs/sec ~ 30.66 MB/sec
Pub stats: 1,076,537 msgs/sec ~ 16.43 MB/sec
Sub stats: 1,004,615 msgs/sec ~ 15.33 MB/sec
```
## Run a 1:N throughput test
When specifying multiple publishers, or multiple subscribers, `nats-bench` will also report statistics for each publisher and subscriber individually, along with min/max/avg and standard deviation.
Let's increase both the number of messages, and the number of subscribers.:
```bash
% nats-bench -np 1 -ns 5 -n 10000000 -ms 16 foo
```
Output:
```bash
Starting benchmark [msgs=10000000, msgsize=16, pubs=1, subs=5]
NATS Pub/Sub stats: 5,730,851 msgs/sec ~ 87.45 MB/sec
Pub stats: 955,279 msgs/sec ~ 14.58 MB/sec
Sub stats: 4,775,709 msgs/sec ~ 72.87 MB/sec
[1] 955,157 msgs/sec ~ 14.57 MB/sec (10000000 msgs)
[2] 955,150 msgs/sec ~ 14.57 MB/sec (10000000 msgs)
[3] 955,157 msgs/sec ~ 14.57 MB/sec (10000000 msgs)
[4] 955,156 msgs/sec ~ 14.57 MB/sec (10000000 msgs)
[5] 955,153 msgs/sec ~ 14.57 MB/sec (10000000 msgs)
min 955,150 | avg 955,154 | max 955,157 | stddev 2 msgs
```
## Run a N:M throughput test
When more than 1 publisher is specified, `nats-bench` evenly distributes the total number of messages \(`-n`\) across the number of publishers \(`-np`\).
Now let's increase the number of publishers and examine the output:
```bash
% nats-bench -np 5 -ns 5 -n 10000000 -ms 16 foo
```
The output:
```bash
Starting benchmark [msgs=10000000, msgsize=16, pubs=5, subs=5]
NATS Pub/Sub stats: 6,716,465 msgs/sec ~ 102.49 MB/sec
Pub stats: 1,119,653 msgs/sec ~ 17.08 MB/sec
[1] 226,395 msgs/sec ~ 3.45 MB/sec (2000000 msgs)
[2] 225,955 msgs/sec ~ 3.45 MB/sec (2000000 msgs)
[3] 225,889 msgs/sec ~ 3.45 MB/sec (2000000 msgs)
[4] 224,552 msgs/sec ~ 3.43 MB/sec (2000000 msgs)
[5] 223,933 msgs/sec ~ 3.42 MB/sec (2000000 msgs)
min 223,933 | avg 225,344 | max 226,395 | stddev 937 msgs
Sub stats: 5,597,054 msgs/sec ~ 85.40 MB/sec
[1] 1,119,461 msgs/sec ~ 17.08 MB/sec (10000000 msgs)
[2] 1,119,466 msgs/sec ~ 17.08 MB/sec (10000000 msgs)
[3] 1,119,444 msgs/sec ~ 17.08 MB/sec (10000000 msgs)
[4] 1,119,444 msgs/sec ~ 17.08 MB/sec (10000000 msgs)
[5] 1,119,430 msgs/sec ~ 17.08 MB/sec (10000000 msgs)
min 1,119,430 | avg 1,119,449 | max 1,119,466 | stddev 12 msgs
```

30
nats-tools/nk.md Normal file
View File

@@ -0,0 +1,30 @@
# nk
`nk` is a command line tool that generates `nkeys`. NKeys are a highly secure public-key signature system based on [Ed25519](https://ed25519.cr.yp.to/).
With NKeys the server can verify identity without ever storing secrets on the server. The authentication system works by requiring a connecting client to provide its public key and digitally sign a challenge with its private key. The server generates a random challenge with every connection request, making it immune to playback attacks. The generated signature is validated a public key, thus proving the identity of the client. If the public key validation succeeds, authentication succeeds.
> NKey is an awesome replacement for token authentication, because a connecting client will have to prove it controls the private key for the authorized public key.
## Installing nk
To get started with NKeys, youll need the `nk` tool from [https://github.com/nats-io/nkeys/tree/master/nk](https://github.com/nats-io/nkeys/tree/master/nk) repository. If you have _go_ installed, enter the following at a command prompt:
```bash
> go get github.com/nats-io/nk
```
## Generating NKeys and Configuring the Server
To generate a _User_ NKEY:
```text
> nk -gen user -pubout
SUACSSL3UAHUDXKFSNVUZRF5UHPMWZ6BFDTJ7M6USDXIEDNPPQYYYCU3VY
UDXU4RCSJNZOIQHZNWXHXORDPRTGNJAHAHFRGZNEEJCPQTT2M7NLCNF4
```
The first output line starts with the letter `S` for _Seed_. The second letter `U` stands for _User_. Seeds are private keys; you should treat them as secrets and guard them with care.
The second line starts with the letter `U` for _User_, and is a public key which can be safely shared.

43
nats-tools/nsc/README.md Normal file
View File

@@ -0,0 +1,43 @@
# nsc
NATS account configurations are built using the `nsc` tool. The NSC tool allows you to:
* Create and edit Operators, Accounts, Users
* Manage subscribe and publish permissions for Users
* Add and delete Exports and Imports
* Generate Activation tokens
* Generate User credential files
* Describe Operators, Accounts, Users, and Activations
* Push account JWTs to a server or pull account JWTs from a server
## Installation
Installing `nsc` is easy:
```text
curl -L https://raw.githubusercontent.com/nats-io/nsc/master/install.py | python
```
The script will download the latest version of `nsc` and install it into your system.
## Tutorials
You can find various task-oriented tutorials to working with the tool here:
* [Basic Usage](nsc.md)
* [Configuring Streams](streams.md)
* [Configuring Services](services.md)
* [Signing Keys](signing_keys.md)
* [Revoking Users or Activations](revocation.md)
* [Working with Managed Operators](managed.md)
## Tool Documentation
For more specific browsing of the tool syntax, check out the `nsc` tool documentation. It can be found within the tool itself:
```text
> nsc help
```
Or an online version [here](https://nats-io.github.io/nsc).

60
nats-tools/nsc/managed.md Normal file
View File

@@ -0,0 +1,60 @@
# Managed Operators
You can use `nsc` to administer multiple operators. Operators can be thought of as the owners of nats-servers, and fall into two categories: local and managed. The key difference, pardon the pun, is that managed operators are ones which you don't have the nkey for. An example of a managed operator is the Synadia service called NGS. Synadia has the keys.
Accounts, as represented by their JWTs, are signed by the operator. Some operators may use local copies of JWTs, others may use the [nats-account-server](../nas/) to manage their JWTs. Synadia uses a custom server for their JWTs that works similarly to the open-sourced account server.
There are a few special commands when dealing with server based operators:
* Account JWTs can be pushed to the server using `nsc push`
* Account JWTs can be pulled from a server using `nsc pull`
For managed operators this push/pull behavior is built into `nsc`. Each time you edit your account JWT `nsc` will push the change to a managed operator's server and pull the signed response. If this fails the JWT on disk may not match the value on the server. You can always push or pull the account again without editing it. Note - push only works if the operator JWT was configured with an account server URL.
The managed operator will not only sign your account JWT with its key, but may also edit the JWT to include limits to constrain your access to their NATS servers. Some operators may also add demonstration or standard imports. Generally you can remove these, although the operator gets the final call on all Account edits. As with any deployment, the managed operator doesn't track user JWTs.
To start using a managed operator you need to tell `nsc` about it. There are a couple ways to do this. First you can manually tell `nsc` to download the operator JWT using the `add operator` command:
```bash
% nsc add operator -u http://localhost:6060/jwt/v1/operator
```
The URL you pass in should be provided to you by the operator. The second way to add a managed operator is with the `init` command:
```bash
% nsc init -u http://localhost:6060/jwt/v1/operator -n alpha
```
or
```bash
% nsc init -o synadia -n alpha
```
In the second case you can use the name of an existing operator, or a well known one \(currently only "synadia"\).
Once you add a managed operator you can add accounts to it normally, with the caveat that new accounts are pushed and pulled as described above.
## Defining "Well Known Operators"
To define a well known operator, you would tell `nsc` about an operator that you want people in your environment to use by name with a simple environment variable of the form `nsc_<operator name>_operator` the value of this environment variable should be the URL for getting the operator JWT. For example:
```bash
export nsc_zoom_operator=https://account-server-host/jwt/v1/operator
```
will tell `nsc` that there is a well known operator named zoom with its JWT at `https://account-server-host/jwt/v1/operator`. With this definition you can now use the `-u` flag with the name "zoom" to add the operator to an `nsc` store directory.
The operator JWT should have its account JWT server property set to point to the appropriate URL. For our example this would be:
```bash
nsc edit operator -u https://account-server-host/jwt/v1
```
You can also set one or more service urls. These allow the `nsc tool` actions like pub and sub to work. For example:
```bash
nsc edit operator -n nats://localhost:4222
nsc tool pub hello world
```

315
nats-tools/nsc/nsc.md Normal file
View File

@@ -0,0 +1,315 @@
# Basics
NATS uses JWTs to armor the various identity and authorization artifacts. These JWTs are created with the `nsc` tool. NSC simplifies the tasks of creating and managing identities and other JWT artifacts.
Theres a logical hierarchy to the entities:
* `Operators` are responsible for running nats-servers, and signing account JWTs that set the limits on what an account can do, such as the number of connections, data limits, etc.
* `Accounts` are responsible for issuing user JWTs, and for declaring what subjects can be exported to other accounts, and what subjects they import from other accounts and what the local subjects for those imports are.
* `Users` are issued by an account, and encode limits regarding usage and authorization over the subject space.
NSC allows you to create, edit, delete these entities, and will be central to all account based configuration.
In this guide, youll run end-to-end on some of the configuration scenarios:
* generate JWTs
* make JWTs accessible to a nats-server
* configure a nats-server to use JWTs
Lets run through the process of creating some identities and JWTs and work through the process.
## The NSC Environment
By default JWTs are written to ~/.nsc and secrets to ~/.nkeys. nsc also tracks a value called the "stores directory". This directory contains the operators you are currently working with. By default the stores directory is ~/.nsc/nats but you can switch it to another folder if you want to separate JWTs for use in a revision control system, or co-locate them with a project, etc..
To see the current NSC environment use the command `nsc env`:
```text
> nsc env
╭──────────────────────────────────────────╮
│ NSC Environment │
├──────────────────┬─────┬─────────────────┤
│ Setting │ Set │ Effective Value │
├──────────────────┼─────┼─────────────────┤
│ $NKEYS_PATH │ No │ ~/.nkeys │
│ $NSC_HOME │ No │ ~/.nsc │
│ Config │ │ ~/.nsc/nsc.json │
├──────────────────┼─────┼─────────────────┤
│ Stores Dir │ │ ~/.nsc/nats │
│ Default Operator │ │ │
│ Default Account │ │ │
│ Default Cluster │ │ │
╰──────────────────┴─────┴─────────────────╯
```
As you can see there is a setting for the nkeys folder and the nsc home. By default youll see that generated secrets are stored in `~/.nkeys`, and configurations in `~/.nsc/nats`. All operations are assumed to be in a context of the current operator and current account. When working with multiple operators and accounts you may need to set the current one. You can easily do so by issuing the `nsc env` and provide flags to set the current operator or account. See `nsc env —help` for more details.
You can easily change the home and keys locations by setting `NSC_HOME` and `NKEYS_PATH` respectively in your environment to your desired locations. The environment itself is stored in the `NSC_HOME`. Operator folders are in the stores directory which can be inside `NSC_HOME` or external to it.
> The $NKEYS\_PATH stores secrets. Since nkeys relies on cryptographic signatures to prove identity, anyone with access to your private keys will be able to assume your identity. With that said, treat them as secrets and guard them carefully.
## Creating an Operator
Lets create an operator called `Test`:
```text
> nsc add operator -n Test
Generated operator key - private key stored “~/.nkeys/Test/Test.nk”
Success! - added operator "Test"
```
With the above incantation, the tool generated an NKEY for the operator, stored the private key safely in `~/.nkeys/Test/Test.nk`. The file contains a single line, with the seed value for the NKEY.
> You can tell the key is a seed if it starts with the letter `S`. The type of the key is will be the second letter an `O`, `A` or `U` for _Operator_, _Account_ or _User_. If the key does not start with an `S` you have instead a public key.
The tool also created a JWT with all default settings for the operator test, and stored it in `~/.nsc/nats/Test/Test.jwt`. The `~/.nsc/nats/Test` directory will also contain a directory where accounts related to this operator will live.
You can view the JWT by entering the command:
```text
> nsc describe operator
╭───────────────────────────────────────╮
│ Operator Details │
├─────────────┬─────────────────────────┤
│ Name │ Test │
│ Operator ID │ OCEWHXFL3I5I │
│ Issuer ID │ OCEWHXFL3I5I │
│ Issued │ 2019-06-11 16:25:37 UTC │
│ Expires │ │
╰─────────────┴─────────────────────────╯
```
Note that the Operator ID is truncated to simplify the output, to get the full ID, do:
```text
> nsc describe operator -W
╭────────────────────────────────────────────────────────────────────────╮
│ Operator Details │
├─────────────┬──────────────────────────────────────────────────────────┤
│ Name │ Test │
│ Operator ID │ OCEWHXFL3I5IWPFK2674IUQTFHRZXHI52S2DKQIQJXRXC6P6GWSINZ3H │
│ Issuer ID │ OCEWHXFL3I5IWPFK2674IUQTFHRZXHI52S2DKQIQJXRXC6P6GWSINZ3H │
│ Issued │ 2019-06-11 16:25:37 UTC │
│ Expires │ │
╰─────────────┴──────────────────────────────────────────────────────────╯
```
The operator JWT contains two important URLs. The `account-jwt-server-url` is used by `nsc` when you want to push JWTs to an account server. The `service-url`s are used by `nsc` when you run the tool commands, like `nsc tool pub`.
With an operator, we are ready to create our first account.
## Creating an Account
Lets create an account called `TestAccount`:
```text
> nsc add account -n TestAccount
Generated account key - private key stored “~/.nkeys/Test/accounts/TestAccount/TestAccount.nk"
Success! - added account "TestAccount"
```
As we did with the operator, we can describe the account:
```text
> nsc describe account
╭─────────────────────────────────────────────────────╮
│ Account Details │
├───────────────────────────┬─────────────────────────┤
│ Name │ TestAccount │
│ Account ID │ ADM7UGD4FV52 │
│ Issuer ID │ OCEWHXFL3I5I │
│ Issued │ 2019-06-11 16:25:57 UTC │
│ Expires │ │
├───────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Leaf Node Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├───────────────────────────┼─────────────────────────┤
│ Imports │ None │
│ Exports │ None │
╰───────────────────────────┴─────────────────────────╯
```
Again, specifying the `-W` flag will print the complete account ID \(the public key identifying the account\).
Note that the issuer for the account is the ID for the operator \(the public key identifying the operator\).
Now we are ready to add a user.
## Creating a User
Lets add a user named TestUser:
```text
> nsc add user -n TestUser
Generated user key - private key stored "~/.nkeys/Test/accounts/TestAccount/users/TestUser.nk"
Generated user creds file "~/.nkeys/Test/accounts/TestAccount/users/TestUser.creds"
Success! - added user "TestUser" to "TestAccount"
```
Note that when we added the user, we got a message telling us about a `.creds` file being created. The `.creds` file contains the JWT describing the user, and the private \(seed\) key for the user. This file is formatted in a special way for use by nats client libraries. Client libraries can extract the JWT and seed key, and connect to a server expecting JWT authentication, provide the JWT and use the private key to sign the nonce to verify its identity.
And lets describe it:
```text
> nsc describe user
╭───────────────────────────────────────────╮
│ User │
├─────────────────┬─────────────────────────┤
│ Name │ TestUser │
│ User ID │ UBV36EUP2B3Q │
│ Issuer ID │ ADM7UGD4FV52 │
│ Issued │ 2019-06-11 16:26:22 UTC │
│ Expires │ │
├─────────────────┼─────────────────────────┤
│ Max Messages │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Network Src │ Any │
│ Time │ Any │
╰─────────────────┴─────────────────────────╯
```
Lets put all of this together, and create a simple server configuration that accepts sessions from TestUser.
## Account Server Configuration
To configure a server to use accounts you need an _account resolver_. An account resolver exposes a URL where a nats-server can query for JWTs belonging to an account.
A simple built-in resolver is the `MEMORY` resolver which simply statically maps account public keys to an account JWT in the servers configuration file. It is somewhat easier to configure because it doesnt require another moving part, but fails provide the needed experience of setting up an account server. Lets setup an _Account Server_.
Installing the Account Server
```text
> go get github.com/nats-io/nats-account-server
```
The account server has options to enable you to use an nsc directory directly. Lets start one:
```text
> nats-account-server -nsc ~/.nsc/nats/Test
```
Above we pointed the account server to our nsc data directory \(more specifically to the `Test` operator that we created earlier\). By default, the server listens on the localhost at port 9090.
You can also run the account server with a data directory that is not your nsc folder. In this mode you can upload account JWTs to the server. See the help for `nsc push` for more information about how to push JWTs to the account server.
We are now ready to configure the nats-server.
## NATS Server Configuration
If you dont have a nats-server installed, lets do that now:
```text
> go get github.com/nats-io/nats-server
```
Lets create a configuration that references our operator JWT and the nats-account-server as a resolver:
```yaml
operator: /Users/synadia/.nsc/nats/Test/Test.jwt
resolver: URL(http://localhost:9090/jwt/v1/accounts/)
```
At minimum the server requires the `operator` JWT, which we have pointed at directly, and a resolver. The resolver has two types `MEM` and `URL`. We are interested in the `URL` since we want the nats-server to talk to the account server. Note we put the URL of the server with the path `/jwt/v1/accounts`. Currently this is where the account server expects requests for account information.
## Client Testing
Lets install some tooling:
```text
> go get github.com/nats-io/nats.go/examples/nats-pub
> go get github.com/nats-io/nats.go/examples/nats-sub
```
Create a subscriber:
```text
nats-sub -creds ~/.nkeys/Test/accounts/TestAccount/users/TestUser.creds ">"
Listening on [>]
```
Publish a message:
```text
nats-pub -creds ~/.nkeys/Test/accounts/TestAccount/users/TestUser.creds hello NATS
Published [hello] : 'NATS'
```
Subscriber shows:
```text
```
## User Authorization
User authorization, as expected, also works with JWT authentication. With `nsc` you can specify authorization for specific subjects to which the user can or cannot publish or subscribe. By default a user doesn't have any limits on the subjects that it can publish or subscribe to. Any message stream or message published in the account is subscribable by the user. The user can also publish to any subject or imported service. Note that authorization, if configured, must be specified on a per user basis.
When specifying limits it is important to remember that clients by default use generated "inboxes" to allow publish requests. When specifying subscribe and publish permissions, you need to enable clients to subscribe and publish to `_INBOX.>`. You can further restrict it, but you'll be responsible for segmenting the subject space so as to not break request/reply communications between clients.
Let's say you have a service that your account clients can make requests to under `req.a`. To enable the service to receive and respond to requests it requires permissions to subscribe to `req.a` and publish permissions under `_INBOX.>`:
```text
> nsc add user --name TestService --allow-pub "_INBOX.>" --allow-sub "req.a"
Generated user key - private key stored "~/.nkeys/Test/accounts/TestAccount/users/TestService.nk"
Generated user creds file "~/.nkeys/Test/accounts/TestAccount/users/TestService.creds"
Success! - added user "TestService" to "TestAccount"
> nsc describe user --name TestService
╭───────────────────────────────────────────╮
│ User │
├─────────────────┬─────────────────────────┤
│ Name │ TestService │
│ User ID │ UCAYGJXTF5WO │
│ Issuer ID │ ADM7UGD4FV52 │
│ Issued │ 2019-06-11 16:41:03 UTC │
│ Expires │ │
├─────────────────┼─────────────────────────┤
│ Pub Allow │ _INBOX.> │
│ Sub Allow │ req.a │
├─────────────────┼─────────────────────────┤
│ Max Messages │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Network Src │ Any │
│ Time │ Any │
╰─────────────────┴─────────────────────────╯
```
As you can see this client is not limited to publishing responses to `_INBOX.>` addresses, and to subscribing to the service's request subject.
Similarly, we can limit a client:
```text
> nsc add user --name TestClient --allow-pub "req.a" --allow-sub "_INBOX.>"
Generated user key - private key stored "~/.nkeys/Test/accounts/TestAccount/users/TestClient.nk"
Generated user creds file "~/.nkeys/Test/accounts/TestAccount/users/TestClient.creds"
Success! - added user "TestClient" to "TestAccount"
> nsc describe user --name TestClient
╭───────────────────────────────────────────╮
│ User │
├─────────────────┬─────────────────────────┤
│ Name │ TestClient │
│ User ID │ UDJ3LCVNTYXL │
│ Issuer ID │ ADM7UGD4FV52 │
│ Issued │ 2019-06-11 16:43:46 UTC │
│ Expires │ │
├─────────────────┼─────────────────────────┤
│ Pub Allow │ req.a │
│ Sub Allow │ _INBOX.> │
├─────────────────┼─────────────────────────┤
│ Max Messages │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Network Src │ Any │
│ Time │ Any │
╰─────────────────┴─────────────────────────╯
```
The client has the opposite permissions of the service. It can publish on the request subject `req.a`, and receive replies on an inbox.

View File

@@ -0,0 +1,29 @@
# Revocation
NATS supports two types of revocations. Both of these are stored in the Account JWT, so that the nats-server can see the revocations and apply them.
Users are revoked by public key and time. Access to an export, called an activation, can be revoked for a specific account at a specific time. The use of time here can be confusing, but is designed to support the primary uses of revocation.
When a user or activation is revoked at time T, it means that any user JWT or activation token created before that time is invalid. If a new user JWT or new activation token is created after T it can be used. This allows an account owner to revoke a user and renew their access at the same time.
Let's look at an example. Suppose you created a user JWT with access to the subject "billing". Later you decide you don't want that user to have access to "billing". Revoke the user, say at noon on May 1st 2019, and create a new user JWT without access to "billing". The user can no longer log in with the old JWT because it is revoked, but they can log in with the new JWT because it was created after noon May 1st 2019.
`nsc` provides a number of commands to create, remove or list revocations:
```bash
Usage:
nsc revocations [command]
Available Commands:
add_activation Revoke an accounts access to an export
add_user Revoke a user
delete_activation Remove an account revocation from an export
delete_user Remove a user revocation
list_activations List account revocations for an export
list_users List users revoked in an account
```
Both add commands take the flag `--at` which defaults to 0, for now, which can be used to set the unix timestamp as described above. By default revocations are at the current time, but you can set them in the past for situations where you know when a problem occurred and was fixed.
Deleting a revocation is permanent and can allow an old activation or user JWT to be valid again. Therefore delete should only be used if you are sure the tokens in question have expired.

298
nats-tools/nsc/services.md Normal file
View File

@@ -0,0 +1,298 @@
# Services
To share services that other accounts can reach via request reply, you have to _Export_ a _Service_. _Services_ are associated with the account performing the replies and are advertised in the exporting accounts' JWT.
## Adding a Public Service Export
To add a service to your account:
```text
> nsc add export --name "srv" --subject "help" --service
Success! - added public service export "srv"
```
To review the service export:
```text
> nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ TestAccount │
│ Account ID │ AC7PO3MREV26 │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-29 14:20:13 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Imports │ None │
╰──────────────────────────┴─────────────────────────╯
╭───────────────────────────────────╮
│ Exports │
├──────┬─────────┬─────────┬────────┤
│ Name │ Type │ Subject │ Public │
├──────┼─────────┼─────────┼────────┤
│ help │ Service │ help │ Yes │
╰──────┴─────────┴─────────┴────────╯
```
## Importing a Service
Importing a service enables you to send requests to the remote _Account_. To import a Service, you have to create an _Import_. To create an import you need to know:
* The exporting accounts public key
* The subject the service is listening on
* You can map the services subject to a different subject
* Self-imports are not valid; you can only import services from other accounts.
To learn how to inspect a JWT from an account server, [check this article](../nas/inspecting_jwts.md).
```text
> nsc add import --src-account AC7PO3MREV26U3LFZFP5BN3HAI32X3PKLBRVMPAETLEHWPQEUG7EJY4H --remote-subject help --service
Success! - added service import "help"
```
Verifying our work:
```text
> nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ AccountB │
│ Account ID │ AAL5Q2B3SMSO │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-29 14:37:49 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Exports │ None │
╰──────────────────────────┴─────────────────────────╯
╭─────────────────────────────────────────────────────────────────────────╮
│ Imports │
├─────────┬─────────┬─────────┬─────────┬─────────┬──────────────┬────────┤
│ Name │ Type │ Remote │ Local │ Expires │ From Account │ Public │
├─────────┼─────────┼─────────┼─────────┼─────────┼──────────────┼────────┤
│ help │ Service │ help │ help │ │ AC7PO3MREV26 │ Yes │
╰─────────┴─────────┴─────────┴─────────┴─────────┴──────────────┴────────╯
```
### Testing the Service
To test the service, we can install the `nats-req` and `nats-rply` tools:
Set up a process to handle the request:
```text
> go get github.com/nats-io/nats.go/examples/nats-rply
> nats-rply -creds ~/.nkeys/Test/accounts/AccountB/users/userb.creds "help" "I will help"
Listening on [help]
```
Send the request:
```text
> go get github.com/nats-io/nats.go/examples/nats-req
> nats-req -creds ~/.nkeys/Test/accounts/AccountB/users/userb.creds help me
Published [help] : 'me'
```
The service receives the request:
```text
```
And the response is received by the requestor:
```text
Received [_INBOX.v6KAX0v1bu87k49hbg3dgn.StIGJF0D] : 'I will help'
```
## Securing Services
If you want to create a service that is only accessible to accounts you designate you can create a _private_ service. The export will be visible in your account, but subscribing accounts will require an authorization token that must be created by you and generated specifically for the requesting account.
Lets create an account and user for our stream client:
```text
> nsc add account --name AccountB
Generated account key - private key stored “~/.nkeys/Test/accounts/AccountB/AccountB"
Success! - added account "AccountB"
> nsc add user --name userb
Generated user key - private key stored "~/.nkeys/Test/accounts/AccountB/users/userb”
Generated user creds file "~/.nkeys/Test/accounts/AccountB/users/userb.creds"
Success! - added user “userb” to “AccountB”
```
The authorization token is simply a JWT signed by your account where you authorize the client account to import your service.
### Creating a Private Service Export
```text
> nsc add export --name phelp --subject "help.>" --private --service
Success! - added private service export "phelp"
```
As before, we declared an export, but this time we added the `--private` flag. The other thing to note is that the subject for the request has a wildcard. This enables the account to map specific subjects to specifically authorized accounts.
```text
> nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ TestAccount │
│ Account ID │ AC7PO3MREV26 │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-29 14:59:42 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Imports │ None │
╰──────────────────────────┴─────────────────────────╯
╭────────────────────────────────────╮
│ Exports │
├───────┬─────────┬─────────┬────────┤
│ Name │ Type │ Subject │ Public │
├───────┼─────────┼─────────┼────────┤
│ phelp │ Service │ help.> │ No │
╰───────┴─────────┴─────────┴────────╯
```
### Generating an Activation Token
For the foreign account to _import_ a private service and be able to send requests, you have to generate an activation token. The activation token in addition to granting permission to the account allows you to subset the services subject:
To generate a token, youll need to know the public key of the account importing the service.
```text
> nsc generate activation -o /tmp/activation.jwt --target-account AAL5Q2B3SMSO5AS3APJFUNAIKUCEQJPAQ76XEBTVOCQCXXGKP3YMGGN4 --subject "help.AAL5Q2B3SM" --service
generated "phelp" activation for account "AAL5Q2B3SMSO5AS3APJFUNAIKUCEQJPAQ76XEBTVOCQCXXGKP3YMGGN4".
JTI is "IY4ZUWLNLOTO5N5UDLOFEBCOMHB6MKQMK4ZELA2BSPKMXSEARXOA"
```
In the above invocation, we generated an activation redirecting the output to `/tmp/activation.jwt`. The activation only allows the client account to perform requests on `help.AAL5Q2B3SM`.
For completeness, the contents of the JWT file looks like this:
```text
> cat /tmp/activation.jwt
-----BEGIN NATS ACTIVATION JWT-----
eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5In0.eyJqdGkiOiJJWTRaVVdMTkxPVE81TjVVRExPRkVCQ09NSEI2TUtRTUs0WkVMQTJCU1BLTVhTRUFSWE9BIiwiaWF0IjoxNTU2NTUwMDczLCJpc3MiOiJBQzdQTzNNUkVWMjZVM0xGWkZQNUJOM0hBSTMyWDNQS0xCUlZNUEFFVExFSFdQUUVVRzdFSlk0SCIsIm5hbWUiOiJoZWxwLkFBTDVRMkIzU00iLCJzdWIiOiJBQUw1UTJCM1NNU081QVMzQVBKRlVOQUlLVUNFUUpQQVE3NlhFQlRWT0NRQ1hYR0tQM1lNR0dONCIsInR5cGUiOiJhY3RpdmF0aW9uIiwibmF0cyI6eyJzdWJqZWN0IjoiaGVscC5BQUw1UTJCM1NNIiwidHlwZSI6InNlcnZpY2UifX0.VFYHPA0e67RFR-XFy7Q7pS90hzZvP5k3OsldjaDrIXP4UdpuQeUhv9qK9EMK40pcgH6NzJ7gmaZLU6RpAcbXAg
------END NATS ACTIVATION JWT------
```
When decoded it looks like this:
```text
> nsc describe jwt -f /tmp/activation.jwt
╭───────────────────────────────────────────╮
│ Activation │
├─────────────────┬─────────────────────────┤
│ Import Type │ Service │
│ Import Subject │ help.AAL5Q2B3SM │
│ Account ID │ AAL5Q2B3SMSO │
│ Issuer ID │ AC7PO3MREV26 │
│ Issued │ 2019-04-29 15:01:13 UTC │
│ Expires │ │
├─────────────────┼─────────────────────────┤
│ Max Messages │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Network Src │ Any │
│ Time │ Any │
╰─────────────────┴─────────────────────────╯
```
The token can be shared directly with the client account.
> If you manage many tokens for many accounts, you may want to host activation tokens on a web server and share the URL with the account. The benefit to the hosted approach is that any updates to the token would be available to the importing account whenever their account is updated, provided the URL you host them in is stable.
## Importing a Private Service
As with streams, importing a private service is more natural than a public one because the activation token stores all the necessary details. Again, the token can be an actual file path or a remote URL.
```text
> nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ AccountB │
│ Account ID │ AAL5Q2B3SMSO │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-29 15:26:39 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Exports │ None │
╰──────────────────────────┴─────────────────────────╯
╭─────────────────────────────────────────────────────────────────────────────────╮
│ Imports │
├─────────┬─────────┬─────────────────┬─────────┬─────────┬──────────────┬────────┤
│ Name │ Type │ Remote │ Local │ Expires │ From Account │ Public │
├─────────┼─────────┼─────────────────┼─────────┼─────────┼──────────────┼────────┤
│ help │ Service │ help.AAL5Q2B3SM │ help │ │ AC7PO3MREV26 │ No │
╰─────────┴─────────┴─────────────────┴─────────┴─────────┴──────────────┴────────╯
```
### Testing the Private Service
Start the replier:
```text
> nats-rply -creds ~/.nkeys/Test/accounts/TestAccount/users/TestUser.creds "help.>" "I will help"
Listening on [help.>]
```
Send a request:
```text
> nats-req -creds ~/.nkeys/Test/accounts/AccountB/users/userb.creds help me
Published [help] : 'me'
```
The service receives the message:
```text
```
The requester receives its response:
```text
Received [_INBOX.N3IiqWbiAQfPoINCBpBrUM.ZjBNtkB3] : 'I will help'
```

View File

@@ -0,0 +1,150 @@
# Signing Keys
As previously discussed, NKEYs are identities, and if someone gets a hold of an account or operator nkey they can do everything you can do as you.
NATS has a strategies to let you deal with scenarios where your private keys escape out in the wild.
The first and most important line of defense is _Signing Keys_. _Signing Keys_ allow you have multiple NKEY identities of the same kind \(Operator or Account\) that have the same degree of trust as the standard _Issuer_ nkey.
The concept behind the signing key is that you can issue a JWT for an operator or an account that lists multiple nkeys. Typically the issuer will match the _Subject_ of the entity issuing the JWT. With SigningKeys, a JWT is considered valid if it is signed by the _Subject_ of the _Issuer_ or one of its signing keys. This enables guarding the private key of the Operator or Account more closely while allowing _Accounts_, _Users_ or _Activation Tokens_ be signed using alternate private keys.
If an issue should arise where somehow a signing key escapes into the wild, you would remove the compromised signing key from the entity, add a new one, and reissue the entity. When a JWT is validated, if the signing key is missing, the operation is rejected. You are also on the hook to re-issue all JWTs \(accounts, users, activation tokens\) that were signed with the compromised signing key.
This is effectively a large hammer. You can mitigate the process a bit by having a larger number of signing keys and then rotating the signing keys to get a distribution you can easily handle in case of a compromise. In a future release, well have a revocation process were you can invalidate a single JWT by its unique JWT ID \(JTI\). For now a sledge hammer you have.
With greater security process, theres greater complexity. With that said, `nsc` doesnt track public or private signing keys. As these are only identities that when in use presume a manual use. That means that you the user will have to track and manage your private keys more closely.
Lets get a feel for the workflow. We are going to:
* Create an operator with a signing key
* Create an account with a signing key
* The account will be signed using the operators signing key
* Create an user with the accounts signing key
All signing key operations revolve around the global `nsc` flag `-K` or `--private-key`. Whenever you want to modify an entity, you have to supply the parent key so that the JWT is signed. Normally this happens automatically but in the case of signing keys, youll have to supply the flag by hand.
Creating the operator:
```text
> nsc add operator -n O2
Generated operator key - private key stored "/Users/synadia/.nkeys/O2/O2.nk"
Success! - added operator "O2"
```
To add a signing key we have to first generate one with `nk`. `NSC` doesnt at this time offer a way to generate keys that are not associated with an entity. This means that you will have to generate and store the secrets yourself:
```text
# generate an operator keypair:
> nk -gen operator -pubout
SOAIHSQSAM3ZJI5W6U5M4INH7FUCQQ5ETJ5RMPVJZCJLTDREY6ZNEE6LZQ
ODMYCI5TSZY6MFLOBBQ2RNRBRAXRKJKAC5UACRC6H6CJXCLR2STTGAAQ
```
> On a production environment private keys should be saved to a file and always referenced from the secured file.
Now we are going to edit the operator by adding a signing key with the `--sk` flag providing the generated operator public key \(the one starting with `O`\):
```text
> nsc edit operator --sk ODMYCI5TSZY6MFLOBBQ2RNRBRAXRKJKAC5UACRC6H6CJXCLR2STTGAAQ
Success! - edited operator
-----BEGIN NATS OPERATOR JWT-----
eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5In0.eyJqdGkiOiJPMk5BMkNaQ1ZINkQyTEVCQkNDVUFHTEZaWFJPTTdKTEs1Q1ZXRDZMVlpPVU9TUExDS0dBIiwiaWF0IjoxNTU2NTczNTYzLCJpc3MiOiJPQks3M09MUU9KV05ZVE4yTzQ2SVpRTjRXTVNDN0hWVk5BM1k2VFdQV0tDRlhJV1MzWExTQVVJUyIsIm5hbWUiOiJPMiIsInN1YiI6Ik9CSzczT0xRT0pXTllUTjJPNDZJWlFONFdNU0M3SFZWTkEzWTZUV1BXS0NGWElXUzNYTFNBVUlTIiwidHlwZSI6Im9wZXJhdG9yIiwibmF0cyI6eyJzaWduaW5nX2tleXMiOlsiT0RNWUNJNVRTWlk2TUZMT0JCUTJSTlJCUkFYUktKS0FDNVVBQ1JDNkg2Q0pYQ0xSMlNUVEdBQVEiXX19.-VNSZhmOa3TrGglTZ3pGU3BPScb0uj5rdvTHzzOyZ18_WlCBfo6H8S01S3D2qf9J36lKhPplMtupheYqEo04Aw
------END NATS OPERATOR JWT------
```
Check our handy work:
```text
> nsc describe operator
╭────────────────────────────────────────╮
│ Operator Details │
├──────────────┬─────────────────────────┤
│ Name │ O2 │
│ Operator ID │ OBK73OLQOJWN │
│ Issuer ID │ OBK73OLQOJWN │
│ Issued │ 2019-04-29 21:32:43 UTC │
│ Expires │ │
├──────────────┼─────────────────────────┤
│ Signing Keys │ ODMYCI5TSZY6 │
╰──────────────┴─────────────────────────╯
```
Now lets create an account called `A` and sign it the generated operator private signing key. To sign it with the key specify the `-K` flag and the private key or a path to the private key:
```text
> nsc add account --name A -K SOAIHSQSAM3ZJI5W6U5M4INH7FUCQQ5ETJ5RMPVJZCJLTDREY6ZNEE6LZQ
Generated account key - private key stored "/Users/synadia/.nkeys/O2/accounts/A/A.nk"
Success! - added account "A"
```
Lets generate an account signing key, again we use `nk`:
```text
> nk -gen account -pubout
SAAK3EL5BW4ZOR7JVTXZ4TJ6RQBSOIXK27AFPPSYVP4KDHJKSRQFVRAHIA
ABHYL27UAHHQXA5HLH2YWHFQBIP4YMPC7RNZ4PSFRAMJHSSZUUIXF2RV
```
Lets add the signing key to the account, and remember to sign the account with the operator signing key:
```text
> nsc edit account --sk ABHYL27UAHHQXA5HLH2YWHFQBIP4YMPC7RNZ4PSFRAMJHSSZUUIXF2RV -K SOAIHSQSAM3ZJI5W6U5M4INH7FUCQQ5ETJ5RMPVJZCJLTDREY6ZNEE6LZQ
Success! - edited account "A"
> nsc describe account
╭─────────────────────────────────────────────────────╮
│ Account Details │
├───────────────────────────┬─────────────────────────┤
│ Name │ A │
│ Account ID │ AD7HDY5AS3LT │
│ Issuer ID │ ODMYCI5TSZY6 │
│ Issued │ 2019-04-30 22:33:13 UTC │
│ Expires │ │
├───────────────────────────┼─────────────────────────┤
│ Signing Keys │ ABHYL27UAHHQ │
├───────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Leaf Node Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├───────────────────────────┼─────────────────────────┤
│ Imports │ None │
│ Exports │ None │
╰───────────────────────────┴─────────────────────────╯
```
We can see that the signing key `ABHYL27UAHHQ` was added to the account. Also the issuer is the operator signing key \(specified by the `-K`\).
Now lets create a user and signing it with account signing key starting with `ABHYL27UAHHQ`.
```text
> nsc add user --name U -K SAAK3EL5BW4ZOR7JVTXZ4TJ6RQBSOIXK27AFPPSYVP4KDHJKSRQFVRAHIA
Generated user key - private key stored "/Users/synadia/.nkeys/O2/accounts/A/users/U.nk"
Generated user creds file "/Users/synadia/.nkeys/O2/accounts/A/users/U.creds"
Success! - added user "U" to "A"
> nsc describe user
╭───────────────────────────────────────────╮
│ User │
├─────────────────┬─────────────────────────┤
│ Name │ U │
│ User ID │ UDYKZHLXFH56 │
│ Issuer ID │ ABHYL27UAHHQ │
│ Issuer Account │ AD7HDY5AS3LT │
│ Issued │ 2019-04-30 22:43:46 UTC │
│ Expires │ │
├─────────────────┼─────────────────────────┤
│ Max Messages │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Network Src │ Any │
│ Time │ Any │
╰─────────────────┴─────────────────────────╯
```
As expected, the issuer is now the signing key we generated earlier. To map the user to the actual account, an `Issuer Account` field was added to the JWT that identifies the public key of account _A_.

297
nats-tools/nsc/streams.md Normal file
View File

@@ -0,0 +1,297 @@
# Streams
To share messages you publish with other accounts, you have to _Export_ a _Stream_. _Exports_ are associated with the account performing the export and advertised in exporting accounts JWT.
### Adding a Public Stream Export
To add a stream to your account:
```text
> nsc add export --name "abc" --subject "a.b.c.>"
Success! - added public stream export "abc"
```
> Note that we have exported stream with a subject that contains a wildcard. Any subject that matches the pattern will be exported.
To check that the export is how you intended:
```text
> nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ TestAccount │
│ Account ID │ AC7PO3MREV26 │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-29 14:20:13 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Imports │ None │
╰──────────────────────────┴─────────────────────────╯
╭───────────────────────────────────╮
│ Exports │
├──────┬─────────┬─────────┬────────┤
│ Name │ Type │ Subject │ Public │
├──────┼─────────┼─────────┼────────┤
│ abc │ Stream │ a.b.c.> │ Yes │
╰──────┴─────────┴─────────┴────────╯
```
Messages this account publishes on `a.b.c.>` will be forwarded to all accounts that import this stream.
### Importing a Stream
Importing a stream enables you to receive messages that are published by a different _Account_. To import a Stream, you have to create an _Import_. To create an _Import_ you need to know:
* The exporting accounts public key
* The subject where the stream is published
* You can map the streams subject to a different subject
* Self-imports are not valid; you can only import streams from other accounts.
To learn how to inspect a JWT from an account server, [check this article](../nas/inspecting_jwts.md).
With the required information, we can add an import to the public stream.
```text
> nsc add import --src-account AC7PO3MREV26U3LFZFP5BN3HAI32X3PKLBRVMPAETLEHWPQEUG7EJY4H --remote-subject "a.b.c.>" --local-subject "abc.>"
Success! - added stream import "a.b.c.>"
```
> Note we did fancy things here: The remote stream publishes messages as `a.b.c.>`, but we changed the prefix to be something else in the importing accounts subject space. We changed it to `abc.>`. Subscribers in our account can listen to `abc.>` to get the messages. The message will be delivered as `abc.a.b.c.>`.
And verifying it:
```text
> nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ AccountB │
│ Account ID │ AAL5Q2B3SMSO │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-25 21:33:58 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Exports │ None │
╰──────────────────────────┴─────────────────────────╯
╭────────────────────────────────────────────────────────────────────╮
│ Imports │
├───────┬────────┬─────────┬───────┬─────────┬──────────────┬────────┤
│ Name │ Type │ Remote │ Local │ Expires │ From Account │ Public │
├───────┼────────┼─────────┼───────┼─────────┼──────────────┼────────┤
│ abc.> │ Stream │ a.b.c.> │ abc.> │ │ AC7PO3MREV26 │ Yes │
╰───────┴────────┴─────────┴───────┴─────────┴──────────────┴────────╯
```
## Securing Streams
If you want to create a stream that is only accessible to accounts you designate you can create a _private_ stream. The export will be visible in your account, but _subscribing_ accounts will require an authorization token that must be created by you and generated specifically for the subscribing account.
The authorization token is simply a JWT signed by your account where you authorize the client account to import your export.
### Creating a Private Stream Export
```text
> nsc add export --name pabc --subject "a.b.c.>" --private
Success! - added private stream export "pabc"
```
Like before we defined an export, but this time we added the `--private` flag.
```text
> nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ TestAccount │
│ Account ID │ AC7PO3MREV26 │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-25 21:51:02 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Imports │ None │
╰──────────────────────────┴─────────────────────────╯
╭──────────────────────────────────╮
│ Exports │
├──────┬────────┬─────────┬────────┤
│ Name │ Type │ Subject │ Public │
├──────┼────────┼─────────┼────────┤
│ pabc │ Stream │ a.b.c.> │ No │
╰──────┴────────┴─────────┴────────╯
```
### Generating an Activation Token
For a foreign account to _import_ a private stream, you have to generate an activation token. The activation token in addition to granting permissions to the account, it also allows you to subset the exported streams subject.
Lets create an account and user for our stream client:
```text
> nsc add account --name AccountB
Generated account key - private key stored “~/.nkeys/Test/accounts/AccountB/AccountB"
Success! - added account "AccountB"
> nsc add user --name userb
Generated user key - private key stored "~/.nkeys/Test/accounts/AccountB/users/userb”
Generated user creds file "~/.nkeys/Test/accounts/ACcountB/users/userb.creds"
Success! - added user “userb” to “AccountB”
```
To generate a token, youll need to know the public key of the account importing the stream.
```text
> nsc generate activation -o /tmp/activation.jwt --target-account AAL5Q2B3SMSO5AS3APJFUNAIKUCEQJPAQ76XEBTVOCQCXXGKP3YMGGN4 —subject a.b.c.d
generated "pabc" activation for account "AAL5Q2B3SMSO5AS3APJFUNAIKUCEQJPAQ76XEBTVOCQCXXGKP3YMGGN4".
JTI is "VNT3Y32I5FNTEHIVL6PINEJNNZ6Z2BGGEJ2QWNA3TPQ4A4KBRGHQ"
```
In the above invocation, we generated an activation redirecting the output to `/tmp/activation.jwt`. The exporting account exported `a.b.c.>`, but on the activation token will only grant permission to `a.b.c.d` to the target account.
For completeness, the contents of the JWT file look like this:
```text
> cat /tmp/activation.jwt
-----BEGIN NATS ACTIVATION JWT-----
eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5In0.eyJqdGkiOiJWTlQzWTMySTVGTlRFSElWTDZQSU5FSk5OWjZaMkJHR0VKMlFXTkEzVFBRNEE0S0JSR0hRIiwiaWF0IjoxNTU2MjI5NDk0LCJpc3MiOiJBQzdQTzNNUkVWMjZVM0xGWkZQNUJOM0hBSTMyWDNQS0xCUlZNUEFFVExFSFdQUUVVRzdFSlk0SCIsIm5hbWUiOiJhLmIuYy5kIiwic3ViIjoiQUFMNVEyQjNTTVNPNUFTM0FQSkZVTkFJS1VDRVFKUEFRNzZYRUJUVk9DUUNYWEdLUDNZTUdHTjQiLCJ0eXBlIjoiYWN0aXZhdGlvbiIsIm5hdHMiOnsic3ViamVjdCI6ImEuYi5jLmQiLCJ0eXBlIjoic3RyZWFtIn19.eA0W-mcxFXyIpEk0MUgaLjj7t5jxEHTar7MNY5IYcJ7NHlDoHU5IFog2LlFW_hpTCFA4qa989vqECsiTuBuCAA
------END NATS ACTIVATION JWT------
```
When decoded it looks like this:
```text
> nsc describe jwt -f /tmp/activation.jwt
╭───────────────────────────────────────────╮
│ Activation │
├─────────────────┬─────────────────────────┤
│ Import Type │ Stream │
│ Import Subject │ a.b.c.d │
│ Account ID │ AAL5Q2B3SMSO │
│ Issuer ID │ AC7PO3MREV26 │
│ Issued │ 2019-04-25 21:58:14 UTC │
│ Expires │ │
├─────────────────┼─────────────────────────┤
│ Max Messages │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Network Src │ Any │
│ Time │ Any │
╰─────────────────┴─────────────────────────╯
```
The token can be shared directly with the client account.
> If you manage many tokens for many accounts, you may want to host activation tokens on a web server and share the URL with the account. The benefit to the hosted approach is that any updates to the token would be available to the importing account whenever their account is updated, provided the URL you host them in is stable.
## Importing a Private Stream
Importing a private stream is more natural than a public one as the activation token given to you already has all the necessary details. Note that the token can be an actual file path or a remote URL.
```text
> nsc add import --token /tmp/activation.jwt
Success! - added stream import "a.b.c.d"
```
```text
> nsc describe account
nsc describe account
╭────────────────────────────────────────────────────╮
│ Account Details │
├──────────────────────────┬─────────────────────────┤
│ Name │ AccountB │
│ Account ID │ AAL5Q2B3SMSO │
│ Issuer ID │ OAYI3YUZSWDN │
│ Issued │ 2019-04-25 22:04:29 UTC │
│ Expires │ │
├──────────────────────────┼─────────────────────────┤
│ Max Connections │ Unlimited │
│ Max Data │ Unlimited │
│ Max Exports │ Unlimited │
│ Max Imports │ Unlimited │
│ Max Msg Payload │ Unlimited │
│ Max Subscriptions │ Unlimited │
│ Exports Allows Wildcards │ True │
├──────────────────────────┼─────────────────────────┤
│ Exports │ None │
╰──────────────────────────┴─────────────────────────╯
╭────────────────────────────────────────────────────────────────────────╮
│ Imports │
├─────────┬────────┬─────────┬─────────┬─────────┬──────────────┬────────┤
│ Name │ Type │ Remote │ Local │ Expires │ From Account │ Public │
├─────────┼────────┼─────────┼─────────┼─────────┼──────────────┼────────┤
│ a.b.c.d │ Stream │ a.b.c.d │ a.b.c.d │ │ AC7PO3MREV26 │ No │
╰─────────┴────────┴─────────┴─────────┴─────────┴──────────────┴────────╯
```
### Testing the Private Stream
Start the `nats-account-server`:
```text
> nats-account-server -nsc ~/.nsc/nats/Test
```
Create a config for the nats server `server.conf`:
```text
operator: /Users/synadia/.nsc/nats/Test/Test.jwt
resolver: URL(http://localhost:9090/jwt/v1/accounts/)
```
Start the `nats-server`:
```text
> nats-server -c server.conf
```
Start the subscriber for the client account:
```text
> nats-sub -creds ~/.nkeys/Test/accounts/AccountB/users/userb.creds ">"
Listening on [>]
```
Publish messages to the stream:
```text
# Client wont get this one since it only has permission
# for messages a.b.c.d
> nats-pub -creds ~/.nkeys/Test/accounts/TestAccount/users/TestUser.creds a.b.c.a "hello"
Published [a.b.c.a] : 'hello'
> nats-pub -creds ~/.nkeys/Test/accounts/TestAccount/users/TestUser.creds a.b.c.d "hello"
Published [a.b.c.d] : 'hello'
```
The subscriber as expected prints a message on the stream that it was allowed to receive:
```text
```