class ChefVault::ItemKeys

Attributes

skip_reencryption[RW]

@!attribute [rw] skip_reencryption

@return [TrueClass,FalseClass] whether symetrical key is reencrypted all the time or re-used from previous computations

Public Class Methods

encode_key(key_string, data_bag_shared_secret) click to toggle source
# File lib/chef-vault/item_keys.rb, line 274
def self.encode_key(key_string, data_bag_shared_secret)
  public_key = OpenSSL::PKey::RSA.new(key_string)
  Base64.encode64(public_key.public_encrypt(data_bag_shared_secret))
end
from_data_bag_item(data_bag_item) click to toggle source
# File lib/chef-vault/item_keys.rb, line 228
def self.from_data_bag_item(data_bag_item)
  item = new(data_bag_item.data_bag, data_bag_item.name)
  item.raw_data = data_bag_item.raw_data
  item
end
load(vault, name) click to toggle source
# File lib/chef-vault/item_keys.rb, line 234
def self.load(vault, name)
  begin
    data_bag_item = Chef::DataBagItem.load(vault, name)
  rescue Net::HTTPClientException => http_error
    if http_error.response.code == "404"
      raise ChefVault::Exceptions::KeysNotFound,
        "#{vault}/#{name} could not be found"
    else
      raise http_error
    end
  rescue Chef::Exceptions::ValidationFailed
    raise ChefVault::Exceptions::KeysNotFound,
      "#{vault}/#{name} could not be found"
  end

  from_data_bag_item(data_bag_item)
end
new(vault, name) click to toggle source
Calls superclass method
# File lib/chef-vault/item_keys.rb, line 28
def initialize(vault, name)
  super() # parentheses required to strip off parameters
  @data_bag = vault
  @raw_data["id"] = name
  @raw_data["admins"] = []
  @raw_data["clients"] = []
  @raw_data["search_query"] = []
  @raw_data["mode"] = "default"
  @cache = {} # write-back cache for keys
end

Public Instance Methods

[](key) click to toggle source
# File lib/chef-vault/item_keys.rb, line 39
def [](key)
  # return options immediately
  return @raw_data[key] if %w{id admins clients search_query mode}.include?(key)

  # check if the key is in the write-back cache
  ckey = @cache[key]
  return ckey unless ckey.nil?

  # check if the key is saved in sparse mode
  skey = sparse_key(sparse_id(key)) if sparse?
  if skey
    skey[key]
  else
    # fallback to raw data
    @raw_data[key]
  end
end
add(chef_key, data_bag_shared_secret) click to toggle source
# File lib/chef-vault/item_keys.rb, line 68
def add(chef_key, data_bag_shared_secret)
  type = chef_key.type
  unless @raw_data.key?(type)
    raise ChefVault::Exceptions::V1Format,
      "cannot manage a v1 vault.  See UPGRADE.md for help"
  end
  @cache[chef_key.name] = skip_reencryption ? self[chef_key.name] : nil
  begin
    @cache[chef_key.name] ||= ChefVault::ItemKeys.encode_key(chef_key.key, data_bag_shared_secret)
  rescue OpenSSL::PKey::RSAError
    raise OpenSSL::PKey::RSAError, "While adding #{chef_key.type} an invalid or old (pre chef-server 12) format public key was found for #{chef_key.name}"
  end
  @raw_data[type] << chef_key.name unless @raw_data[type].include?(chef_key.name)
  @raw_data[type]
end
admins() click to toggle source
# File lib/chef-vault/item_keys.rb, line 116
def admins
  @raw_data["admins"]
end
clear_encrypted() click to toggle source
# File lib/chef-vault/item_keys.rb, line 84
def clear_encrypted
  @cache.clear
  self["clients"].each { |client| @raw_data.delete(client) }
  self["admins"].each { |admin| @raw_data.delete(admin) }
end
clients() click to toggle source
# File lib/chef-vault/item_keys.rb, line 112
def clients
  @raw_data["clients"]
end
delete(chef_key) click to toggle source
# File lib/chef-vault/item_keys.rb, line 90
def delete(chef_key)
  @cache[chef_key.name] = false
  raw_data[chef_key.type].delete(chef_key.name)
  raw_data.delete(chef_key.name)
