Control-Plane Integrations
The backend is the control plane for sensors. It never touches the alert data path (that is Suricata → sensor → data collector → Kafka). Instead it is responsible for trust and commands: issuing claim codes and certificates, provisioning NATS credentials, sending start/stop commands, and tracking sensor status.
This page maps the backend services that implement those responsibilities. For the end-to-end walkthrough, see the Control Plane scenario.
Responsibilities at a glance
1. Claim codes and enrollment
A sensor is onboarded with a one-time claim code, not an SSH/Ansible push. The relevant controllers:
| Controller | Role |
|---|---|
API/Controllers/ClaimCodes/ClaimCodesController.cs | Operator-facing claim-code management. |
API/Controllers/ClaimCodes/SensorClaimController.cs | Sensor-facing claim redeem (POST /api/sensors/claim/redeem). |
API/Controllers/Sensors/SensorsController.cs | Sensor registration, enrollment (CSR → cert), heartbeat, cert renew/revoke. |
The enrollment exchange (POST /api/sensors/{id}/agent/enroll) takes the sensor's CSR and returns a signed mTLS client certificate plus a sensor token. See Sensor → Enrollment & PKI for the client side.
2. gRPC services (mTLS)
Two gRPC services are mapped in Extensions/WebApplicationExtensions.cs:
app.MapGrpcService<SensorHealthcheckService>();
app.MapGrpcService<SensorEventStreamService>();
SensorHealthcheckService(Protos/sensor_healthcheck.proto) — sensors report health.SensorEventStreamService(Protos/sensor_event.proto) — the target mTLS ingestion path for alert events. Currently it authenticates the client certificate and enforces liveness (it logs events and checks the client-cert serial against the active sensor list) rather than persisting to Kafka. The operational data path today still flows through the Data Collector; see the Data Plane scenario for how the two relate.
Both are guarded by SensorMtlsInterceptor (Infrastructure/Grpc/SensorMtlsInterceptor.cs), registered via AddGrpc(options => options.Interceptors.Add(typeof(SensorMtlsInterceptor))) in Extensions/ServiceCollectionExtensions.cs.
3. NATS account/user provisioning
The backend does not sign any NATS JWTs — it delegates to the NATS Provisioner.
| Service | File | Role |
|---|---|---|
NatsProvisionerClient | Infrastructure/Services/NatsProvisionerClient.cs | HTTP client for POST /accounts, POST /users, POST /revoke. Sends the shared secret via SharedSecretHeaderName and routes calls through the resilient HTTP service (circuit breaker key nats-provisioner). |
NatsTenantProvisioningWorker | Infrastructure/Services/NatsTenantProvisioningWorker.cs | BackgroundService that reconciles tenants whose NatsAccountPubKey is null or status pending, calls CreateAccountAsync, then MarkNatsAccountProvisioned. Runs every IntervalSeconds (min 5s). |
Both are gated by NatsProvisionerOptions.Enabled; when disabled they throw/return rather than calling out.
4. NATS control messaging
Once credentials exist, the backend talks to sensors over NATS:
| Service | File | Subject | Role |
|---|---|---|---|
NatsControlPublisher | Infrastructure/Services/NatsControlPublisher.cs | rxc.<tenant>.<sensor>.cmd (JetStream) | Publishes SensorControlCommand (start/stop) onto the command stream. Subject built by CommandSubject(tenantId, sensorId). Requires NatsMessagingOptions.Enabled. |
VirtualSensorStatusConsumer | Infrastructure/Services/VirtualSensorStatusConsumer.cs | rxc.*.*.status (core NATS) | Subscribes to all sensor status subjects, matches each message to a virtual sensor, and applies status transitions (Apply). |
Commands go out over JetStream (durable, work-queue) so a sensor that is briefly offline still receives them. Status comes back over core NATS as fire-and-forget telemetry.
Configuration summary
| Option group | Drives |
|---|---|
NatsProvisionerOptions (Enabled, BaseUrl, SharedSecret, SharedSecretHeaderName, IntervalSeconds) | Provisioner HTTP client + reconcile worker. |
NatsMessagingOptions (Enabled, connection/creds) | Control publisher + status consumer. |
See Configuration Reference for the concrete keys, and NATS Provisioner for the service on the other side of the shared secret.