Unverified Commit 386a2346 authored by r-vdp's avatar r-vdp
Browse files

nixos/mosquitto: use acl-file/password-file plugins

Mosquitto 2.1 deprecated the acl_file and password_file config options
in favour of plugins shipping the same code, with removal scheduled for
3.0. Switch the per-listener config generation over to load the plugins
instead.

per_listener_settings is also deprecated but kept for now since the
module design is built around per-listener auth and the 3.0 replacement
semantics are not yet finalised upstream.

A version assertion is added since the plugins only ship with 2.1+.
parent 068672d9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -147,6 +147,8 @@

- `services.crabfit` was removed because its upstream packages are unmaintained and insecure.

- `services.mosquitto` now generates per-listener authentication and access control via the upstream `password-file` and `acl-file` plugins instead of the deprecated `password_file` and `acl_file` options. The plugins contain the same code, so behaviour is unchanged, but [](#opt-services.mosquitto.package) must now be at least version 2.1.

- `sing-box` has been updated to 1.13.0, which has removed some deprecated options.  See [upstream documentation](https://sing-box.sagernet.org/configuration/) for details and migration options.

- `services.statsd` has been removed because the packages it relies on do not exist anymore in nixpkgs.
+6 −5
Original line number Diff line number Diff line
@@ -83,9 +83,10 @@ localhost).

Almost all options of Mosquitto are available for configuration at their appropriate levels, some
as NixOS options written in camel case, the remainders under `settings` with their exact names in
the Mosquitto config file. The exceptions are `acl_file` (which is always set according to the
`acl` attributes of a listener and its users) and `per_listener_settings` (which is always set to
`true`).
the Mosquitto config file. The exceptions are `per_listener_settings` (which is always set to
`true`) and the per-listener access control, which is always configured via instances of the
`acl-file` and `password-file` plugins generated from the `acl` and `users` attributes of each
listener.

### Password authentication {#module-services-mosquitto-config-passwords}

@@ -101,8 +102,8 @@ will not be able to use the broker.

### ACL format {#module-services-mosquitto-config-acl}

Every listener has a Mosquitto `acl_file` attached to it. This ACL is configured via two
attributes of the config:
Every listener has an instance of the Mosquitto `acl-file` plugin attached to it. This ACL is
configured via two attributes of the config:

  * the `acl` attribute of the listener configures pattern ACL entries and topic ACL entries
    for anonymous users. Each entry must be prefixed with `pattern` or `topic` to distinguish
+17 −2
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
let
  cfg = config.services.mosquitto;

  pluginLibDir = "${lib.getLib cfg.package}/lib";

  # note that mosquitto config parsing is very simplistic as of may 2021.
  # often times they'll e.g. strtok() a line, check the first two tokens, and ignore the rest.
  # there's no escaping available either, so we have to prevent any being necessary.
@@ -400,10 +402,16 @@ let
    idx: listener:
    [
      "listener ${toString listener.port} ${toString listener.address}"
      "acl_file ${cfg.dataDir}/acl-${toString idx}.conf"
    ]
    ++ lib.optional (!listener.omitPasswordAuth) "password_file ${cfg.dataDir}/passwd-${toString idx}"
    ++ formatFreeform { } listener.settings
    ++ [
      "plugin ${pluginLibDir}/mosquitto_acl_file.so"
      "plugin_opt_acl_file ${cfg.dataDir}/acl-${toString idx}.conf"
    ]
    ++ lib.optionals (!listener.omitPasswordAuth) [
      "plugin ${pluginLibDir}/mosquitto_password_file.so"
      "plugin_opt_password_file ${cfg.dataDir}/passwd-${toString idx}"
    ]
    ++ lib.concatMap formatAuthPlugin listener.authPlugins;

  freeformBridgeKeys = {
@@ -648,6 +656,13 @@ let
  globalAsserts =
    prefix: cfg:
    lib.flatten [
      {
        assertion = lib.versionAtLeast cfg.package.version "2.1";
        message = ''
          ${prefix}.package must be at least version 2.1, since the generated
          configuration relies on the acl-file and password-file plugins.
        '';
      }
      (assertKeysValid "${prefix}.settings" freeformGlobalKeys cfg.settings)
      (lib.imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners)
      (lib.mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges)