-
Notifications
You must be signed in to change notification settings - Fork 0
NatsAuth
MaxThom edited this page Sep 5, 2025
·
1 revision
This guide sets up NATS authentication using NKeys with two isolated accounts:
- MirDev: Development environment
- MirTest: Testing/staging environment
# Generate MirDev account
nk -gen account -pubout > mirdev.nk
# Example output:
# SAABXI3YM7XQL5J5VQZZYGGLLH3WPTGBUBP5QHHEV2GFHCF7LHCOZ4DEV
# ADDEV3JXYTXOJEL6LNAXDREUGRX35BOLZI3B4PFFAC7IRPR3OA4QNKDEV
# Generate MirTest account
nk -gen account -pubout > mirtest.nk
# Example output:
# SAACYX2KEOOQ52BMGX3W5F6L5OXQZJDVWT3GVWL3Y7HXSGVQRH2EATEST
# ACTEST7PZTKJSBTR7BF6TBK3D776734PWHWDKO7HFMQOM5BIOYPSTESTNote: The first line is the seed (private key starting with 'S'), the second is the public key (starting with 'A').
Create nats-server.conf:
port: 4222
accounts {
MirDev: {
nkey: ADDEV3JXYTXOJEL6LNAXDREUGRX35BOLZI3B4PFFAC7IRPR3OA4QNKDEV
}
MirTest: {
nkey: ACTEST7PZTKJSBTR7BF6TBK3D776734PWHWDKO7HFMQOM5BIOYPSTEST
}
}# Create directory
mkdir -p /etc/mir
chmod 700 /etc/mir
# Extract just the seeds (first line)
head -n1 mirdev.nk > /etc/mir/mirdev.seed
head -n1 mirtest.nk > /etc/mir/mirtest.seed
# Set restrictive permissions
chmod 600 /etc/mir/*.seed
# Remove original files with both keys
rm mirdev.nk mirtest.nkpackage main
import (
"log"
"github.com/nats-io/nats.go"
)
func main() {
// Connect to MirDev
ncDev, err := nats.Connect("nats://localhost:4222",
nats.NkeyOptionFromSeed("/etc/mir/mirdev.seed"))
if err != nil {
log.Fatal("Dev connection failed:", err)
}
defer ncDev.Close()
// Connect to MirTest
ncTest, err := nats.Connect("nats://localhost:4222",
nats.NkeyOptionFromSeed("/etc/mir/mirtest.seed"))
if err != nil {
log.Fatal("Test connection failed:", err)
}
defer ncTest.Close()
}# Start NATS server
nats-server -c nats-server.conf
# Test MirDev account (terminal 1)
nats sub --nkey=/etc/mir/mirdev.seed ">"
# Test MirTest account (terminal 2)
nats pub --nkey=/etc/mir/mirtest.seed test.subject "hello"
# Note: Messages published in MirTest won't be visible in MirDev subscription1. Signal-based reload (most common):
# Send HUP signal to NATS server process
kill -HUP <nats-server-pid>
# Or using systemctl if running as service
systemctl reload nats-server
2. Using NATS CLI:
# Reload configuration
nats-server --signal reload
# Or using nats CLI tool
nats server request reload
3. Docker
docker exec <nats-container> nats-server --signal reload
``
## Environment-Based Configuration
For easier switching between environments:
```bash
# Set environment variable
export NATS_NKEY_SEED_FILE=/etc/mir/mirdev.seed # or mirtest.seed
# In your Go code
seedFile := os.Getenv("NATS_NKEY_SEED_FILE")
if seedFile == "" {
seedFile = "/etc/mir/mirdev.seed" // default
}
nc, err := nats.Connect("nats://localhost:4222",
nats.NkeyOptionFromSeed(seedFile))- Never commit seed files to version control
- Keep different seeds for different environments
- Use file permissions to restrict access (600 or 400)
- Consider encrypting seeds at rest for production
- Backup seeds securely - losing them means losing access
- Complete isolation between Dev and Test environments
- No passwords transmitted over network
- Simple management - just one seed per environment
- Secure - uses Ed25519 public key cryptography
- Easy rotation - generate new keys anytime
While NKeys provide strong authentication, they don't encrypt data in transit. For production deployments, TLS encryption is essential to protect sensitive telemetry and command data.
# Create certificate directory
mkdir -p /etc/mir/certs
cd /etc/mir/certs
# Generate Certificate Authority (CA)
openssl genrsa -out ca-key.pem 4096
openssl req -new -x509 -days 3650 -key ca-key.pem -out ca.pem \
-subj "/C=US/ST=State/L=City/O=MirIoT/CN=Mir-CA"
# Generate server certificate
openssl genrsa -out server-key.pem 4096
openssl req -new -key server-key.pem -out server.csr \
-subj "/C=US/ST=State/L=City/O=MirIoT/CN=mir-nats-server"
# Create server extensions file (important for hostname verification)
cat > server-extfile.cnf <<EOF
subjectAltName = DNS:localhost,DNS:mir-nats-server,DNS:*.mir.local,IP:127.0.0.1
EOF
# Sign server certificate
openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-out server-cert.pem -extfile server-extfile.cnf -CAcreateserial
# Generate client certificate
openssl genrsa -out client-key.pem 4096
openssl req -new -key client-key.pem -out client.csr \
-subj "/C=US/ST=State/L=City/O=MirIoT/CN=mir-client"
# Sign client certificate
openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-out client-cert.pem -CAcreateserial
# Clean up and set permissions
rm *.csr *.cnf
chmod 400 *-key.pem
chmod 444 *.pem# Install certbot
sudo apt-get install certbot
# Generate certificate
sudo certbot certonly --standalone -d nats.yourdomain.com
# Copy certificates
sudo cp /etc/letsencrypt/live/nats.yourdomain.com/fullchain.pem /etc/mir/certs/server-cert.pem
sudo cp /etc/letsencrypt/live/nats.yourdomain.com/privkey.pem /etc/mir/certs/server-key.pem
sudo chmod 400 /etc/mir/certs/server-key.pemUpdate nats-server.conf to include TLS:
port: 4222
# TLS Configuration
tls {
cert_file: "/etc/mir/certs/server-cert.pem"
key_file: "/etc/mir/certs/server-key.pem"
ca_file: "/etc/mir/certs/ca.pem"
verify: true # Require client certificates
}
# Account configuration with NKeys (unchanged)
accounts {
MirDev: {
nkey: ADDEV3JXYTXOJEL6LNAXDREUGRX35BOLZI3B4PFFAC7IRPR3OA4QNKDEV
}
MirTest: {
nkey: ACTEST7PZTKJSBTR7BF6TBK3D776734PWHWDKO7HFMQOM5BIOYPSTEST
}
}
# Cluster TLS (if using clustered NATS)
cluster {
tls {
cert_file: "/etc/mir/certs/server-cert.pem"
key_file: "/etc/mir/certs/server-key.pem"
ca_file: "/etc/mir/certs/ca.pem"
}
}package main
import (
"crypto/tls"
"log"
"github.com/nats-io/nats.go"
)
func main() {
// Connect with both TLS encryption and NKey authentication
nc, err := nats.Connect("tls://localhost:4222",
// NKey authentication
nats.NkeyOptionFromSeed("/etc/mir/mirdev.seed"),
// TLS encryption
nats.ClientCert("/etc/mir/certs/client-cert.pem", "/etc/mir/certs/client-key.pem"),
nats.RootCAs("/etc/mir/certs/ca.pem"))
if err != nil {
log.Fatal("Secure connection failed:", err)
}
defer nc.Close()
// Alternative: Custom TLS config
tlsConfig := &tls.Config{
ServerName: "mir-nats-server",
MinVersion: tls.VersionTLS12,
}
ncCustom, err := nats.Connect("tls://localhost:4222",
nats.NkeyOptionFromSeed("/etc/mir/mirdev.seed"),
nats.Secure(tlsConfig),
nats.RootCAs("/etc/mir/certs/ca.pem"))
}For IoT devices, generate unique certificates per device:
#!/bin/bash
# generate-device-cert.sh
DEVICE_ID=$1
if [ -z "$DEVICE_ID" ]; then
echo "Usage: $0 <device-id>"
exit 1
fi
# Generate device certificate
openssl genrsa -out device-${DEVICE_ID}-key.pem 4096
openssl req -new -key device-${DEVICE_ID}-key.pem -out device-${DEVICE_ID}.csr \
-subj "/C=US/ST=State/L=City/O=MirIoT/OU=Devices/CN=device-${DEVICE_ID}"
# Sign with CA
openssl x509 -req -days 365 -in device-${DEVICE_ID}.csr \
-CA ca.pem -CAkey ca-key.pem \
-out device-${DEVICE_ID}-cert.pem -CAcreateserial
rm device-${DEVICE_ID}.csr
chmod 400 device-${DEVICE_ID}-key.pem# Verify certificate
openssl x509 -in server-cert.pem -text -noout
# Test TLS connection
openssl s_client -connect localhost:4222 -CAfile ca.pem
# Test with NATS CLI
nats --tlscert=client-cert.pem --tlskey=client-key.pem --tlsca=ca.pem \
--nkey=/etc/mir/mirdev.seed \
--server=tls://localhost:4222 pub test "hello"For data stored in JetStream, add encryption at rest:
jetstream {
store_dir: /data/jetstream
cipher: chachapoly
key: $JS_KEY # Use environment variable
}- Authentication: NKeys verify device/client identity
- Encryption in Transit: TLS protects data between devices and NATS
- Encryption at Rest: JetStream cipher protects stored messages
- Authorization: Account isolation ensures data segregation
- Certificate Management: Unique certificates per device for additional security
- Use TLS 1.2 or higher in production
- Rotate certificates regularly (automate with cron)
- Monitor certificate expiration dates
- Use strong cipher suites only
- Implement certificate pinning for IoT devices
- Store private keys securely with restricted permissions (400)