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

GitBook: [master] 82 pages modified

This commit is contained in:
Ginger Collison 2019-12-18 22:09:45 +00:00 committed by gitbook-bot
parent 7e27f03c98
commit b082996143
No known key found for this signature in database
GPG Key ID: 07D2180C7B12D0FF
71 changed files with 865 additions and 930 deletions

View File

@ -6,13 +6,13 @@
## NATS Concepts
* [What is NATS](concepts/intro.md)
* [Subject-Based Messaging](concepts/subjects.md)
* [Publish-Subscribe](concepts/pubsub.md)
* [Request-Reply](concepts/reqreply.md)
* [Queue Groups](concepts/queue.md)
* [Acknowledgements](concepts/acks.md)
* [Sequence Numbers](concepts/seq_num.md)
* [What is NATS](nats-concepts/intro.md)
* [Subject-Based Messaging](nats-concepts/subjects.md)
* [Publish-Subscribe](nats-concepts/pubsub.md)
* [Request-Reply](nats-concepts/reqreply.md)
* [Queue Groups](nats-concepts/queue.md)
* [Acknowledgements](nats-concepts/acks.md)
* [Sequence Numbers](nats-concepts/seq_num.md)
## Developing With NATS
@ -102,7 +102,7 @@
## NATS Tools
* [Introduction](nats-tools/README.md)
* [Introduction](nats-tools/nats-tools.md)
* [mkpasswd](nats-tools/mkpasswd.md)
* [nk](nats-tools/nk.md)
* [nsc](nats-tools/nsc/README.md)
@ -173,7 +173,7 @@
* [Persistence](nats-streaming-server/configuring/persistence/README.md)
* [File Store](nats-streaming-server/configuring/persistence/file_store.md)
* [SQL Store](nats-streaming-server/configuring/persistence/sql_store.md)
* [Securing](nats-streaming-server/configuring/tls/README.md)
* [Securing](nats-streaming-server/configuring/tls.md)
* [Process Signaling](nats-streaming-server/process-signaling.md)
* [Windows Service](nats-streaming-server/windows-service.md)
* [Embedding NATS Streaming Server](nats-streaming-server/embedding.md)
@ -188,8 +188,9 @@
## NATS on Kubernetes
* [Introduction](nats-kubernetes/README.md)
* [NATS Streaming Cluster with FT Mode](nats-kubernetes/stan-ft-k8s-aws.md)
* [NATS + Prometheus Operator](nats-kubernetes/prometheus-and-nats-operator.md)
* [NATS + Cert Manager](nats-kubernetes/nats-cluster-and-cert-manager.md)
* [Securing a NATS Cluster with cfssl](nats-kubernetes/operator-tls-setup-with-cfssl.md)
* [Introduction](nats-on-kubernetes/nats-kubernetes.md)
* [NATS Streaming Cluster with FT Mode](nats-on-kubernetes/stan-ft-k8s-aws.md)
* [NATS and Prometheus Operator](nats-on-kubernetes/prometheus-and-nats-operator.md)
* [NATS Cluster and Cert Manager](nats-on-kubernetes/nats-cluster-and-cert-manager.md)
* [Securing a NATS Cluster with cfssl](nats-on-kubernetes/operator-tls-setup-with-cfssl.md)

View File

@ -173,13 +173,11 @@ public class SlowConsumerListener {
{% tab title="JavaScript" %}
```javascript
// slow consumer detection is not configurable on NATS JavaScript client.
```
{% endtab %}
{% tab title="Python" %}
```python
nc = NATS()
async def error_cb(e):
@ -235,3 +233,4 @@ public class SlowConsumerListener {
```
{% endtab %}
{% endtabs %}

View File

@ -215,7 +215,6 @@ The API for drain can generally be used instead of unsubscribe:
{% tabs %}
{% tab title="Go" %}
```go
nc, err := nats.Connect("demo.nats.io")
if err != nil {
log.Fatal(err)

View File

@ -127,15 +127,15 @@ If you run this example with the publish examples that send to `updates`, you wi
Added in NATS Server v2.1.2, Queue Permissions allow you to express authorization for queue groups. As queue groups are integral to implementing horizontally scalable microservices, control of who is allowed to join a specific queue group is important to the overall security model.
A Queue Permission can be defined with the syntax `<subject> <queue>`, where the name of the queue can also use wildcards, for example the following would allow clients to join queue groups v1 and v2.*, but won't allow plain subscriptions:
A Queue Permission can be defined with the syntax `<subject> <queue>`, where the name of the queue can also use wildcards, for example the following would allow clients to join queue groups v1 and v2.\*, but won't allow plain subscriptions:
```hcl
```text
allow = ["foo v1", "foo v2.*"]
```
The full wildcard can also be used, for example the following would prevent plain subscriptions on `bar` but allow the client to join any queue:
```
```text
allow = ["bar >"]
```
@ -155,3 +155,4 @@ users = [
}
]
```

View File

@ -69,7 +69,6 @@ nc.subscribe('time', (msg, reply) => {
nc.publish(msg.reply, new Date().toLocaleTimeString());
}
});
```
{% endtab %}

View File

@ -126,7 +126,6 @@ NATS.start(servers:["nats://127.0.0.1:4222"]) do |nc|
end.resume
end
```
{% endtab %}

View File

