Class: Hiera::Backend::Vault_backend

Inherits:
Object
  • Object
show all
Defined in:
lib/hiera/backend/vault_backend.rb

Instance Method Summary collapse

Constructor Details

#initializeVault_backend

Returns a new instance of Vault_backend.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/hiera/backend/vault_backend.rb', line 6

def initialize()
  require 'json'
  require 'vault'

  @config = Config[:vault]
  @config[:mounts] ||= {}
  @config[:mounts][:generic] ||= ['secret']
  @config[:default_field_parse] ||= 'string' # valid values: 'string', 'json'

  if not ['string','json'].include?(@config[:default_field_parse])
    raise Exception, "[hiera-vault] invalid value for :default_field_parse: '#{@config[:default_field_behavior]}', should be one of 'string','json'"
  end

  # :default_field_behavior:
  #   'ignore' => ignore additional fields, if the field is not present return nil
  #   'only'   => only return value of default_field when it is present and the only field, otherwise return hash as normal
  @config[:default_field_behavior] ||= 'ignore'

  if not ['ignore','only'].include?(@config[:default_field_behavior])
    raise Exception, "[hiera-vault] invalid value for :default_field_behavior: '#{@config[:default_field_behavior]}', should be one of 'ignore','only'"
  end

  begin
    @vault = Vault::Client.new
    @vault.configure do |config|
      config.address = @config[:addr] if @config[:addr]
      config.token = @config[:token] if @config[:token]
      config.ssl_pem_file = @config[:ssl_pem_file] if @config[:ssl_pem_file]
      config.ssl_verify = @config[:ssl_verify] if @config[:ssl_verify]
      config.ssl_ca_cert = @config[:ssl_ca_cert] if config.respond_to? :ssl_ca_cert
      config.ssl_ca_path = @config[:ssl_ca_path] if config.respond_to? :ssl_ca_path
      config.ssl_ciphers = @config[:ssl_ciphers] if config.respond_to? :ssl_ciphers
    end

    fail if @vault.sys.seal_status.sealed?
    Hiera.debug("[hiera-vault] Client configured to connect to #{@vault.address}")
  rescue Exception => e
    @vault = nil
    Hiera.warn("[hiera-vault] Skipping backend. Configuration error: #{e}")
  end
end

Instance Method Details

#lookup(key, scope, order_override, resolution_type) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/hiera/backend/vault_backend.rb', line 48

def lookup(key, scope, order_override, resolution_type)
  return nil if @vault.nil?

  Hiera.debug("[hiera-vault] Looking up #{key} in vault backend")

  answer = nil
  found = false

  # Only generic mounts supported so far
  @config[:mounts][:generic].each do |mount|
    path = Backend.parse_string(mount, scope, { 'key' => key })
    Hiera.debug("Looking in path #{path}")
    new_answer = lookup_generic("#{path}/#{key}", scope)
    #Hiera.debug("[hiera-vault] Answer: #{new_answer}:#{new_answer.class}")
    next if new_answer.nil?
    case resolution_type
    when :array
      raise Exception, "Hiera type mismatch: expected Array and got #{new_answer.class}" unless new_answer.kind_of? Array or new_answer.kind_of? String
      answer ||= []
      answer << new_answer
    when :hash
      raise Exception, "Hiera type mismatch: expected Hash and got #{new_answer.class}" unless new_answer.kind_of? Hash
      answer ||= {}
      answer = Backend.merge_answer(new_answer,answer)
    else
      answer = new_answer
      break
    end
  end

  return answer
end

#lookup_generic(key, scope) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/hiera/backend/vault_backend.rb', line 81

def lookup_generic(key, scope)
    begin
      secret = @vault.logical.read(key)
    rescue Vault::HTTPConnectionError
      Hiera.debug("[hiera-vault] Could not connect to read secret: #{key}")
    rescue Vault::HTTPError => e
      Hiera.warn("[hiera-vault] Could not read secret #{key}: #{e.errors.join("\n").rstrip}")
    end

    return nil if secret.nil?

    Hiera.debug("[hiera-vault] Read secret: #{key}")
    if @config[:default_field] and (@config[:default_field_behavior] == 'ignore' or (secret.data.has_key?(@config[:default_field].to_sym) and secret.data.length == 1))
      return nil if not secret.data.has_key?(@config[:default_field].to_sym)
      # Return just our default_field
      data = secret.data[@config[:default_field].to_sym]
      if @config[:default_field_parse] == 'json'
        begin
          data = JSON.parse(data)
        rescue JSON::ParserError => e
          Hiera.debug("[hiera-vault] Could not parse string as json: #{e}")
        end
      end
    else
      # Turn secret's hash keys into strings
      data = secret.data.inject({}) { |h, (k, v)| h[k.to_s] = v; h }
    end
    #Hiera.debug("[hiera-vault] Data: #{data}:#{data.class}")

    return Backend.parse_answer(data, scope)
end