233 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| { config, lib, pkgs, ...}:
 | |
| 
 | |
| with lib;
 | |
| 
 | |
| let
 | |
|   cfg = config.services.mosquitto;
 | |
| 
 | |
|   listenerConf = optionalString cfg.ssl.enable ''
 | |
|     listener ${toString cfg.ssl.port} ${cfg.ssl.host}
 | |
|     cafile ${cfg.ssl.cafile}
 | |
|     certfile ${cfg.ssl.certfile}
 | |
|     keyfile ${cfg.ssl.keyfile}
 | |
|   '';
 | |
| 
 | |
|   passwordConf = optionalString cfg.checkPasswords ''
 | |
|     password_file ${cfg.dataDir}/passwd
 | |
|   '';
 | |
| 
 | |
|   mosquittoConf = pkgs.writeText "mosquitto.conf" ''
 | |
|     pid_file /run/mosquitto/pid
 | |
|     acl_file ${aclFile}
 | |
|     persistence true
 | |
|     allow_anonymous ${boolToString cfg.allowAnonymous}
 | |
|     bind_address ${cfg.host}
 | |
|     port ${toString cfg.port}
 | |
|     ${passwordConf}
 | |
|     ${listenerConf}
 | |
|     ${cfg.extraConf}
 | |
|   '';
 | |
| 
 | |
|   userAcl = (concatStringsSep "\n\n" (mapAttrsToList (n: c:
 | |
|     "user ${n}\n" + (concatStringsSep "\n" c.acl)) cfg.users
 | |
|   ));
 | |
| 
 | |
|   aclFile = pkgs.writeText "mosquitto.acl" ''
 | |
|     ${cfg.aclExtraConf}
 | |
|     ${userAcl}
 | |
|   '';
 | |
| 
 | |
| in
 | |
| 
 | |
