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 / DAP 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 / DAP 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 or DAP instance..

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

    • authn_login: The identity you are using to authenticate to the Conjur / DAP 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 DAP instance on the agent. This variable overrides ‘ssl_certificate`.

    • ssl_certificate: The raw PEM-encoded x509 CA certificate chain for the DAP 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.



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
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
# File 'lib/puppet/functions/conjur/secret.rb', line 8

Puppet::Functions.create_function :'conjur::secret' do
  # @param variable_id Conjur / DAP 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 or DAP instance..
  #   - account: Name of the Conjur account that contains this variable.
  #   - authn_login: The identity you are using to authenticate to the Conjur / DAP 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 DAP instance on the agent. This variable overrides `ssl_certificate`.
  #   - ssl_certificate: The _raw_ PEM-encoded x509 CA certificate chain for the DAP 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 / DAP 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 / DAP
  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