diff options
author | root <root@collector.localdomain> | 2010-03-11 20:23:27 -0600 |
---|---|---|
committer | root <root@collector.localdomain> | 2010-03-11 20:23:27 -0600 |
commit | 9882c5ddb540ce1e36e7b72a47fe578abe79c9b4 (patch) | |
tree | cd117f327dd1d37526edc7a906aaa96d3db210cd |
First commit for sudoers module.
This doesnt work... yet.
-rw-r--r-- | NOTES | 5 | ||||
-rw-r--r-- | README | 5 | ||||
-rw-r--r-- | files/sudoers | 27 | ||||
-rw-r--r-- | lib/puppet/provider/sudoers/parsed.rb | 123 | ||||
-rw-r--r-- | lib/puppet/type/sudoers.rb | 94 | ||||
-rw-r--r-- | manifests/init.pp | 10 | ||||
-rw-r--r-- | manifests/tests/sudo.pp | 1 | ||||
-rw-r--r-- | tests/sudo.pp | 1 | ||||
-rw-r--r-- | tests/sudoers-delete.pp | 21 | ||||
-rw-r--r-- | tests/sudoers.pp | 21 |
10 files changed, 308 insertions, 0 deletions
@@ -0,0 +1,5 @@ +only properties can be accessed by the parsedfile provider, this sucks. + +what is the difference between self.function and function? why must I use self for everything? + +I will not support multiline @@ -0,0 +1,5 @@ +This is a type and a provider for managing sudoers file. + +It doesnt work yet, but it will. still trying to learn how parsedfile works and how much I can push its boundaries. + +It will update this README when its ready for consumption. diff --git a/files/sudoers b/files/sudoers new file mode 100644 index 0000000..bb03635 --- /dev/null +++ b/files/sudoers @@ -0,0 +1,27 @@ +# +# DO NOT EDIT! This file is managed by Puppet so any changes you make locally will be lost. +# +## Command Aliases +## These are groups of related commands... + +## Installation and management of software +Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/up2date, /usr/bin/yum, /sbin/service httpd *, /sbin/service interchange *, /sbin/service puppet *, /sbin/service mvc_cached * + +# +# This flag needs to be off for ControlTier to work: +# +# Defaults requiretty +Defaults env_reset +Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE INPUTRC KDEDIR \ + LS_COLORS MAIL PS1 PS2 QTDIR USERNAME \ + LANG LC_ADDRESS LC_CTYPE LC_COLLATE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC \ + LC_PAPER LC_TELEPHONE LC_TIME LC_ALL LANGUAGE LINGUAS \ + _XKB_CHARSET XAUTHORITY" +# +# User and group based sudo permissions +# + +root ALL=(ALL) ALL +%wheel ALL=(ALL) ALL +%interch ALL=NOPASSWD: SOFTWARE diff --git a/lib/puppet/provider/sudoers/parsed.rb b/lib/puppet/provider/sudoers/parsed.rb new file mode 100644 index 0000000..520eef5 --- /dev/null +++ b/lib/puppet/provider/sudoers/parsed.rb @@ -0,0 +1,123 @@ +require 'puppet/provider/parsedfile' +sudoers = "/etc/sudoers" + +# +# crontab does the same thing, it uses a comment to specify uniqueness +# + +Puppet::Type.type(:sudoers).provide( + :parsed, + :parent => Puppet::Provider::ParsedFile, + :default_target => '/etc/sudoers', + # what the heck does this mean? + :filetype => :flat +) do + + desc "The sudoers provider that uses the ParsedFile class" + + commands :visudo => 'visudo' + + # this is just copied from hosts + text_line :comment, :match => %r{^#}, :post_parse => proc { |record| + # we determine the name from the comment above user spec lines + if record[:line] =~ /Puppet Name: (.+)\s*$/ +# ok, we set record name, but how is this applied to the next line? + record[:name] = $1 + end + } + + text_line :blank, :match => /^\s*$/; + + # ignore for now, I will support this line later + text_line :defaults, :match => /^Defaults/ + +# I need to parse the , delim list into an array +# I am pretty sure that I would do this with a block statement + +# +# it seems like I have to put type here for it to be accessible to +# to_line +# + + +# not bothering to specify match or fields, I will determine all of this +# in post_parse + +# parse everything else? + record_line :parsed, :fields => %w{line}, + :match => /(.*)/, + :post_parse => proc { |hash| + puts "\npost_parse" + puts hash[:line] + if (hash[:line] =~ /^\s*(User_Alias|Runas_Alias|Host_Alias|Cmnd_Alias)\s+(\S+)\s*=\s*(.+)$/) + hash[:sudo_alias] = $1 + hash[:name] = $2 + hash[:items] = $3 + hash[:items]=hash[:items].gsub(/\s/, '').split(',') + #puts hash.to_yaml + elsif (hash[:line] =~ /^(.*)?=(.*)$/) + # should name already be set when get get here? + hash = parse_user_spec($1, $2) + else + raise ArgumentError, "unexpected line #{hash[:line]}" + end + } + + def self.parse_user_spec(lhs, rhs) + lhs_array = lhs.split(',') + end + + def self.to_line(hash) + puts "\nEntering self.to_line for #{hash[:name]}" + puts hash.to_yaml + # dynamically call a function based on the value of hash[:type] + if(hash[:type] == 'alias') + self.alias_to_line(hash) + elsif(hash[:type] == 'spec') + spec_to_line(hash) + elsif(hash[:type] == 'default') + default_to_line(hash) + end + end + + def self.spec_to_line(hash) + "spec" + end + + def self.alias_to_line(hash) + # do I need to ensure that the required elements are here? + # shouldnt the type do that? check file, its similar + # since different attributes make sense based on ensure value (dir/file/symlink) + items=hash[:items] + items=items.join(',') if items.class == Array + "#{hash[:sudo_alias]} #{hash[:name]}=#{items}" + end + + def default_to_line(hash) + "default" + end + + def self.flush(record) +# a little pre-flush host visudo action +# + super(record) + end + +# lets assume that runas is always there and lets not deal with options yet +# record_line :spec, :fields => %w{users hosts runas specs type}, +# :match => %r{(\S+)\s+(\S+)=(\(\S+\))\s+(.+)}, +# :post_parse => proc { |hash| +# puts 'spec' +# } + +# I dont know if I can properly support multiple commands +# because they are composite, one command, one runas, multiple tags +# record_line :spec, :fields => %w{user host runas tags commands name}, +# :match => %r{^\s*(\S+)\s+(\S+)\s*=\s*(\(\S+\))?(.+)$}, +# :optional => %w{runas tags} + +# I need to override flush to validate sudoers +# +# +# +end diff --git a/lib/puppet/type/sudoers.rb b/lib/puppet/type/sudoers.rb new file mode 100644 index 0000000..6c94269 --- /dev/null +++ b/lib/puppet/type/sudoers.rb @@ -0,0 +1,94 @@ +Puppet::Type.newtype(:sudoers) do + @doc = "Manage the contents of /etc/sudoers + +there are two types of things here: + + sudoer{'NAME': + ensure => (absent|present) + type => (alias|spec) # required?? + alias => (User_alias|Runas_alias|Host_alias|Cmnd_alias), + items => [] # this is only for aliases + user_list => [] + host_list => [] + operator_list => [] + # NOPASSWD, PASSWD, NOEXEC, EXEC, SETENV and NOSETENV + tag_list => [] + command_list => [] + } + + alias NAME - starts with CAP ([A-Z]([A-Z][0-9]_)*) + +aliases, user specifications + User_alias + Runas_alias + Host_alias + Cmnd_alias + +alias spec: + + Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 + + +order matters!! + + + " + # we can either remove or add lines + # they should also be purgable?(whats the namesvar for specs?) + ensurable + + newparam(:name) do + desc "Either the name of the alias to create + or for user specification, a random string in a comment that serves as a place holder (kind of ugly, but its true) + " + + isnamevar + end + +# +# this has to be a property to be found by parsedfile, but +# its really a parameter + + newproperty(:type) do + desc "Either determines which type of sudo configuration line is + is being managed. Either user_spec or alias" + end + + newproperty(:sudo_alias) do + desc "Types of alias." + end + + newproperty(:items, :array_matching => :all) do + desc "list of items applied to an alias" + end + + newproperty(:target) do + desc "Location of the shells file" + + defaultto do + if + @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile) + @resource.class.defaultprovider.default_target + else + nil + end + end + end + + newproperty(:users, :array_matching => :all) do + desc "list of users for user spec" + end + + newproperty(:hosts, :array_matching => :all) do + desc "list of hosts for user spec" + end + + newproperty(:runas, :array_matching => :all) do + desc "user to run commands as" + end + newproperty(:commands, :array_matching => :all) do + desc "commands to run" + end + +end + diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..ba052c2 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,10 @@ +# sudo class +class sudo { + package { "sudo": ensure => present } + file{"/etc/sudoers": + owner => "root", + group => "root", + mode => "400", + source => ["puppet:///modules/site-files/sudoers", "puppet:///modules/sudo/sudoers" ] + } +} diff --git a/manifests/tests/sudo.pp b/manifests/tests/sudo.pp new file mode 100644 index 0000000..a27b70b --- /dev/null +++ b/manifests/tests/sudo.pp @@ -0,0 +1 @@ +include sudo diff --git a/tests/sudo.pp b/tests/sudo.pp new file mode 100644 index 0000000..a27b70b --- /dev/null +++ b/tests/sudo.pp @@ -0,0 +1 @@ +include sudo diff --git a/tests/sudoers-delete.pp b/tests/sudoers-delete.pp new file mode 100644 index 0000000..3085a63 --- /dev/null +++ b/tests/sudoers-delete.pp @@ -0,0 +1,21 @@ +sudoers{'blah1': + target => '/tmp/sudoers', + ensure => absent, + alias => 'Cmnd_Alias', + items => ['blah4', 'blah2'], + linetype => 'alias', +} +#sudoers{'blah2': +# target => '/tmp/sudoers', +## ensure => present, +# alias => 'Host_Alias', +# items => ['blah2', 'blah3'], +# type => 'alias', +#} +##sudoers{'blah3': +# target => '/tmp/sudoers', +## ensure => present, +# users => 'dan', +# hosts => 'localhost', +# type => 'spec', +#} diff --git a/tests/sudoers.pp b/tests/sudoers.pp new file mode 100644 index 0000000..ee829d1 --- /dev/null +++ b/tests/sudoers.pp @@ -0,0 +1,21 @@ +sudoers{'blah1': + #target => '/tmp/sudoers', + ensure => present, + sudo_alias => 'Cmnd_Alias', + items => ['blah4', 'blah2'], + type => 'alias', +} +sudoers{'blah2': + #target => '/tmp/sudoers', + ensure => present, + sudo_alias => 'Host_Alias', + items => ['blah2', 'blah3'], + type => 'alias', +} +#sudoers{'blah3': +# target => '/tmp/sudoers', +# ensure => present, +# users => 'dan', +# hosts => 'localhost', +# type => 'spec', +#} |