All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
2 Optional[String[1]] $sudogroup = undef,
4 $include_directory = '/etc/sudoers.d'
9 validate_cmd => "sh -c 'if ! visudo --check --file=%; then cat %; exit 1; fi'",
11 $default_target = '00-defaults'
15 include sudo::defaults
18 Optional[String[1]] $parameter = undef,
19 Variant[String[1],Array[String[1]],Integer,Boolean] $value = true,
20 Enum['generic','host','user','cmnd','runas'] $context = 'generic',
21 Optional[Variant[Array[String[1]],String[1]]] $list = undef,
22 String[1] $target = $sudo::default_target,
24 Optional[String[1]] $comment = undef,
25 Boolean $newline_before = true,
27 $param = $parameter ? { undef => $name, default => $parameter }
28 $_list = type($list) ? { list => $list, default => [$list] }
29 sudo::internals::add_sudoers_fragment { "${name}":
31 content => template("sudo/option_line.erb"),
38 Enum['host','user','cmnd','runas'] $type,
39 Optional[Variant[Array[String[1]],String[1]]] $list = undef,
40 String[1] $target = $sudo::default_target,
42 Optional[String[1]] $comment = undef,
43 Boolean $newline_before = true,
45 if $name !~ /^[[:upper:]][[:upper:]_[:digit:]]*$/ {
46 fail("sudoers alias definition '$name' can only contain uppercase letter, numbers, and the underscore")
48 $_list = type($list) ? { list => $list, default => [$list] }
49 sudo::internals::add_sudoers_fragment { "${name}":
51 content => template("sudo/alias_line.erb"),
58 Variant[Array[String[1]],String[1]] $who,
59 Variant[Array[String[1]],String[1]] $where = 'ALL',
60 Optional[Variant[Array[String[1]],String[1]]] $as_whom = 'ALL',
61 Optional[Variant[Array[String[1]],String[1]]] $as_group = 'ALL',
62 Variant[Array[String[1]],String[1]] $what,
63 String[1] $target = $sudo::default_target,
65 Optional[String[1]] $comment = undef,
66 Boolean $newline_before = true,
69 $_comment = $comment ? { undef => $name, default => $comment }
70 sudo::internals::add_sudoers_fragment { "${name}":
72 content => template("sudo/rule_line.erb"),
88 $include_directory = $sudo::include_directory
90 * => $sudo::file_defaults
93 content => template("sudo/sudoers.erb"),
94 validate_cmd => "visudo --check --strict --file=%",
100 ignore => ["*.local","*-local-*","local-*"],
102 "$include_directory/README":
104 # This directory is managed by Puppet
106 # Local files can be named any of:
115 class sudo::defaults (
116 Optional[String[1]] $sudogroup = undef,
117 Boolean $root_may_sudo = true,
118 Optional[Hash] $generic = undef,
119 Optional[Hash] $user = undef,
120 Optional[Hash] $host = undef,
121 Optional[Hash] $runas = undef,
122 Optional[Hash] $cmnd = undef,
124 $netfacts = $facts[networking] ? { undef => $facts, default => $facts[networking] }
125 sudo::alias { "LOCALHOST":
127 list => [ "localhost"
128 , $netfacts[hostname]
134 $sudogroup_target = "00-sudogroup"
136 group { "$sudogroup":
140 sudo::rule { "sudogroup":
141 who => "%$sudogroup",
142 where => "LOCALHOST",
143 require => Sudo::Alias["LOCALHOST"],
144 what => "PASSWD: ALL",
145 target => "$sudogroup_target",
146 comment => "Members of the ${sudogroup} group can use sudo (with password)",
151 $rootsudo_target = "00-root_may_sudo"
153 sudo::option { "syslog":
157 target => "$rootsudo_target",
158 comment => "No need to log root usage of sudo",
160 sudo::rule { "root_may_sudo":
162 where => "LOCALHOST",
163 require => Sudo::Alias["LOCALHOST"],
164 what => "NOPASSWD: ALL",
165 target => "$rootsudo_target",
166 comment => "root may inadvertedly run sudo, so let them:",
171 concat::fragment { "sudo::defaults::generic comment":
172 target => "sudoers_file_$sudo::default_target",
174 content => "\n# Generated from the sudo::defaults::generic class parameter:\n",
176 $generic.each | $param, $value | {
177 sudo::option { "$param":
180 newline_before => false,
181 require => Concat::Fragment["sudo::defaults::generic comment"],
184 concat::fragment { "sudo::defaults::generic end":
185 target => "sudoers_file_$sudo::default_target",
187 content => "# End sudo::defaults::generic class parameters\n",
191 $context_hash = {"user"=>$user,"host"=>$host,"runas"=>$runas,"cmnd"=>$cmnd}
192 $context_hash.keys.each | $index, $context | {
193 $defaults = $context_hash[$context]
195 concat::fragment { "sudo::defaults::${context} comment":
196 target => "sudoers_$default_target",
197 order => 17 + $index * 3,
198 content => "\n# Generated from the sudo::defaults::${context} class parameter:\n",
200 $defaults.each | $list, $items | {
201 $items.each | $param, $value | {
202 sudo::option { "${context}_${list}_${param}":
207 order => 18 + $index * 3,
208 newline_before => false,
212 concat::fragment { "sudo::defaults::${context} end":
213 target => "sudoers_$default_target",
214 order => 19 + $index * 3,
215 content => "# End sudo::defaults::${context} class parameters\n",
221 class sudo::internals {
223 define add_sudoers_fragment (
227 Optional[String[1]] $comment = undef,
229 sudo::internals::ensure_sudoers_file { "${name}":
232 $ts = strftime("%s.%N")
233 # include the timestamp to preserve order in the output if execution
235 concat::fragment { "${ts}_sudoers_fragment_${target}_${name}":
236 target => "sudoers_file_${target}",
241 define ensure_sudoers_file(
244 ensure_resource('concat', "sudoers_file_${target}", {
246 path => "${sudo::include_directory}/$target",
247 warn => "# THIS FILE IS MANAGED BY PUPPET; CHANGES WILL BE OVERWRITTEN\n",
248 require => File[$sudo::include_directory],
249 } + $sudo::file_defaults,