chef-vault 1.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.
@@ -0,0 +1 @@
1
+ *.gem
@@ -0,0 +1,100 @@
1
+
2
+ = Chef-Vault
3
+
4
+ = DESCRIPTION:
5
+
6
+ Gem that allows you to encrypt passwords & certificates using the public key of
7
+ a list of chef nodes. This allows only those chef nodes to decrypt the
8
+ password or certificate.
9
+
10
+ = INSTALLATION:
11
+
12
+ Be sure you are running the latest version Chef. Versions earlier than 0.10.0
13
+ don't support plugins:
14
+
15
+ gem install chef
16
+
17
+ This plugin is distributed as a Ruby Gem. To install it, run:
18
+
19
+ gem install chef-vault
20
+
21
+ Depending on your system's configuration, you may need to run this command with
22
+ root privileges.
23
+
24
+ = CONFIGURATION:
25
+
26
+ = KNIFE COMMANDS:
27
+
28
+ This plugin provides the following Knife subcommands.
29
+ Specific command options can be found by invoking the subcommand with a
30
+ <tt>--help</tt> flag
31
+
32
+ == knife encrypt password
33
+
34
+ Use this knife command to encrypt the username and password that you want to
35
+ protect.
36
+
37
+ knife encrypt password --search SEARCH --username USERNAME --password PASSWORD --admins ADMINS
38
+
39
+ == knife decrypt password
40
+
41
+ Use this knife command to dencrypt the password that is protected
42
+
43
+ knife decrypt password --username USERNAME
44
+
45
+ == knife encrypt cert
46
+
47
+ Use this knife command to encrypt the contents of a certificate that you want
48
+ to protect.
49
+
50
+ knife encrypt cert --search SEARCH --cert CERT --password PASSWORD --name NAME --admins ADMINS
51
+
52
+ == knife decrypt cert
53
+
54
+ Use this knife command to dencrypt the certificate that is protected
55
+
56
+ knife decrypt cert --name NAME
57
+
58
+ = USAGE IN RECIPES
59
+
60
+ To use this gem in a recipe to decrypt data you must first install the gem
61
+ via a chef_gem resource. Once the gem is installed require the gem and then
62
+ you can create a new instance of ChefVault.
63
+
64
+ == Example Code (password)
65
+
66
+ chef_gem "chef-vault"
67
+
68
+ require 'chef-vault'
69
+
70
+ vault = ChefVault.new("passwords")
71
+ user = vault.user("Administrator")
72
+ password = user.decrypt_password
73
+
74
+ == Example Code (certificate)
75
+
76
+ chef_gem "chef-vault"
77
+
78
+ require 'chef-vault'
79
+
80
+ vault = ChefVault.new("certs")
81
+ cert = vault.certificate("domain.com")
82
+ contents = cert.decrypt_contents
83
+
84
+ = LICENSE:
85
+
86
+ Author:: Kevin Moser (<kevin.moser@nordstrom.com>)
87
+ Copyright:: Copyright (c) 2013 Nordstrom, Inc.
88
+ License:: Apache License, Version 2.0
89
+
90
+ Licensed under the Apache License, Version 2.0 (the "License");
91
+ you may not use this file except in compliance with the License.
92
+ You may obtain a copy of the License at
93
+
94
+ http://www.apache.org/licenses/LICENSE-2.0
95
+
96
+ Unless required by applicable law or agreed to in writing, software
97
+ distributed under the License is distributed on an "AS IS" BASIS,
98
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
99
+ See the License for the specific language governing permissions and
100
+ limitations under the License.
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "chef-vault/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "chef-vault"
7
+ s.version = ChefVault::VERSION
8
+ s.has_rdoc = true
9
+ s.authors = ["Kevin Moser"]
10
+ s.email = ["kevin.moser@nordstrom.com"]
11
+ s.summary = "Data encryption support for chef using data bags"
12
+ s.description = s.summary
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.add_dependency "chef", ">= 0.10.10"
16
+ s.require_paths = ["lib"]
17
+ end
@@ -0,0 +1,43 @@
1
+ #
2
+ # Author:: Kevin Moser (<kevin.moser@nordstrom.com>)
3
+ #
4
+ # Copyright:: 2013, Nordstrom, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef'
20
+ require 'chef-vault/user'
21
+ require 'chef-vault/certificate'
22
+ require 'chef-vault/version'
23
+
24
+ class ChefVault
25
+
26
+ attr_accessor :data_bag
27
+
28
+ def initialize(data_bag)
29
+ @data_bag = data_bag
30
+ end
31
+
32
+ def version
33
+ VERSION
34
+ end
35
+
36
+ def user(username)
37
+ ChefVault::User.new(@data_bag, username)
38
+ end
39
+
40
+ def certificate(name)
41
+ ChefVault::Certificate.new(@data_bag, name)
42
+ end
43
+ end
@@ -0,0 +1,27 @@
1
+ class ChefVault
2
+ class Certificate
3
+ attr_accessor :name
4
+
5
+ def initialize(data_bag, name)
6
+ @name = name
7
+ @data_bag = data_bag
8
+ end
9
+
10
+ def decrypt_contents
11
+ # use the private client_key file to create a decryptor
12
+ private_key = open(Chef::Config[:client_key]).read
13
+ private_key = OpenSSL::PKey::RSA.new(private_key)
14
+ keys = Chef::DataBagItem.load(@data_bag, "#{name}_keys")
15
+
16
+ unless keys[Chef::Config[:node_name]]
17
+ throw "#{name} is not encrypted for you! Rebuild the certificate data bag"
18
+ end
19
+
20
+ node_key = Base64.decode64(keys[Chef::Config[:node_name]])
21
+ shared_secret = private_key.private_decrypt(node_key)
22
+ certificate = Chef::EncryptedDataBagItem.load(@data_bag, @name, shared_secret)
23
+
24
+ certificate["contents"]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ class ChefVault
2
+ class User
3
+ attr_accessor :username
4
+
5
+ def initialize(data_bag, username)
6
+ @username = username
7
+ @data_bag = data_bag
8
+ end
9
+
10
+ def decrypt_password
11
+ # use the private client_key file to create a decryptor
12
+ private_key = open(Chef::Config[:client_key]).read
13
+ private_key = OpenSSL::PKey::RSA.new(private_key)
14
+ keys = Chef::DataBagItem.load(@data_bag, "#{username}_keys")
15
+
16
+ unless keys[Chef::Config[:node_name]]
17
+ throw "Password for #{username} is not encrypted for you! Rebuild the password data bag"
18
+ end
19
+
20
+ node_key = Base64.decode64(keys[Chef::Config[:node_name]])
21
+ shared_secret = private_key.private_decrypt(node_key)
22
+ cred = Chef::EncryptedDataBagItem.load(@data_bag, @username, shared_secret)
23
+
24
+ cred["password"]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,4 @@
1
+ class ChefVault
2
+ VERSION = "1.0.0"
3
+ MAJOR, MINOR, TINY = VERSION.split('.')
4
+ end
@@ -0,0 +1,43 @@
1
+ require 'chef/knife'
2
+
3
+ class DecryptCert < Chef::Knife
4
+ deps do
5
+ require 'chef/search/query'
6
+ require 'chef/shef/ext'
7
+ require 'json'
8
+ end
9
+
10
+ banner "knife decrypt cert --name NAME"
11
+
12
+ option :name,
13
+ :short => '-N NAME',
14
+ :long => '--name NAME',
15
+ :description => 'Certificate data bag name'
16
+
17
+ def run
18
+ unless config[:name]
19
+ puts("You must supply a certificate to decrypt")
20
+ exit 1
21
+ end
22
+ Shef::Extensions.extend_context_object(self)
23
+
24
+ data_bag = "certs"
25
+ data_bag_path = "./data_bags/#{data_bag}"
26
+
27
+ name = config[:name].gsub(".", "_")
28
+
29
+ user_private_key = OpenSSL::PKey::RSA.new(open(Chef::Config[:client_key]).read())
30
+ key = JSON.parse(IO.read("#{data_bag_path}/#{name}_keys.json"))
31
+ unless key[Chef::Config[:node_name]]
32
+ puts("Can't find a key for #{Chef::Config[:node_name]}... You can't decrypt!")
33
+ exit 1
34
+ end
35
+
36
+ data_bag_shared_key = user_private_key.private_decrypt(Base64.decode64(key[Chef::Config[:node_name]]))
37
+
38
+ certificate = JSON.parse(open("#{data_bag_path}/#{name}.json").read())
39
+ certificate = Chef::EncryptedDataBagItem.new certificate, data_bag_shared_key
40
+
41
+ puts("certificate:\n#{certificate['contents']}")
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ require 'chef/knife'
2
+
3
+ class DecryptPassword < Chef::Knife
4
+ deps do
5
+ require 'chef/search/query'
6
+ require 'chef/shef/ext'
7
+ require 'json'
8
+ end
9
+
10
+ banner "knife decrypt password --username USERNAME"
11
+
12
+ option :username,
13
+ :short => '-U USERNAME',
14
+ :long => '--username USERNAME',
15
+ :description => 'username of account to encrypt'
16
+
17
+ def run
18
+ unless config[:username]
19
+ puts("You must supply a username to decrypt")
20
+ exit 1
21
+ end
22
+ Shef::Extensions.extend_context_object(self)
23
+
24
+ data_bag_path = "./data_bags/passwords"
25
+
26
+ username = config[:username]
27
+
28
+ user_private_key = OpenSSL::PKey::RSA.new(open(Chef::Config[:client_key]).read())
29
+ key = JSON.parse(IO.read("#{data_bag_path}/#{username}_keys.json"))
30
+ unless key[Chef::Config[:node_name]]
31
+ puts("Can't find a key for #{Chef::Config[:node_name]}... You can't decrypt!")
32
+ exit 1
33
+ end
34
+
35
+ data_bag_shared_key = user_private_key.private_decrypt(Base64.decode64(key[Chef::Config[:node_name]]))
36
+
37
+ credential = JSON.parse(open("#{data_bag_path}/#{username}.json").read())
38
+ credential = Chef::EncryptedDataBagItem.new credential, data_bag_shared_key
39
+
40
+ puts("username: #{credential['username']}, password: #{credential['password']}")
41
+ end
42
+ end
@@ -0,0 +1,165 @@
1
+ require 'chef/knife'
2
+
3
+ class EncryptCert < Chef::Knife
4
+ deps do
5
+ require 'chef/search/query'
6
+ require 'chef/shef/ext'
7
+ end
8
+
9
+ banner "knife encrypt cert --search SEARCH --cert CERT --password PASSWORD --name NAME --admins ADMINS"
10
+
11
+ option :search,
12
+ :short => '-S SEARCH',
13
+ :long => '--search SEARCH',
14
+ :description => 'node search for nodes to encrypt to'
15
+
16
+ option :cert,
17
+ :short => '-C CERT',
18
+ :long => '--cert CERT',
19
+ :description => 'cert with contents to encrypt'
20
+
21
+ option :admins,
22
+ :short => '-A ADMINS',
23
+ :long => '--admins ADMINS',
24
+ :description => 'administrators who can decrypt certificate'
25
+
26
+ option :password,
27
+ :short => '-P PASSWORD',
28
+ :long => '--password PASSWORD',
29
+ :description => 'optional pfx password'
30
+
31
+ option :name,
32
+ :short => '-N NAME',
33
+ :long => '--name NAME',
34
+ :description => 'optional data bag name'
35
+
36
+ def run
37
+ unless config[:search]
38
+ puts("You must supply either -S or --search")
39
+ exit 1
40
+ end
41
+ unless config[:cert]
42
+ puts("You must supply either -C or --cert")
43
+ exit 1
44
+ end
45
+ unless config[:admins]
46
+ puts("You must supply either -A or --admins")
47
+ exit 1
48
+ end
49
+ Shef::Extensions.extend_context_object(self)
50
+
51
+ data_bag = "certs"
52
+ data_bag_path = "./data_bags/#{data_bag}"
53
+
54
+ node_search = config[:search]
55
+ admins = config[:admins]
56
+ file_to_encrypt = config[:cert]
57
+ contents = open(file_to_encrypt, "rb").read
58
+ name = config[:name] ? config[:name].gsub(".", "_") : File.basename(file_to_encrypt, ".*").gsub(".", "_")
59
+
60
+ current_dbi = Hash.new
61
+ current_dbi_keys = Hash.new
62
+ if File.exists?("#{data_bag_path}/#{name}_keys.json") && File.exists?("#{data_bag_path}/#{name}.json")
63
+ current_dbi_keys = JSON.parse(open("#{data_bag_path}/#{name}_keys.json").read())
64
+ current_dbi = JSON.parse(open("#{data_bag_path}/#{name}.json").read())
65
+
66
+ unless equal?(data_bag, name, "contents", contents)
67
+ puts("FATAL: Content in #{data_bag_path}/#{name}.json does not match content in file supplied!")
68
+ exit 1
69
+ end
70
+ else
71
+ puts("INFO: Existing data bag #{data_bag}/#{name} does not exist in #{data_bag_path}, continuing as fresh build...")
72
+ end
73
+
74
+ # Get the public keys for all of the nodes to encrypt for. Skipping the nodes that are already in
75
+ # the data bag
76
+ keyfob = Hash.new
77
+ public_keys = search(:node, node_search).map(&:name).map do |client|
78
+ begin
79
+ if current_dbi_keys[client]
80
+ puts("INFO: Skipping #{client} as it is already in the data bag...")
81
+ else
82
+ puts("INFO: Adding #{client} to public_key array...")
83
+ cert_der = api.get("clients/#{client}")['certificate']
84
+ cert = OpenSSL::X509::Certificate.new cert_der
85
+ keyfob[client]=OpenSSL::PKey::RSA.new cert.public_key
86
+ end
87
+ rescue Exception => node_error
88
+ puts("WARNING: Caught exception: #{node_error.message} while processing #{client}, so skipping...")
89
+ end
90
+ end
91
+
92
+ # Get the public keys for the admin users, skipping users already in the data bag
93
+ public_keys << admins.split(",").map do |user|
94
+ begin
95
+ if current_dbi_keys[user]
96
+ puts("INFO: Skipping #{user} as it is already in the data bag")
97
+ else
98
+ puts("INFO: Adding #{user} to public_key array...")
99
+ public_key = api.get("users/#{user}")['public_key']
100
+ keyfob[user] = OpenSSL::PKey::RSA.new public_key
101
+ end
102
+ rescue Exception => user_error
103
+ puts("WARNING: Caught exception: #{user_error.message} while processing #{user}, so skipping...")
104
+ end
105
+ end
106
+
107
+ if public_keys.length == 0
108
+ puts "A node search for #{node_search} returned no results"
109
+ exit 1
110
+ end
111
+
112
+ # Get the current secret, is nil if current secret does not exist yet
113
+ current_secret = get_shared_secret(data_bag, name)
114
+ data_bag_shared_key = current_secret ? current_secret : OpenSSL::PKey::RSA.new(245).to_pem.lines.to_a[1..-2].join
115
+ enc_db_key_dbi = current_dbi_keys.empty? ? Mash.new({id: "#{name}_keys"}) : current_dbi_keys
116
+
117
+ # Encrypt for every new node not already in the data bag
118
+ keyfob.each do |node,pkey|
119
+ puts("INFO: Encrypting for #{node}...")
120
+ enc_db_key_dbi[node] = Base64.encode64(pkey.public_encrypt(data_bag_shared_key))
121
+ end unless keyfob.empty?
122
+
123
+ # Delete existing keys data bag and rewrite the whole bag from memory
124
+ puts("INFO: Writing #{data_bag_path}/#{name}_keys.json...")
125
+ File.delete("#{data_bag_path}/#{name}_keys.json") if File.exists?("#{data_bag_path}/#{name}_keys.json")
126
+ File.open("#{data_bag_path}/#{name}_keys.json",'w').write(JSON.pretty_generate(enc_db_key_dbi))
127
+
128
+ # If the existing certificate bag does not exist, write it out with the correct certificate
129
+ # Otherwise leave the existing bag alone
130
+ if current_dbi.empty?
131
+ dbi_mash = Mash.new({id: name, contents: contents})
132
+ dbi_mash.merge!({password: config[:password]}) if config[:password]
133
+ dbi = Chef::DataBagItem.from_hash(dbi_mash)
134
+ edbi = Chef::EncryptedDataBagItem.encrypt_data_bag_item(dbi, data_bag_shared_key)
135
+
136
+ puts("INFO: Writing #{data_bag_path}/#{name}.json...")
137
+ open("#{data_bag_path}/#{name}.json",'w').write(JSON.pretty_generate(edbi))
138
+ end
139
+
140
+ puts("INFO: Successfully wrote #{data_bag_path}/#{name}.json & #{data_bag_path}/#{name}_keys.json!")
141
+ end
142
+
143
+ def equal?(db, dbi, key, value)
144
+ data_bag_path = "./data_bags/#{db}"
145
+
146
+ shared_secret = get_shared_secret(db, dbi)
147
+ dbi = JSON.parse(open("#{data_bag_path}/#{dbi}.json").read())
148
+ dbi = Chef::EncryptedDataBagItem.new dbi, shared_secret
149
+
150
+ dbi[key] == value
151
+ end
152
+
153
+ def get_shared_secret(db, dbi)
154
+ data_bag_path = "./data_bags/#{db}"
155
+
156
+ private_key = OpenSSL::PKey::RSA.new(open(Chef::Config[:client_key]).read())
157
+ key = File.exists?("#{data_bag_path}/#{dbi}_keys.json") ? JSON.parse(open("#{data_bag_path}/#{dbi}_keys.json").read()) : nil
158
+
159
+ begin
160
+ private_key.private_decrypt(Base64.decode64(key[Chef::Config[:node_name]]))
161
+ rescue
162
+ nil
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,161 @@
1
+ require 'chef/knife'
2
+
3
+ class EncryptPassword < Chef::Knife
4
+ deps do
5
+ require 'chef/search/query'
6
+ require 'chef/shef/ext'
7
+ end
8
+
9
+ banner "knife encrypt password --search SEARCH --username USERNAME --password PASSWORD --admins ADMINS"
10
+
11
+ option :search,
12
+ :short => '-S SEARCH',
13
+ :long => '--search SEARCH',
14
+ :description => 'node search for nodes to encrypt for'
15
+
16
+ option :username,
17
+ :short => '-U USERNAME',
18
+ :long => '--username USERNAME',
19
+ :description => 'username of account to encrypt'
20
+
21
+ option :password,
22
+ :short => '-P PASSWORD',
23
+ :long => '--password PASSWORD',
24
+ :description => 'password of account to encrypt'
25
+
26
+ option :admins,
27
+ :short => '-A ADMINS',
28
+ :long => '--admins ADMINS',
29
+ :description => 'administrators who can decrypt password'
30
+
31
+ def run
32
+ unless config[:search]
33
+ puts("You must supply either -S or --search")
34
+ exit 1
35
+ end
36
+ unless config[:username]
37
+ puts("You must supply either -U or --username")
38
+ exit 1
39
+ end
40
+ unless config[:password]
41
+ puts("You must supply either -P or --password")
42
+ exit 1
43
+ end
44
+ unless config[:admins]
45
+ puts("You must supply either -A or --admins")
46
+ exit 1
47
+ end
48
+ Shef::Extensions.extend_context_object(self)
49
+
50
+ data_bag = "passwords"
51
+ data_bag_path = "./data_bags/#{data_bag}"
52
+
53
+ node_search = config[:search]
54
+ admins = config[:admins]
55
+ username = config[:username]
56
+ password = config[:password]
57
+ current_dbi = Hash.new
58
+ current_dbi_keys = Hash.new
59
+ if File.exists?("#{data_bag_path}/#{username}_keys.json") && File.exists?("#{data_bag_path}/#{username}.json")
60
+ current_dbi_keys = JSON.parse(open("#{data_bag_path}/#{username}_keys.json").read())
61
+ current_dbi = JSON.parse(open("#{data_bag_path}/#{username}.json").read())
62
+
63
+ unless equal?(data_bag, username, "password", password)
64
+ puts("FATAL: Password in #{data_bag_path}/#{username}.json does not match password supplied!")
65
+ exit 1
66
+ end
67
+ else
68
+ puts("INFO: Existing data bag #{data_bag}/#{username} does not exist in #{data_bag_path}, continuing as fresh build...")
69
+ end
70
+
71
+ # Get the public keys for all of the nodes to encrypt for. Skipping the nodes that are already in
72
+ # the data bag
73
+ keyfob = Hash.new
74
+ public_keys = search(:node, node_search).map(&:name).map do |client|
75
+ begin
76
+ if current_dbi_keys[client]
77
+ puts("INFO: Skipping #{client} as it is already in the data bag...")
78
+ else
79
+ puts("INFO: Adding #{client} to public_key array...")
80
+ cert_der = api.get("clients/#{client}")['certificate']
81
+ cert = OpenSSL::X509::Certificate.new cert_der
82
+ keyfob[client]=OpenSSL::PKey::RSA.new cert.public_key
83
+ end
84
+ rescue Exception => node_error
85
+ puts("WARNING: Caught exception: #{node_error.message} while processing #{client}, so skipping...")
86
+ end
87
+ end
88
+
89
+ # Get the public keys for the admin users, skipping users already in the data bag
90
+ public_keys << admins.split(",").map do |user|
91
+ begin
92
+ if current_dbi_keys[user]
93
+ puts("INFO: Skipping #{user} as it is already in the data bag")
94
+ else
95
+ puts("INFO: Adding #{user} to public_key array...")
96
+ public_key = api.get("users/#{user}")['public_key']
97
+ keyfob[user] = OpenSSL::PKey::RSA.new public_key
98
+ end
99
+ rescue Exception => user_error
100
+ puts("WARNING: Caught exception: #{user_error.message} while processing #{user}, so skipping...")
101
+ end
102
+ end
103
+
104
+ if public_keys.length == 0
105
+ puts "A node search for #{node_search} returned no results"
106
+ exit 1
107
+ end
108
+
109
+ # Get the current secret, is nil if current secret does not exist yet
110
+ current_secret = get_shared_secret(data_bag, username)
111
+ data_bag_shared_key = current_secret ? current_secret : OpenSSL::PKey::RSA.new(245).to_pem.lines.to_a[1..-2].join
112
+ enc_db_key_dbi = current_dbi_keys.empty? ? Mash.new({id: "#{username}_keys"}) : current_dbi_keys
113
+
114
+ # Encrypt for every new node not already in the data bag
115
+ keyfob.each do |node,pkey|
116
+ puts("INFO: Encrypting for #{node}...")
117
+ enc_db_key_dbi[node] = Base64.encode64(pkey.public_encrypt(data_bag_shared_key))
118
+ end unless keyfob.empty?
119
+
120
+ # Delete existing keys data bag and rewrite the whole bag from memory
121
+ puts("INFO: Writing #{data_bag_path}/#{username}_keys.json...")
122
+ File.delete("#{data_bag_path}/#{username}_keys.json") if File.exists?("#{data_bag_path}/#{username}_keys.json")
123
+ File.open("#{data_bag_path}/#{username}_keys.json",'w').write(JSON.pretty_generate(enc_db_key_dbi))
124
+
125
+ # If the existing password bag does not exist, write it out with the correct password
126
+ # Otherwise leave the existing bag alone
127
+ if current_dbi.empty?
128
+ dbi_mash = Mash.new({id: username, username: username, password: password})
129
+ dbi = Chef::DataBagItem.from_hash(dbi_mash)
130
+ edbi = Chef::EncryptedDataBagItem.encrypt_data_bag_item(dbi, data_bag_shared_key)
131
+
132
+ puts("INFO: Writing #{data_bag_path}/#{username}.json...")
133
+ open("#{data_bag_path}/#{username}.json",'w').write(JSON.pretty_generate(edbi))
134
+ end
135
+
136
+ puts("INFO: Successfully wrote #{data_bag_path}/#{username}.json & #{data_bag_path}/#{username}_keys.json!")
137
+ end
138
+
139
+ def equal?(db, dbi, key, value)
140
+ data_bag_path = "./data_bags/#{db}"
141
+
142
+ shared_secret = get_shared_secret(db, dbi)
143
+ dbi = JSON.parse(open("#{data_bag_path}/#{dbi}.json").read())
144
+ dbi = Chef::EncryptedDataBagItem.new dbi, shared_secret
145
+
146
+ dbi[key] == value
147
+ end
148
+
149
+ def get_shared_secret(db, dbi)
150
+ data_bag_path = "./data_bags/#{db}"
151
+
152
+ private_key = OpenSSL::PKey::RSA.new(open(Chef::Config[:client_key]).read())
153
+ key = File.exists?("#{data_bag_path}/#{dbi}_keys.json") ? JSON.parse(open("#{data_bag_path}/#{dbi}_keys.json").read()) : nil
154
+
155
+ begin
156
+ private_key.private_decrypt(Base64.decode64(key[Chef::Config[:node_name]]))
157
+ rescue
158
+ nil
159
+ end
160
+ end
161
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chef-vault
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kevin Moser
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: chef
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.10.10
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 0.10.10
30
+ description: Data encryption support for chef using data bags
31
+ email:
32
+ - kevin.moser@nordstrom.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - README.rdoc
39
+ - chef-vault.gemspec
40
+ - lib/chef-vault.rb
41
+ - lib/chef-vault/certificate.rb
42
+ - lib/chef-vault/user.rb
43
+ - lib/chef-vault/version.rb
44
+ - lib/chef/knife/DecryptCert.rb
45
+ - lib/chef/knife/DecryptPassword.rb
46
+ - lib/chef/knife/EncryptCert.rb
47
+ - lib/chef/knife/EncryptPassword.rb
48
+ homepage:
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.24
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Data encryption support for chef using data bags
72
+ test_files: []