Skip to content

Instantly share code, notes, and snippets.

@antaflos
Created October 11, 2018 13:33
Show Gist options
  • Save antaflos/1208b0cfa87a9aeb6a7151bd96da1268 to your computer and use it in GitHub Desktop.
Save antaflos/1208b0cfa87a9aeb6a7151bd96da1268 to your computer and use it in GitHub Desktop.
Puppet::Functions.create_function(:file_eyaml_lookup_key) do
unless Puppet.features.hiera_eyaml?
raise Puppet::DataBinding::LookupError, 'Lookup using function '\
'file_eyaml_lookup_key is only supported when the hiera_eyaml '\
'library is present'
end
dispatch :file_eyaml_lookup_key do
param 'String[1]', :key
param 'Hash[String[1],Any]', :options
param 'Puppet::LookupContext', :context
end
require 'hiera/backend/eyaml/options'
require 'hiera/backend/eyaml/encryptor'
def file_eyaml_lookup_key(key, options, context)
return context.cached_value(key) if context.cache_has_key(key)
# Set interpolate = true by default and override it with the value of
# options['interpolate'], if set.
interpolate = true
interpolate = options['interpolate'] unless options['interpolate'].nil?
# Set extension = enc by default and override it with the value of
# options['extension'], if set. Thus the file path and name from which we
# will look up the encrypted contents is constructed from
# path + key + '.' + enc
# If the value is the "special" string 'none' then no extension will be
# added when constructing the file path and name and we will effectively
# not distinguish between files with encrypted content and regular content.
extension = options['extension'] || 'enc'
if !options['extension'].nil? && options['extension'] == 'none'
extension = nil
end
context.explain { "Setting interpolate = #{interpolate}" }
context.explain { "Setting extension = #{extension}" }
options.each_pair do |k, v|
unless ['path', 'interpolate', 'extension'].include?(k)
Hiera::Backend::Eyaml::Options[k.to_sym] = v
context.explain { "Setting Eyaml option '#{k}' to '#{v}'" }
end
end
data = nil
encrypted_data_file_path = File.join(options['path'], key)
encrypted_data_file_path += '.' + extension unless extension.nil?
regular_data_file_path = File.join(options['path'], key)
if File.exist?(encrypted_data_file_path)
data = context.cached_file_data(encrypted_data_file_path) do |content|
decrypt(content, encrypted_data_file_path, context)
end
elsif File.exist?(regular_data_file_path)
data = context.cached_file_data(regular_data_file_path)
context.explain { "#{regular_data_file_path}: returning data as is "\
"from regular, non-encrypted file" }
if encrypted?(data)
warnmsg = "#{regular_data_file_path}: file contents appear to be "\
"Eyaml-encrypted but file does not have extension '#{extension}', "\
"therefore no decryption was attempted"
context.explain { warnmsg }
end
else
context.not_found
end
if interpolate == true
context.cache(key, context.interpolate(data))
else
context.cache(key, data)
end
end
def encrypted?(data)
/^ENC\[.*?\]$/ =~ data ? true : false
end
def decrypt(data, path, context)
unless encrypted?(data)
warnmsg = "#{path}: file contents do not seem to be Eyaml-encrypted, "\
"even though file name suggests they should be; returning data as is"
context.explain { warnmsg }
return data
end
enc_method, enc_data = data.match(/^ENC\[((\w+),)?([a-zA-Z0-9\+\/=]+?)\]$/)[2,3]
begin
encryptor = Hiera::Backend::Eyaml::Encryptor.find(enc_method)
encryptor.decrypt(encryptor.decode(enc_data))
rescue StandardError => e
context.explain { "failed to decrypt contents: #{e.message}" }
nil
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment