Puppet Function: conjur::secret

Defined in:
lib/puppet/functions/conjur/secret.rb
Function type:
Ruby 4.x API

Overview

conjur::secret(String $variable_id, Optional[Hash] $options)Sensitive

Function to retrieve a Conjur secret

Examples:

Agent-based identity invocation

Deferred(conjur::secret, ['production/postgres/password'])

Server-based identity invocation

$sslcert = @("EOT")
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
|-EOT

$dbpass = Deferred(conjur::secret, ['production/postgres/password', {
  appliance_url => "https://my.conjur.org",
  account => "myaccount",
  authn_login => "host/myhost",
  authn_api_key => Sensitive("2z9mndg1950gcx1mcrs6w18bwnp028dqkmc34vj8gh2p500ny1qk8n"),
  ssl_certificate => $sslcert
}])

Parameters:

  • variable_id (String)

    Conjur variable ID that you want the value of.

  • options (Optional[Hash])

    Optional parameter specifying server identity overrides The following keys are supported in the options hash:

    • appliance_url: The URL of the Conjur instance.

    • account: Name of the Conjur account that contains this variable.

    • authn_login: The identity you are using to authenticate to the Conjur instance.

    • authn_api_key: The API key of the identity you are using to authenticate with (must be Sensitive type).

    • cert_file: The absolute path to CA certificate chain for the Conjur instance on the agent. This variable overrides ‘ssl_certificate`.

    • ssl_certificate: The raw PEM-encoded x509 CA certificate chain for the Conjur instance. Overwritten by the contents read from ‘cert_file` when it is present.

    • version: Conjur API version, defaults to 5.

Returns:

  • (Sensitive)

    Value of the Conjur variable.



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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/puppet/functions/conjur/secret.rb', line 12

Puppet::Functions.create_function :'conjur::secret' do
  # @param variable_id Conjur variable ID that you want the value of.
  # @param options Optional parameter specifying server identity overrides
  #   The following keys are supported in the options hash:
  #   - appliance_url: The URL of the Conjur instance.
  #   - account: Name of the Conjur account that contains this variable.
  #   - authn_login: The identity you are using to authenticate to the Conjur instance.
  #   - authn_api_key: The API key of the identity you are using to authenticate with (must be Sensitive type).
  #   - cert_file: The absolute path to CA certificate chain for the Conjur instance on the agent. This variable overrides `ssl_certificate`.
  #   - ssl_certificate: The _raw_ PEM-encoded x509 CA certificate chain for the Conjur instance. Overwritten by the contents read from `cert_file` when it is present.
  #   - version: Conjur API version, defaults to 5.
  # @return [Sensitive] Value of the Conjur variable.
  # @example Agent-based identity invocation
  #   Deferred(conjur::secret, ['production/postgres/password'])
  # @example Server-based identity invocation
  #   $sslcert = @("EOT")
  #   -----BEGIN CERTIFICATE-----
  #   ...
  #   -----END CERTIFICATE-----
  #   |-EOT
  #
  #   $dbpass = Deferred(conjur::secret, ['production/postgres/password', {
  #     appliance_url => "https://my.conjur.org",
  #     account => "myaccount",
  #     authn_login => "host/myhost",
  #     authn_api_key => Sensitive("2z9mndg1950gcx1mcrs6w18bwnp028dqkmc34vj8gh2p500ny1qk8n"),
  #     ssl_certificate => $sslcert
  #   }])
  dispatch :with_credentials do
    required_param 'String', :variable_id
    optional_param 'Hash', :options

    return_type 'Sensitive'
  end

  def authentication_path(, )
    ['authn', , , 'authenticate']
      .map(&URI.method(:encode_www_form_component)).join('/')
  end

  # Authenticates against a Conjur server returning the API token
  def authenticate(url, ssl_certificate, , , authn_api_key)
    Conjur::PuppetModule::HTTP.post(
      url,
      authentication_path(, ),
      ssl_certificate,
      authn_api_key.unwrap,
    )
  end

  # Fetches a variable from Conjur
  def get_variable(url, ssl_certificate, , variable_id, token)
    secrets_path = [
      'secrets',
      URI.encode_www_form_component(),
      'variable',
      ERB::Util.url_encode(variable_id),
    ].join('/')

    Conjur::PuppetModule::HTTP.get(
      url,
      secrets_path,
      ssl_certificate,
      token,
    )
  end

  def with_credentials(id, options = {})
    # If we got an options hash, it may be frozen so we make a copy that is not since
    # we will be modifying it
    opts = options.dup

    if opts['authn_api_key']
      raise "Value of 'authn_api_key' must be wrapped in 'Sensitive()'!" \
        unless opts['authn_api_key'].is_a? Puppet::Pops::Types::PSensitiveType::Sensitive
    end

    opts['version'] ||= 5

    # If we didn't get any config from the server, assume it's on the agent
    if opts['appliance_url'].nil? || opts['appliance_url'].empty?
      config = Conjur::PuppetModule::Config.load
      raise 'Conjur configuration not found on system' if config.empty?

      creds = Conjur::PuppetModule::Identity.load(config)
      raise 'Conjur identity not found on system' unless creds

      # Overwrite values in the options hash with the ones from the agent. We may at
      # some point want to support partial overwrite of only the set values.
      ['appliance_url', 'account', 'ssl_certificate', 'version'].each do |key|
        opts[key] = config[key]
      end

      opts['authn_login'], authn_api_key = creds
      opts['authn_api_key'] = Puppet::Pops::Types::PSensitiveType::Sensitive.new(authn_api_key)
    end

    # If cert_file is set, use it to override ssl_certificate
    if opts['cert_file']
      raise "Cert file '#{opts['cert_file']}' cannot be found!" unless File.file?(opts['cert_file'])
      opts['ssl_certificate'] = File.read opts['cert_file']
    end

    Puppet.debug('Instantiating Conjur client...')
    Puppet.debug('Fetching Conjur token')
    token = authenticate(opts['appliance_url'], opts['ssl_certificate'], opts['account'],
                         opts['authn_login'], opts['authn_api_key'])
    Puppet.info('Conjur token retrieved')

    Puppet.debug("Fetching Conjur secret '#{id}'...")
    secret = get_variable(opts['appliance_url'], opts['ssl_certificate'], opts['account'],
                          id, token)
    Puppet.info("Conjur secret #{id} retrieved")

    Puppet::Pops::Types::PSensitiveType::Sensitive.new(secret)
  end
end