vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / security / doas.nix
blob457a48a987aab001c0971fd47352854808b8319a
1 { config, lib, pkgs, ... }:
3 with lib;
4 let
5   cfg = config.security.doas;
7   inherit (pkgs) doas;
9   mkUsrString = user: toString user;
11   mkGrpString = group: ":${toString group}";
13   mkOpts = rule: concatStringsSep " " [
14     (optionalString rule.noPass "nopass")
15     (optionalString rule.noLog "nolog")
16     (optionalString rule.persist "persist")
17     (optionalString rule.keepEnv "keepenv")
18     "setenv { SSH_AUTH_SOCK TERMINFO TERMINFO_DIRS ${concatStringsSep " " rule.setEnv} }"
19   ];
21   mkArgs = rule:
22     if (rule.args == null) then ""
23     else if (length rule.args == 0) then "args"
24     else "args ${concatStringsSep " " rule.args}";
26   mkRule = rule:
27     let
28       opts = mkOpts rule;
30       as = optionalString (rule.runAs != null) "as ${rule.runAs}";
32       cmd = optionalString (rule.cmd != null) "cmd ${rule.cmd}";
34       args = mkArgs rule;
35     in
36     optionals (length cfg.extraRules > 0) [
37       (
38         optionalString (length rule.users > 0)
39           (map (usr: "permit ${opts} ${mkUsrString usr} ${as} ${cmd} ${args}") rule.users)
40       )
41       (
42         optionalString (length rule.groups > 0)
43           (map (grp: "permit ${opts} ${mkGrpString grp} ${as} ${cmd} ${args}") rule.groups)
44       )
45     ];
49   ###### interface
51   options.security.doas = {
53     enable = mkOption {
54       type = with types; bool;
55       default = false;
56       description = ''
57         Whether to enable the {command}`doas` command, which allows
58         non-root users to execute commands as root.
59       '';
60     };
62     wheelNeedsPassword = mkOption {
63       type = with types; bool;
64       default = true;
65       description = ''
66         Whether users of the `wheel` group must provide a password to
67         run commands as super user via {command}`doas`.
68       '';
69     };
71     extraRules = mkOption {
72       default = [];
73       description = ''
74         Define specific rules to be set in the
75         {file}`/etc/doas.conf` file. More specific rules should
76         come after more general ones in order to yield the expected behavior.
77         You can use `mkBefore` and/or `mkAfter` to ensure
78         this is the case when configuration options are merged. Be aware that
79         this option cannot be used to override the behaviour allowing
80         passwordless operation for root.
81       '';
82       example = literalExpression ''
83         [
84           # Allow execution of any command by any user in group doas, requiring
85           # a password and keeping any previously-defined environment variables.
86           { groups = [ "doas" ]; noPass = false; keepEnv = true; }
88           # Allow execution of "/home/root/secret.sh" by user `backup` OR user
89           # `database` OR any member of the group with GID `1006`, without a
90           # password.
91           { users = [ "backup" "database" ]; groups = [ 1006 ];
92             cmd = "/home/root/secret.sh"; noPass = true; }
94           # Allow any member of group `bar` to run `/home/baz/cmd1.sh` as user
95           # `foo` with argument `hello-doas`.
96           { groups = [ "bar" ]; runAs = "foo";
97             cmd = "/home/baz/cmd1.sh"; args = [ "hello-doas" ]; }
99           # Allow any member of group `bar` to run `/home/baz/cmd2.sh` as user
100           # `foo` with no arguments.
101           { groups = [ "bar" ]; runAs = "foo";
102             cmd = "/home/baz/cmd2.sh"; args = [ ]; }
104           # Allow user `abusers` to execute "nano" and unset the value of
105           # SSH_AUTH_SOCK, override the value of ALPHA to 1, and inherit the
106           # value of BETA from the current environment.
107           { users = [ "abusers" ]; cmd = "nano";
108             setEnv = [ "-SSH_AUTH_SOCK" "ALPHA=1" "BETA" ]; }
109         ]
110       '';
111       type = with types; listOf (
112         submodule {
113           options = {
115             noPass = mkOption {
116               type = with types; bool;
117               default = false;
118               description = ''
119                 If `true`, the user is not required to enter a
120                 password.
121               '';
122             };
124             noLog = mkOption {
125               type = with types; bool;
126               default = false;
127               description = ''
128                 If `true`, successful executions will not be logged
129                 to
130                 {manpage}`syslogd(8)`.
131               '';
132             };
134             persist = mkOption {
135               type = with types; bool;
136               default = false;
137               description = ''
138                 If `true`, do not ask for a password again for some
139                 time after the user successfully authenticates.
140               '';
141             };
143             keepEnv = mkOption {
144               type = with types; bool;
145               default = false;
146               description = ''
147                 If `true`, environment variables other than those
148                 listed in
149                 {manpage}`doas(1)`
150                 are kept when creating the environment for the new process.
151               '';
152             };
154             setEnv = mkOption {
155               type = with types; listOf str;
156               default = [];
157               description = ''
158                 Keep or set the specified variables. Variables may also be
159                 removed with a leading '-' or set using
160                 `variable=value`. If the first character of
161                 `value` is a '$', the value to be set is taken from
162                 the existing environment variable of the indicated name. This
163                 option is processed after the default environment has been
164                 created.
166                 NOTE: All rules have `setenv { SSH_AUTH_SOCK }` by
167                 default. To prevent `SSH_AUTH_SOCK` from being
168                 inherited, add `"-SSH_AUTH_SOCK"` anywhere in this
169                 list.
170               '';
171             };
173             users = mkOption {
174               type = with types; listOf (either str int);
175               default = [];
176               description = "The usernames / UIDs this rule should apply for.";
177             };
179             groups = mkOption {
180               type = with types; listOf (either str int);
181               default = [];
182               description = "The groups / GIDs this rule should apply for.";
183             };
185             runAs = mkOption {
186               type = with types; nullOr str;
187               default = null;
188               description = ''
189                 Which user or group the specified command is allowed to run as.
190                 When set to `null` (the default), all users are
191                 allowed.
193                 A user can be specified using just the username:
194                 `"foo"`. It is also possible to only allow running as
195                 a specific group with `":bar"`.
196               '';
197             };
199             cmd = mkOption {
200               type = with types; nullOr str;
201               default = null;
202               description = ''
203                 The command the user is allowed to run. When set to
204                 `null` (the default), all commands are allowed.
206                 NOTE: It is best practice to specify absolute paths. If a
207                 relative path is specified, only a restricted PATH will be
208                 searched.
209               '';
210             };
212             args = mkOption {
213               type = with types; nullOr (listOf str);
214               default = null;
215               description = ''
216                 Arguments that must be provided to the command. When set to
217                 `[]`, the command must be run without any arguments.
218               '';
219             };
220           };
221         }
222       );
223     };
225     extraConfig = mkOption {
226       type = with types; lines;
227       default = "";
228       description = ''
229         Extra configuration text appended to {file}`doas.conf`. Be aware that
230         this option cannot be used to override the behaviour allowing
231         passwordless operation for root.
232       '';
233     };
234   };
237   ###### implementation
239   config = mkIf cfg.enable {
241     security.doas.extraRules = mkOrder 600 [
242       {
243         groups = [ "wheel" ];
244         noPass = !cfg.wheelNeedsPassword;
245       }
246     ];
248     security.wrappers.doas =
249       { setuid = true;
250         owner = "root";
251         group = "root";
252         source = "${doas}/bin/doas";
253       };
255     environment.systemPackages = [
256       doas
257     ];
259     security.pam.services.doas = {
260       allowNullPassword = true;
261       sshAgentAuth = true;
262     };
264     environment.etc."doas.conf" = {
265       source = pkgs.runCommand "doas-conf"
266         {
267           src = pkgs.writeText "doas-conf-in" ''
268             # To modify this file, set the NixOS options
269             # `security.doas.extraRules` or `security.doas.extraConfig`. To
270             # completely replace the contents of this file, use
271             # `environment.etc."doas.conf"`.
273             # extraRules
274             ${concatStringsSep "\n" (lists.flatten (map mkRule cfg.extraRules))}
276             # extraConfig
277             ${cfg.extraConfig}
279             # "root" is allowed to do anything.
280             permit nopass keepenv root
281           '';
282           preferLocalBuild = true;
283         }
284         # Make sure that the doas.conf file is syntactically valid.
285         "${pkgs.buildPackages.doas}/bin/doas -C $src && cp $src $out";
286       mode = "0440";
287     };
289   };
291   meta.maintainers = with maintainers; [ cole-h ];