switch to emqx
This commit is contained in:
@@ -17,75 +17,30 @@ let
|
||||
];
|
||||
ingesterKeys = [ "ingester_postgres_password" ];
|
||||
postgresAdminKeys = [ "postgres_admin_password" ];
|
||||
hivemqKeys = [ "hivemq_ingester_password" "hivemq_admin_password" "hivemq_device_password" ];
|
||||
emqxKeys = [
|
||||
"emqx_ingester_password"
|
||||
"emqx_admin_password"
|
||||
"emqx_device_password"
|
||||
];
|
||||
|
||||
# HiveMQ file-RBAC credentials.xml. Only the passwords are secret; the role/
|
||||
# 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.
|
||||
# EMQX authn bootstrap CSV (bootstrap_type = plain). Seeds the broker's
|
||||
# built-in auth database on first start. Broker users:
|
||||
# ingester — the Go ingester; SUBSCRIBE the whole device tree (see the ACL
|
||||
# in gebos-emqx.nix).
|
||||
# admin — operational break-glass; is_superuser bypasses the ACL.
|
||||
# bender — shared device user for the whole fleet (Option A). Tenant
|
||||
# isolation is enforced downstream by the ingester's IMSI→tenant
|
||||
# registry, NOT at the broker. TODO(Option B): per-device users
|
||||
# (username == IMSI) — see the ACL comment in gebos-emqx.nix.
|
||||
#
|
||||
# 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>
|
||||
<user>
|
||||
<name>ingester</name>
|
||||
<password>${ingesterPassword}</password>
|
||||
<roles><id>ingest</id></roles>
|
||||
</user>
|
||||
<user>
|
||||
<name>admin</name>
|
||||
<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>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>
|
||||
<permission><topic>#</topic></permission>
|
||||
</permissions>
|
||||
</role>
|
||||
</roles>
|
||||
</file-rbac>
|
||||
# Plaintext passwords are acceptable here because the file is sops-encrypted
|
||||
# at rest and rendered 0400 into a tmpfs at runtime; passwords must not
|
||||
# contain commas (CSV).
|
||||
emqxUsersCsv = ingesterPassword: adminPassword: devicePassword: ''
|
||||
user_id,password,is_superuser
|
||||
ingester,${ingesterPassword},false
|
||||
admin,${adminPassword},true
|
||||
bender,${devicePassword},false
|
||||
'';
|
||||
|
||||
# Render an env file body from a list of (key, envVarName) pairs.
|
||||
@@ -112,7 +67,7 @@ let
|
||||
lib.optionals cfg.supabase supabaseKeys
|
||||
++ lib.optionals cfg.ingester ingesterKeys
|
||||
++ lib.optionals cfg.postgresAdmin postgresAdminKeys
|
||||
++ lib.optionals cfg.hivemq hivemqKeys;
|
||||
++ lib.optionals cfg.emqx emqxKeys;
|
||||
in
|
||||
{
|
||||
options.services.gebos.secrets = {
|
||||
@@ -126,24 +81,24 @@ in
|
||||
postgresAdmin = lib.mkEnableOption ''
|
||||
Postgres bootstrap admin password applied via a one-shot ALTER ROLE unit.'';
|
||||
|
||||
hivemq = lib.mkEnableOption ''
|
||||
HiveMQ file-RBAC credentials.xml (ingester + admin MQTT users), rendered
|
||||
0400/gebos-hivemq for the broker's file-RBAC extension.'';
|
||||
emqx = lib.mkEnableOption ''
|
||||
EMQX broker secrets: the authn bootstrap users.csv (ingester + admin +
|
||||
device MQTT users).'';
|
||||
|
||||
hivemqCredentialsFile = lib.mkOption {
|
||||
emqxBootstrapUsersFile = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
Path of the rendered HiveMQ file-RBAC credentials.xml consumed by the
|
||||
gebos-hivemq broker. Resolves to the sops-templated secret when sops
|
||||
material is present and the hivemq toggle is on, else to a baked-in
|
||||
Path of the rendered EMQX authn bootstrap users.csv consumed by the
|
||||
gebos-emqx broker. Resolves to the sops-templated secret when sops
|
||||
material is present and the emqx toggle is on, else to a baked-in
|
||||
dev-defaults file (so first-boot eval and local VMs work).
|
||||
'';
|
||||
default =
|
||||
if hasSecrets && cfg.hivemq
|
||||
then config.sops.templates."hivemq-credentials".path
|
||||
else "${pkgs.writeText "hivemq-credentials-dev.xml"
|
||||
(hivemqCredentialsXml "dev-ingester" "dev-admin" "dev-device")}";
|
||||
if hasSecrets && cfg.emqx
|
||||
then config.sops.templates."emqx-users.csv".path
|
||||
else "${pkgs.writeText "emqx-users-dev.csv"
|
||||
(emqxUsersCsv "dev-ingester" "dev-admin" "dev-device")}";
|
||||
};
|
||||
|
||||
envFile = lib.mkOption {
|
||||
@@ -182,16 +137,15 @@ in
|
||||
owner = "root";
|
||||
};
|
||||
|
||||
# Rendered as a standalone file (not env) — the file-RBAC extension reads
|
||||
# credentials.xml directly. Owned by the broker user so preStart can link
|
||||
# it into the extension's conf/ dir.
|
||||
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_device_password;
|
||||
# Rendered as a standalone file — the gebos-emqx preStart copies it into
|
||||
# the broker state dir, chowned to the container's emqx uid.
|
||||
templates."emqx-users.csv" = lib.mkIf cfg.emqx {
|
||||
content = emqxUsersCsv
|
||||
config.sops.placeholder.emqx_ingester_password
|
||||
config.sops.placeholder.emqx_admin_password
|
||||
config.sops.placeholder.emqx_device_password;
|
||||
mode = "0400";
|
||||
owner = "gebos-hivemq";
|
||||
owner = "root";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user