chef-vault 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []