secure_data_bag 2.2.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a9feeb1dfc414c24ff0245dd5942cef163e5d4c
4
- data.tar.gz: 89258e6b058db11c62d7dbd39af9eba58eef2700
3
+ metadata.gz: b22224b0b2102fd71b07fdc51184af1897b5b74e
4
+ data.tar.gz: 0bf974e3ba411d700bc55ed5d42fc9a7246258dd
5
5
  SHA512:
6
- metadata.gz: 0d2aceb5f872a953842a29d00351bd2474696925dad5dda15bf6b09844b09652196f8fcb9e0c8e79f2ec5cb4e07aac152a48813eac87edce6ffea53983995465
7
- data.tar.gz: d07e7e41cad38f400f64a84892ee03b089a49c88328c812d73433a5d711b067b533de271ae06ffa389db96c4f777f1c8bc72bc68069ee42f76c8a874088c2516
6
+ metadata.gz: 894f9fbfcf7dd4c3ad755302a06f0fd2dd489681f7336ad07609cedb7c3f09158c3b7560c8e2ea0211fa5147681b34514185b4cc442a4824896c6518e8491afd
7
+ data.tar.gz: 0710828746350ae0988324d280618527290e44bab263a6c464faab86215de89da56ff50fd4664c82eed4cc00f80973a1596bc414bc9bcdc1e2721f5ab3e4ff66
@@ -0,0 +1,8 @@
1
+ secure_data_bag
2
+ ======
3
+ # 2.2.0
4
+ * Add support for printing data bag items after edit via `knife secure bag edit --print-after`
5
+ * Resolve problem where `knife secure bag edit` would not encode fields
6
+
7
+ # 2.1.x
8
+ * Alot of initial commits ;)
data/README.md CHANGED
@@ -1,41 +1,105 @@
1
- # SecureDataBag
1
+ # SecureDataBag / Knife Secure Bag
2
2
 
3
- Provides a mechanism to partially encrypt data bag items on a per-key basis which gives us the opportunity to still search for every other field.
3
+ Knife Secure Bag provides a consistent interface to DataBagItem, EncryptedDataBagItem as well as the custom created SecureDataBagItem while also providing a few extra handy features to help in your DataBag workflows.
4
4
 
5
- When specifying keys to encrypt, the library will recursively walk through the data bag content searching for encryption candidates.
5
+ SecureDataBagItem, can not only manage your existing DataBagItems and EncryptedDataBagItems, but it also provides you with a DataBag type which enables you to selectively encrypt only some of the fields in your DataBag thus allowing you to be able to search for the remaining fields.
6
6
 
7
7
  ## Installation
8
8
 
9
- Add this line to your application's Gemfile:
9
+ To build and install the plugin add it your Gemfile or run:
10
10
 
11
- gem 'secure_data_bag'
11
+ ```shell
12
+ gem install secure_data_bag
13
+ ```
12
14
 
13
- And then execute:
15
+ ## Configuration
16
+
17
+ #### Knife Secure Bag
18
+
19
+ Defaults for the Knife command may be provided in your _knife.rb_ file.
20
+
21
+ ```ruby
22
+ knife[:secure_data_bag][:encrypted_keys] = %w(
23
+ password
24
+ ssh_keys
25
+ ssh_ids
26
+ public_keys
27
+ private_keys
28
+ keys
29
+ secret
30
+ )
31
+ knife[:secure_data_bag][:secret_file] = "#{local_dir}/secret.pem"
32
+ knife[:secure_data_bag][:export_root] = "#{kitchen_dir}/data_bags"
33
+ knife[:secure_data_bag][:export_on_upload] = true
34
+ knife[:secure_data_bag][:defaults][:secrets][:export_format] = 'plain'
35
+ ```
14
36
 
15
- $ bundle
37
+ To break this up:
16
38
 
17
- Or install it yourself as:
39
+ `knife[:secure_data_bag][:encrypted_keys] = []`
18
40
 
19
- $ gem install secure_data_bag
41
+ When Knife Secure Bag encrypts a hash with an _encryption format_ of *nested*, it will recursively walk through the hash from the bottom up and encrypt any key found within this array.
20
42
 
21
- ## Usage
43
+ `knife[:secure_data_bag][:secret_file]`
22
44
 
23
- For the most part, this behaves exactly like a standard DataBagItem would. Encryption and Decryption of attributes ought to be completely transparent.
45
+ When encryption is required, the shared secret found at this location will be loaded.
24
46
 
25
- SecureDataBagItem is also able to read either standard DataBagItem objects or EncryptedDataBagItem since the encryption mechanism is on a per-key basis and is entirely compatible with EncryptedDataBagItem's format. One caveat, however, is that SecureDataBagItem can not be read by EncryptedDataBagItem.
47
+ `knife[:secure_data_bag][:export_root]`
26
48
 
27
- SecureDataBagItem is also built on Mash rather than Hash so you'll find it more compatible with symbol keys.
49
+ When exporting a data\_bag\_item, files will be created in below this root directory. Typically this would be the data\_bag folder located within your kitchen.
28
50
 
29
- ```
30
- > secret_key = SecureDataBagItem.load_key("/path/to/secret")
31
- > secret_key = nil # Load default secret
51
+ `knife[:secure_data_bag][:export_on_upload]`
52
+
53
+ When a data\_bag\_item is edited using `knife secure bag edit`, it may be automatically exported to the _export\_root_.
54
+
55
+ `knife[:secure_data_bag][:defaults][:secrets][:export_format]`
56
+
57
+ The configuration file additionally supports the _defaults_ hash which provides default values for all _command line arguments_ that one might use. Of all of them only the _export\_format_ key is likely to be of much use.
58
+
59
+ ## Examples
60
+
61
+ #### Chef cookbook recipe
62
+
63
+ ```ruby
64
+ metadata = {}
65
+
66
+ # Define the keys we wish to encrypt
67
+ metadata[:encrypted_keys] = %w(encoded)
68
+
69
+ # Optionally load a specific shared secret. Otherwise, the global
70
+ # encrypted\_data\_bag\_secret will be automatically used.
71
+ secret_key = SecureDataBagItem.load_key("/path/to/secret")
72
+
73
+ # Create a hash of data to use as an exampe
74
+ raw_data = {
75
+ id: "item",
76
+ data_bag: "data_bag",
77
+ encoded: "my string",
78
+ unencoded: "other string"
79
+ }
80
+
81
+ # Instantiate a SecureDataBagItem from a hash
82
+ item = SecureDataBagItem.from_hash(data, metadata)
32
83
 
33
- > data = { id:"databag", "encoded":"my string", "unencoded":"other string" }
84
+ # Or more explicitely
85
+ item = SecureDataBagItem.from_hash(data, encrypted_keys: %w(encoded))
34
86
 
35
- > item = SecureDataBagItem.from_hash(data, key: secret_key)
36
- > item.raw_data # Unencoded hash
87
+ # Or load from server
88
+ item = SecureDataBagItem.load("data_bag", "item")
89
+
90
+ # Print the un-encrypted raw data
91
+ pp item.raw_data
92
+
93
+ # Print the un-encrypted `encoded` key
94
+ pp item['encoded']
95
+
96
+ # Print the encrypted hash as a data_bag_item hash
97
+ pp item.to_hash
98
+
99
+ =begin
37
100
  {
38
- id: "databag",
101
+ id: "item",
102
+ data_bag: "data_bag",
39
103
  encoded: {
40
104
  encrypted_data: "encoded",
41
105
  cipher: aes-256-cbc,
@@ -44,41 +108,96 @@ SecureDataBagItem is also built on Mash rather than Hash so you'll find it more
44
108
  }
45
109
  unencoded: "other string",
46
110
  }
