make caddy a L4 proxy to terminate TLS for HiveMQ

This commit is contained in:
Lars Nolden
2026-06-29 17:23:02 +02:00
parent 70c2ada986
commit bf8b25f374
3 changed files with 100 additions and 20 deletions
+39 -7
View File
@@ -17,12 +17,30 @@ let
];
ingesterKeys = [ "ingester_postgres_password" ];
postgresAdminKeys = [ "postgres_admin_password" ];
hivemqKeys = [ "hivemq_ingester_password" "hivemq_admin_password" ];
hivemqKeys = [ "hivemq_ingester_password" "hivemq_admin_password" "hivemq_device_password" ];
# HiveMQ file-RBAC credentials.xml. Only the passwords are secret; the role/
# topic policy is structural. `ingester` may subscribe to the whole telemetry
# tree (t/<tenant>/d/<device>/<metric>); `admin` is an operational superuser.
hivemqCredentialsXml = ingesterPassword: adminPassword: ''
# topic policy is structural. Devices publish under `acrios/<IMSI>/<metric>`
# (set by the sender firmware's mqtt_topic_base), so that is the namespace the
# ingester consumes and the device role is scoped to.
#
# Roles:
# ingest — the Go ingester; SUBSCRIBE the whole device tree.
# device — physical senders; full access under acrios/ (publish telemetry
# + the LWT/status and any downlink topics the firmware uses).
# superuser — operational break-glass.
#
# Option A (current): one shared `device` user (`bender`) for the whole fleet.
# Tenant isolation is enforced downstream by the ingester's IMSI→tenant
# registry lookup, NOT at the broker — any device could publish under any IMSI.
#
# TODO(Option B / per-device auth): give each sender its own RBAC user with
# username == IMSI and scope its role to `acrios/${{username}}/#`, so the
# broker enforces that a device can only publish under its own IMSI (real
# anti-spoofing + per-device revocation). Requires setting mqtt_user = <IMSI>
# on each device and a per-device password provisioning flow (generate → sops
# → push to device). file-RBAC hot-reloads, so added users need no restart.
hivemqCredentialsXml = ingesterPassword: adminPassword: devicePassword: ''
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<file-rbac>
<users>
@@ -36,17 +54,30 @@ let
<password>${adminPassword}</password>
<roles><id>superuser</id></roles>
</user>
<user>
<name>bender</name>
<password>${devicePassword}</password>
<roles><id>device</id></roles>
</user>
</users>
<roles>
<role>
<id>ingest</id>
<permissions>
<permission>
<topic>t/#</topic>
<topic>acrios/#</topic>
<activity>SUBSCRIBE</activity>
</permission>
</permissions>
</role>
<role>
<id>device</id>
<permissions>
<!-- No <activity> = PUBLISH and SUBSCRIBE; covers telemetry,
the LWT/status topic, and any downlink under acrios/. -->
<permission><topic>acrios/#</topic></permission>
</permissions>
</role>
<role>
<id>superuser</id>
<permissions>
@@ -112,7 +143,7 @@ in
if hasSecrets && cfg.hivemq
then config.sops.templates."hivemq-credentials".path
else "${pkgs.writeText "hivemq-credentials-dev.xml"
(hivemqCredentialsXml "dev-ingester" "dev-admin")}";
(hivemqCredentialsXml "dev-ingester" "dev-admin" "dev-device")}";
};
envFile = lib.mkOption {
@@ -157,7 +188,8 @@ in
templates."hivemq-credentials" = lib.mkIf cfg.hivemq {
content = hivemqCredentialsXml
config.sops.placeholder.hivemq_ingester_password
config.sops.placeholder.hivemq_admin_password;
config.sops.placeholder.hivemq_admin_password
config.sops.placeholder.hivemq_device_password;
mode = "0400";
owner = "gebos-hivemq";
};