File: //var/lib/puppet/lib/puppet/provider/hdssh_authorized_key/parsed.rb
require 'puppet/util/logging'
Puppet::Type.type(:hdssh_authorized_key).provide(
:parsed,
:parent => Puppet::Provider
) do
desc "Parse and generate authorized_keys files for SSH."
attr_accessor :present
attr_accessor :absent
attr_accessor :purge
attr_accessor :user
attr_accessor :target
attr_accessor :real_lines
def dir_perm
0700
end
def file_perm
0600
end
def create
userinfo = Etc.getpwnam(@resource.value(:user))
if userinfo == nil
raise Puppet::Error "Could not get uid for user #{@resource.value(:user)}"
else
uid = userinfo.uid
end
#Make sure we can write to the file
target = @resource.value(:target)
if File.exists?('/usr/bin/lsattr') and File.exists?('/usr/bin/chattr') and File.exists?(target)
if %x[/usr/bin/lsattr #{target}] =~ /^[^i]*i[^i]*\s+/
output = %x[/usr/bin/chattr -ia #{target}]
if not $?.success?
raise Puppet::Error, "Could not chattr -ia authorized keys file"
end
end
end
unless File.exist?(dir = File.dirname(target))
Puppet.info "Creating #{dir}"
Dir.mkdir(dir, dir_perm)
File.chown(uid, nil, dir)
end
#Write the file. Existing lines first, then the real keys
begin
f = File.new(target,'w')
f.write("### SSH keys managed by Puppet\n### If you have any questions, please contact the support department\n")
@real_lines.each do |line|
f.write(line)
end
@resource.value(:present).each do |key|
if key =~ /\S+/
f.write(key+"\n")
end
end
f.close
File.chown(uid, nil, target)
File.chmod(file_perm, target)
rescue Exception => e
raise Puppet::Error, "Could not write SSH authorized keys file '#{target}' (#{e})"
end
end
def exists?
#Puppet.send_log(:warning, @resource.value(:present).join("\n\n"))
#Puppet.send_log(:warning, @resource.value(:absent).join("\n\n"))
@real_lines = [] #The real set of lines to use. Only put comments and unmanaged keys in here. We'll stick the real keys in the file in the 'create' function
#Read the target file (if it exists), and compare each line to the list of 'present' keys. If we get something else, and purge is true, then we have to call create
if not File.exists?(@resource.value(:target))
if (@resource.value(:present).length == 0)
return true
else
@resource.value(:present).each do |key|
Puppet.send_log(:notice, "Adding SSH key: #{key}")
end
return false
end
end
present_key_found = [] #true/false whether the key at index x of present keys array was found in the file itself. If any of these are 0 at the end, then we need to run create
@resource.value(:present).each do |key|
present_key_found.push(false)
end
ret = true
lines = File.readlines(@resource.value(:target))
lines.each do |line|
#Don't toss the banner in there, it'll get readded later
if line == "### SSH keys managed by Puppet\n" or line == "### If you have any questions, please contact the support department\n"
next
end
if line =~ /^\s*#/ or line =~ /^\s*$/
@real_lines.push(line)
Puppet.send_log(:debug, "Found comment line in authorized keys")
next
end
found = false
@resource.value(:present).each_with_index do |key, i|
if line =~ /#{Regexp.escape(key)}/
Puppet.send_log(:debug,"Found SSH key that was supposed to be here: #{key}")
present_key_found[i] = true
found = true
break
end
end
if !found
if @resource.value(:purge) == :true
Puppet.send_log(:notice,"Removing SSH key found that is not in the whitelist: #{line.strip}")
ret = false
else
found = false
@resource.value(:absent).each do |key|
#If a key that is supposed to be absent is actually in the file, return false, so we can get rid of it
if line =~ /#{Regexp.escape(key)}/
Puppet.send_log(:notice,"Removing SSH key that was in the blacklist: #{key}")
found = true
ret = false
break
end
end
if ! found
@real_lines.push(line)
end
end
end
end
if ret
#Make sure that EVERY key that is supposed to be here actually is present
present_key_found.each_with_index do |found, i|
if found == false
Puppet.send_log(:notice, "Adding SSH key: #{@resource.value(:present)[i]}")
ret = false;
end
end
return ret
else
return false
end
end
def destroy
end
end