diff --git a/lib/puppet/functions/vault_lookup/lookup.rb b/lib/puppet/functions/vault_lookup/lookup.rb index 80149df..20b28c5 100644 --- a/lib/puppet/functions/vault_lookup/lookup.rb +++ b/lib/puppet/functions/vault_lookup/lookup.rb @@ -16,6 +16,7 @@ optional_param 'String', :secret_id optional_param 'Optional[String]', :approle_path_segment optional_param 'String', :agent_sink_file + optional_param 'Optional[Integer]', :gen_secret_len return_type 'Sensitive' end @@ -50,7 +51,8 @@ def lookup_opts_hash(cache, path, options = {}) role_id: options['role_id'], secret_id: options['secret_id'], approle_path_segment: options['approle_path_segment'], - agent_sink_file: options['agent_sink_file']) + agent_sink_file: options['agent_sink_file'], + gen_secret_len: options['gen_secret_len']) end # Lookup with a path and positional arguments. @@ -68,7 +70,8 @@ def lookup(cache, role_id = nil, secret_id = nil, approle_path_segment = nil, - agent_sink_file = nil) + agent_sink_file = nil, + gen_secret_len = nil) PuppetX::VaultLookup::Lookup.lookup(cache: cache, path: path, @@ -81,6 +84,7 @@ def lookup(cache, role_id: role_id, secret_id: secret_id, approle_path_segment: approle_path_segment, - agent_sink_file: agent_sink_file) + agent_sink_file: agent_sink_file, + gen_secret_len: gen_secret_len) end end diff --git a/lib/puppet_x/vault_lookup/lookup.rb b/lib/puppet_x/vault_lookup/lookup.rb index 3425ae7..dfcc7a9 100644 --- a/lib/puppet_x/vault_lookup/lookup.rb +++ b/lib/puppet_x/vault_lookup/lookup.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'puppet' +require 'securerandom' module PuppetX module VaultLookup @@ -17,7 +18,8 @@ def self.lookup(cache:, role_id: nil, secret_id: nil, approle_path_segment: nil, - agent_sink_file: nil) + agent_sink_file: nil, + gen_secret_len: nil) if vault_addr.nil? Puppet.debug 'No Vault address was set on function, defaulting to value from VAULT_ADDR env value' @@ -98,7 +100,8 @@ def self.lookup(cache:, uri: secret_uri, token: token, namespace: namespace, - key: field) + key: field, + gen_secret_len: gen_secret_len) sensitive_data = Puppet::Pops::Types::PSensitiveType::Sensitive.new(data) Puppet.debug "Caching found data for #{path}" @@ -114,11 +117,33 @@ def self.auth_login_body(cert_role) end end - def self.get_secret(client:, uri:, token:, namespace:, key:) + def self.get_secret(client:, uri:, token:, namespace:, key:, gen_secret_len:) headers = { 'X-Vault-Token' => token, 'X-Vault-Namespace' => namespace }.delete_if { |_key, value| value.nil? } secret_response = client.get(uri, headers: headers, options: { include_system_store: true }) + + if secret_response.code == 404 and !gen_secret_len.nil? + # generate a new secret + Puppet.debug "Generating new secret at #{uri}" + new_secret = SecureRandom.alphanumeric(gen_secret_len) + param = { value: new_secret } + generate_response = client.post(uri, + JSON.generate(param), + headers: headers.merge({'Content-Type' => 'application/json'}), + options: { include_system_store: true }) + + unless generate_response.code >= 200 && generate_response.code <= 299 + message = "Received #{generate_response.code} generate_response code from vault at #{uri} for secret put" + raise Puppet::Error, append_api_errors(message, generate_response) + end + + secret_response = client.get(uri, + headers: headers, + options: { include_system_store: true }) + end + + unless secret_response.success? message = "Received #{secret_response.code} response code from vault at #{uri} for secret lookup" raise Puppet::Error, append_api_errors(message, secret_response)