Loading nixos/modules/services/networking/mosquitto.nix +56 −9 Original line number Diff line number Diff line Loading @@ -42,12 +42,15 @@ let }; passwordFile = mkOption { type = uniq (nullOr types.path); type = uniq (nullOr path); example = "/path/to/file"; default = null; description = lib.mdDoc '' Specifies the path to a file containing the clear text password for the MQTT user. The file is securely passed to mosquitto by leveraging systemd credentials. No special permissions need to be set on this file. ''; }; Loading @@ -64,7 +67,7 @@ let }; hashedPasswordFile = mkOption { type = uniq (nullOr types.path); type = uniq (nullOr path); example = "/path/to/file"; default = null; description = mdDoc '' Loading @@ -73,6 +76,9 @@ let To generate hashed password install the `mosquitto` package and use `mosquitto_passwd`, then remove the `username:` prefix from the generated file. The file is securely passed to mosquitto by leveraging systemd credentials. No special permissions need to be set on this file. ''; }; Loading Loading @@ -102,15 +108,43 @@ let message = "Cannot set more than one password option for user ${n} in ${prefix}"; }) users; makePasswordFile = users: path: listenerScope = index: "listener-${toString index}"; userScope = prefix: index: "${prefix}-user-${toString index}"; credentialID = prefix: credential: "${prefix}-${credential}"; toScopedUsers = listenerScope: users: pipe users [ attrNames (imap0 (index: user: nameValuePair user (users.${user} // { scope = userScope listenerScope index; }) )) listToAttrs ]; userCredentials = user: credentials: pipe credentials [ (filter (credential: user.${credential} != null)) (map (credential: "${credentialID user.scope credential}:${user.${credential}}")) ]; usersCredentials = listenerScope: users: credentials: pipe users [ (toScopedUsers listenerScope) (mapAttrsToList (_: user: userCredentials user credentials)) concatLists ]; systemdCredentials = listeners: listenerCredentials: pipe listeners [ (imap0 (index: listener: listenerCredentials (listenerScope index) listener)) concatLists ]; makePasswordFile = listenerScope: users: path: let makeLines = store: file: makeLines = store: file: let scopedUsers = toScopedUsers listenerScope users; in mapAttrsToList (n: u: "addLine ${escapeShellArg n} ${escapeShellArg u.${store}}") (filterAttrs (_: u: u.${store} != null) users) (name: user: ''addLine ${escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'') (filterAttrs (_: user: user.${store} != null) scopedUsers) ++ mapAttrsToList (n: u: "addFile ${escapeShellArg n} ${escapeShellArg "${u.${file}}"}") (filterAttrs (_: u: u.${file} != null) users); (name: user: ''addFile ${escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'') (filterAttrs (_: user: user.${file} != null) scopedUsers); plainLines = makeLines "password" "passwordFile"; hashedLines = makeLines "hashedPassword" "hashedPasswordFile"; in Loading Loading @@ -581,6 +615,19 @@ in ExecStart = "${cfg.package}/bin/mosquitto -c ${configFile}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; # Credentials SetCredential = let listenerCredentials = listenerScope: listener: usersCredentials listenerScope listener.users [ "password" "hashedPassword" ]; in systemdCredentials cfg.listeners listenerCredentials; LoadCredential = let listenerCredentials = listenerScope: listener: usersCredentials listenerScope listener.users [ "passwordFile" "hashedPasswordFile" ]; in systemdCredentials cfg.listeners listenerCredentials; # Hardening CapabilityBoundingSet = ""; DevicePolicy = "closed"; Loading Loading @@ -653,7 +700,7 @@ in concatStringsSep "\n" (imap0 (idx: listener: makePasswordFile listener.users "${cfg.dataDir}/passwd-${toString idx}") (idx: listener: makePasswordFile (listenerScope idx) listener.users "${cfg.dataDir}/passwd-${toString idx}") cfg.listeners); }; Loading Loading
nixos/modules/services/networking/mosquitto.nix +56 −9 Original line number Diff line number Diff line Loading @@ -42,12 +42,15 @@ let }; passwordFile = mkOption { type = uniq (nullOr types.path); type = uniq (nullOr path); example = "/path/to/file"; default = null; description = lib.mdDoc '' Specifies the path to a file containing the clear text password for the MQTT user. The file is securely passed to mosquitto by leveraging systemd credentials. No special permissions need to be set on this file. ''; }; Loading @@ -64,7 +67,7 @@ let }; hashedPasswordFile = mkOption { type = uniq (nullOr types.path); type = uniq (nullOr path); example = "/path/to/file"; default = null; description = mdDoc '' Loading @@ -73,6 +76,9 @@ let To generate hashed password install the `mosquitto` package and use `mosquitto_passwd`, then remove the `username:` prefix from the generated file. The file is securely passed to mosquitto by leveraging systemd credentials. No special permissions need to be set on this file. ''; }; Loading Loading @@ -102,15 +108,43 @@ let message = "Cannot set more than one password option for user ${n} in ${prefix}"; }) users; makePasswordFile = users: path: listenerScope = index: "listener-${toString index}"; userScope = prefix: index: "${prefix}-user-${toString index}"; credentialID = prefix: credential: "${prefix}-${credential}"; toScopedUsers = listenerScope: users: pipe users [ attrNames (imap0 (index: user: nameValuePair user (users.${user} // { scope = userScope listenerScope index; }) )) listToAttrs ]; userCredentials = user: credentials: pipe credentials [ (filter (credential: user.${credential} != null)) (map (credential: "${credentialID user.scope credential}:${user.${credential}}")) ]; usersCredentials = listenerScope: users: credentials: pipe users [ (toScopedUsers listenerScope) (mapAttrsToList (_: user: userCredentials user credentials)) concatLists ]; systemdCredentials = listeners: listenerCredentials: pipe listeners [ (imap0 (index: listener: listenerCredentials (listenerScope index) listener)) concatLists ]; makePasswordFile = listenerScope: users: path: let makeLines = store: file: makeLines = store: file: let scopedUsers = toScopedUsers listenerScope users; in mapAttrsToList (n: u: "addLine ${escapeShellArg n} ${escapeShellArg u.${store}}") (filterAttrs (_: u: u.${store} != null) users) (name: user: ''addLine ${escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'') (filterAttrs (_: user: user.${store} != null) scopedUsers) ++ mapAttrsToList (n: u: "addFile ${escapeShellArg n} ${escapeShellArg "${u.${file}}"}") (filterAttrs (_: u: u.${file} != null) users); (name: user: ''addFile ${escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'') (filterAttrs (_: user: user.${file} != null) scopedUsers); plainLines = makeLines "password" "passwordFile"; hashedLines = makeLines "hashedPassword" "hashedPasswordFile"; in Loading Loading @@ -581,6 +615,19 @@ in ExecStart = "${cfg.package}/bin/mosquitto -c ${configFile}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; # Credentials SetCredential = let listenerCredentials = listenerScope: listener: usersCredentials listenerScope listener.users [ "password" "hashedPassword" ]; in systemdCredentials cfg.listeners listenerCredentials; LoadCredential = let listenerCredentials = listenerScope: listener: usersCredentials listenerScope listener.users [ "passwordFile" "hashedPasswordFile" ]; in systemdCredentials cfg.listeners listenerCredentials; # Hardening CapabilityBoundingSet = ""; DevicePolicy = "closed"; Loading Loading @@ -653,7 +700,7 @@ in concatStringsSep "\n" (imap0 (idx: listener: makePasswordFile listener.users "${cfg.dataDir}/passwd-${toString idx}") (idx: listener: makePasswordFile (listenerScope idx) listener.users "${cfg.dataDir}/passwd-${toString idx}") cfg.listeners); }; Loading