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 +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
data/secure_data_bag.gemspec
CHANGED
@@ -4,23 +4,24 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'secure_data_bag/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'secure_data_bag'
|
8
8
|
spec.version = SecureDataBag::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
13
|
-
spec.license =
|
14
|
-
spec.homepage =
|
15
|
-
|
9
|
+
spec.authors = ['Jonathan Serafini']
|
10
|
+
spec.email = ['jonathan@lightspeedretail.com']
|
11
|
+
spec.summary = 'Mechanism to partially encryot data bag items'
|
12
|
+
spec.description = IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
13
|
+
spec.license = 'MIT'
|
14
|
+
spec.homepage =
|
15
|
+
'https://github.com/JonathanSerafini/chef-secure_data_bag'
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency 'chef'
|
22
22
|
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'rspec'
|
26
|
+
spec.add_development_dependency 'cookstyle'
|
26
27
|
end
|
data/spec/item_spec.rb
CHANGED
@@ -4,14 +4,14 @@ require 'chef/data_bag_item'
|
|
4
4
|
require 'chef/encrypted_data_bag_item'
|
5
5
|
|
6
6
|
describe SecureDataBag::Item do
|
7
|
-
let(:key) {
|
8
|
-
let(:secret) {
|
9
|
-
let(:fields) { [
|
7
|
+
let(:key) { 'password' }
|
8
|
+
let(:secret) { 'data/secret.pem' }
|
9
|
+
let(:fields) { ['encoded'] }
|
10
10
|
|
11
|
-
let(:simple_data) { {
|
12
|
-
let(:nested_data) { simple_data.merge(
|
11
|
+
let(:simple_data) { { 'id' => 'test', decoded: 'decoded', encoded: 'encoded' } }
|
12
|
+
let(:nested_data) { simple_data.merge(nested: simple_data) }
|
13
13
|
|
14
|
-
let(:item) { SecureDataBag::Item.new(key:key, fields:fields) }
|
14
|
+
let(:item) { SecureDataBag::Item.new(key: key, fields: fields) }
|
15
15
|
|
16
16
|
let(:dbag_item) do
|
17
17
|
dbag_item = Chef::DataBagItem.new
|
@@ -31,29 +31,28 @@ describe SecureDataBag::Item do
|
|
31
31
|
nested_item
|
32
32
|
end
|
33
33
|
|
34
|
-
it
|
34
|
+
it 'encodes simple data' do
|
35
35
|
dbag = simple_item
|
36
36
|
data = dbag.encoded_data
|
37
|
-
expect(data[:decoded]).to eq(
|
38
|
-
expect(data[:encoded]).not_to eq(
|
37
|
+
expect(data[:decoded]).to eq('decoded')
|
38
|
+
expect(data[:encoded]).not_to eq('encoded')
|
39
39
|
expect(data[:encoded][:encrypted_data]).not_to eq(nil)
|
40
40
|
end
|
41
41
|
|
42
|
-
it
|
42
|
+
it 'encodes nested data' do
|
43
43
|
dbag = nested_item
|
44
44
|
data = dbag.encoded_data
|
45
|
-
expect(data[:nested][:decoded]).to eq(
|
46
|
-
expect(data[:nested][:encoded]).not_to eq(
|
45
|
+
expect(data[:nested][:decoded]).to eq('decoded')
|
46
|
+
expect(data[:nested][:encoded]).not_to eq('encoded')
|
47
47
|
expect(data[:nested][:encoded][:encrypted_data]).not_to eq(nil)
|
48
48
|
end
|
49
49
|
|
50
|
-
it
|
50
|
+
it 'decodes encrypted_data_bag_item' do
|
51
51
|
edbag = Chef::EncryptedDataBagItem.encrypt_data_bag_item(dbag_item, key)
|
52
52
|
dbag = item
|
53
53
|
dbag.raw_data = edbag
|
54
54
|
data = dbag.raw_data
|
55
|
-
expect(data[:decoded]).to eq(
|
56
|
-
expect(data[:encoded]).to eq(
|
55
|
+
expect(data[:decoded]).to eq('decoded')
|
56
|
+
expect(data[:encoded]).to eq('encoded')
|
57
57
|
end
|
58
58
|
end
|
59
|
-
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: secure_data_bag
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Serafini
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: chef
|
@@ -66,8 +66,103 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
-
|
70
|
-
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: cookstyle
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: "# SecureDataBag / Knife Secure Bag\n\nKnife Secure Bag provides a consistent
|
84
|
+
interface to DataBagItem, EncryptedDataBagItem as well as the custom created SecureDataBagItem
|
85
|
+
while also providing a few extra handy features to help in your DataBag workflows.
|
86
|
+
\n\nSecureDataBagItem, can not only manage your existing DataBagItems and EncryptedDataBagItems,
|
87
|
+
but it also provides you with a DataBag type which enables you to selectively encrypt
|
88
|
+
only some of the fields in your DataBag thus allowing you to be able to search for
|
89
|
+
the remaining fields. \n\n## Installation\n\nTo build and install the plugin add
|
90
|
+
it your Gemfile or run: \n\n```shell\ngem install secure_data_bag\n```\n\n## Configuration\n\n####
|
91
|
+
Knife Secure Bag\n\nDefaults for the Knife command may be provided in your _knife.rb_
|
92
|
+
file.\n\n```ruby\nknife[:secure_data_bag][:encrypted_keys] = %w(\n password\n ssh_keys\n
|
93
|
+
\ ssh_ids\n public_keys\n private_keys\n keys\n secret\n)\nknife[:secure_data_bag][:secret_file]
|
94
|
+
= \"#{local_dir}/secret.pem\"\nknife[:secure_data_bag][:export_root] = \"#{kitchen_dir}/data_bags\"\nknife[:secure_data_bag][:export_on_upload]
|
95
|
+
= true\nknife[:secure_data_bag][:defaults][:secrets][:export_format] = 'plain'\n```\n\nTo
|
96
|
+
break this up:\n\n`knife[:secure_data_bag][:encrypted_keys] = []`\n\nWhen Knife
|
97
|
+
Secure Bag encrypts a hash with an _encryption format_ of *nested*, it will recursively
|
98
|
+
walk through the hash from the bottom up and encrypt any key found within this array.\n\n`knife[:secure_data_bag][:secret_file]`\n\nWhen
|
99
|
+
encryption is required, the shared secret found at this location will be loaded.
|
100
|
+
\n\n`knife[:secure_data_bag][:export_root]`\n\nWhen exporting a data\\_bag\\_item,
|
101
|
+
files will be created in below this root directory. Typically this would be the
|
102
|
+
data\\_bag folder located within your kitchen.\n\n`knife[:secure_data_bag][:export_on_upload]`\n\nWhen
|
103
|
+
a data\\_bag\\_item is edited using `knife secure bag edit`, it may be automatically
|
104
|
+
exported to the _export\\_root_.\n\n`knife[:secure_data_bag][:defaults][:secrets][:export_format]`\n\nThe
|
105
|
+
configuration file additionally supports the _defaults_ hash which provides default
|
106
|
+
values for all _command line arguments_ that one might use. Of all of them only
|
107
|
+
the _export\\_format_ key is likely to be of much use.\n\n## Examples\n\n#### Chef
|
108
|
+
cookbook recipe\n\n```ruby\nmetadata = {}\n\n# Define the keys we wish to encrypt\nmetadata[:encrypted_keys]
|
109
|
+
= %w(encoded)\n\n# Optionally load a specific shared secret. Otherwise, the global
|
110
|
+
\n# encrypted\\_data\\_bag\\_secret will be automatically used.\nsecret_key = SecureDataBagItem.load_key(\"/path/to/secret\")\n\n#
|
111
|
+
Create a hash of data to use as an exampe\nraw_data = {\n\tid: \"item\", \n data_bag:
|
112
|
+
\"data_bag\",\n\tencoded: \"my string\", \n\tunencoded: \"other string\"\n}\n\n#
|
113
|
+
Instantiate a SecureDataBagItem from a hash\nitem = SecureDataBagItem.from_hash(data,
|
114
|
+
metadata)\n\n# Or more explicitely\nitem = SecureDataBagItem.from_hash(data, encrypted_keys:
|
115
|
+
%w(encoded))\n\n# Or load from server\nitem = SecureDataBagItem.load(\"data_bag\",
|
116
|
+
\"item\")\n\n# Print the un-encrypted raw data\npp item.raw_data\n\n# Print the
|
117
|
+
un-encrypted `encoded` key\npp item['encoded']\n\n# Print the encrypted hash as
|
118
|
+
a data_bag_item hash\npp item.to_hash\n\n=begin\n{ \n id: \"item\", \n
|
119
|
+
\ data_bag: \"data_bag\",\n encoded: {\n encrypted_data: \"encoded\",\n
|
120
|
+
\ cipher: aes-256-cbc,\n iv: 13453453dkgfefg==\n version: 1\n }\n unencoded:
|
121
|
+
\ \"other string\",\n}\n=end\n```\n\n## Usage\n\n#### Knife commands\n\nPrint an
|
122
|
+
DataBagItem, EncryptedDataBagItem or SecureDataBagItem, auto-detecting the encryption
|
123
|
+
method used as plain text.\n\n```shell\nknife secure bag show -F js secrets secret_item\n```\n\nPrint
|
124
|
+
an DataBagItem, EncryptedDataBagItem or SecureDataBagItem, auto-detecting the encryption
|
125
|
+
method used as a SecureDataBagItem in encrypted format.\n\n```shell\nknife secure
|
126
|
+
bag show -F js secrets secret_item --enc-format nested\n```\n\nEdit an EncryptedDataBagItem,
|
127
|
+
preserve it's encryption type, and export a copy to the _data\\_bag_ folder in your
|
128
|
+
kitchen.\n\n```shell\nknife secure bag edit secrets secret_item --export\n```\n\n##
|
129
|
+
Knife SubCommands\n\nMost of the SubCommands support the following command-line
|
130
|
+
options:\n\n`--enc-format [plain,encrypted,nested]`\n\nEnsure that, when displaying
|
131
|
+
or uploading the data\\_bag\\_item, we forcibly encrypt the data\\_bag\\_item using
|
132
|
+
the specified format instead of preserving the existing format. \n\nIn this case:
|
133
|
+
\n- plain: refers to a DataBagItem\n- encrypted: refers to an EnrytpedDataBagItem\n-
|
134
|
+
nested: refers to a SecureDataBagItem\n\n`--dec-format [plain,encrypted,nested]`\n\nAttempt
|
135
|
+
to decrypt the data\\_bag\\_item using the given format rather than the auto-detected
|
136
|
+
one. The only real reason to use this is when you wish to specifically select _plain_
|
137
|
+
as the format so as to not decrypt the item.\n\n`--enc-keys key1,key2,key3`\n\nProvide
|
138
|
+
a comma delimited list of hash keys which should be encrypted when encrypting the
|
139
|
+
data\\_bag\\_item. This list will be concatenated with any key names listed in the
|
140
|
+
configuration file or which were previously encrypted. \n\n`--export`\n\nExport
|
141
|
+
the data\\_bag\\_item to json file in either of _export-format_ or _enc-format_.\n\n`--export-format`\n\nOverrides
|
142
|
+
the encryption format only for the _export_ feature.\n\n`--export-root`\n\nRoot
|
143
|
+
directly under which a folder should exist for each _data_bag_ into which to export
|
144
|
+
_data_bag_items_ as json files.\n\nWhen displaying the content of the _data\\_bag\\_item_,
|
145
|
+
an additional key of *_secure_metadata* will be added to the output which contains
|
146
|
+
gem specific metadata such as the encryption formats and any encrypted keys found.
|
147
|
+
This key will _not_ be saved with the item, however it may be manipulated to alter
|
148
|
+
the behavior of the _edit_ or _export_ commands.\n\n#### knife secure bag show DATA_BAG
|
149
|
+
ITEM\n\nThis command functions just like `knife data bag show` and is used to print
|
150
|
+
out the content of either a DataBagItem, EncryptedDataBagItem or SecureDataBagItem.\n\nBy
|
151
|
+
default, it will auto-detect the Item type, and print it's unencrypted version to
|
152
|
+
the terminal. This behavior, however, may be altered using the previously mentioned
|
153
|
+
command line options.\n\n#### knife secure bag open PATH\n\nThis commands functions
|
154
|
+
much like `knife secure bag show`, however it is designed to load a _data\\_bag\\_item_
|
155
|
+
from disk as opposed to loading it from Chef server. This may be of use when view
|
156
|
+
the content of an exported encrypted file.\n\n#### knife secure bag edit DATA_BAG
|
157
|
+
DATA_BAG_ITEM\n\nThis command functions just like `knife data bag edit` and is used
|
158
|
+
to edit either a DataBagItem, EncryptedDataBagItem or a SecureDataBagItem. It supports
|
159
|
+
all of the same options as `knife secure bag show`. \n\n#### knife secure bag from
|
160
|
+
file DATA_BAG PATH\n\nThis command functions just like `knife data bag from file`
|
161
|
+
and is used to upload either a DataBagItem, EncryptedDataBagItem or a SecureDataBagItem.
|
162
|
+
It supports all of the same options as `knife secure bag show`. \n\n## Recipe DSL\n\nThe
|
163
|
+
gem additionally provides a few Recipe DSL methods which may be useful.\n\n```ruby\nload_secure_item
|
164
|
+
= secure_data_bag_item(\n data_bag_name, \n data_bag_item, \n cache: false\n)\n\nload_plain_item
|
165
|
+
= data_bag_item(data_bag_name, data_bag_item)\nconvert_plain_to_secure = secure_data_bag_item!(load_plain_item)\n```\n\n"
|
71
166
|
email:
|
72
167
|
- jonathan@lightspeedretail.com
|
73
168
|
executables: []
|
@@ -76,18 +171,28 @@ extra_rdoc_files: []
|
|
76
171
|
files:
|
77
172
|
- ".gitignore"
|
78
173
|
- ".rspec"
|
174
|
+
- CHANGELOG.md
|
79
175
|
- Gemfile
|
80
176
|
- LICENSE.txt
|
81
177
|
- README.md
|
82
178
|
- Rakefile
|
83
179
|
- lib/chef/config.rb
|
84
180
|
- lib/chef/dsl/data_query.rb
|
85
|
-
- lib/chef/knife/secure_bag_base.rb
|
86
181
|
- lib/chef/knife/secure_bag_edit.rb
|
87
182
|
- lib/chef/knife/secure_bag_from_file.rb
|
183
|
+
- lib/chef/knife/secure_bag_open.rb
|
88
184
|
- lib/chef/knife/secure_bag_show.rb
|
185
|
+
- lib/chef/knife/secure_data_bag/base_mixin.rb
|
186
|
+
- lib/chef/knife/secure_data_bag/defaults_mixin.rb
|
187
|
+
- lib/chef/knife/secure_data_bag/export_mixin.rb
|
188
|
+
- lib/chef/knife/secure_data_bag/secrets_mixin.rb
|
89
189
|
- lib/secure_data_bag.rb
|
190
|
+
- lib/secure_data_bag/check_encrypted.rb
|
191
|
+
- lib/secure_data_bag/constants.rb
|
192
|
+
- lib/secure_data_bag/decryptor.rb
|
90
193
|
- lib/secure_data_bag/dsl/data_query.rb
|
194
|
+
- lib/secure_data_bag/encryptor.rb
|
195
|
+
- lib/secure_data_bag/exceptions.rb
|
91
196
|
- lib/secure_data_bag/item.rb
|
92
197
|
- lib/secure_data_bag/version.rb
|
93
198
|
- secure_data_bag.gemspec
|
@@ -113,10 +218,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
218
|
version: '0'
|
114
219
|
requirements: []
|
115
220
|
rubyforge_project:
|
116
|
-
rubygems_version: 2.
|
221
|
+
rubygems_version: 2.2.3
|
117
222
|
signing_key:
|
118
223
|
specification_version: 4
|
119
|
-
summary:
|
224
|
+
summary: Mechanism to partially encryot data bag items
|
120
225
|
test_files:
|
121
226
|
- spec/item_spec.rb
|
122
227
|
- spec/spec_helper.rb
|
@@ -1,74 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'chef/knife'
|
3
|
-
|
4
|
-
class Chef
|
5
|
-
class Knife
|
6
|
-
module SecureBagBase
|
7
|
-
def self.included(includer)
|
8
|
-
includer.class_eval do
|
9
|
-
deps do
|
10
|
-
require 'secure_data_bag'
|
11
|
-
end
|
12
|
-
|
13
|
-
option :secret,
|
14
|
-
short: "-s SECRET",
|
15
|
-
long: "--secret",
|
16
|
-
description: "The secret key to use to encrypt data bag item values"
|
17
|
-
|
18
|
-
option :secret_file,
|
19
|
-
long: "--secret-file SECRET_FILE",
|
20
|
-
description: "A file containing a secret key to use to encrypt data bag item values"
|
21
|
-
|
22
|
-
option :encoded_fields,
|
23
|
-
long: "--encoded-fields FIELD1,FIELD2,FIELD3",
|
24
|
-
description: "List of attribute keys for which to encode values",
|
25
|
-
proc: Proc.new { |s| s.split(',') }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def encoded_fields
|
30
|
-
config[:encoded_fields] ||
|
31
|
-
Chef::Config[:knife][:secure_data_bag][:fields]
|
32
|
-
end
|
33
|
-
|
34
|
-
def secret_file
|
35
|
-
config[:secret_file] ||
|
36
|
-
SecureDataBag::Item.secret_path
|
37
|
-
end
|
38
|
-
|
39
|
-
def secret
|
40
|
-
@secret ||= read_secret
|
41
|
-
end
|
42
|
-
|
43
|
-
def use_encryption
|
44
|
-
true
|
45
|
-
end
|
46
|
-
|
47
|
-
def read_secret
|
48
|
-
if config[:secret] then config[:secret]
|
49
|
-
else SecureDataBag::Item.load_secret(secret_file)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def require_secret
|
54
|
-
if not secret
|
55
|
-
show_usage
|
56
|
-
ui.fatal("A secret or secret_file must be specified")
|
57
|
-
exit 1
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def data_for_create(hash={})
|
62
|
-
hash[:id] = @data_bag_item_name
|
63
|
-
hash
|
64
|
-
end
|
65
|
-
|
66
|
-
def data_for_save(hash)
|
67
|
-
@encoded_fields = hash.delete(:_encoded_fields)
|
68
|
-
hash
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|