secure_data_bag 2.2.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
-