feat(membershipd): enable NATS nkey auth (enforce) and TLS flags
Opens the store before NATS so the authenticator can consult IsAuthorized. Under --bus-auth enforce the embedded NATS gets the nkey authenticator (only allowlisted identities connect); --tls-cert/--tls-key make it present the server certificate and require TLS. External NATS manages its own auth/TLS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+45
-19
@@ -17,6 +17,7 @@ import (
|
||||
server "github.com/nats-io/nats-server/v2/server"
|
||||
|
||||
"github.com/enmanuel/unibus/pkg/blobstore"
|
||||
"github.com/enmanuel/unibus/pkg/busauth"
|
||||
"github.com/enmanuel/unibus/pkg/embeddednats"
|
||||
"github.com/enmanuel/unibus/pkg/membership"
|
||||
)
|
||||
@@ -41,6 +42,8 @@ func main() {
|
||||
natsPort = flag.Int("nats-port", 4250, "embedded NATS listen port (when --nats-url empty)")
|
||||
natsStore = flag.String("nats-store", "./local_files/jetstream", "embedded JetStream store dir")
|
||||
busAuth = flag.String("bus-auth", "off", "control-plane auth rollout: off|soft|enforce (feature flag bus-auth)")
|
||||
tlsCert = flag.String("tls-cert", "", "PATH to the NATS server certificate (deploy/tls/server.crt); enables TLS on the embedded data plane")
|
||||
tlsKey = flag.String("tls-key", "", "path to the NATS server private key (deploy/tls/server.key); required with --tls-cert")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
@@ -52,25 +55,8 @@ func main() {
|
||||
log.SetFlags(log.LstdFlags | log.Lmsgprefix)
|
||||
log.SetPrefix("[membershipd] ")
|
||||
|
||||
// Data plane: embedded or external NATS.
|
||||
var ns *server.Server
|
||||
natsClientURL := *natsURL
|
||||
if natsClientURL == "" {
|
||||
var err error
|
||||
// Bind the embedded NATS to the same interface as the HTTP API so a single
|
||||
// --bind flag governs reachability: 127.0.0.1 keeps the whole stack
|
||||
// loopback-only; 0.0.0.0 exposes both planes to the LAN.
|
||||
ns, err = embeddednats.StartHost(*natsStore, *bind, *natsPort)
|
||||
if err != nil {
|
||||
log.Fatalf("start embedded nats: %v", err)
|
||||
}
|
||||
natsClientURL = embeddednats.ClientURL(ns)
|
||||
log.Printf("embedded NATS (JetStream) ready: %s", natsClientURL)
|
||||
} else {
|
||||
log.Printf("using external NATS: %s", natsClientURL)
|
||||
}
|
||||
|
||||
// Control plane: SQLite store + blob store + HTTP API.
|
||||
// Control plane store first: the NATS authenticator consults IsAuthorized, so
|
||||
// the store must exist before the embedded server starts.
|
||||
store, err := membership.Open(*dbPath)
|
||||
if err != nil {
|
||||
log.Fatalf("open membership store: %v", err)
|
||||
@@ -84,6 +70,46 @@ func main() {
|
||||
}
|
||||
log.Printf("blob store: %s", *storeDir)
|
||||
|
||||
// Data plane: embedded or external NATS. For the embedded server, enforce
|
||||
// turns on the nkey authenticator (only allowlisted identities may connect)
|
||||
// and --tls-cert/--tls-key turn on TLS. An external NATS manages its own
|
||||
// auth/TLS, so those flags do not apply to it.
|
||||
var ns *server.Server
|
||||
natsClientURL := *natsURL
|
||||
if natsClientURL == "" {
|
||||
cfg := embeddednats.ServerConfig{
|
||||
// Bind the embedded NATS to the same interface as the HTTP API so a
|
||||
// single --bind flag governs reachability: 127.0.0.1 keeps the whole
|
||||
// stack loopback-only; 0.0.0.0 exposes both planes to the LAN.
|
||||
StoreDir: *natsStore,
|
||||
Host: *bind,
|
||||
Port: *natsPort,
|
||||
}
|
||||
if authMode == membership.AuthEnforce {
|
||||
cfg.Auth = busauth.NewNkeyAuthenticator(store.IsAuthorized)
|
||||
log.Printf("NATS nkey authentication: ON (enforce)")
|
||||
}
|
||||
if *tlsCert != "" || *tlsKey != "" {
|
||||
if *tlsCert == "" || *tlsKey == "" {
|
||||
log.Fatalf("--tls-cert and --tls-key must be set together")
|
||||
}
|
||||
tlsCfg, err := busauth.ServerTLSConfig(*tlsCert, *tlsKey)
|
||||
if err != nil {
|
||||
log.Fatalf("load NATS TLS: %v", err)
|
||||
}
|
||||
cfg.TLS = tlsCfg
|
||||
log.Printf("NATS TLS: ON (%s)", *tlsCert)
|
||||
}
|
||||
ns, err = embeddednats.StartServer(cfg)
|
||||
if err != nil {
|
||||
log.Fatalf("start embedded nats: %v", err)
|
||||
}
|
||||
natsClientURL = embeddednats.ClientURL(ns)
|
||||
log.Printf("embedded NATS (JetStream) ready: %s", natsClientURL)
|
||||
} else {
|
||||
log.Printf("using external NATS: %s", natsClientURL)
|
||||
}
|
||||
|
||||
srv := membership.NewServer(store, blobs, authMode)
|
||||
log.Printf("control-plane auth: %s", authMode)
|
||||
addr := *bind + ":" + *httpPort
|
||||
|
||||
Reference in New Issue
Block a user