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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +165 -46
- data/Rakefile +1 -2
- data/lib/chef/config.rb +2 -4
- data/lib/chef/dsl/data_query.rb +1 -2
- data/lib/chef/knife/secure_bag_edit.rb +31 -33
- data/lib/chef/knife/secure_bag_from_file.rb +13 -22
- data/lib/chef/knife/secure_bag_open.rb +37 -0
- data/lib/chef/knife/secure_bag_show.rb +40 -35
- data/lib/chef/knife/secure_data_bag/base_mixin.rb +80 -0
- data/lib/chef/knife/secure_data_bag/defaults_mixin.rb +32 -0
- data/lib/chef/knife/secure_data_bag/export_mixin.rb +85 -0
- data/lib/chef/knife/secure_data_bag/secrets_mixin.rb +57 -0
- data/lib/secure_data_bag.rb +5 -7
- data/lib/secure_data_bag/check_encrypted.rb +29 -0
- data/lib/secure_data_bag/constants.rb +5 -0
- data/lib/secure_data_bag/decryptor.rb +149 -0
- data/lib/secure_data_bag/dsl/data_query.rb +6 -6
- data/lib/secure_data_bag/encryptor.rb +185 -0
- data/lib/secure_data_bag/exceptions.rb +4 -0
- data/lib/secure_data_bag/item.rb +197 -149
- data/lib/secure_data_bag/version.rb +1 -3
- data/secure_data_bag.gemspec +14 -13
- data/spec/item_spec.rb +15 -16
- data/spec/spec_helper.rb +0 -1
- metadata +112 -7
- data/lib/chef/knife/secure_bag_base.rb +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b22224b0b2102fd71b07fdc51184af1897b5b74e
|
4
|
+
data.tar.gz: 0bf974e3ba411d700bc55ed5d42fc9a7246258dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 894f9fbfcf7dd4c3ad755302a06f0fd2dd489681f7336ad07609cedb7c3f09158c3b7560c8e2ea0211fa5147681b34514185b4cc442a4824896c6518e8491afd
|
7
|
+
data.tar.gz: 0710828746350ae0988324d280618527290e44bab263a6c464faab86215de89da56ff50fd4664c82eed4cc00f80973a1596bc414bc9bcdc1e2721f5ab3e4ff66
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,41 +1,105 @@
|
|
1
|
-
# SecureDataBag
|
1
|
+
# SecureDataBag / Knife Secure Bag
|
2
2
|
|
3
|
-
|
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
|
-
|
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
|
-
|
9
|
+
To build and install the plugin add it your Gemfile or run:
|
10
10
|
|
11
|
-
|
11
|
+
```shell
|
12
|
+
gem install secure_data_bag
|
13
|
+
```
|
12
14
|
|
13
|
-
|
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
|
-
|
37
|
+
To break this up:
|
16
38
|
|
17
|
-
|
39
|
+
`knife[:secure_data_bag][:encrypted_keys] = []`
|
18
40
|
|
19
|
-
|
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
|
-
|
43
|
+
`knife[:secure_data_bag][:secret_file]`
|
22
44
|
|
23
|
-
|
45
|
+
When encryption is required, the shared secret found at this location will be loaded.
|
24
46
|
|
25
|
-
|
47
|
+
`knife[:secure_data_bag][:export_root]`
|
26
48
|
|
27
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
84
|
+
# Or more explicitely
|
85
|
+
item = SecureDataBagItem.from_hash(data, encrypted_keys: %w(encoded))
|
34
86
|
|
35
|
-
|
36
|
-
|
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: "
|
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
|
-
|
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
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
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
|
-
|
80
|
-
|
81
|
-
|
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
|
2
|
-
|
1
|
+
require 'bundler/gem_tasks'
|
data/lib/chef/config.rb
CHANGED
data/lib/chef/dsl/data_query.rb
CHANGED
@@ -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
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
include SecureDataBag::BaseMixin
|
11
|
+
include SecureDataBag::ExportMixin
|
12
|
+
include SecureDataBag::SecretsMixin
|
13
|
+
include SecureDataBag::DefaultsMixin
|
12
14
|
|
13
|
-
|
14
|
-
|
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
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
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
|
54
|
-
|
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
|
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 '
|
18
|
+
require 'chef/encrypted_data_bag_item'
|
16
19
|
end
|
17
20
|
|
18
|
-
banner
|
19
|
-
category
|
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
|
27
|
-
|
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(
|
38
|
-
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
|
-
|