31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
# File 'lib/chef/knife/EncryptPassword.rb', line 31
def run
unless config[:search]
puts("You must supply either -S or --search")
exit 1
end
unless config[:username]
puts("You must supply either -U or --username")
exit 1
end
unless config[:password]
puts("You must supply either -P or --password")
exit 1
end
unless config[:admins]
puts("You must supply either -A or --admins")
exit 1
end
Shef::Extensions.extend_context_object(self)
data_bag = "passwords"
data_bag_path = "./data_bags/#{data_bag}"
node_search = config[:search]
admins = config[:admins]
username = config[:username]
password = config[:password]
current_dbi = Hash.new
current_dbi_keys = Hash.new
if File.exists?("#{data_bag_path}/#{username}_keys.json") && File.exists?("#{data_bag_path}/#{username}.json")
current_dbi_keys = JSON.parse(open("#{data_bag_path}/#{username}_keys.json").read())
current_dbi = JSON.parse(open("#{data_bag_path}/#{username}.json").read())
unless equal?(data_bag, username, "password", password)
puts("FATAL: Password in #{data_bag_path}/#{username}.json does not match password supplied!")
exit 1
end
else
puts("INFO: Existing data bag #{data_bag}/#{username} does not exist in #{data_bag_path}, continuing as fresh build...")
end
keyfob = Hash.new
public_keys = search(:node, node_search).map(&:name).map do |client|
begin
if current_dbi_keys[client]
puts("INFO: Skipping #{client} as it is already in the data bag...")
else
puts("INFO: Adding #{client} to public_key array...")
cert_der = api.get("clients/#{client}")['certificate']
cert = OpenSSL::X509::Certificate.new cert_der
keyfob[client]=OpenSSL::PKey::RSA.new cert.public_key
end
rescue Exception => node_error
puts("WARNING: Caught exception: #{node_error.message} while processing #{client}, so skipping...")
end
end
public_keys << admins.split(",").map do |user|
begin
if current_dbi_keys[user]
puts("INFO: Skipping #{user} as it is already in the data bag")
else
puts("INFO: Adding #{user} to public_key array...")
public_key = api.get("users/#{user}")['public_key']
keyfob[user] = OpenSSL::PKey::RSA.new public_key
end
rescue Exception => user_error
puts("WARNING: Caught exception: #{user_error.message} while processing #{user}, so skipping...")
end
end
if public_keys.length == 0
puts "A node search for #{node_search} returned no results"
exit 1
end
current_secret = get_shared_secret(data_bag, username)
data_bag_shared_key = current_secret ? current_secret : OpenSSL::PKey::RSA.new(245).to_pem.lines.to_a[1..-2].join
enc_db_key_dbi = current_dbi_keys.empty? ? Mash.new({id: "#{username}_keys"}) : current_dbi_keys
keyfob.each do |node,pkey|
puts("INFO: Encrypting for #{node}...")
enc_db_key_dbi[node] = Base64.encode64(pkey.public_encrypt(data_bag_shared_key))
end unless keyfob.empty?
puts("INFO: Writing #{data_bag_path}/#{username}_keys.json...")
File.delete("#{data_bag_path}/#{username}_keys.json") if File.exists?("#{data_bag_path}/#{username}_keys.json")
File.open("#{data_bag_path}/#{username}_keys.json",'w').write(JSON.pretty_generate(enc_db_key_dbi))
if current_dbi.empty?
dbi_mash = Mash.new({id: username, username: username, password: password})
dbi = Chef::DataBagItem.from_hash(dbi_mash)
edbi = Chef::EncryptedDataBagItem.encrypt_data_bag_item(dbi, data_bag_shared_key)
puts("INFO: Writing #{data_bag_path}/#{username}.json...")
open("#{data_bag_path}/#{username}.json",'w').write(JSON.pretty_generate(edbi))
end
puts("INFO: Successfully wrote #{data_bag_path}/#{username}.json & #{data_bag_path}/#{username}_keys.json!")
end
|