Class: SecureDataBag::Item

Inherits:
Chef::DataBagItem
  • Object
show all
Defined in:
lib/secure_data_bag/secure_data_bag_item.rb,
lib/secure_data_bag/decryptor.rb,
lib/secure_data_bag/encryptor.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.

Defined Under Namespace

Classes: Decryptor, Encryptor

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key = nil) ⇒ Item

Returns a new instance of Item.



15
16
17
18
19
20
21
22
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 15

def initialize(key=nil)
  super()

  @secret = Chef::Config[:encrypted_data_bag_secret]
  @key = key
  @raw_data = {}
  @encode_fields = ["password"]
end

Class Method Details

.from_hash(h, key = nil) ⇒ Object

Transitions



162
163
164
165
166
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 162

def self.from_hash(h, key=nil)
  item = new(key)
  item.raw_data = h
  item
end

.from_item(h, key = nil) ⇒ Object



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

def self.from_item(h, key=nil)
  item = self.from_hash(h.to_hash, key)
  item.data_bag h.data_bag
  item
end

.load_secret(path = nil) ⇒ Object



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

def self.load_secret(path=nil)
  path ||= 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

Encoder / Decoder



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

def decode_data!
  #
  # Ensure that we save previously encoded fields into our list of fields
  # we wish to encode next time
  #
  encode_fields.concat(encryption[:encoded_fields]).uniq!
  @raw_data = decoded_data if encoded?
  @raw_data
end

#decoded_dataObject



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

def decoded_data
  data = Decryptor.new(raw_data, encryption, key).for_decrypted_item
  data[:encryption][:encoded_fields] = []
  data
end

#encode_data!Object



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

def encode_data!
  @raw_data = encoded_data
end

#encode_fields(arg = nil) ⇒ Object

Fields we wish to encode

  • this differs from encryption and will get merged into the latter upon an encode



117
118
119
120
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 117

def encode_fields(arg=nil)
  arg = Array(arg).uniq if arg
  set_or_return(:encode_fields, arg, kind_of: Array).uniq
end

#encoded?Boolean

Determine whether the data is encoded or not

  • yeah, it’s pretty naive

Returns:

  • (Boolean)


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

def encoded?
  not encryption[:encoded_fields].empty?
end

#encoded_dataObject



146
147
148
149
150
151
152
153
154
155
156
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 146

def encoded_data
  #
  # When encoding data we'll merge those fields already encoded during
  # the previous state, found in encryption[:encoded_fields] with those
  # which we wish to encode
  #
  encryption = self.encryption.dup
  encryption[:encoded_fields] = @encode_fields.
    concat(encryption[:encoded_fields]).uniq
  Encryptor.new(raw_data, encryption, key).for_encrypted_item
end

#encryption(arg = nil) ⇒ Object

Wrapper for raw_data encryption settings

  • always ensure that encryption hash is present

  • always ensure encryption settings have defaults



77
78
79
80
81
82
83
84
85
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 77

def encryption(arg=nil)
  @raw_data[:encryption] ||= {}
  @raw_data[:encryption] = arg unless arg.nil?
  encryption = @raw_data[:encryption]
  encryption[:iv] = nil if encryption[:iv].nil?
  encryption[:cipher] = "aes-256-cbc" if encryption[:cipher].nil?
  encryption[:encoded_fields] = [] if encryption[:encoded_fields].nil?
  encryption
end

#key(arg = nil) ⇒ Object



32
33
34
35
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 32

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

#load_keyObject



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

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



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

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

#secret(arg = nil) ⇒ Object

Methods for encryption key



28
29
30
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 28

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

#to_hash(encoded = true) ⇒ Object



174
175
176
177
178
179
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 174

def to_hash(encoded = true)
  result = encoded ? encoded_data : decoded_data
  result["chef_type"] = "data_bag_item"
  result["data_bag"] = self.data_bag
  result
end

#to_json(*a) ⇒ Object



181
182
183
184
185
186
187
188
189
190
# File 'lib/secure_data_bag/secure_data_bag_item.rb', line 181

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