summaryrefslogtreecommitdiff
path: root/lib/hiera/backend/trocla_backend.rb
blob: db342e99fffec5ec002aaa41442b5f213d0d9095 (plain)
1
2
3
4
5
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
47
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# Custom hiera backend for trocla
#
# Only reacts to key namespace trocla::password::<trocla_key>. Looks up
# additional parameters via hiera itself as
# trocla::options::<trocla_key>::format (string) and
# trocla::options::<trocla_key>::options (hash). Looks for <trocla_key> in
# trocla as hiera/<source>/<trocla> with <source> iterating over the configured
# hiera hierarchy. If not found, makes a normal trocla lookup with
# <trocla_key> that might create a new password on the first run.
#
# example entry in hiera.yaml:
# backends:
#   - ...
#   - trocla
# trocla:
#   configfile: /etc/puppet/troclarc.yaml
#   default_format: plain
#   default_options:
#     length: 16
#
# example usage in hiera yaml file:
# kerberos::kdc_database_password: "%{hiera('trocla::password::kdc_database_password')}"
# trocla::options::kdc_database_password::format: 'plain'
# trocla::options::kdc_database_password::options:
#   length: 71
class Hiera
  module Backend
    class Trocla_backend
      attr_accessor :trocla
      def initialize
        Hiera.debug("Hiera Trocla backend starting")
        require 'trocla'
        unless File.readable?(config[:configfile])
          Hiera.warn("Trocla config file #{config[:configfile]} is not readable")
          return
        end

        @trocla = Trocla.new(config[:configfile])
      end

      def lookup(key, scope, order_override, resolution_type)
        return nil unless trocla

        Hiera.debug("Looking up #{key} in trocla backend")


        # we only accept trocla::password:: lookups because we do hiera lookups
        # ourselves and could otherwise cause loops
        return nil unless key.start_with?(config[:password_namespace])

        # cut off trocla hiera namespace: trocla::password::root -> root
        trocla_key = key.sub(/^#{config[:password_namespace]}/,'')
        Hiera.debug("Looking for key #{trocla_key} in trocla")

        # HERE BE DRAGONS: hiera lookups from backend to determine additional
        # trocla options for this password
        format = Backend.lookup(config[:options_namespace] + trocla_key + '::format',
                                config[:default_format], scope, nil, :priority)

        answer = nil
        # Go looking for existing password as hiera/<source>/<trocla_key>.
        # Would need to be initialised externally, e.g by calling
        # trocla('hiera/osfamily/Debian/jessie/root' in site.pp.  Alternatively
        # we could use hiera's concept of datafiles to look into different
        # trocla password stores. But this would need somehow providing
        # different troclarcs as well.
        Backend.datasources(scope, order_override) do |source|
          Hiera.debug("Looking for data source #{source}")
          break if answer = trocla.get_password(
                                      'hiera/' + source + '/' + trocla_key,
                                      format)
        end

        unless answer
          # lookup and maybe create a new password
          options = Backend.lookup(config[:options_namespace] + trocla_key + '::options',
                                   config[:default_options], scope, nil, :hash)
          answer = trocla.password(trocla_key, format, options)
        end

        return answer
      end

      private
      def config
        @config ||= {
            :configfile         => '/etc/puppet/troclarc.yaml',
            :default_format     => 'plain',
            :default_options    => {},
            :password_namespace => 'trocla::password::',
            :options_namespace  => 'trocla::options::',
        }.merge(Config[:trocla] || {})
      end
    end
  end
end