Class: SecureDataBag::Item

Inherits:
Chef::DataBagItem
  • Object
show all
Defined in:
lib/secure_data_bag/secure_data_bag_item.rb

Overview

SecureDataBagItem extends the standard DataBagItem by providing it with encryption / decryption capabilities.

Although it does provide methods which may be used to specifically perform crypto functions, it should be used the same way.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Item

Returns a new instance of Item.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 17

def initialize(opts={})
  super()

  @secret = Chef::Config[:encrypted_data_bag_secret]
  @key = opts[:key]

  unless opts[:data].nil?
    self.raw_data = opts[:data]
  end

  encoded_fields(
    opts[:fields] ||
    Chef::Config[:knife][:secure_data_bag][:fields] ||
    ["password"]
  )
end

Class Method Details

.from_hash(h, opts = {}) ⇒ Object

Transitions



177
178
179
180
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 177

def self.from_hash(h, opts={})
  item = new(opts.merge(data:h))
  item
end

.from_item(h, opts = {}) ⇒ Object



182
183
184
185
186
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 182

def self.from_item(h, opts={})
  item = self.from_hash(h.to_hash, opts)
  item.data_bag h.data_bag
  item
end

.load(data_bag, name, opts = {}) ⇒ Object



83
84
85
86
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 83

def self.load(data_bag, name, opts={})
  data = super(data_bag, name)
  new(opts.merge(data:data.to_hash))
end

.load_secret(path = nil) ⇒ Object



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
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 51

def self.load_secret(path=nil)
  path ||= 
    Chef::Config[:knife][:secure_data_bag][:secret_file] ||
    Chef::Config[:encrypted_data_bag_secret]

  unless path
   raise ArgumentError, "No secret specified and no secret found."
  end

  key = case path
        when /^\w+:\/\// # Remove key
          begin
            Kernel.open(path).read.strip
          rescue Errno::ECONNREFUSED
            raise ArgumentError, "Remove key not available from '#{path}'"
          rescue OpenURI::HTTPError
            raise ArgumentError, "Remove key not found at '#{path}'"
          end
        else
          unless File.exist?(path)
            raise Errno::ENOENT, "file not found '#{path}'"
          end
          IO.read(path).strip
        end

  if key.size < 1
    raise ArgumentError, "invalid zero length path in '#{path}'"
  end

  key
end

Instance Method Details

#decode_data!Object

Raw Data decoder methods



115
116
117
118
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 115

def decode_data!
  @raw_data = decoded_data
  @raw_data
end

#decode_hash(hash) ⇒ Object



126
127
128
129
130
131
132
133
134
135
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 126

def decode_hash(hash)
  hash.each do |k,v|
    v = if encoded_value?(v) then decode_value(v)
        elsif v.is_a?(Hash) then decode_hash(v)
        else v
        end
    hash[k] = v
  end
  hash
end

#decode_value(value) ⇒ Object



137
138
139
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 137

def decode_value(value)
  Chef::EncryptedDataBagItem::Decryptor.for(value, key).for_decrypted_item
end

#decoded_dataObject



120
121
122
123
124
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 120

def decoded_data
  if encoded_value?(@raw_data) then decode_value(@raw_data)
  else decode_hash(@raw_data)
  end
end

#encode_data!Object

Raw Data encoded methods



149
150
151
152
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 149

def encode_data!
  @raw_data = encoded_data
  @raw_data
end

#encode_hash(hash) ⇒ Object



158
159
160
161
162
163
164
165
166
167
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 158

def encode_hash(hash)
  hash.each do |k,v|
    v = if encoded_fields.include?(k) then encode_value(v)
        elsif v.is_a?(Hash) then encode_hash(v)
        else v
        end
    hash[k] = v
  end
  hash
end

#encode_value(value) ⇒ Object



169
170
171
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 169

def encode_value(value)
  Chef::EncryptedDataBagItem::Encryptor.new(value, key).for_encrypted_item
end

#encoded_dataObject



154
155
156
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 154

def encoded_data
  encode_hash(@raw_data.dup)
end

#encoded_fields(arg = nil) ⇒ Object

Fields we wish to encode



106
107
108
109
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 106

def encoded_fields(arg=nil)
  arg = arg.uniq if arg.is_a?(Array)
  set_or_return(:encoded_fields, arg, kind_of: Array, default:[]).uniq
end

#encoded_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


141
142
143
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 141

def encoded_value?(value)
  value.is_a?(Hash) and value.key?(:encrypted_data)
end

#key(arg = nil) ⇒ Object



42
43
44
45
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 42

def key(arg=nil)
  @key = arg unless arg.nil?
  @key ||= load_key
end

#load_keyObject



47
48
49
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 47

def load_key
  @key = self.class.load_secret(secret)
end

#raw_data=(data) ⇒ Object

Setter for @raw_data

  • ensure the data we receive is a Mash to support symbols

  • pass it to DataBagItem for additional validation

  • ensure the data has the encryption hash

  • decode the data



96
97
98
99
100
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 96

def raw_data=(data)
  data = Mash.new(data)
  super(data)
  decode_data!
end

#secret(arg = nil) ⇒ Object

Methods for encryption key



38
39
40
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 38

def secret(arg=nil)
  set_or_return(:secret, arg, kind_of: String)
end

#to_hash(opts = {}) ⇒ Object



188
189
190
191
192
193
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 188

def to_hash(opts={})
  result = opts[:encoded] ? encoded_data : @raw_data
  result["chef_type"] = "data_bag_item"
  result["data_bag"] = data_bag
  result
end

#to_json(*a) ⇒ Object



195
196
197
198
199
200
201
202
203
204
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 195

def to_json(*a)
  result = {
    name: self.object_name,
    json_class: "Chef::DataBagItem",
    chef_type: "data_bag_item",
    data_bag: data_bag,
    raw_data: encoded_data
  }
  result.to_json(*a)
end