| 
									
										
										
										
											2014-04-14 16:26:48 +02:00
										 |  |  |  | { config, lib, pkgs, ... }: | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 16:26:48 +02:00
										 |  |  |  | with lib; | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | let | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   cfg = config.security.sudo; | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |   inherit (pkgs) sudo; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |   toUserString = user: if (isInt user) then "#${toString user}" else "${user}"; | 
					
						
							|  |  |  |  |   toGroupString = group: if (isInt group) then "%#${toString group}" else "%${group}"; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   toCommandOptionsString = options: | 
					
						
							|  |  |  |  |     "${concatStringsSep ":" options}${optionalString (length options != 0) ":"} "; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   toCommandsString = commands: | 
					
						
							|  |  |  |  |     concatStringsSep ", " ( | 
					
						
							|  |  |  |  |       map (command: | 
					
						
							|  |  |  |  |         if (isString command) then | 
					
						
							|  |  |  |  |           command | 
					
						
							|  |  |  |  |         else | 
					
						
							|  |  |  |  |           "${toCommandOptionsString command.options}${command.command}" | 
					
						
							|  |  |  |  |       ) commands | 
					
						
							|  |  |  |  |     ); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  | in | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   ###### interface | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   options = { | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |     security.sudo.enable = mkOption { | 
					
						
							| 
									
										
										
										
											2013-10-30 17:37:45 +01:00
										 |  |  |  |       type = types.bool; | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |       default = true; | 
					
						
							|  |  |  |  |       description = | 
					
						
							|  |  |  |  |         ''
 | 
					
						
							|  |  |  |  |           Whether to enable the <command>sudo</command> command, which | 
					
						
							|  |  |  |  |           allows non-root users to execute commands as root. | 
					
						
							|  |  |  |  |         '';
 | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-01 13:00:52 +02:00
										 |  |  |  |     security.sudo.package = mkOption { | 
					
						
							|  |  |  |  |       type = types.package; | 
					
						
							|  |  |  |  |       default = pkgs.sudo; | 
					
						
							|  |  |  |  |       defaultText = "pkgs.sudo"; | 
					
						
							|  |  |  |  |       description = ''
 | 
					
						
							|  |  |  |  |         Which package to use for `sudo`. | 
					
						
							|  |  |  |  |       '';
 | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-13 14:37:32 +02:00
										 |  |  |  |     security.sudo.wheelNeedsPassword = mkOption { | 
					
						
							| 
									
										
										
										
											2013-10-30 17:37:45 +01:00
										 |  |  |  |       type = types.bool; | 
					
						
							| 
									
										
										
										
											2012-08-13 14:37:32 +02:00
										 |  |  |  |       default = true; | 
					
						
							|  |  |  |  |       description = | 
					
						
							|  |  |  |  |         ''
 | 
					
						
							| 
									
										
										
										
											2018-03-16 21:50:46 +00:00
										 |  |  |  |           Whether users of the <code>wheel</code> group must | 
					
						
							|  |  |  |  |           provide a password to run commands as super user via <command>sudo</command>. | 
					
						
							| 
									
										
										
										
											2013-04-03 12:54:40 +02:00
										 |  |  |  |         '';
 | 
					
						
							| 
									
										
										
										
											2012-08-13 14:37:32 +02:00
										 |  |  |  |       }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |     security.sudo.configFile = mkOption { | 
					
						
							| 
									
										
										
										
											2013-10-30 17:37:45 +01:00
										 |  |  |  |       type = types.lines; | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |       # Note: if syntax errors are detected in this file, the NixOS | 
					
						
							|  |  |  |  |       # configuration will fail to build. | 
					
						
							|  |  |  |  |       description = | 
					
						
							|  |  |  |  |         ''
 | 
					
						
							|  |  |  |  |           This string contains the contents of the | 
					
						
							|  |  |  |  |           <filename>sudoers</filename> file. | 
					
						
							|  |  |  |  |         '';
 | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2014-10-30 13:59:21 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |     security.sudo.extraRules = mkOption { | 
					
						
							|  |  |  |  |       description = ''
 | 
					
						
							|  |  |  |  |         Define specific rules to be in the <filename>sudoers</filename> file. | 
					
						
							| 
									
										
										
										
											2018-07-01 15:26:07 -04:00
										 |  |  |  |         More specific rules should come after more general ones in order to | 
					
						
							|  |  |  |  |         yield the expected behavior. You can use mkBefore/mkAfter to ensure | 
					
						
							|  |  |  |  |         this is the case when configuration options are merged. | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |       '';
 | 
					
						
							|  |  |  |  |       default = []; | 
					
						
							| 
									
										
										
										
											2020-02-10 01:37:07 +01:00
										 |  |  |  |       example = literalExample ''
 | 
					
						
							|  |  |  |  |         [ | 
					
						
							|  |  |  |  |           # Allow execution of any command by all users in group sudo, | 
					
						
							|  |  |  |  |           # requiring a password. | 
					
						
							|  |  |  |  |           { groups = [ "sudo" ]; commands = [ "ALL" ]; } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           # Allow execution of "/home/root/secret.sh" by user `backup`, `database` | 
					
						
							|  |  |  |  |           # and the group with GID `1006` without a password. | 
					
						
							|  |  |  |  |           { users = [ "backup" "database" ]; groups = [ 1006 ]; | 
					
						
							|  |  |  |  |             commands = [ { command = "/home/root/secret.sh"; options = [ "SETENV" "NOPASSWD" ]; } ]; } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           # Allow all users of group `bar` to run two executables as user `foo` | 
					
						
							|  |  |  |  |           # with arguments being pre-set. | 
					
						
							|  |  |  |  |           { groups = [ "bar" ]; runAs = "foo"; | 
					
						
							|  |  |  |  |             commands = | 
					
						
							|  |  |  |  |               [ "/home/baz/cmd1.sh hello-sudo" | 
					
						
							|  |  |  |  |                   { command = '''/home/baz/cmd2.sh ""'''; options = [ "SETENV" ]; } ]; }
 | 
					
						
							|  |  |  |  |         ] | 
					
						
							|  |  |  |  |       '';
 | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |       type = with types; listOf (submodule { | 
					
						
							|  |  |  |  |         options = { | 
					
						
							|  |  |  |  |           users = mkOption { | 
					
						
							| 
									
										
										
										
											2019-08-08 22:48:27 +02:00
										 |  |  |  |             type = with types; listOf (either str int); | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |             description = ''
 | 
					
						
							|  |  |  |  |               The usernames / UIDs this rule should apply for. | 
					
						
							|  |  |  |  |             '';
 | 
					
						
							|  |  |  |  |             default = []; | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           groups = mkOption { | 
					
						
							| 
									
										
										
										
											2019-08-08 22:48:27 +02:00
										 |  |  |  |             type = with types; listOf (either str int); | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |             description = ''
 | 
					
						
							|  |  |  |  |               The groups / GIDs this rule should apply for. | 
					
						
							|  |  |  |  |             '';
 | 
					
						
							|  |  |  |  |             default = []; | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           host = mkOption { | 
					
						
							| 
									
										
										
										
											2019-08-08 22:48:27 +02:00
										 |  |  |  |             type = types.str; | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |             default = "ALL"; | 
					
						
							|  |  |  |  |             description = ''
 | 
					
						
							|  |  |  |  |               For what host this rule should apply. | 
					
						
							|  |  |  |  |             '';
 | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           runAs = mkOption { | 
					
						
							| 
									
										
										
										
											2019-08-08 22:48:27 +02:00
										 |  |  |  |             type = with types; str; | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |             default = "ALL:ALL"; | 
					
						
							|  |  |  |  |             description = ''
 | 
					
						
							|  |  |  |  |               Under which user/group the specified command is allowed to run. | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |               A user can be specified using just the username: <code>"foo"</code>. | 
					
						
							|  |  |  |  |               It is also possible to specify a user/group combination using <code>"foo:bar"</code> | 
					
						
							|  |  |  |  |               or to only allow running as a specific group with <code>":bar"</code>. | 
					
						
							|  |  |  |  |             '';
 | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           commands = mkOption { | 
					
						
							|  |  |  |  |             description = ''
 | 
					
						
							|  |  |  |  |               The commands for which the rule should apply. | 
					
						
							|  |  |  |  |             '';
 | 
					
						
							| 
									
										
										
										
											2019-08-08 22:48:27 +02:00
										 |  |  |  |             type = with types; listOf (either str (submodule { | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |               options = { | 
					
						
							|  |  |  |  |                 command = mkOption { | 
					
						
							| 
									
										
										
										
											2019-08-08 22:48:27 +02:00
										 |  |  |  |                   type = with types; str; | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |                   description = ''
 | 
					
						
							|  |  |  |  |                     A command being either just a path to a binary to allow any arguments, | 
					
						
							|  |  |  |  |                     the full command with arguments pre-set or with <code>""</code> used as the argument, | 
					
						
							|  |  |  |  |                     not allowing arguments to the command at all. | 
					
						
							|  |  |  |  |                   '';
 | 
					
						
							|  |  |  |  |                 }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 options = mkOption { | 
					
						
							|  |  |  |  |                   type = with types; listOf (enum [ "NOPASSWD" "PASSWD" "NOEXEC" "EXEC" "SETENV" "NOSETENV" "LOG_INPUT" "NOLOG_INPUT" "LOG_OUTPUT" "NOLOG_OUTPUT" ]); | 
					
						
							|  |  |  |  |                   description = ''
 | 
					
						
							|  |  |  |  |                     Options for running the command. Refer to the <a href="https://www.sudo.ws/man/1.7.10/sudoers.man.html">sudo manual</a>. | 
					
						
							|  |  |  |  |                   '';
 | 
					
						
							|  |  |  |  |                   default = []; | 
					
						
							|  |  |  |  |                 }; | 
					
						
							|  |  |  |  |               }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             })); | 
					
						
							|  |  |  |  |           }; | 
					
						
							|  |  |  |  |         }; | 
					
						
							|  |  |  |  |       }); | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-30 13:59:21 +01:00
										 |  |  |  |     security.sudo.extraConfig = mkOption { | 
					
						
							|  |  |  |  |       type = types.lines; | 
					
						
							|  |  |  |  |       default = ""; | 
					
						
							|  |  |  |  |       description = ''
 | 
					
						
							|  |  |  |  |         Extra configuration text appended to <filename>sudoers</filename>. | 
					
						
							|  |  |  |  |       '';
 | 
					
						
							|  |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |   ###### implementation | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |   config = mkIf cfg.enable { | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-10 21:49:52 -07:00
										 |  |  |  |     # We `mkOrder 600` so that the default rule shows up first, but there is | 
					
						
							|  |  |  |  |     # still enough room for a user to `mkBefore` it. | 
					
						
							|  |  |  |  |     security.sudo.extraRules = mkOrder 600 [ | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |       { groups = [ "wheel" ]; | 
					
						
							|  |  |  |  |         commands = [ { command = "ALL"; options = (if cfg.wheelNeedsPassword then [ "SETENV" ] else [ "NOPASSWD" "SETENV" ]); } ]; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     ]; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-23 15:14:16 +01:00
										 |  |  |  |     security.sudo.configFile = | 
					
						
							|  |  |  |  |       ''
 | 
					
						
							| 
									
										
										
										
											2014-10-30 13:59:21 +01:00
										 |  |  |  |         # Don't edit this file. Set the NixOS options ‘security.sudo.configFile’ | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |         # or ‘security.sudo.extraRules’ instead. | 
					
						
							| 
									
										
										
										
											2012-11-23 15:14:16 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         # Keep SSH_AUTH_SOCK so that pam_ssh_agent_auth.so can do its magic. | 
					
						
							|  |  |  |  |         Defaults env_keep+=SSH_AUTH_SOCK | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # "root" is allowed to do anything. | 
					
						
							| 
									
										
										
										
											2016-09-13 23:15:56 +10:00
										 |  |  |  |         root        ALL=(ALL:ALL) SETENV: ALL | 
					
						
							| 
									
										
										
										
											2012-11-23 15:14:16 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-17 21:56:08 +07:00
										 |  |  |  |         # extraRules | 
					
						
							|  |  |  |  |         ${concatStringsSep "\n" ( | 
					
						
							|  |  |  |  |           lists.flatten ( | 
					
						
							|  |  |  |  |             map ( | 
					
						
							|  |  |  |  |               rule: if (length rule.commands != 0) then [ | 
					
						
							|  |  |  |  |                 (map (user: "${toUserString user}	${rule.host}=(${rule.runAs})	${toCommandsString rule.commands}") rule.users) | 
					
						
							|  |  |  |  |                 (map (group: "${toGroupString group}	${rule.host}=(${rule.runAs})	${toCommandsString rule.commands}") rule.groups) | 
					
						
							|  |  |  |  |               ] else [] | 
					
						
							|  |  |  |  |             ) cfg.extraRules | 
					
						
							|  |  |  |  |           ) | 
					
						
							|  |  |  |  |         )} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-30 13:59:21 +01:00
										 |  |  |  |         ${cfg.extraConfig} | 
					
						
							| 
									
										
										
										
											2012-11-23 15:14:16 +01:00
										 |  |  |  |       '';
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-29 05:33:56 -06:00
										 |  |  |  |     security.wrappers = { | 
					
						
							| 
									
										
										
										
											2020-10-01 13:00:52 +02:00
										 |  |  |  |       sudo.source = "${cfg.package.out}/bin/sudo"; | 
					
						
							|  |  |  |  |       sudoedit.source = "${cfg.package.out}/bin/sudoedit"; | 
					
						
							| 
									
										
										
										
											2017-01-29 05:33:56 -06:00
										 |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |     environment.systemPackages = [ sudo ]; | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-15 14:47:51 +02:00
										 |  |  |  |     security.pam.services.sudo = { sshAgentAuth = true; }; | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-14 19:51:29 +02:00
										 |  |  |  |     environment.etc.sudoers = | 
					
						
							| 
									
										
										
										
											2014-06-09 00:54:13 +04:00
										 |  |  |  |       { source = | 
					
						
							|  |  |  |  |           pkgs.runCommand "sudoers" | 
					
						
							| 
									
										
										
										
											2018-11-08 11:59:03 +01:00
										 |  |  |  |           { | 
					
						
							|  |  |  |  |             src = pkgs.writeText "sudoers-in" cfg.configFile; | 
					
						
							|  |  |  |  |             preferLocalBuild = true; | 
					
						
							|  |  |  |  |           } | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  |           # Make sure that the sudoers file is syntactically valid. | 
					
						
							|  |  |  |  |           # (currently disabled - NIXOS-66) | 
					
						
							| 
									
										
										
										
											2018-02-28 14:37:26 -05:00
										 |  |  |  |           "${pkgs.buildPackages.sudo}/sbin/visudo -f $src -c && cp $src $out"; | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  |         mode = "0440"; | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  |       }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2009-08-16 14:49:14 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-02 16:07:15 +00:00
										 |  |  |  | } |