end
destroy() click to toggle source
Calls superclass method
# File lib/chef-vault/item_keys.rb, line 200
def destroy
  if Chef::Config[:solo_legacy_mode]
    data_bag_path = File.join(Chef::Config[:data_bag_path], data_bag)
    data_bag_item_path = File.join(data_bag_path, @raw_data["id"])
    data_bag_sparse_keys_path = File.join(data_bag_path, sparse_id("*"))
    # destroy all sparse keys
    FileUtils.rm(Dir.glob("#{data_bag_sparse_keys_path}.json"))
    # destroy this metadata
    FileUtils.rm("#{data_bag_item_path}.json")
    nil
  else
    # destroy all sparse keys
    rgx = Regexp.new("^#{sparse_id(".*")}")
    items = Chef::DataBag.load(data_bag).keys.select { |item| item =~ rgx }
    items.each do |id|
      Chef::DataBagItem.from_hash("data_bag" => data_bag, "id" => id)
        .destroy(data_bag, id)
    end
    # destroy this metadata
    super(data_bag, id)
  end
end
include?(key) click to toggle source
# File lib/chef-vault/item_keys.rb, line 57
def include?(key)
  # check if the key is in the write-back cache
  ckey = @cache[key]
  return (ckey ? true : false) unless ckey.nil?
  # check if the key is saved in sparse mode
  return true if sparse? && sparse_key(sparse_id(key))

  # fallback to non-sparse mode if sparse key is not found
  @raw_data.keys.include?(key)
end
mode(mode = nil) click to toggle source
# File lib/chef-vault/item_keys.rb, line 96
def mode(mode = nil)
  if mode
    @raw_data["mode"] = mode
  else
    @raw_data["mode"]
  end
end
save(item_id = @raw_data["id"]) click to toggle source
Calls superclass method
# File lib/chef-vault/item_keys.rb, line 120
def save(item_id = @raw_data["id"])
  # create data bag if not running in solo mode
  unless Chef::Config[:solo_legacy_mode]
    begin
      Chef::DataBag.load(data_bag)
    rescue Net::HTTPClientException => http_error
      if http_error.response.code == "404"
        chef_data_bag = Chef::DataBag.new
        chef_data_bag.name data_bag
        chef_data_bag.create
      end
    end
  end

  # write cached keys to data
  @cache.each do |key, val|
    # delete across all modes on key deletion
    if val == false
      # sparse mode key deletion
      if Chef::Config[:solo_legacy_mode]
        delete_solo(sparse_id(key))
      else
        begin
          Chef::DataBagItem.from_hash("data_bag" => data_bag,
                                      "id" => sparse_id(key))
            .destroy(data_bag, sparse_id(key))
        rescue Net::HTTPClientException => http_error
          raise http_error unless http_error.response.code == "404"
        end
      end
      # default mode key deletion
      @raw_data.delete(key)
    else
      if @raw_data["mode"] == "sparse"
        # sparse mode key creation
        skey = Chef::DataBagItem.from_hash(
          "data_bag" => data_bag,
          "id" => sparse_id(key),
          key => val
        )
        if Chef::Config[:solo_legacy_mode]
          save_solo(skey.id, skey.raw_data)
        else
          skey.save
        end
      else
        # default mode key creation
        @raw_data[key] = val
      end
    end
  end

  if @raw_data["mode"] == "sparse"
    @raw_data.each do |key, val|
      next if %w{ id clients admins search_query mode }.include?(key)

      skey = Chef::DataBagItem.from_hash(
        "data_bag" => data_bag,
        "id" => sparse_id(key),
        key => val
      )
      @raw_data.delete(key)
      if Chef::Config[:solo_legacy_mode]
        save_solo(skey.id, skey.raw_data)
      else
        skey.save
      end
    end
  end

  # save raw data
  if Chef::Config[:solo_legacy_mode]
    save_solo(item_id)
  else
    super
  end
  # clear write-back cache
  @cache = {}
end
search_query(search_query = nil) click to toggle source
# File lib/chef-vault/item_keys.rb, line 104
def search_query(search_query = nil)
  if search_query
    @raw_data["search_query"] = search_query
  else
    @raw_data["search_query"]
  end
end
sparse?() click to toggle source

@private

# File lib/chef-vault/item_keys.rb, line 254
def sparse?
  @raw_data["mode"] == "sparse"
end
sparse_id(key, item_id = @raw_data["id"]) click to toggle source
# File lib/chef-vault/item_keys.rb, line 258
def sparse_id(key, item_id = @raw_data["id"])
  "#{item_id.chomp("_keys")}_key_#{key}"
end
sparse_key(sid) click to toggle source
# File lib/chef-vault/item_keys.rb, line 262
def sparse_key(sid)
  if Chef::Config[:solo_legacy_mode]
    load_solo(sid)
  else
    begin
      Chef::DataBagItem.load(@data_bag, sid)
    rescue Net::HTTPClientException => http_error
      nil if http_error.response.code == "404"
    end
  end
end
to_json(*a) click to toggle source
Calls superclass method
# File lib/chef-vault/item_keys.rb, line 223
def to_json(*a)
  json = super
  json.gsub(self.class.name, self.class.superclass.name)
end