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
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
|
-
|