47
-
48
- > item.to_hash
49
- {
50
- id: "databag",
51
- chef_type: "data_bag_item",
52
- data_bag: "",
53
- encoded: "my string",
54
- unencoded: "other string"
55
- }
111
+ =end
56
112
  ```
57
113
 
58
- A few knife commands are also provided which allow you to edit / show / from file any DataBagItem or EncryptedDataBagItem and convert them to SecureDataBag::Item format.
114
+ ## Usage
59
115
 
60
- ```
61
- knife secure bag --help
62
- ** SECURE BAG COMMANDS **
63
- knife secure bag edit BAG [ITEM] (options)
64
- knife secure bag from file BAG FILE|FLDR [FILE|FLDR] (options)
65
- knife secure bag show BAG [ITEM] (options)
66
- ```
116
+ #### Knife commands
67
117
 
68
- Additionally it accepts the following command-line options :
118
+ Print an DataBagItem, EncryptedDataBagItem or SecureDataBagItem, auto-detecting the encryption method used as plain text.
69
119
 
120
+ ```shell
121
+ knife secure bag show -F js secrets secret_item
70
122
  ```
71
- --secret-file /path/to/secret.pem
72
- --secret passcode
73
- --encoded-fields field_one,field_two,field_three
123
+
124
+ Print an DataBagItem, EncryptedDataBagItem or SecureDataBagItem, auto-detecting the encryption method used as a SecureDataBagItem in encrypted format.
125
+
126
+ ```shell
127
+ knife secure bag show -F js secrets secret_item --enc-format nested
74
128
  ```
75
129
 
76
- Which may also be configured in knife.rb:
130
+ Edit an EncryptedDataBagItem, preserve it's encryption type, and export a copy to the _data\_bag_ folder in your kitchen.
77
131
 
132
+ ```shell
133
+ knife secure bag edit secrets secret_item --export
78
134
  ```
79
- knife[:secure_data_bag] = {
80
- fields: ["password","ssh_keys"],
81
- secret_file: "/path/to/secret.pem"
82
- }
135
+
136
+ ## Knife SubCommands
137
+
138
+ Most of the SubCommands support the following command-line options:
139
+
140
+ `--enc-format [plain,encrypted,nested]`
141
+
142
+ Ensure that, when displaying or uploading the data\_bag\_item, we forcibly encrypt the data\_bag\_item using the specified format instead of preserving the existing format.
143
+
144
+ In this case:
145
+ - plain: refers to a DataBagItem
146
+ - encrypted: refers to an EnrytpedDataBagItem
147
+ - nested: refers to a SecureDataBagItem
148
+
149
+ `--dec-format [plain,encrypted,nested]`
150
+
151
+ Attempt to decrypt the data\_bag\_item using the given format rather than the auto-detected one. The only real reason to use this is when you wish to specifically select _plain_ as the format so as to not decrypt the item.
152
+
153
+ `--enc-keys key1,key2,key3`
154
+
155
+ Provide a comma delimited list of hash keys which should be encrypted when encrypting the data\_bag\_item. This list will be concatenated with any key names listed in the configuration file or which were previously encrypted.
156
+
157
+ `--export`
158
+
159
+ Export the data\_bag\_item to json file in either of _export-format_ or _enc-format_.
160
+
161
+ `--export-format`
162
+
163
+ Overrides the encryption format only for the _export_ feature.
164
+
165
+ `--export-root`
166
+
167
+ Root directly under which a folder should exist for each _data_bag_ into which to export _data_bag_items_ as json files.
168
+
169
+ When displaying the content of the _data\_bag\_item_, an additional key of *_secure_metadata* will be added to the output which contains gem specific metadata such as the encryption formats and any encrypted keys found. This key will _not_ be saved with the item, however it may be manipulated to alter the behavior of the _edit_ or _export_ commands.
170
+
171
+ #### knife secure bag show DATA_BAG ITEM
172
+
173
+ This command functions just like `knife data bag show` and is used to print out the content of either a DataBagItem, EncryptedDataBagItem or SecureDataBagItem.
174
+
175
+ By default, it will auto-detect the Item type, and print it's unencrypted version to the terminal. This behavior, however, may be altered using the previously mentioned command line options.
176
+
177
+ #### knife secure bag open PATH
178
+
179
+ This commands functions much like `knife secure bag show`, however it is designed to load a _data\_bag\_item_ from disk as opposed to loading it from Chef server. This may be of use when view the content of an exported encrypted file.
180
+
181
+ #### knife secure bag edit DATA_BAG DATA_BAG_ITEM
182
+
183
+ This command functions just like `knife data bag edit` and is used to edit either a DataBagItem, EncryptedDataBagItem or a SecureDataBagItem. It supports all of the same options as `knife secure bag show`.
184
+
185
+ #### knife secure bag from file DATA_BAG PATH
186
+
187
+ This command functions just like `knife data bag from file` and is used to upload either a DataBagItem, EncryptedDataBagItem or a SecureDataBagItem. It supports all of the same options as `knife secure bag show`.
188
+
189
+ ## Recipe DSL
190
+
191
+ The gem additionally provides a few Recipe DSL methods which may be useful.
192
+
193
+ ```ruby
194
+ load_secure_item = secure_data_bag_item(
195
+ data_bag_name,
196
+ data_bag_item,
197
+ cache: false
198
+ )
199
+
200
+ load_plain_item = data_bag_item(data_bag_name, data_bag_item)
201
+ convert_plain_to_secure = secure_data_bag_item!(load_plain_item)
83
202
  ```
84
203
 
data/Rakefile CHANGED
@@ -1,2 +1 @@
1
- require "bundler/gem_tasks"
2
-
1
+ require 'bundler/gem_tasks'
@@ -1,14 +1,12 @@
1
-
2
1
  require 'chef/config'
3
2
 
4
3
  class Chef
5
4
  class Config
6
5
  config_context :knife do
7
6
  config_context :secure_data_bag do
8
- default :secret_file, nil
9
- default :fields, nil
7
+ config_context :export_metadata do
8
+ end
10
9
  end
11
10
  end
12
11
  end
13
12
  end
14
-
@@ -1,4 +1,3 @@
1
1
 
2
- require "chef/dsl/data_query"
2
+ require 'chef/dsl/data_query'
3
3
  Chef::DSL::DataQuery.send(:include, SecureDataBag::DSL::DataQuery)
4
-
@@ -1,60 +1,58 @@
1
-
2
- require 'chef/knife/secure_bag_base'
3
1
  require 'chef/knife/data_bag_edit'
2
+ require_relative 'secure_data_bag/base_mixin'
3
+ require_relative 'secure_data_bag/export_mixin'
4
+ require_relative 'secure_data_bag/secrets_mixin'
5
+ require_relative 'secure_data_bag/defaults_mixin'
4
6
 
5
7
  class Chef
6
8
  class Knife
7
9
  class SecureBagEdit < Knife::DataBagEdit
8
- include Knife::SecureBagBase
9
-
10
- banner "knife secure bag edit BAG [ITEM] (options)"
11
- category "secure bag"
10
+ include SecureDataBag::BaseMixin
11
+ include SecureDataBag::ExportMixin
12
+ include SecureDataBag::SecretsMixin
13
+ include SecureDataBag::DefaultsMixin
12
14
 
13
- def load_item(bag, item_name)
14
- item = SecureDataBag::Item.load(bag, item_name)
15
- hash = item.to_hash(encoded: false)
16
- hash["_encoded_fields"] = item.encoded_fields
17
- hash
18
- end
15
+ banner 'knife secure bag edit BAG [ITEM] (options)'
16
+ category 'secure bag'
19
17
 
20
18
  def run
21
19
  if @name_args.length != 2
22
- stdout.puts "You must supply the data bag and an item to edit!"
20
+ stdout.puts 'You must supply the data bag and an item to edit.'
23
21
  stdout.puts opt_parser
24
22
  exit 1
25
23
  end
26
24
 
25
+ config_defaults_for_data_bag!(@name_args[0])
26
+
27
27
  # Load the SecureBagItem, EncryptedDataBagItem or DataBagItem
28
- item = load_item(@name_args[0], @name_args[1])
28
+ item = load_item(@name_args[0], @name_args[1], config_metadata)
29
+ item_metadata = item.metadata.dup
30
+ item.encryption_format = 'plain'
29
31
 
30
32
  # Allow the user to modify the content
31
- edited_item = edit_hash(item)
32
-
33
- # Fetch the fields that are to be encoded
34
- fields_to_encode = edited_item.delete("_encoded_fields")
35
- if fields_to_encode and not fields_to_encode.empty?
36
- ui.info("Saving with secure fields: #{fields_to_encode.join(", ")}")
37
- else
38
- ui.info("Saving without any secure fields")
39
- end
33
+ data = item.to_hash(metadata: true)
34
+ data[::SecureDataBag::METADATA_KEY] = item_metadata
35
+
36
+ # Edit the hash
37
+ edited_item = edit_hash(data)
38
+ item_metadata = edited_item.delete(::SecureDataBag::METADATA_KEY)
40
39
 
41
40
  # Generate a new SecureBagItem
42
- item_to_save = SecureDataBag::Item.new(
43
- data: edited_item,
44
- fields: fields_to_encode
45
- )
46
- item_to_save.data_bag @name_args[0] # Set data_bag to match initial
47
- item_to_save["id"] = @name_args[1] # Ensure id was not changed
41
+ item_to_save = ::SecureDataBag::Item
42
+ .from_hash(edited_item, item_metadata)
43
+ item_to_save.data_bag @name_args[0]
44
+ item_to_save['id'] = @name_args[1]
45
+
48
46
  item_to_save.save
47
+ stdout.puts("Saved as #{@name_args[0]}[#{@name_args[1]}]")
49
48
 
50
- stdout.puts("Saved data_bag_item[#{@name_args[1]}]")
49
+ export!(@name_args[0], @name_args[1], item_to_save) if should_export?
51
50
 
52
51
  if config[:print_after]
53
- data_to_print = item_to_save.to_hash(encoded: true)
54
- ui.output(Chef::JSONCompat.to_json_pretty(data_to_print))
52
+ data_to_print = item_to_save.to_hash
53
+ stdout.puts(Chef::JSONCompat.to_json_pretty(data_to_print))
55
54
  end
56
55
  end
57
56
  end
58
57
  end
59
58
  end
60
-
@@ -1,42 +1,34 @@
1
-
2
- require 'chef/knife/secure_bag_base'
3
1
  require 'chef/knife/data_bag_from_file'
2
+ require_relative 'secure_data_bag/base_mixin'
3
+ require_relative 'secure_data_bag/secrets_mixin'
4
+ require_relative 'secure_data_bag/defaults_mixin'
4
5
 
5
6
  class Chef
6
7
  class Knife
7
8
  class SecureBagFromFile < Knife::DataBagFromFile
8
- include Knife::SecureBagBase
9
+ include SecureDataBag::BaseMixin
10
+ include SecureDataBag::SecretsMixin
11
+ include SecureDataBag::DefaultsMixin
9
12
 
10
13
  deps do
11
14
  require 'chef/data_bag'
12
15
  require 'chef/data_bag_item'
13
16
  require 'chef/knife/core/object_loader'
14
17
  require 'chef/json_compat'
15
- require 'secure_data_bag'
18
+ require 'chef/encrypted_data_bag_item'
16
19
  end
17
20
 
18
- banner "knife secure bag from file BAG FILE|FLDR [FILE|FLDR] (options)"
19
- category "secure bag"
20
-
21
- option :all,
22
- short: "-a",
23
- long: "--all",
24
- description: "Upload all data bags or all items for specified databag"
21
+ banner 'knife secure bag from file BAG FILE|FLDR [FILE|FLDR] (options)'
22
+ category 'secure bag'
25
23
 
26
- def load_data_bag_hash(hash)
27
- item = SecureDataBag::Item.from_hash hash,
28
- fields: encoded_fields,
29
- secret: secret
30
- item
31
- end
24
+ def load_data_bag_items(data_bag, items = nil)
25
+ config_defaults_for_data_bag!(data_bag)
32
26
 
33
- def load_data_bag_items(data_bag, items=nil)
34
27
  items ||= find_all_data_bag_items(data_bag)
35
28
  item_paths = normalize_item_paths(items)
36
29
  item_paths.each do |item_path|
37
- item = loader.load_from("#{data_bags_path}", data_bag, item_path)
38
- item = load_data_bag_hash(item)
39
- item.data_bag(data_bag)
30
+ item = loader.load_from(data_bags_path, data_bag, item_path)
31
+ item = create_item(data_bag, item_path, item)
40
32
  item.save
41
33
  ui.info("Updated data_bag_item[#{item.data_bag}::#{item.id}]")
42
34
  end
@@ -44,4 +36,3 @@ class Chef
44
36
  end
45
37
  end
46
38
  end
47
-