Class: Conjur::Variable

Inherits:
RestClient::Resource
  • Object
show all
Includes:
ActsAsAsset
Defined in:
lib/conjur/variable.rb

Overview

Secrets stored in Conjur are represented by Variables. The code responsible for the actual encryption of variables is open source as part of the Slosilo library.

You should not generally create instances of this class directly. Instead, you can get them from API methods such as API#create_variable and API#variable.

Conjur variables store metadata (mime-type and secret kind) with each secret.

Variables are versioned. Storing secrets in multiple places is a bad security practice, but overwriting a secret accidentally can create a major problem for development and ops teams. Conjur discourages bad security practices while avoiding ops disasters by storing all previous versions of a secret.

Important

A common pitfall when trying to access older versions of a variable is to assume that 0 is the oldest version. In fact, 0 references the latest version, while 1 is the oldest.

Permissions

  • To read the value of a variable, you must have permission to 'execute' the variable.
  • To add a value to a variable, you must have permission to 'update' the variable.
  • To show metadata associated with a variable, but not the value of the secret, you must have 'read' permission on the variable.

When you create a secret, the creator role is granted all three of the above permissions.

Examples:

Get a variable and access its metadata and the latest value

variable = api.variable 'example'
puts variable.kind      # "example-secret"
puts variable.mime_type # "text/plain"
puts variable.value     # "supahsecret"

Variable permissions

# use our 'admin' api to create a variable 'permissions-example
admin_var = admin_api.create_variable 'text/plain', 'example', 'permissions-example'

# get a 'view' to it from user 'alice'
alice_var = alice_api.variable admin_var.id

# Initilally, all of the following raise a RestClient::Forbidden exception
alice_var.attributes
alice_var.value
alice_var.add_value 'hi'

# Allow alice to see the variables attributes
admin_var.permit 'read', alice
alice_var.attributes # OK

# Allow alice to update the variable
admin_var.permit 'update', alice
alice_var.add_value 'hello'

# Notice that alice still can't see the variable's value:
alice_var.value # raises RestClient::Forbidden

# Finally, we let alice execute the variable
admin_var.permit 'execute', alice
alice_var.value # 'hello'

Variables are versioned

var = api.variable 'version-example'
# Unless you set a variables value when you create it, the variable starts out without a value and version_count
# is 0.
var.version_count # => 0
var.value # raises RestClient::ResourceNotFound (404)

# Add a value
var.add_value 'value 1'
var.version_count # => 1
var.value # => 'value 1'

# Add another value
var.add_value 'value 2'
var.version_count # => 2

# 'value' with no argument returns the most recent value
var.value # => 'value 2'

# We can access older versions by their 1 based index:
var.value 1 # => 'value 1'
var.value 2 # => 'value 2'
# Notice that version 0 of a variable is always the most recent:
var.value 0 # => 'value 2'

Instance Method Summary collapse

Methods included from ActsAsAsset

#add_member, #remove_member

Methods included from HasAttributes

#attributes, #invalidate, #refresh, #save, #to_json

Methods included from ActsAsResource

#deny, #permit, #resource, #resource_kind, #resourceid

Methods included from HasOwner

#ownerid, #userid

Methods included from Exists

#exists?

Methods included from HasId

#id

Instance Method Details

#add_value(value)

This method returns an undefined value.

Add a new value to the variable.

You must have the 'update' permission on a variable to call this method.

Examples:

Add a value to a variable

var = api.variable 'my-secret'
puts var.version_count     #  1
puts var.value             #  'supersecret'
var.add_value "new_secret"
puts var.version_count     # 2
puts var.value             # 'new_secret'

Parameters:

  • value (String)

    the new value to add



153
154
155
156
157
158
159
160
# File 'lib/conjur/variable.rb', line 153

def add_value value
  log do |logger|
    logger << "Adding a value to variable #{id}"
  end
  invalidate do
    self['values'].post value: value
  end
end

#expires_in(interval) ⇒ Hash

Set the variable to expire after the given interval. The interval can either be an ISO8601 duration or it can the number of seconds for which the variable should be valid. Once a variable has expired, its value will no longer be retrievable.

You must have the 'update' permission on a variable to call this method.

Examples:

Use an ISO8601 duration to set the expiration for a variable to tomorrow

var = api.variable 'my-secret'
var.expires_in "P1D"

Use ActiveSupport to set the expiration for a variable to tomorrow

require 'active_support/all'
var = api.variable 'my-secret'
var.expires_in 1.day

Parameters:

  • interval

    a String containing an ISO8601 duration, otherwise the number of seconds before the variable xpires

Returns:

  • (Hash)

    description of the variable's expiration, including the (Conjur server) time when it expires



232
233
234
235
# File 'lib/conjur/variable.rb', line 232

def expires_in interval
  duration = interval.respond_to?(:to_str) ? interval : "PT#{interval.to_i}S"
  JSON::parse(self['expiration'].post(duration: duration).body)
end

#kindString

Note:

this is not the same as the kind part of a qualified Conjur id.

The kind of secret represented by this variable, for example, 'postgres-url' or 'aws-secret-access-key'.

You must have the 'read' permission on a variable to call this method.

This attribute is only for human consumption, and does not take part in the Conjur permissions model.

Returns:

  • (String)

    a string representing the kind of secret.



122
123
124
# File 'lib/conjur/variable.rb', line 122

def kind
  attributes['kind']
end

#mime_typeString

The MIME Type of the variable's value.

You must have the 'read' permission on a variable to call this method.

This attribute is used by the Conjur services to set a response Content-Type header when returning the value of a variable. Conjur applies the same MIME Type to all versions of a variable, so if you plan on accessing the variable in a way that depends on a correct Content-Type header you should make sure to store appropriate data for the mime type in all versions.

Returns:

  • (String)

    a MIME type, such as 'text/plain' or 'application/octet-stream'.



136
137
138
# File 'lib/conjur/variable.rb', line 136

def mime_type
  attributes['mime_type']
end

#value(version = nil, options = {}) ⇒ String

Return the version of a variable.

You must have the 'execute' permission on a variable to call this method.

When no argument is given, the most recent version is returned.

When a version argument is given, the method returns a version according to the following rules:

  • If version is 0, the most recent version is returned.
  • If version is less than 0 or greater than #version_count, a RestClient::ResourceNotFound exception will be raised.
  • If #version_count is 0, a RestClient::ResourceNotFound exception will be raised.
  • If version is >= 1 and version <= #version_count, the version at the 1 based index given by version will be returned.

Examples:

Fetch all versions of a variable

versions = (1..var.version_count).map do |version|
  var.value version
end

Get the current version of a variable

# All of these return the same thing:
var.value
var.value 0
var.value var.version_count

Get the value of an expired variable

var.value nil, show_expired: true

Parameters:

  • version (Integer) (defaults to: nil)

    the 1 based version.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :show_expired (Boolean, false)

    show value even if variable has expired

Returns:

  • (String)

    the value of the variable



208
209
210
211
212
213
# File 'lib/conjur/variable.rb', line 208

def value(version = nil, options = {})
  url = 'value'
  options['version'] = version if version
  url << '?' + options.to_query unless options.empty?
  self[url].get.body
end

#version_countInteger

Return the number of versions of the variable.

You must have the 'read' permission on a variable to call this method.

Examples:

var.version_count # => 4
var.add_value "something new"
var.version_count # => 5

Returns:

  • (Integer)

    the number of versions



172
173
174
# File 'lib/conjur/variable.rb', line 172

def version_count
  self.attributes['version_count']
end