Commit 533ff854 authored by datafoo's avatar datafoo
Browse files

nixos/mosquitto: leverage systemd credentials

Use systemd credentials for all variations of user passwords.
Password files do not need special permissions anymore.
parent 874e84b6
Loading
Loading
Loading
Loading
+56 −9
Original line number Diff line number Diff line
@@ -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.
        '';
      };

@@ -64,7 +67,7 @@ let
      };

      hashedPasswordFile = mkOption {
        type = uniq (nullOr types.path);
        type = uniq (nullOr path);
        example = "/path/to/file";
        default = null;
        description = mdDoc ''
@@ -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.
        '';
      };

@@ -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
@@ -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";
@@ -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);
    };