feat(mesh): NATS TLS + token auth client support
- CastleNATSClient accepts a token; a tls:// server URL makes nats-py verify the
broker against the system CA (trusts the wildcard's Let's Encrypt issuer, no
custom CA needed)
- config: CASTLE_API_NATS_TOKEN; main wires it through
Server side (instance): nats-server.conf gains tls{} (wildcard cert via
expose.tcp.tls) + authorization{token}; clients use tls://castle-nats.<domain>.
This commit is contained in:
@@ -17,6 +17,7 @@ class Settings(BaseSettings):
|
||||
# Mesh coordination (all off by default — single-node works without them)
|
||||
nats_enabled: bool = False
|
||||
nats_url: str = "nats://localhost:4222"
|
||||
nats_token: str | None = None
|
||||
mdns_enabled: bool = False
|
||||
|
||||
model_config = {
|
||||
|
||||
@@ -68,6 +68,7 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
||||
local_hostname=registry.node.hostname,
|
||||
local_registry=registry,
|
||||
servers=settings.nats_url,
|
||||
token=settings.nats_token,
|
||||
)
|
||||
await nats_client.start()
|
||||
app.state.nats_client = nats_client
|
||||
|
||||
@@ -50,10 +50,12 @@ class CastleNATSClient:
|
||||
local_hostname: str,
|
||||
local_registry: NodeRegistry,
|
||||
servers: str | list[str] = "nats://localhost:4222",
|
||||
token: str | None = None,
|
||||
) -> None:
|
||||
self._local_hostname = local_hostname
|
||||
self._local_registry = local_registry
|
||||
self._servers = servers
|
||||
self._token = token or None
|
||||
self._nc: nats.NATS | None = None
|
||||
self._kv = None
|
||||
self._presence_kv = None
|
||||
@@ -77,9 +79,13 @@ class CastleNATSClient:
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Connect, publish our registry, seed state, and start watchers."""
|
||||
# A `tls://` server URL makes nats-py verify the server against the system
|
||||
# CA bundle — which trusts the wildcard's Let's Encrypt issuer, so no custom
|
||||
# CA is needed. `token` authenticates this node to the broker.
|
||||
self._nc = await nats.connect(
|
||||
self._servers,
|
||||
name=f"castle-{self._local_hostname}",
|
||||
token=self._token,
|
||||
max_reconnect_attempts=-1, # reconnect forever — nodes come and go
|
||||
)
|
||||
js = self._nc.jetstream()
|
||||
|
||||
Reference in New Issue
Block a user