@ -92,7 +92,6 @@ await nc.unsubscribe(sid)
# Won't be received...
await nc.publish("updates", b'...')
```
{% endtab %}

View File

@ -370,7 +370,6 @@ formatted = zoneDateTime.String()
nc.Publish("time.eu.east", []byte(formatted))
nc.Publish("time.eu.east.warsaw", []byte(formatted))
```
{% endtab %}
@ -392,7 +391,6 @@ nc.publish("time.eu.east.warsaw", formatted.getBytes(StandardCharsets.UTF_8));
nc.flush(Duration.ZERO);
nc.close();
```
{% endtab %}
@ -402,7 +400,6 @@ nc.publish('time.us.east');
nc.publish('time.us.central');
nc.publish('time.us.mountain');
nc.publish('time.us.west');
```
{% endtab %}
@ -419,7 +416,6 @@ await nc.publish("time.eu.east", b'...')
await nc.publish("time.eu.east.warsaw", b'...')
await nc.close()
```
{% endtab %}
@ -434,7 +430,6 @@ NATS.start do |nc|
nc.drain
end
```
{% endtab %}
@ -444,7 +439,6 @@ nc.publish('time.us.east');
nc.publish('time.us.central');
nc.publish('time.us.mountain');
nc.publish('time.us.west');
```
{% endtab %}
{% endtabs %}

View File

@ -57,7 +57,6 @@ nc.close();
{% tab title="TypeScript" %}
```typescript
// Reconnect buffer size is not configurable on NATS Typescript client
```
{% endtab %}
{% endtabs %}

6
faq.md
View File

@ -24,7 +24,7 @@
* [Does NATS support replay/redelivery of historical data?](faq.md#does-nats-support-replayredelivery-of-historical-data)
* [How do I gracefully shut down an asynchronous subscriber?](faq.md#how-do-i-gracefully-shut-down-an-asynchronous-subscriber)
* [How do I create subjects?](faq.md#how-do-i-create-subjects)
* [Does adding a “max_age” to a “channel” for NATS streaming server connected to a SQL store, retroactively delete messages?](faq.md#does-adding-a-max_age-to-a-channel-for-nats-streaming-server-connected-to-a-sql-store-retroactively-delete-messages)
* [Does adding a “max\_age” to a “channel” for NATS streaming server connected to a SQL store, retroactively delete messages?](faq.md#does-adding-a-max_age-to-a-channel-for-nats-streaming-server-connected-to-a-sql-store-retroactively-delete-messages)
* [What is the upgrade path from NATS 1.x to 2.x?](faq.md#what-is-the-upgrade-path-from-nats-1-x-to-2-x)
## General
@ -141,11 +141,11 @@ To gracefully shutdown an asynchronous subscriber so that any outstanding MsgHan
Subjects are created and pruned \(deleted\) dynamically based on interest \(subscriptions\). This means that a subject does not exist in a NATS cluster until a client subscribes to it, and the subject goes away after the last subscribing client unsubscribes from that subject.
### Does adding a “max_age” to a “channel” for NATS streaming server connected to a SQL store, retroactively delete messages?
### Does adding a “max\_age” to a “channel” for NATS streaming server connected to a SQL store, retroactively delete messages?
Yes, any channel limit will be applied on startup. For more information, see [Store Limits](nats-streaming-server/configuring/storelimits.md#limits-are-retroactive).
### What is the upgrade path from NATS 1.x to 2.x?
NATS 2.0 is completely backwards compatible with NATS < 2.x configure files and clients. Just run the new server. Be sure to review the [What's New in 2.0](whats_new_20.md) for great new features.
NATS 2.0 is completely backwards compatible with NATS &lt; 2.x configure files and clients. Just run the new server. Be sure to review the [What's New in 2.0](whats_new_20.md) for great new features.

View File

@ -1,58 +0,0 @@
# NATS on Kubernetes
In this section you can find several examples of how to deploy NATS, NATS Streaming
and other tools from the NATS ecosystem on Kubernetes.
* [Getting Started](README.md#getting-started)
* [Creating a NATS Streaming Cluster in k8s with FT mode](stan-ft-k8s-aws.md)
* [NATS + Prometheus Operator](prometheus-and-nats-operator)
* [NATS + Cert Manager in k8s](nats-cluster-and-cert-manager.md)
* [Securing a NATS Cluster using cfssl](operator-tls-setup-with-cfssl.md)
## Running NATS on K8S
### Getting started
The fastest and easiest way to get started is with just one shell command:
```sh
curl -sSL https://nats-io.github.io/k8s/setup.sh | sh
```
*In case you don't have a cluster already, you can find some notes on how to create a small cluster using one of the hosted Kubernetes providers [here](https://github.com/nats-io/k8s/docs/create-k8s-cluster.md).*
This will run a `nats-setup` container with the [required policy](https://github.com/nats-io/k8s/blob/master/setup/bootstrap-policy.yml)
and deploy a NATS cluster on Kubernetes with external access, TLS and
decentralized authorization.
[![asciicast](https://asciinema.org/a/282135.svg)](https://asciinema.org/a/282135)
By default, the installer will deploy the [Prometheus Operator](https://github.com/coreos/prometheus-operator) and the
[Cert Manager](https://github.com/jetstack/cert-manager) for metrics and TLS support, and the NATS instances will
also bind the 4222 host port for external access.
You can customize the installer to install without TLS or without Auth
to have a simpler setup as follows:
```sh
# Disable TLS
curl -sSL https://nats-io.github.io/k8s/setup.sh | sh -s -- --without-tls
# Disable Auth and TLS (also disables NATS surveyor and NATS Streaming)
curl -sSL https://nats-io.github.io/k8s/setup.sh | sh -s -- --without-tls --without-auth
```
**Note**: Since [NATS Streaming](https://github.com/nats-io/nats-streaming-server) will be running as a [leafnode](https://github.com/nats-io/docs/tree/master/leafnodes) to NATS
(under the STAN account) and that [NATS Surveyor](https://github.com/nats-io/nats-surveyor)
requires the [system account](,,/nats-server/nats_admin/sys_accounts) to monitor events, disabling auth also means that NATS Streaming and NATS Surveyor based monitoring will be disabled.
The monitoring dashboard setup using NATS Surveyor can be accessed by using port-forward:
kubectl port-forward deployments/nats-surveyor-grafana 3000:3000
Next, open the following URL in your browser:
http://127.0.0.1:3000/d/nats/nats-surveyor?refresh=5s&orgId=1
![surveyor](https://user-images.githubusercontent.com/26195/69106844-79fdd480-0a24-11ea-8e0c-213f251fad90.gif)

View File

@ -1,422 +0,0 @@
# Secure NATS Cluster in Kubernetes using the NATS Operator
## Features
- Clients TLS setup
- TLS based auth certs via secret
+ Reloading supported by only updating secret
- Routes TLS setup
- Advertising public IP per NATS server for external access
### Creating the Certificates
#### Generating the Root CA Certs
```js
{
"CN": "nats.io",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "nats.io"
}
]
}
```
```sh
(
cd certs
# CA certs
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
)
```
Setup the profiles for the Root CA, we will have 3 main profiles: one
for the clients connecting, one for the servers, and another one for
the full mesh routing connections between the servers.
```js :tangle certs/ca-config.json
{
"signing": {
"default": {
"expiry": "43800h"
},
"profiles": {
"server": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
},
"client": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
},
"route": {
"expiry": "43800h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
```
#### Generating the NATS server certs
First we generate the certificates for the server.
```js
{
"CN": "nats.io",
"hosts": [
"localhost",
"*.nats-cluster.default.svc",
"*.nats-cluster-mgmt.default.svc",
"nats-cluster",
"nats-cluster-mgmt",
"nats-cluster.default.svc",
"nats-cluster-mgmt.default.svc",
"nats-cluster.default.svc.cluster.local",
"nats-cluster-mgmt.default.svc.cluster.local",
"*.nats-cluster.default.svc.cluster.local",
"*.nats-cluster-mgmt.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "Operator"
}
]
}
```
```sh
(
# Generating the peer certificates
cd certs
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server.json | cfssljson -bare server
)
```
#### Generating the NATS server routes certs
We will also be setting up TLS for the full mesh routes.
```js
{
"CN": "nats.io",
"hosts": [
"localhost",
"*.nats-cluster.default.svc",
"*.nats-cluster-mgmt.default.svc",
"nats-cluster",
"nats-cluster-mgmt",
"nats-cluster.default.svc",
"nats-cluster-mgmt.default.svc",
"nats-cluster.default.svc.cluster.local",
"nats-cluster-mgmt.default.svc.cluster.local",
"*.nats-cluster.default.svc.cluster.local",
"*.nats-cluster-mgmt.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "Operator"
}
]
}
```
```sh
# Generating the peer certificates
(
cd certs
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=route route.json | cfssljson -bare route
)
```
#### Generating the certs for the clients (CNCF && ACME)
```js
{
"CN": "nats.io",
"hosts": [""],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "CNCF"
}
]
}
```
```sh
(
cd certs
# Generating NATS client certs
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client.json | cfssljson -bare client
)
```
#### Kubectl create
```sh :results output
cd certs
kubectl create secret generic nats-tls-example --from-file=ca.pem --from-file=server-key.pem --from-file=server.pem
kubectl create secret generic nats-tls-routes-example --from-file=ca.pem --from-file=route-key.pem --from-file=route.pem
kubectl create secret generic nats-tls-client-example --from-file=ca.pem --from-file=client-key.pem --from-file=client.pem
```
### Create the Auth secret
```js
{
"users": [
{ "username": "CN=nats.io,OU=ACME" },
{ "username": "CN=nats.io,OU=CNCF",
"permissions": {
"publish": ["hello.*"],
"subscribe": ["hello.world"]
}
}
],
"default_permissions": {
"publish": ["SANDBOX.*"],
"subscribe": ["PUBLIC.>"]
}
}
```
```sh
kubectl create secret generic nats-tls-users --from-file=users.json
```
### Create a cluster with TLS
```sh
echo '
apiVersion: "nats.io/v1alpha2"
kind: "NatsCluster"
metadata:
name: "nats-cluster"
spec:
size: 3
# Using custom edge nats server image for TLS verify and map support.
serverImage: "wallyqs/nats-server"
version: "edge-2.0.0-RC5"
tls:
enableHttps: true
# Certificates to secure the NATS client connections:
serverSecret: "nats-tls-example"
# Certificates to secure the routes.
routesSecret: "nats-tls-routes-example"
auth:
tlsVerifyAndMap: true
clientsAuthSecret: "nats-tls-users"
# How long to wait for authentication
clientsAuthTimeout: 5
pod:
# To be able to reload the secret changes
enableConfigReload: true
reloaderImage: connecteverything/nats-server-config-reloader
# Bind the port 4222 as the host port to allow external access.
enableClientsHostPort: true
# Initializer container that resolves the external IP from the
# container where it is running.
advertiseExternalIP: true
# Image of container that resolves external IP from K8S API
bootconfigImage: "wallyqs/nats-boot-config"
bootconfigImageTag: "0.5.0"
# Service account required to be able to find the external IP
template:
spec:
serviceAccountName: "nats-server"
' | kubectl apply -f -
```
### Create APP using certs
#### Adding a new pod which uses the certificates
Development
```go
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"time"
"github.com/nats-io/go-nats"
"github.com/nats-io/nuid"
)
func main() {
var (
serverList string
rootCACertFile string
clientCertFile string
clientKeyFile string
)
flag.StringVar(&serverList, "s", "tls://nats-1.nats-cluster.default.svc:4222", "List of NATS of servers available")
flag.StringVar(&rootCACertFile, "cacert", "./certs/ca.pem", "Root CA Certificate File")
flag.StringVar(&clientCertFile, "cert", "./certs/client.pem", "Client Certificate File")
flag.StringVar(&clientKeyFile, "key", "./certs/client-key.pem", "Client Private key")
flag.Parse()
log.Println("NATS endpoint:", serverList)
log.Println("Root CA:", rootCACertFile)
log.Println("Client Cert:", clientCertFile)
log.Println("Client Key:", clientKeyFile)
// Connect options
rootCA := nats.RootCAs(rootCACertFile)
clientCert := nats.ClientCert(clientCertFile, clientKeyFile)
alwaysReconnect := nats.MaxReconnects(-1)
var nc *nats.Conn
var err error
for {
nc, err = nats.Connect(serverList, rootCA, clientCert, alwaysReconnect)
if err != nil {
log.Printf("Error while connecting to NATS, backing off for a sec... (error: %s)", err)
time.Sleep(1 * time.Second)
continue
}
break
}
nc.Subscribe("discovery.*.status", func(m *nats.Msg) {
log.Printf("[Received on %q] %s", m.Subject, string(m.Data))
})
discoverySubject := fmt.Sprintf("discovery.%s.status", nuid.Next())
info := struct {
InMsgs uint64 `json:"in_msgs"`
OutMsgs uint64 `json:"out_msgs"`
Reconnects uint64 `json:"reconnects"`
CurrentServer string `json:"current_server"`
Servers []string `json:"servers"`
}{}
for range time.NewTicker(1 * time.Second).C {
stats := nc.Stats()
info.InMsgs = stats.InMsgs
info.OutMsgs = stats.OutMsgs
info.Reconnects = stats.Reconnects
info.CurrentServer = nc.ConnectedUrl()
info.Servers = nc.Servers()
payload, err := json.Marshal(info)
if err != nil {
log.Printf("Error marshalling data: %s", err)
}
err = nc.Publish(discoverySubject, payload)
if err != nil {
log.Printf("Error during publishing: %s", err)
}
nc.Flush()
}
}
```
```text
FROM golang:1.11.0-alpine3.8 AS builder
COPY . /go/src/github.com/nats-io/nats-kubernetes/examples/nats-cluster-routes-tls/app
WORKDIR /go/src/github.com/nats-io/nats-kubernetes/examples/nats-cluster-routes-tls/app
RUN apk add --update git
RUN go get -u github.com/nats-io/go-nats
RUN go get -u github.com/nats-io/nuid
RUN CGO_ENABLED=0 go build -o nats-client-app -v -a ./client.go
FROM scratch
COPY --from=builder /go/src/github.com/nats-io/nats-kubernetes/examples/nats-cluster-routes-tls/app/nats-client-app /nats-client-app
ENTRYPOINT ["/nats-client-app"]
```
```sh
docker build . -t wallyqs/nats-client-app
docker run wallyqs/nats-client-app
docker push wallyqs/nats-client-app
```
Pod spec
```sh :results output
echo '
apiVersion: apps/v1beta2
kind: Deployment
# The name of the deployment
metadata:
name: nats-client-app
spec:
# This selector has to match the template.metadata.labels section
# which is below in the PodSpec
selector:
matchLabels:
name: nats-client-app
# Number of instances
replicas: 1
# PodSpec
template:
metadata:
labels:
name: nats-client-app
spec:
volumes:
- name: "client-tls-certs"
secret:
secretName: "nats-tls-client-example"
containers:
- name: nats-client-app
command: ["/nats-client-app", "-s", "tls://nats-cluster.default.svc:4222", "-cacert", '/etc/nats-client-tls-certs/ca.pem', '-cert', '/etc/nats-client-tls-certs/client.pem', '-key', '/etc/nats-client-tls-certs/client-key.pem']
image: wallyqs/nats-client-app:latest
imagePullPolicy: Always
volumeMounts:
- name: "client-tls-certs"
mountPath: "/etc/nats-client-tls-certs/"
' | kubectl apply -f -
```

View File

@ -50,7 +50,7 @@ spec:
secretName: nats-ca
```
Now create the certs that will match the DNS name used by the clients to connect, in this case traffic is within Kubernetes so we are using the name `nats` which is backed up by a headless service (here is an [example](https://github.com/nats-io/k8s/blob/master/nats-server/nats-server-plain.yml#L24-L47) of sample deployment)
Now create the certs that will match the DNS name used by the clients to connect, in this case traffic is within Kubernetes so we are using the name `nats` which is backed up by a headless service \(here is an [example](https://github.com/nats-io/k8s/blob/master/nats-server/nats-server-plain.yml#L24-L47) of sample deployment\)
```yaml
---
@ -72,7 +72,7 @@ spec:
- nats.default.svc
```
In case of using the NATS operator, the Routes use a service named `$YOUR_CLUSTER-mgmt` (this may change in the future)
In case of using the NATS operator, the Routes use a service named `$YOUR_CLUSTER-mgmt` \(this may change in the future\)
```yaml
---
@ -134,11 +134,11 @@ spec:
Confirm that the pods were deployed:
``` sh
```bash
kubectl get pods -o wide
```
``` sh
```bash
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
nats-1 1/1 Running 0 4s 172.17.0.8 minikube <none>
nats-2 1/1 Running 0 3s 172.17.0.9 minikube <none>
@ -147,7 +147,7 @@ nats-3 1/1 Running 0 2s 172.17.0.10 minikube <none>
Follow the logs:
``` sh
```bash
kubectl logs nats-1
```
@ -158,3 +158,4 @@ kubectl logs nats-1
[1] 2019/12/18 12:27:23.921047 [INF] Server id is NDA6JC3TGEADLLBEPFAQ4BN4PM3WBN237KIXVTFCY3JSTDOSRRVOJCXN
[1] 2019/12/18 12:27:23.921055 [INF] Server is ready
```

View File

@ -0,0 +1,54 @@
# Introduction
In this section you can find several examples of how to deploy NATS, NATS Streaming and other tools from the NATS ecosystem on Kubernetes.
* [Getting Started](nats-kubernetes.md#getting-started)
* [Creating a NATS Streaming Cluster in k8s with FT mode](stan-ft-k8s-aws.md)
* [NATS + Prometheus Operator](https://github.com/nats-io/nats.docs/tree/ccb05cdf9225a46fc872a6deab55dca4e072e902/nats-kubernetes/prometheus-and-nats-operator/README.md)
* [NATS + Cert Manager in k8s](nats-cluster-and-cert-manager.md)
* [Securing a NATS Cluster using cfssl](operator-tls-setup-with-cfssl.md)
## Running NATS on K8S
### Getting started
The fastest and easiest way to get started is with just one shell command:
```bash
curl -sSL https://nats-io.github.io/k8s/setup.sh | sh
```
_In case you don't have a cluster already, you can find some notes on how to create a small cluster using one of the hosted Kubernetes providers_ [_here_](https://github.com/nats-io/k8s/docs/create-k8s-cluster.md)_._
This will run a `nats-setup` container with the [required policy](https://github.com/nats-io/k8s/blob/master/setup/bootstrap-policy.yml) and deploy a NATS cluster on Kubernetes with external access, TLS and decentralized authorization.
[![asciicast](https://asciinema.org/a/282135.svg)](https://asciinema.org/a/282135)
By default, the installer will deploy the [Prometheus Operator](https://github.com/coreos/prometheus-operator) and the [Cert Manager](https://github.com/jetstack/cert-manager) for metrics and TLS support, and the NATS instances will also bind the 4222 host port for external access.
You can customize the installer to install without TLS or without Auth to have a simpler setup as follows:
```bash
# Disable TLS
curl -sSL https://nats-io.github.io/k8s/setup.sh | sh -s -- --without-tls
# Disable Auth and TLS (also disables NATS surveyor and NATS Streaming)
curl -sSL https://nats-io.github.io/k8s/setup.sh | sh -s -- --without-tls --without-auth
```
**Note**: Since [NATS Streaming](https://github.com/nats-io/nats-streaming-server) will be running as a [leafnode](https://github.com/nats-io/docs/tree/master/leafnodes) to NATS \(under the STAN account\) and that [NATS Surveyor](https://github.com/nats-io/nats-surveyor) requires the [system account](https://github.com/nats-io/nats.docs/tree/ccb05cdf9225a46fc872a6deab55dca4e072e902/nats-kubernetes/,,/nats-server/nats_admin/sys_accounts/README.md) to monitor events, disabling auth also means that NATS Streaming and NATS Surveyor based monitoring will be disabled.
The monitoring dashboard setup using NATS Surveyor can be accessed by using port-forward:
```text
kubectl port-forward deployments/nats-surveyor-grafana 3000:3000
```
Next, open the following URL in your browser:
```text
http://127.0.0.1:3000/d/nats/nats-surveyor?refresh=5s&orgId=1
```
![surveyor](https://user-images.githubusercontent.com/26195/69106844-79fdd480-0a24-11ea-8e0c-213f251fad90.gif)

View File

@ -0,0 +1,393 @@
# Securing a NATS Cluster with cfssl
## Secure NATS Cluster in Kubernetes using the NATS Operator
### Features
* Clients TLS setup
* TLS based auth certs via secret
* Reloading supported by only updating secret
* Routes TLS setup
* Advertising public IP per NATS server for external access
### Creating the Certificates
### **Generating the Root CA Certs**
```javascript
{
"CN": "nats.io",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "nats.io"
}
]
}
```
```bash
(
cd certs
# CA certs
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
)
```
Setup the profiles for the Root CA, we will have 3 main profiles: one for the clients connecting, one for the servers, and another one for the full mesh routing connections between the servers.
```bash
{ "signing": { "default": { "expiry": "43800h" }, "profiles": { "server": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "client auth" ] }, "route": { "expiry": "43800h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] } } } }
```
### **Generating the NATS server certs**
First we generate the certificates for the server.
```text
{
"CN": "nats.io",
"hosts": [
"localhost",
"*.nats-cluster.default.svc",
"*.nats-cluster-mgmt.default.svc",
"nats-cluster",
"nats-cluster-mgmt",
"nats-cluster.default.svc",
"nats-cluster-mgmt.default.svc",
"nats-cluster.default.svc.cluster.local",
"nats-cluster-mgmt.default.svc.cluster.local",
"*.nats-cluster.default.svc.cluster.local",
"*.nats-cluster-mgmt.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "Operator"
}
]
}
```
```bash
(
# Generating the peer certificates
cd certs
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server.json | cfssljson -bare server
)
```
### **Generating the NATS server routes certs**
We will also be setting up TLS for the full mesh routes.
```javascript
{
"CN": "nats.io",
"hosts": [
"localhost",
"*.nats-cluster.default.svc",
"*.nats-cluster-mgmt.default.svc",
"nats-cluster",
"nats-cluster-mgmt",
"nats-cluster.default.svc",
"nats-cluster-mgmt.default.svc",
"nats-cluster.default.svc.cluster.local",
"nats-cluster-mgmt.default.svc.cluster.local",
"*.nats-cluster.default.svc.cluster.local",
"*.nats-cluster-mgmt.default.svc.cluster.local"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "Operator"
}
]
}
```
```bash
# Generating the peer certificates
(
cd certs
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=route route.json | cfssljson -bare route
)
```
**Generating the certs for the clients \(CNCF && ACME\)**
```javascript
{
"CN": "nats.io",
"hosts": [""],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"OU": "CNCF"
}
]
}
```
```bash
(
cd certs
# Generating NATS client certs
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client.json | cfssljson -bare client
)
```
**Kubectl create**
\`\`\`sh :results output cd certs kubectl create secret generic nats-tls-example --from-file=ca.pem --from-file=server-key.pem --from-file=server.pem kubectl create secret generic nats-tls-routes-example --from-file=ca.pem --from-file=route-key.pem --from-file=route.pem kubectl create secret generic nats-tls-client-example --from-file=ca.pem --from-file=client-key.pem --from-file=client.pem
```text
### Create the Auth secret
```js
{
"users": [
{ "username": "CN=nats.io,OU=ACME" },
{ "username": "CN=nats.io,OU=CNCF",
"permissions": {
"publish": ["hello.*"],
"subscribe": ["hello.world"]
}
}
],
"default_permissions": {
"publish": ["SANDBOX.*"],
"subscribe": ["PUBLIC.>"]
}
}
```
```bash
kubectl create secret generic nats-tls-users --from-file=users.json
```
#### Create a cluster with TLS
```bash
echo '
apiVersion: "nats.io/v1alpha2"
kind: "NatsCluster"
metadata:
name: "nats-cluster"
spec:
size: 3
# Using custom edge nats server image for TLS verify and map support.
serverImage: "wallyqs/nats-server"
version: "edge-2.0.0-RC5"
tls:
enableHttps: true
# Certificates to secure the NATS client connections:
serverSecret: "nats-tls-example"
# Certificates to secure the routes.
routesSecret: "nats-tls-routes-example"
auth:
tlsVerifyAndMap: true
clientsAuthSecret: "nats-tls-users"
# How long to wait for authentication
clientsAuthTimeout: 5
pod:
# To be able to reload the secret changes
enableConfigReload: true
reloaderImage: connecteverything/nats-server-config-reloader
# Bind the port 4222 as the host port to allow external access.
enableClientsHostPort: true
# Initializer container that resolves the external IP from the
# container where it is running.
advertiseExternalIP: true
# Image of container that resolves external IP from K8S API
bootconfigImage: "wallyqs/nats-boot-config"
bootconfigImageTag: "0.5.0"
# Service account required to be able to find the external IP
template:
spec:
serviceAccountName: "nats-server"
' | kubectl apply -f -
```
#### Create APP using certs
**Adding a new pod which uses the certificates**
Development
```go
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"time"
"github.com/nats-io/go-nats"
"github.com/nats-io/nuid"
)
func main() {
var (
serverList string
rootCACertFile string
clientCertFile string
clientKeyFile string
)
flag.StringVar(&serverList, "s", "tls://nats-1.nats-cluster.default.svc:4222", "List of NATS of servers available")
flag.StringVar(&rootCACertFile, "cacert", "./certs/ca.pem", "Root CA Certificate File")
flag.StringVar(&clientCertFile, "cert", "./certs/client.pem", "Client Certificate File")
flag.StringVar(&clientKeyFile, "key", "./certs/client-key.pem", "Client Private key")
flag.Parse()
log.Println("NATS endpoint:", serverList)
log.Println("Root CA:", rootCACertFile)
log.Println("Client Cert:", clientCertFile)
log.Println("Client Key:", clientKeyFile)
// Connect options
rootCA := nats.RootCAs(rootCACertFile)
clientCert := nats.ClientCert(clientCertFile, clientKeyFile)
alwaysReconnect := nats.MaxReconnects(-1)
var nc *nats.Conn
var err error
for {
nc, err = nats.Connect(serverList, rootCA, clientCert, alwaysReconnect)
if err != nil {
log.Printf("Error while connecting to NATS, backing off for a sec... (error: %s)", err)
time.Sleep(1 * time.Second)
continue
}
break
}
nc.Subscribe("discovery.*.status", func(m *nats.Msg) {
log.Printf("[Received on %q] %s", m.Subject, string(m.Data))
})
discoverySubject := fmt.Sprintf("discovery.%s.status", nuid.Next())
info := struct {
InMsgs uint64 `json:"in_msgs"`
OutMsgs uint64 `json:"out_msgs"`
Reconnects uint64 `json:"reconnects"`
CurrentServer string `json:"current_server"`
Servers []string `json:"servers"`
}{}
for range time.NewTicker(1 * time.Second).C {
stats := nc.Stats()
info.InMsgs = stats.InMsgs
info.OutMsgs = stats.OutMsgs
info.Reconnects = stats.Reconnects
info.CurrentServer = nc.ConnectedUrl()
info.Servers = nc.Servers()
payload, err := json.Marshal(info)
if err != nil {
log.Printf("Error marshalling data: %s", err)
}
err = nc.Publish(discoverySubject, payload)
if err != nil {
log.Printf("Error during publishing: %s", err)
}
nc.Flush()
}
}
```
```text
FROM golang:1.11.0-alpine3.8 AS builder
COPY . /go/src/github.com/nats-io/nats-kubernetes/examples/nats-cluster-routes-tls/app
WORKDIR /go/src/github.com/nats-io/nats-kubernetes/examples/nats-cluster-routes-tls/app
RUN apk add --update git
RUN go get -u github.com/nats-io/go-nats
RUN go get -u github.com/nats-io/nuid
RUN CGO_ENABLED=0 go build -o nats-client-app -v -a ./client.go
FROM scratch
COPY --from=builder /go/src/github.com/nats-io/nats-kubernetes/examples/nats-cluster-routes-tls/app/nats-client-app /nats-client-app
ENTRYPOINT ["/nats-client-app"]
```
```bash
docker build . -t wallyqs/nats-client-app
docker run wallyqs/nats-client-app
docker push wallyqs/nats-client-app
```
Pod spec
\`\`\`sh :results output echo ' apiVersion: apps/v1beta2 kind: Deployment
## The name of the deployment
metadata: name: nats-client-app
spec:
## This selector has to match the template.metadata.labels section
## which is below in the PodSpec
selector: matchLabels: name: nats-client-app
## Number of instances
replicas: 1
## PodSpec
template: metadata: labels: name: nats-client-app spec: volumes:
* name: "client-tls-certs"
secret:
secretName: "nats-tls-client-example"
containers:
* name: nats-client-app
command: \["/nats-client-app", "-s", "tls://nats-cluster.default.svc:4222", "-cacert", '/etc/nats-client-tls-certs/ca.pem', '-cert', '/etc/nats-client-tls-certs/client.pem', '-key', '/etc/nats-client-tls-certs/client-key.pem'\]
image: wallyqs/nats-client-app:latest
imagePullPolicy: Always
volumeMounts:
* name: "client-tls-certs"
mountPath: "/etc/nats-client-tls-certs/"
' \| kubectl apply -f -
\`\`\`

View File

@ -1,16 +1,15 @@
# Prometheus Operator + NATS Operator
# NATS and Prometheus Operator
## Installing the Operators
Install the NATS Operator:
``` sh
```bash
$ kubectl apply -f https://raw.githubusercontent.com/nats-io/nats-operator/master/deploy/00-prereqs.yaml
$ kubectl apply -f https://raw.githubusercontent.com/nats-io/nats-operator/master/deploy/10-deployment.yaml
```
Install the Prometheus Operator along with its RBAC definition (prometheus-operator service account):
Install the Prometheus Operator along with its RBAC definition \(prometheus-operator service account\):
```yaml
apiVersion: rbac.authorization.k8s.io/v1
@ -285,13 +284,11 @@ spec:
## Confirm
```
```text
kubectl port-forward prometheus-prometheus-0 9090:9090
```
Results:
<img height="400" width="1000" src="https://user-images.githubusercontent.com/26195/59470419-2066fd80-8e27-11e9-9e3e-250296a091da.png">
### Results
![](https://user-images.githubusercontent.com/26195/59470419-2066fd80-8e27-11e9-9e3e-250296a091da.png)

View File

@ -1,12 +1,10 @@
# Creating a NATS Streaming cluster in K8S with FT mode
# NATS Streaming Cluster with FT Mode
## Preparation
First, we need a Kubernetes cluster with a provider that offers a
service with a `ReadWriteMany` filesystem available. In this short guide,
we will create the cluster on AWS and then use EFS for the filesystem:
First, we need a Kubernetes cluster with a provider that offers a service with a `ReadWriteMany` filesystem available. In this short guide, we will create the cluster on AWS and then use EFS for the filesystem:
```
```text
# Create 3 nodes Kubernetes cluster
eksctl create cluster --name nats-eks-cluster \
--nodes 3 \
@ -17,18 +15,17 @@ eksctl create cluster --name nats-eks-cluster \
eksctl utils write-kubeconfig --name nats-eks-cluster --region us-east-2
```
For the FT mode to work, we will need to create an EFS volume which
can be shared by more than one pod. Go into the [AWS console](https://us-east-2.console.aws.amazon.com/efs/home?region=us-east-2#/wizard/1) and create one and make the sure that it is in a security group where the k8s nodes will have access to it. In case of clusters created via eksctl, this will be a security group named `ClusterSharedNodeSecurityGroup`:
For the FT mode to work, we will need to create an EFS volume which can be shared by more than one pod. Go into the [AWS console](https://us-east-2.console.aws.amazon.com/efs/home?region=us-east-2#/wizard/1) and create one and make the sure that it is in a security group where the k8s nodes will have access to it. In case of clusters created via eksctl, this will be a security group named `ClusterSharedNodeSecurityGroup`:
<img width="1063" alt="Screen Shot 2019-12-04 at 11 25 08 AM" src="https://user-images.githubusercontent.com/26195/70177488-5ef0bd00-16d2-11ea-9cf3-e0c3196bc7da.png">
![Screen Shot 2019-12-04 at 11 25 08 AM](https://user-images.githubusercontent.com/26195/70177488-5ef0bd00-16d2-11ea-9cf3-e0c3196bc7da.png)
<img width="1177" alt="Screen Shot 2019-12-04 at 12 40 13 PM" src="https://user-images.githubusercontent.com/26195/70179769-9497a500-16d6-11ea-9e18-2a8588a71819.png">
![Screen Shot 2019-12-04 at 12 40 13 PM](https://user-images.githubusercontent.com/26195/70179769-9497a500-16d6-11ea-9e18-2a8588a71819.png)
### Creating the EFS provisioner
Confirm from the FilesystemID from the cluster and the DNS name, we will use those values to create an EFS provisioner controller within the K8S cluster:
<img width="852" alt="Screen Shot 2019-12-04 at 12 08 35 PM" src="https://user-images.githubusercontent.com/26195/70177502-657f3480-16d2-11ea-9d00-b9a8c2f5320b.png">
![Screen Shot 2019-12-04 at 12 08 35 PM](https://user-images.githubusercontent.com/26195/70177502-657f3480-16d2-11ea-9d00-b9a8c2f5320b.png)
```yaml
---
@ -172,7 +169,7 @@ spec:
Result of deploying the manifest:
```sh
```bash
serviceaccount/efs-provisioner created
clusterrole.rbac.authorization.k8s.io/efs-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-efs-provisioner created
@ -186,8 +183,7 @@ persistentvolumeclaim/efs created
### Setting up the NATS Streaming cluster
Now create a NATS Streaming cluster with FT mode enabled and using NATS embedded mode
that is mounting the EFS volume:
Now create a NATS Streaming cluster with FT mode enabled and using NATS embedded mode that is mounting the EFS volume:
```yaml
---
@ -342,7 +338,7 @@ spec:
Your cluster now will look something like this:
```
```text
kubectl get pods
NAME READY STATUS RESTARTS AGE
efs-provisioner-6b7866dd4-4k5wx 1/1 Running 0 21m
@ -353,7 +349,7 @@ stan-2 2/2 Running 0 4m42s
If everything was setup properly, one of the servers will be the active node.
```
```text
$ kubectl logs stan-0 -c stan
[1] 2019/12/04 20:40:40.429359 [INF] STREAM: Starting nats-streaming-server[test-cluster] version 0.16.2
[1] 2019/12/04 20:40:40.429385 [INF] STREAM: ServerID: 7j3t3Ii7e2tifWqanYKwFX
@ -388,3 +384,4 @@ $ kubectl logs stan-0 -c stan
[1] 2019/12/04 20:40:41.671541 [INF] STREAM: ----------------------------------
[1] 2019/12/04 20:40:41.671546 [INF] STREAM: Streaming Server is ready
```

View File

@ -124,7 +124,7 @@ authorization: {
| `max_traced_msg_len` | Set a limit to the trace of the payload of a message |
| `disable_sublist_cache` | Disable sublist cache globally for accounts. |
| [`operator`](../../nats-tools/nsc/nsc.md#nats-server-configuration) | Path to an operator JWT |
| [`ping_interval`](../../developing-with-nats/intro/pingpong.md) | Interval in seconds in which the server checks if a connection is active |
| [`ping_interval`]() | Interval in seconds in which the server checks if a connection is active |
| `port` | Port for client connections |
| `reconnect_error_reports` | Number of failed attempt to reconnect a route, gateway or leaf node connection. Default is to report every attempt. |
| [`resolver`](../../nats-tools/nsc/nsc.md#nats-server-configuration) | Resolver type `MEMORY` or `URL` for account JWTs |

View File

@ -9,14 +9,13 @@ Leaf nodes are useful in IoT and edge scenarios and when the local server traffi
* Subjects that the user is allowed to publish are exported to the cluster.
* Subjects the user is allowed to subscribe to, are imported into the leaf node.
> Leaf Nodes are an important component as a way to bridge traffic between local NATS servers you control and servers that are managed by a third-party. Synadia's [NATS Global Service \(NGS\)](https://www.synadia.com/) allows accounts to use leaf nodes, but gain accessibility to the global network to inexpensively connect geographically distributed servers or small clusters.
[LeafNode Configuration Options](leafnode_conf.md)
## LeafNode Configuration Tutorial
The main server is just a standard NATS server. Clients to the main cluster are just using token authentication, but any kind of authentication can be used. The server allows leaf node connections at port 7422 (default port):
The main server is just a standard NATS server. Clients to the main cluster are just using token authentication, but any kind of authentication can be used. The server allows leaf node connections at port 7422 \(default port\):
```text
leafnodes {
@ -28,6 +27,7 @@ authorization {
```
Start the server:
```bash
nats-server -c /tmp/server.conf
...
@ -35,14 +35,13 @@ nats-server -c /tmp/server.conf
...
```
We create a replier on the server to listen for requests on 'q', which it will aptly respond with '42':
```bash
nats-rply -s nats://s3cr3t@localhost q 42
```
The leaf node, allows local clients to connect to through port 4111, and doesn't require any kind of authentication. The configuration specifies where the remote cluster is located, and specifies how to connect to it (just a simple token in this case):
The leaf node, allows local clients to connect to through port 4111, and doesn't require any kind of authentication. The configuration specifies where the remote cluster is located, and specifies how to connect to it \(just a simple token in this case\):
```text
listen: "127.0.0.1:4111"
@ -158,7 +157,6 @@ Check your email, verify the email, and specify an credit card, after that:
╰───────────────────────────┴──────────────────────────────────────────────────────────╯
....
```
Note the limits on the account, specify that the account can have up-to 2 leaf node connections. Let's use them:
@ -172,7 +170,6 @@ Note the limits on the account, specify that the account can have up-to 2 leaf n
Let's craft a leaf node connection much like we did earlier:
```text
leafnodes {
remotes = [
@ -210,10 +207,7 @@ Published [q] : ''
Received [_INBOX.hgG0zVcVcyr4G5KBwOuyJw.uUYkEyKr] : '42'
```
## Leaf Authorization
In some cases you may want to restrict what messages can be exported from the leaf node or imported from the leaf connection. You can specify restrictions by limiting what the leaf connection client can publish and subscribe to. See [NATS Authorization](../securing_nats/authorization.md) for how you can do this.

View File

@ -1,38 +1,41 @@
# Configuration
## `leafnodes` Configuration Block
| Property | Description |
| :------ | :---- |
| :--- | :--- |
| `advertise` | Hostport `<host>:<port>` to advertise to other servers. |
| `authorization` | Authorization block. [**See Authorization Block section below**](#authorization-block). |
| `authorization` | Authorization block. [**See Authorization Block section below**](leafnode_conf.md#authorization-block). |
| `host` | Interface where the server will listen for incoming leafnode connections. |
| `listen` | Combines `host` and `port` as `<host>:<port>` |
| `no_advertise` | if `true` the leafnode shouldn't be advertised. |
| `port` | Port where the server will listen for incoming leafnode connections (default is 7422). |
| `port` | Port where the server will listen for incoming leafnode connections \(default is 7422\). |
| `remotes` | List of `remote` entries specifying servers where leafnode client connection can be made. |
| `tls` | TLS configuration block (same as other nats-server `tls` configuration). |
| `tls` | TLS configuration block \(same as other nats-server `tls` configuration\). |
## Authorization Block
| Property | Description |
| :------ | :---- |
| :--- | :--- |
| `user` | Username for the leaf node connection. |
| `password` | Password for the user entry. |
| `account` | Account this leaf node connection should be bound to. |
| `timeout` | Maximum number of seconds to wait for leaf node authentication. |
| `users` | List of credentials and account to bind to leaf node connections. [**See User Block section below**](#users-block). |
| `users` | List of credentials and account to bind to leaf node connections. [**See User Block section below**](leafnode_conf.md#users-block). |
### Users Block
| Property | Description |
| :------ | :---- |
| :--- | :--- |
| `user` | Username for the leaf node connection. |
| `password` | Password for the user entry. |
| `account` | Account this leaf node connection should be bound to. |
Here are some examples of using basic user/password authentication for leaf nodes (note while this is using accounts it is not using JWTs)
Here are some examples of using basic user/password authentication for leaf nodes \(note while this is using accounts it is not using JWTs\)
Singleton mode:
```
```text
leafnodes {
port: ...
authorization {
@ -42,10 +45,12 @@ leafnodes {
}
}
```
With above configuration, if a soliciting server creates a Leafnode connection with url: `nats://leaf:secret@host:port`, then the accepting server will bind the leafnode connection to the account "TheAccount". This account need to exist otherwise the connection will be rejected.
Multi-users mode:
```
```text
leafnodes {
port: ...
authorization {
@ -56,13 +61,14 @@ leafnodes {
}
}
```
With the above, if a server connects using `leaf1:secret@host:port`, then the accepting server will bind the connection to account `account1`.
If using `leaf2` user, then the accepting server will bind to connection to `account2`.
If username/password (either singleton or multi-users) is defined, then the connecting server MUST provide the proper credentials otherwise the connection will be rejected.
With the above, if a server connects using `leaf1:secret@host:port`, then the accepting server will bind the connection to account `account1`. If using `leaf2` user, then the accepting server will bind to connection to `account2`.
If username/password \(either singleton or multi-users\) is defined, then the connecting server MUST provide the proper credentials otherwise the connection will be rejected.
If no username/password is provided, it is still possible to provide the account the connection should be associated with:
```
```text
leafnodes {
port: ...
authorization {
@ -70,17 +76,17 @@ leafnodes {
}
}
```
With the above, a connection without credentials will be bound to the account "TheAccount".
If other form of credentials are used (jwt, nkey or other), then the server will attempt to authenticate and if successful associate to the account for that specific user. If the user authentication fails (wrong password, no such user, etc..) the connection will be also rejected.
If other form of credentials are used \(jwt, nkey or other\), then the server will attempt to authenticate and if successful associate to the account for that specific user. If the user authentication fails \(wrong password, no such user, etc..\) the connection will be also rejected.
## LeafNode `remotes` Entry Block
| Property | Description |
| :------ | :---- |
| `url` | Leafnode URL (URL protocol should be `nats-leaf`). |
| `urls` | Leafnode URL array. Supports multiple URLs for discovery, e.g., urls: [ "nats-leaf://host1:7422", "nats-leaf://host2:7422" ]|
| :--- | :--- |
| `url` | Leafnode URL \(URL protocol should be `nats-leaf`\). |
| `urls` | Leafnode URL array. Supports multiple URLs for discovery, e.g., urls: \[ "nats-leaf://host1:7422", "nats-leaf://host2:7422" \] |
| `account` | Account public key identifying the leafnode. Account must be defined locally. |
| `credentials` | Credential file for connecting to the leafnode server. |
| `tls` | A TLS configuration block. Leafnode client will use specified TLS certificates when connecting/authenticating. |
@ -88,7 +94,7 @@ If other form of credentials are used (jwt, nkey or other), then the server will
## `tls` Configuration Block
| Property | Description |
| :------ | :---- |
| :--- | :--- |
| `cert_file` | TLS certificate file. |
| `key_file` | TLS certificate key file. |
| `ca_file` | TLS certificate authority file. |

View File

@ -68,7 +68,7 @@ authorization {
Here's another example, where the `allow` and `deny` options are specified:
```
```text
authorization: {
users = [
{

View File

@ -16,7 +16,7 @@ When detected at the client, the application is notified and messages are droppe
## Slow consumers identified in the client
A [client can detect it is a slow consumer](../../developing-with-nats/intro-5/slow.md) on a local connection and notify the application through use of the asynchronous error callback. It is better to catch a slow consumer locally in the client rather than to allow the server to detect this condition. This example demonstrates how to define and register an asynchronous error handler that will handle slow consumer errors.
A [client can detect it is a slow consumer]() on a local connection and notify the application through use of the asynchronous error callback. It is better to catch a slow consumer locally in the client rather than to allow the server to detect this condition. This example demonstrates how to define and register an asynchronous error handler that will handle slow consumer errors.
```go
func natsErrHandler(nc *nats.Conn, sub *nats.Subscription, natsErr error) {
@ -66,7 +66,7 @@ Apart from using [NATS streaming](../../nats-streaming-concepts/intro.md) or opt
**Scaling with queue subscribers**
This is ideal if you do not rely on message order. Ensure your NATS subscription belongs to a [queue group](../../concepts/queue.md), then scale as required by creating more instances of your service or application. This is a great approach for microservices - each instance of your microservice will receive a portion of the messages to process, and simply add more instances of your service to scale. No code changes, configuration changes, or downtime whatsoever.
This is ideal if you do not rely on message order. Ensure your NATS subscription belongs to a [queue group](../../nats-concepts/queue.md), then scale as required by creating more instances of your service or application. This is a great approach for microservices - each instance of your microservice will receive a portion of the messages to process, and simply add more instances of your service to scale. No code changes, configuration changes, or downtime whatsoever.
**Create a subject namespace that can scale**

View File

@ -38,7 +38,7 @@ nats-sub -s nats://localhost:4222 ">"
`nats-sub` is a subscriber sample included with all NATS clients. `nats-sub` subscribes to a subject and prints out any messages received. You can find the source code to the go version of `nats-sub` \[here\)\([https://github.com/nats-io/nats.go/tree/master/examples](https://github.com/nats-io/nats.go/tree/master/examples)\). After starting the subscriber you should see a message on 'A' that a new client connected.
We have two servers and a client. Time to simulate our rolling upgrade. But wait, before we upgrade 'A', let's introduce a new server 'C'. Server 'C' will join the existing cluster while we perform the upgrade. Its sole purpose is to provide an additional place where clients can go other than 'A' and ensure we don't end up with a single server serving all the clients after the upgrade procedure. Clients will randomly select a server when connecting unless a special option is provided that disables that functionality \(usually called 'DontRandomize' or 'noRandomize'\). You can read more about ["Avoiding the Thundering Herd"](../../developing-with-nats/intro-1/random.md). Suffice it to say that clients redistribute themselves about evenly between all servers in the cluster. In our case 1/2 of the clients on 'A' will jump over to 'B' and the remaining half to 'C'.
We have two servers and a client. Time to simulate our rolling upgrade. But wait, before we upgrade 'A', let's introduce a new server 'C'. Server 'C' will join the existing cluster while we perform the upgrade. Its sole purpose is to provide an additional place where clients can go other than 'A' and ensure we don't end up with a single server serving all the clients after the upgrade procedure. Clients will randomly select a server when connecting unless a special option is provided that disables that functionality \(usually called 'DontRandomize' or 'noRandomize'\). You can read more about ["Avoiding the Thundering Herd"](). Suffice it to say that clients redistribute themselves about evenly between all servers in the cluster. In our case 1/2 of the clients on 'A' will jump over to 'B' and the remaining half to 'C'.
Let's start our temporary server:

View File

@ -1,3 +1,4 @@
# NATS and Docker
## NATS Server Containerization
@ -9,32 +10,32 @@ The NATS server is provided as a Docker image on [Docker Hub](https://hub.docker
To use the Docker container image, install Docker and pull the public image:
```sh
```bash
docker pull nats
```
Run the NATS server image:
```sh
```bash
docker run nats
```
By default the NATS server exposes multiple ports:
- 4222 is for clients.
- 8222 is an HTTP management port for information reporting.
- 6222 is a routing port for clustering.
- Use -p or -P to customize.
* 4222 is for clients.
* 8222 is an HTTP management port for information reporting.
* 6222 is a routing port for clustering.
* Use -p or -P to customize.
### Creating a NATS Cluster
First run a server with the ports exposed on a `docker network`:
```sh
```bash
$ docker network create nats
```
```sh
```bash
docker run --name nats --network nats --rm -p 4222:4222 -p 8222:8222 nats
[INF] Starting nats-server version 2.1.0
[INF] Git commit [1cc5ae0]
@ -47,7 +48,7 @@ docker run --name nats --network nats --rm -p 4222:4222 -p 8222:8222 nats
Next, start another couple of servers and point them to the seed server to make them form a cluster:
```sh
```bash
docker run --name nats-1 --network nats --rm nats --cluster nats://0.0.0.0:6222 --routes=nats://ruser:T0pS3cr3t@nats:6222
docker run --name nats-2 --network nats --rm nats --cluster nats://0.0.0.0:6222 --routes=nats://ruser:T0pS3cr3t@nats:6222
```
@ -56,7 +57,7 @@ docker run --name nats-2 --network nats --rm nats --cluster nats://0.0.0.0:6222
To verify the routes are connected, you can make a request to the monitoring endpoint on `/routez` as follows and confirm that there are now 2 routes:
```sh
```bash
curl http://127.0.0.1:8222/routez
{
"server_id": "ND34PZ64QLLJKSU5SLSWRS5EUXEKNHW5BUVLCNFWA56R4D7XKDYWJFP7",
@ -122,7 +123,7 @@ networks:
Now we use Docker Compose to create the cluster that will be using the `nats` network:
```sh
```bash
$ docker network create nats
$ docker-compose -f nats-cluster.yaml up
@ -146,20 +147,18 @@ nats-1_1 | [1] 2019/10/19 06:41:27.153078 [INF] 172.18.0.4:6222 - rid:3 - Route
Now, the following should work: make a subscription on one of the nodes and publish it from another node. You should be able to receive the message without problems.
```sh
```bash
$ docker run --network nats --rm -it synadia/nats-box
~ # nats-sub -s nats://nats:4222 hello &
Listening on [hello]
~ # nats-pub -s "nats://nats-1:4222" hello first
~ # nats-pub -s "nats://nats-2:4222" hello second
[#1] Received on [hello]: 'first'
[#2] Received on [hello]: 'second'
```
Also stopping the seed node to which the subscription was done, should trigger an automatic failover to the other nodes:
```sh
```bash
$ docker stop nats
...
@ -169,7 +168,7 @@ Reconnected [nats://172.17.0.4:4222]
Publishing again will continue to work after the reconnection:
```sh
```bash
~ # nats-pub -s "nats://nats-1:4222" hello again
~ # nats-pub -s "nats://nats-2:4222" hello again
```
@ -177,3 +176,4 @@ Publishing again will continue to work after the reconnection:
## Tutorial
See the [NATS Docker tutorial](nats-docker-tutorial.md) for more instructions on using the NATS server Docker image.

View File

@ -4,7 +4,7 @@ NATS Streaming provides a rich set of commands and parameters to configure all a
* [Command Line Arguments](cmdline.md)
* [Configuration File](cfgfile.md)
* [Store Limits](storelimits.md/)
* [Store Limits](storelimits.md)
* [Persistence](persistence/)
* [Securing](tls/)
* [Securing](tls.md)

View File

@ -1,4 +1,4 @@
# Configuration file
# Configuration File
You can use a configuration file to configure the options specific to the NATS Streaming Server.

View File

@ -1,4 +1,4 @@
# Command line arguments
# Command Line Arguments
The NATS Streaming Server accepts command line arguments to control its behavior. There is a set of parameters specific to the NATS Streaming Server and some to the embedded NATS Server.

View File

@ -134,6 +134,7 @@ Below is what would be displayed with the above store limits configuration. Noti
Suppose you have set a channel limit to hold at most 100 messages, and the channel currently holds 72 messages. The server is stopped and the message limit for this channel is lowered to 50 messages, then the server is restarted.
On startup, the server will apply the store limits, which means that this channel will now hold the maximum number of messages (50) and the 22 oldest messages will be removed due to the channel limit.
On startup, the server will apply the store limits, which means that this channel will now hold the maximum number of messages \(50\) and the 22 oldest messages will be removed due to the channel limit.
We strongly recommend not raising the limit back to the higher limit if messages have been removed in the previous step because those removed messages may or may not become available again depending on the store implementation or if running in clustering mode or not.

View File

@ -32,7 +32,7 @@ The embedded NATS server specifies TLS server certificates with these:
--tlscacert <file> Client certificate CA for verification
```
The server parameters are used the same way you'd [secure a typical NATS server](../../../nats-server/configuration/securing_nats/tls.md).
The server parameters are used the same way you'd [secure a typical NATS server](../../nats-server/configuration/securing_nats/tls.md).
Proper usage of the NATS Streaming Server requires the use of both client and server parameters.
@ -42,7 +42,7 @@ For example:
% nats-streaming-server -tls_client_cert client-cert.pem -tls_client_key client-key.pem -tls_client_cacert ca.pem -tlscert server-cert.pem -tlskey server-key.pem -tlscacert ca.pem
```
Further TLS related functionality can be found in [Securing NATS &gt; TLS](../../../nats-server/configuration/securing_nats/tls.md). Note that if specifying cipher suites is required, a configuration file for the embedded NATS server can be passed through the `-config` command line parameter.
Further TLS related functionality can be found in [Securing NATS &gt; TLS](../../nats-server/configuration/securing_nats/tls.md). Note that if specifying cipher suites is required, a configuration file for the embedded NATS server can be passed through the `-config` command line parameter.
### Connecting to Remote NATS Server with TLS Enabled

View File

@ -1,11 +0,0 @@
## NATS Tools
The NATS Ecosystem has many tools to support server configuration, enhance monitoring or tune performance:
- [mkpasswd](mkpasswd.md) - Generates or bcrypts passwords
- [nk](nk.md) - Generate NKeys
- [nsc](nsc/README.md) - Configure Operators, Accounts and Users
- [nats account server](nas/README.md) - Serve Account JWTs
- [nats top](nats_top/README.md) - Monitor NATS Server
- [nats-bench](natsbench.md) - Benchmark NATS Server
- [prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter) - Export NATS server metrics to [Prometheus](https://prometheus.io/) and a [Grafana](https://grafana.com) dashboard.

12
nats-tools/nats-tools.md Normal file
View File

@ -0,0 +1,12 @@
# Introduction
The NATS Ecosystem has many tools to support server configuration, enhance monitoring or tune performance:
* [mkpasswd](mkpasswd.md) - Generates or bcrypts passwords
* [nk](nk.md) - Generate NKeys
* [nsc](nsc/) - Configure Operators, Accounts and Users
* [nats account server](nas/) - Serve Account JWTs
* [nats top](nats_top/) - Monitor NATS Server
* [nats-bench](natsbench.md) - Benchmark NATS Server
* [prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter) - Export NATS server metrics to [Prometheus](https://prometheus.io/) and a [Grafana](https://grafana.com) dashboard.

View File

@ -1,15 +1,15 @@
# NATS Account Configuration
# nsc
NATS account configurations are built using the `nsc` tool. The NSC tool allows you to:
- Create and edit Operators, Accounts, Users
- Manage publish and subscribe permissions for Users
- Define Service and Stream exports from an account
- Reference Service and Streams from another account
- Generate Activation tokens that grants access to a private service or stream
- Generate User credential files
- Describe Operators, Accounts, Users, and Activations
- Push and pull account JWTs to an account JWTs server
* Create and edit Operators, Accounts, Users
* Manage publish and subscribe permissions for Users
* Define Service and Stream exports from an account
* Reference Service and Streams from another account
* Generate Activation tokens that grants access to a private service or stream
* Generate User credential files
* Describe Operators, Accounts, Users, and Activations
* Push and pull account JWTs to an account JWTs server
## Installation
@ -25,20 +25,20 @@ The script will download the latest version of `nsc` and install it into your sy
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)
* [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:
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).

View File

@ -1,30 +1,28 @@
# NSC
# Basics
NSC allows you to manage identities. Identities take the form of _nkeys_. Nkeys are a public-key signature system based on Ed25519 for the NATS ecosystem.
The nkey identities are associated with NATS configuration in the form of a Jason Web Token (JWT). The JWT is digitally signed by the private key of an issuer forming a chain of trust. The `nsc` tool creates and manages these identities and allows you to deploy them to a JWT account server, which in turn makes the configurations available to nats-servers.
The nkey identities are associated with NATS configuration in the form of a Jason Web Token \(JWT\). The JWT is digitally signed by the private key of an issuer forming a chain of trust. The `nsc` tool creates and manages these identities and allows you to deploy them to a JWT account server, which in turn makes the configurations available to nats-servers.
Theres a logical hierarchy to the entities:
- `Operators` are responsible for running nats-servers, and issuing account JWTs. Operators 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. An account defines streams and services that can be exported to other accounts. Likewise, they import streams and services from other accounts.
- `Users` are issued by an account, and encode limits regarding usage and authorization over the account's subject space.
* `Operators` are responsible for running nats-servers, and issuing account JWTs. Operators 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. An account defines streams and services that can be exported to other accounts. Likewise, they import streams and services from other accounts.
* `Users` are issued by an account, and encode limits regarding usage and authorization over the account's subject space.
NSC allows you to create, edit, and 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 NKey identities and their associated JWTs
- Make JWTs accessible to a nats-server
- Configure a nats-server to use JWTs
* Generate NKey identities and their associated 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.
## Creating an Operator, Account and User
Lets create an operator called `O` (oh):
Lets create an operator called `O` \(oh\):
```bash
> nsc add operator O
@ -42,7 +40,6 @@ Lets add a service URL to the operator. Service URLs specify where the nats-serv
[ OK ] edited operator "O"
```
Creating an account is just as easy:
```bash
@ -64,14 +61,13 @@ Finally, let's create a user:
As expected, the tool generated an NKEY representing the user, and stored the private key safely in the keystore. In addition, the tool generated a _credentials_ file. A credentials file contains the JWT for the user and the private key for the user. Credential files are used by NATS clients to identify themselves to the system. The client will extract and present the JWT to the nats-server and use the private key to verify its identity.
### NSC Assets
NSC manages three different directories:
- The nsc home directory which stores nsc related data. By default nsc home lives in `~/.nsc` and can be changed via the `$NSC_HOME` environment variable.
- An _nkeys_ directory, which stores all the private keys. This directory by default lives in `~/.nkeys` and can be changed via the `$NKEYS_PATH` environment variable. The contents of the nkeys directory should be treated as secrets.
- A _stores_ directory, which contains JWTs representing the various entities. This directory lives in `$NSC_HOME/nats`, and can be changed using the command `nsc env -s <dir>`. The stores directory can stored under revision control. The JWTs themselves do not contain any secrets.
* The nsc home directory which stores nsc related data. By default nsc home lives in `~/.nsc` and can be changed via the `$NSC_HOME` environment variable.
* An _nkeys_ directory, which stores all the private keys. This directory by default lives in `~/.nkeys` and can be changed via the `$NKEYS_PATH` environment variable. The contents of the nkeys directory should be treated as secrets.
* A _stores_ directory, which contains JWTs representing the various entities. This directory lives in `$NSC_HOME/nats`, and can be changed using the command `nsc env -s <dir>`. The stores directory can stored under revision control. The JWTs themselves do not contain any secrets.
#### The NSC Stores Directory
@ -97,26 +93,27 @@ The nkeys directory contains all the private keys and credential files. As menti
The structure keys directory is machine friendly. All keys are sharded by their kind `O` for operators, `A` for accounts, `U` for users. These prefixes are also part of the public key. The second and third letters in the public key are used to create directories where other like-named keys are stored.
```
```text
tree ~/.nkeys
/Users/aricart/.nkeys
├── creds
   └── O
   └── A
   └── U.creds
└── O
└── A
└── U.creds
└── keys
├── A
   └── DE
   └── ADETPT36WBIBUKM3IBCVM4A5YUSDXFEJPW4M6GGVBYCBW7RRNFTV5NGE.nk
└── DE
└── ADETPT36WBIBUKM3IBCVM4A5YUSDXFEJPW4M6GGVBYCBW7RRNFTV5NGE.nk
├── O
   └── AF
   └── OAFEEYZSYYVI4FXLRXJTMM32PQEI3RGOWZJT7Y3YFM4HB7ACPE4RTJPG.nk
└── AF
└── OAFEEYZSYYVI4FXLRXJTMM32PQEI3RGOWZJT7Y3YFM4HB7ACPE4RTJPG.nk
└── U
└── DB
└── UDBD5FNQPSLIO6CDMIS5D4EBNFKYWVDNULQTFTUZJXWFNYLGFF52VZN7.nk
```
The `nk` files themselves are named after the complete public key, and stored in a single string - the private key in question:
```bash
cat ~/.nkeys/keys/U/DB/UDBD5FNQPSLIO6CDMIS5D4EBNFKYWVDNULQTFTUZJXWFNYLGFF52VZN7.nk
SUAG35IAY2EF5DOZRV6MUSOFDGJ6O2BQCZHSRPLIK6J3GVCX366BFAYSNA
@ -126,7 +123,6 @@ The private keys are encoded into a string, and always begin with an `S` for _se
In addition to containing keys, the nkeys directory contains a `creds` directory. This directory is organized in a way friendly to humans. It stores user credential files or `creds` files for short. A credentials file contains a copy of the user JWT and the private key for the user. These files are used by NATS clients to connect to a NATS server:
```bash
> cat ~/.nkeys/creds/O/A/U.creds
-----BEGIN NATS USER JWT-----
@ -165,8 +161,7 @@ The different entity names are listed along with their public key, and whether t
In some cases you may want to view the private keys:
```
```text
> nsc list keys --show-seeds
╭───────────────────────────────────────────────────────────────────────────────────╮
│ Seeds Keys │
@ -181,8 +176,7 @@ In some cases you may want to view the private keys:
[ERR] error reading seed
```
If you don't have the seed (perhaps you don't control the operator), nsc will decorate the row with a `!`.
If you have more than one account, you can show them all by specifying the `--all` flag.
If you don't have the seed \(perhaps you don't control the operator\), nsc will decorate the row with a `!`. If you have more than one account, you can show them all by specifying the `--all` flag.
## The Operator JWT
@ -203,7 +197,8 @@ You can view a human readable version of the JWT by using `nsc`:
```
Since the operator JWT is just a JWT you can use other tools, such as jwt.io to decode a JWT an inspect it's contents. All JWTs have a header, payload, and signature:
```json
```javascript
{
"typ": "jwt",
"alg": "ed25519"
@ -223,14 +218,9 @@ Since the operator JWT is just a JWT you can use other tools, such as jwt.io to
}
```
All NATS JWTs will use the `algorithm` ed25519 for signature.
The payload will list different things. On our basically empty operator, we will only have standard JWT `claim` fields:
All NATS JWTs will use the `algorithm` ed25519 for signature. The payload will list different things. On our basically empty operator, we will only have standard JWT `claim` fields:
`jti` - a jwt id
`iat` - the timestamp when the JWT was issued in UNIX time
`iss` - the issuer of the JWT, in this case the operator's public key
`sub` - the subject or identity represented by the JWT, in this case the same operator
`type` - since this is an operator JWT, `operator` is the type
`jti` - a jwt id `iat` - the timestamp when the JWT was issued in UNIX time `iss` - the issuer of the JWT, in this case the operator's public key `sub` - the subject or identity represented by the JWT, in this case the same operator `type` - since this is an operator JWT, `operator` is the type
NATS specific is the `nats` object, which is where we add NATS specific JWT configuration to the JWT claim.
@ -293,7 +283,6 @@ The user id is the public key for the user, the issuer is the account. This user
When a user connects to a nats-server, it presents it's user JWT and signs an nonce using its private key. The server verifies if the user is who they say they are by validating that the nonce was signed using the private key associated with the public key, representing the identify of the user. Next, the server fetches the issuer account and validates that the account was issued by a trusted operator completing the chain of trust verification.
Lets put all of this together, and create a simple server configuration that accepts sessions from `U`.
## Account Server Configuration
@ -314,7 +303,7 @@ The account server has options to enable you to use an nsc directory directly. L
> nats-account-server -nsc ~/.nsc/nats/O
```
Above, we pointed the account server to our nsc data directory (more specifically to the `O` operator that we created earlier). By default, the server listens on the localhost at port 9090.
Above, we pointed the account server to our nsc data directory \(more specifically to the `O` 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.
@ -364,14 +353,12 @@ Published [hello] : 'NATS'
Subscriber shows:
```text
[#1] Received on [hello]: NATS
```
```
### NSC Embeds NATS tooling
To make it easier to work, you can use the NATS clients built right into NSC. These tools know how to find the credential files in the keyring.
For convenience, the tools are aliased to `sub`, `pub`, `req`, `reply`:
To make it easier to work, you can use the NATS clients built right into NSC. These tools know how to find the credential files in the keyring. For convenience, the tools are aliased to `sub`, `pub`, `req`, `reply`:
```bash
nsc sub --user U ">"
@ -379,12 +366,10 @@ nsc sub --user U ">"
nsc pub --user U hello NATS
...
```
See `nsc tool -h` for more detailed information.
## 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.
@ -455,7 +440,6 @@ Similarly, we can limit a client:
The client has the opposite permissions of the service. It can publish on the request subject `q`, and receive replies on an inbox.
## The NSC Environment
As your projects become more involved, you may work with one or more accounts. NSC tracks your current operator and account. If you are not in a directory containing an operator, account or user, it will use the last operator/account context.
@ -480,3 +464,4 @@ To view your current environment:
```
If you have multiple accounts, you can use `nsc env --account <account name>` to set the account as the current default. If you have defined `NKEYS_PATH` or `NSC_HOME` in the environment, you'll also see their current effective values. Finally, if you want to set the stores directory to anything other than the default, you can do `nsc env --store <dir containing an operator>`. If you have multiple accounts, you can try having multiple terminals, each in a directory for a different account.

View File

@ -49,10 +49,10 @@ To review the service export:
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.
* 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).
@ -111,12 +111,12 @@ Let's also add a user to make requests from the service:
[ OK ] added user "b" to account "B"
```
### 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. This process will run from account 'A' using user 'U':
```text
> go get github.com/nats-io/nats.go/examples/nats-rply
@ -128,6 +128,7 @@ nsc reply --account A --user U help "I will help"
```
Send the request:
```text
> go get github.com/nats-io/nats.go/examples/nats-req
> nats-req -creds ~/.nkeys/creds/O/B/b.creds help me
@ -135,11 +136,13 @@ Published [help] : 'me'
```
The service receives the request:
```text
Received on [help]: 'me'
```
And the response is received by the requestor:
```text
Received [_INBOX.v6KAX0v1bu87k49hbg3dgn.StIGJF0D] : 'I will help'
```
@ -200,7 +203,6 @@ As before, we declared an export, but this time we added the `--private` flag. T
│ help │ Service │ help │ Yes │ 0 │ - │
│ private.help.* │ Service │ private.help.* │ No │ 0 │ - │
╰────────────────┴─────────┴────────────────┴────────┴─────────────┴──────────╯
```
### Generating an Activation Token
@ -222,16 +224,13 @@ To generate a token, youll need to know the public key of the account importi
╰────────┴──────────────────────────────────────────────────────────┴─────────────┴────────╯
```
```text
> nsc generate activation --account A --target-account AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP2H --subject private.help.AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP2H -o /tmp/activation.jwt
[ OK ] generated "private.help.*" activation for account "AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP2H"
[ OK ] wrote account description to "/tmp/activation.jwt"
```
The command took the account that has the export ('A'), the public key of account B, the subject where requests from account B will be handled, and an output file where the token can be stored.
The subject for the export allows the service to handle all requests coming in on private.help.*, but account B can only request from a specific subject.
The command took the account that has the export \('A'\), the public key of account B, the subject where requests from account B will be handled, and an output file where the token can be stored. The subject for the export allows the service to handle all requests coming in on private.help.\*, but account B can only request from a specific subject.
For completeness, the contents of the JWT file looks like this:
@ -320,9 +319,8 @@ Testing a private service is no different than a public one:
```bash
> nsc reply --account A --user U "private.help.*" "help is here"
listening on [private.help.*]
[#1] received on [private.help.AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP2H]: 'help_me'
> nsc req --account B --user b private.help help_me
published request: [private.help] : 'help_me'
received reply: [_INBOX.3MhS0iCHfqO8wUl1x59bHB.jpE2jvEj] : 'help is here'
```

View File

@ -4,22 +4,22 @@ As previously discussed, NKEYs are identities, and if someone gets a hold of an
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 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.
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.
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
* 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.
@ -42,7 +42,7 @@ operator key stored ~/.nkeys/keys/O/AZ/OAZBRNE7DQGDYT5CSAGWDMI5ENGKOEJ57BXVU6WUT
> 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`):
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 OAZBRNE7DQGDYT5CSAGWDMI5ENGKOEJ57BXVU6WUTHFEAO3CU5GLQYF5
@ -118,7 +118,7 @@ Lets add the signing key to the account, and remember to sign the account wit
╰───────────────────────────┴──────────────────────────────────────────────────────────╯
```
We can see that the signing key `ADUQTJD4TF4O6LTTHCKDKSHKGBN2NECCHHMWFREPKNO6MPA7ZETFEEF7` was added to the account. Also the issuer is the operator signing key (specified by the `-K`).
We can see that the signing key `ADUQTJD4TF4O6LTTHCKDKSHKGBN2NECCHHMWFREPKNO6MPA7ZETFEEF7` 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`.
@ -149,3 +149,4 @@ Now lets create a user and signing it with account signing key starting with
```
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_.

View File

@ -53,10 +53,10 @@ Messages this account publishes on `a.b.c.>` will be forwarded to all accounts t
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.
* 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).
@ -126,7 +126,6 @@ Listening on [a.b.c.>]
> nsc pub --account A --user U a.b.c.hello world
Published [a.b.c.hello] : "world"
...
[#1] received on [a.b.c.hello]: 'world'
```
## Securing Streams
@ -177,7 +176,6 @@ Similarly when we defined an export, but this time we added the `--private` flag
╰───────────────┴────────┴───────────────┴────────┴─────────────┴──────────╯
```
### Generating an Activation Token
For a foreign account to _import_ a private stream, you have to generate an activation token. In addition to granting permissions to the account, the activation token also allows you to subset the exported streams subject.
@ -203,7 +201,7 @@ To generate a token, youll need to know the public key of the account importi
[ OK ] wrote account description to "/tmp/activation.jwt"
```
The command took the account that has the export ('A'), the public key of account B, the subject where the stream will publish to account B.
The command took the account that has the export \('A'\), the public key of account B, the subject where the stream will publish to account B.
For completeness, the contents of the JWT file look like this:
@ -296,6 +294,5 @@ Listening on [private.abc.AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP
> nsc pub --account A --user U private.abc.AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP2H hello
Published [private.abc.AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP2H] : "hello"
...
[#1] received on [private.abc.AAM46E3YF5WOZSE5WNYWHN3YYISVZOSI6XHTF2Q64ECPXSFQZROJMP2H]: 'hello'
```