Skip to content

NATS + SPIFFE Setup

NATS provides event-driven messaging between tentacles. Combined with SPIFFE/SPIRE, it enables mTLS-authenticated communication with per-tentacle identity.

  • Kubernetes cluster with the MCP server installed
  • Helm 3+
  • The exoskeleton Postgres registrar (for NATS authorization storage)
  • SPIRE server and agent deployed (for workload identity)

Deploy the SPIRE server and agent:

Terminal window
# Install SPIRE CRDs
kubectl apply -f https://github.com/spiffe/spire/releases/latest/download/spire-crds.yaml
# Install SPIRE via Helm
helm install spire spire/spire \
--namespace spire-system \
--create-namespace \
--set global.spire.trustDomain=tentacular.local

Deploy NATS with resolver-based authorization:

Terminal window
helm install tentacular-nats nats/nats \
--namespace tentacular-system \
--set auth.enabled=true \
--set auth.resolver.type=full \
--set config.jetstream.enabled=true

Enable NATS and SPIRE registrars:

Terminal window
helm upgrade tentacular-mcp oci://ghcr.io/randybias/tentacular-mcp \
--namespace tentacular-system \
--set exoskeleton.nats.enabled=true \
--set exoskeleton.nats.url=nats://tentacular-nats.tentacular-system.svc:4222 \
--set exoskeleton.spire.enabled=true \
--set exoskeleton.spire.trustDomain=tentacular.local
Terminal window
# Check SPIRE agent health
kubectl -n spire-system exec -it spire-agent-0 -- \
/opt/spire/bin/spire-agent healthcheck
# List registered entries
kubectl -n spire-system exec -it spire-server-0 -- \
/opt/spire/bin/spire-server entry show
workflow.yaml
triggers:
- type: queue
subject: events.incoming
contract:
version: "1"
dependencies:
tentacular-nats:
Terminal window
tntc deploy

The exoskeleton:

  1. Creates a SPIRE registration (ClusterSPIFFEID) for the tentacle pod
  2. Provisions NATS authorization with scoped subject permissions
  3. Injects NATS credentials and trust bundle into the deployment

Each tentacle gets a SPIFFE identity:

spiffe://tentacular.local/ns/<namespace>/wf/<workflow-name>

This identity is:

  • Encoded in an X.509 SVID (SPIFFE Verifiable Identity Document)
  • Automatically rotated by the SPIRE agent
  • Used for mTLS between the tentacle and NATS server
  • Used for authorization decisions (subject access control)

NATS subjects are scoped per-tentacle by the exoskeleton using a deterministic naming convention. You cannot pick arbitrary subject names — they are derived from the tentacle’s identity.

Each tentacle receives a subject prefix based on its (namespace, workflow-name):

tentacular.<namespace>.<workflow-name>.>

For example, a tentacle named hn-digest in namespace tent-dev gets:

  • Subject prefix: tentacular.tent-dev.hn-digest.>
  • NATS user: tentacle.tent-dev.hn-digest

The > suffix is a NATS wildcard — the tentacle can publish and subscribe to any subject under its prefix (e.g., tentacular.tent-dev.hn-digest.events, tentacular.tent-dev.hn-digest.results).

ModeIsolationHow It Works
SPIFFE (recommended)Cryptographically enforcedPer-workflow mTLS certificates via SPIRE SVIDs. Authorization ConfigMap contains explicit allow lists per SPIFFE principal.
Token (fallback)Convention-onlyShared token for all workflows. Subject isolation is by naming convention, not enforced.

In SPIFFE mode, each tentacle’s authorization entry looks like:

User: spiffe://tentacular/ns/tent-dev/tentacles/hn-digest
PublishAllow: [tentacular.tent-dev.hn-digest.>]
SubscribeAllow: [tentacular.tent-dev.hn-digest.>]

Tentacles with queue triggers subscribe to NATS subjects matching their scoped prefix:

triggers:
- type: queue
subject: tentacular.tent-dev.hn-digest.events
  • Connection: TLS + token auth via config.nats_url and secrets.nats.token
  • Request-reply: If a message has a reply subject, the execution result is sent back
  • Graceful shutdown: SIGTERM/SIGINT drain subscriptions before exit

Tentacles can communicate through NATS by publishing to another tentacle’s subject prefix. In SPIFFE mode, explicit authorization entries must be added to allow cross-tentacle publish/subscribe.

  • SPIRE agents are healthy on all nodes
  • Tentacles receive SVIDs (check pod logs for SPIFFE handshake)
  • NATS queue triggers receive and process messages
  • tntc logs my-tentacle shows successful NATS connection
SymptomCauseFix
NATS connection refusedNATS not running or wrong URLCheck NATS pod status and service endpoint
TLS handshake failedSVID not issuedCheck SPIRE agent logs, verify ClusterSPIFFEID exists
authorization violationWrong subject permissionsCheck NATS auth config, re-register via MCP
Queue trigger not firingSubject mismatchVerify subject in trigger matches publisher
nats_url missingConfig not setAdd nats_url to workflow config