diff --git a/nixos/doc/manual/release-notes/rl-2605.section.md b/nixos/doc/manual/release-notes/rl-2605.section.md index f883372fd450..b07a270be3da 100644 --- a/nixos/doc/manual/release-notes/rl-2605.section.md +++ b/nixos/doc/manual/release-notes/rl-2605.section.md @@ -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. diff --git a/nixos/modules/services/networking/mosquitto.md b/nixos/modules/services/networking/mosquitto.md index 53b5beb16b89..b1a6fabb1f2a 100644 --- a/nixos/modules/services/networking/mosquitto.md +++ b/nixos/modules/services/networking/mosquitto.md @@ -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 diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 1d3bf8d671df..21b531533513 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -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)