| {
 | |
| 
 | |
|   ###### Interface
 | |
| 
 | |
|   options = {
 | |
|     services.mosquitto = {
 | |
|       enable = mkEnableOption "Enable the MQTT Mosquitto broker.";
 | |
| 
 | |
|       host = mkOption {
 | |
|         default = "127.0.0.1";
 | |
|         example = "0.0.0.0";
 | |
|         type = types.string;
 | |
|         description = ''
 | |
|           Host to listen on without SSL.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|       port = mkOption {
 | |
|         default = 1883;
 | |
|         example = 1883;
 | |
|         type = types.int;
 | |
|         description = ''
 | |
|           Port on which to listen without SSL.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|       ssl = {
 | |
|         enable = mkEnableOption "Enable SSL listener.";
 | |
| 
 | |
|         cafile = mkOption {
 | |
|           type = types.nullOr types.path;
 | |
|           default = null;
 | |
|           description = "Path to PEM encoded CA certificates.";
 | |
|         };
 | |
| 
 | |
|         certfile = mkOption {
 | |
|           type = types.nullOr types.path;
 | |
|           default = null;
 | |
|           description = "Path to PEM encoded server certificate.";
 | |
|         };
 | |
| 
 | |
|         keyfile = mkOption {
 | |
|           type = types.nullOr types.path;
 | |
|           default = null;
 | |
|           description = "Path to PEM encoded server key.";
 | |
|         };
 | |
| 
 | |
|         host = mkOption {
 | |
|           default = "0.0.0.0";
 | |
|           example = "localhost";
 | |
|           type = types.string;
 | |
|           description = ''
 | |
|             Host to listen on with SSL.
 | |
|           '';
 | |
|         };
 | |
| 
 | |
|         port = mkOption {
 | |
|           default = 8883;
 | |
|           example = 8883;
 | |
|           type = types.int;
 | |
|           description = ''
 | |
|             Port on which to listen with SSL.
 | |
|           '';
 | |
|         };
 | |
|       };
 | |
| 
 | |
|       dataDir = mkOption {
 | |
|         default = "/var/lib/mosquitto";
 | |
|         type = types.path;
 | |
|         description = ''
 | |
|           The data directory.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|       users = mkOption {
 | |
|         type = types.attrsOf (types.submodule {
 | |
|           options = {
 | |
|             password = mkOption {
 | |
|               type = with types; uniq (nullOr str);
 | |
|               default = null;
 | |
|               description = ''
 | |
|                 Specifies the (clear text) password for the MQTT User.
 | |
|               '';
 | |
|             };
 | |
| 
 | |
|             hashedPassword = mkOption {
 | |
|               type = with types; uniq (nullOr str);
 | |
|               default = null;
 | |
|               description = ''
 | |
|                 Specifies the hashed password for the MQTT User.
 | |
|                 <option>hashedPassword</option> overrides <option>password</option>.
 | |
|                 To generate hashed password install <literal>mosquitto</literal>
 | |
|                 package and use <literal>mosquitto_passwd</literal>.
 | |
|               '';
 | |
|             };
 | |
| 
 | |
|             acl = mkOption {
 | |
|               type = types.listOf types.string;
 | |
|               example = [ "topic read A/B" "topic A/#" ];
 | |
|               description = ''
 | |
|                 Control client access to topics on the broker.
 | |
|               '';
 | |
|             };
 | |
|           };
 | |
|         });
 | |
|         example = { john = { password = "123456"; acl = [ "topic readwrite john/#" ]; }; };
 | |
|         description = ''
 | |
|           A set of users and their passwords and ACLs.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|       allowAnonymous = mkOption {
 | |
|         default = false;
 | |
|         type = types.bool;
 | |
|         description = ''
 | |
|           Allow clients to connect without authentication.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|       checkPasswords = mkOption {
 | |
|         default = false;
 | |
|         example = true;
 | |
|         type = types.bool;
 | |
|         description = ''
 | |
|           Refuse connection when clients provide incorrect passwords.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|       extraConf = mkOption {
 | |
|         default = "";
 | |
|         type = types.lines;
 | |
|         description = ''
 | |
|           Extra config to append to `mosquitto.conf` file.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|       aclExtraConf = mkOption {
 | |
|         default = "";
 | |
|         type = types.lines;
 | |
|         description = ''
 | |
|           Extra config to prepend to the ACL file.
 | |
|         '';
 | |
|       };
 | |
| 
 | |
|     };
 | |
|   };
 | |
| 
 | |
| 
 | |
|   ###### Implementation
 | |
| 
 | |
|   config = mkIf cfg.enable {
 | |
| 
 | |
|     systemd.services.mosquitto = {
 | |
|       description = "Mosquitto MQTT Broker Daemon";
 | |
|       wantedBy = [ "multi-user.target" ];
 | |
|       after = [ "network.target" ];
 | |
|       serviceConfig = {
 | |
|         Type = "forking";
 | |
|         User = "mosquitto";
 | |
|         Group = "mosquitto";
 | |
|         RuntimeDirectory = "mosquitto";
 | |
|         WorkingDirectory = cfg.dataDir;
 | |
|         Restart = "on-failure";
 | |
|         ExecStart = "${pkgs.mosquitto}/bin/mosquitto -c ${mosquittoConf} -d";
 | |
|         ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
 | |
|         PIDFile = "/run/mosquitto/pid";
 | |
|       };
 | |
|       preStart = ''
 | |
|         rm -f ${cfg.dataDir}/passwd
 | |
|         touch ${cfg.dataDir}/passwd
 | |
|       '' + concatStringsSep "\n" (
 | |
|         mapAttrsToList (n: c:
 | |
|           if c.hashedPassword != null then
 | |
|             "echo '${n}:${c.hashedPassword}' >> ${cfg.dataDir}/passwd"
 | |
|           else optionalString (c.password != null)
 | |
|             "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} ${c.password}"
 | |
|         ) cfg.users);
 | |
|     };
 | |
| 
 | |
|     users.users.mosquitto = {
 | |
|       description = "Mosquitto MQTT Broker Daemon owner";
 | |
|       group = "mosquitto";
 | |
|       uid = config.ids.uids.mosquitto;
 | |
|       home = cfg.dataDir;
 | |
|       createHome = true;
 | |
|     };
 | |
| 
 | |
|     users.groups.mosquitto.gid = config.ids.gids.mosquitto;
 | |
| 
 | |
|   };
 | |
| }
 | 
