knife-azure 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/azure/custom_errors.rb +1 -1
  3. data/lib/azure/resource_management/ARM_deployment_template.rb +5 -5
  4. data/lib/azure/resource_management/ARM_interface.rb +8 -12
  5. data/lib/azure/resource_management/windows_credentials.rb +7 -8
  6. data/lib/chef/knife/azurerm_server_create.rb +2 -2
  7. data/lib/chef/knife/azurerm_server_delete.rb +1 -1
  8. data/lib/chef/knife/bootstrap/bootstrapper.rb +10 -11
  9. data/lib/chef/knife/bootstrap_azurerm.rb +1 -1
  10. data/lib/chef/knife/helpers/azurerm_base.rb +17 -19
  11. data/lib/knife-azure/version.rb +1 -1
  12. metadata +30 -43
  13. data/lib/azure/service_management/ASM_interface.rb +0 -310
  14. data/lib/azure/service_management/ag.rb +0 -99
  15. data/lib/azure/service_management/certificate.rb +0 -235
  16. data/lib/azure/service_management/connection.rb +0 -102
  17. data/lib/azure/service_management/deploy.rb +0 -221
  18. data/lib/azure/service_management/disk.rb +0 -68
  19. data/lib/azure/service_management/host.rb +0 -184
  20. data/lib/azure/service_management/image.rb +0 -94
  21. data/lib/azure/service_management/loadbalancer.rb +0 -78
  22. data/lib/azure/service_management/rest.rb +0 -125
  23. data/lib/azure/service_management/role.rb +0 -717
  24. data/lib/azure/service_management/storageaccount.rb +0 -127
  25. data/lib/azure/service_management/utility.rb +0 -40
  26. data/lib/azure/service_management/vnet.rb +0 -134
  27. data/lib/chef/knife/azure_ag_create.rb +0 -73
  28. data/lib/chef/knife/azure_ag_list.rb +0 -35
  29. data/lib/chef/knife/azure_image_list.rb +0 -56
  30. data/lib/chef/knife/azure_internal-lb_create.rb +0 -74
  31. data/lib/chef/knife/azure_internal-lb_list.rb +0 -35
  32. data/lib/chef/knife/azure_server_create.rb +0 -531
  33. data/lib/chef/knife/azure_server_delete.rb +0 -136
  34. data/lib/chef/knife/azure_server_list.rb +0 -38
  35. data/lib/chef/knife/azure_server_show.rb +0 -41
  36. data/lib/chef/knife/azure_vnet_create.rb +0 -74
  37. data/lib/chef/knife/azure_vnet_list.rb +0 -35
  38. data/lib/chef/knife/bootstrap_azure.rb +0 -191
  39. data/lib/chef/knife/helpers/azure_base.rb +0 -394
@@ -1,310 +0,0 @@
1
- #
2
- # Copyright:: Copyright (c) Chef Software Inc.
3
- # License:: Apache License, Version 2.0
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- require_relative "../azure_interface"
19
- require_relative "rest"
20
- require_relative "connection"
21
-
22
- module Azure
23
- class ServiceManagement
24
- class ASMInterface < AzureInterface
25
- include AzureAPI
26
-
27
- attr_accessor :connection
28
-
29
- def initialize(params = {})
30
- @rest = Rest.new(params)
31
- @connection = Azure::ServiceManagement::Connection.new(@rest)
32
- super
33
- end
34
-
35
- def list_images
36
- connection.images.all
37
- end
38
-
39
- def list_servers
40
- servers = connection.roles.all
41
- cols = ["DNS Name", "VM Name", "Status", "IP Address", "SSH Port", "WinRM Port", "RDP Port"]
42
- rows = []
43
- servers.each do |server|
44
- rows << server.hostedservicename.to_s + ".cloudapp.net" # Info about the DNS name at http://msdn.microsoft.com/en-us/library/ee460806.aspx
45
- rows << server.name.to_s
46
- rows << begin
47
- state = server.status.to_s.downcase
48
- case state
49
- when "shutting-down", "terminated", "stopping", "stopped"
50
- ui.color(state, :red)
51
- when "pending"
52
- ui.color(state, :yellow)
53
- else
54
- ui.color("ready", :green)
55
- end
56
- end
57
- rows << server.publicipaddress.to_s
58
- rows << server.sshport.to_s
59
- rows << server.winrmport.to_s
60
- ports = server.tcpports
61
- rows << rdp_port(ports)
62
- end
63
- display_list(ui, cols, rows)
64
- end
65
-
66
- def rdp_port(arr_ports)
67
- unless arr_ports
68
- return ""
69
- end
70
-
71
- if arr_ports.length > 0
72
- arr_ports.each do |port|
73
- if port["Name"] == "Remote Desktop"
74
- return port["PublicPort"]
75
- end
76
- end
77
- end
78
- ""
79
- end
80
-
81
- def find_server(params = {})
82
- server = connection.roles.find(params[:name], params = { azure_dns_name: params[:azure_dns_name] })
83
- end
84
-
85
- def delete_server(params = {})
86
- server = find_server({ name: params[:name], azure_dns_name: params[:azure_dns_name] })
87
-
88
- unless server
89
- puts "\n"
90
- ui.error("Server #{params[:name]} does not exist")
91
- exit!
92
- end
93
-
94
- puts "\n"
95
- msg_pair(ui, "DNS Name", server.hostedservicename + ".cloudapp.net")
96
- msg_pair(ui, "VM Name", server.name)
97
- msg_pair(ui, "Size", server.size)
98
- msg_pair(ui, "Public Ip Address", server.publicipaddress)
99
- puts "\n"
100
-
101
- begin
102
- ui.confirm("Do you really want to delete this server")
103
- rescue SystemExit # Need to handle this as confirming with N/n raises SystemExit exception
104
- server = nil # Cleanup is implicitly performed in other cloud plugins
105
- exit!
106
- end
107
-
108
- params[:azure_dns_name] = server.hostedservicename
109
-
110
- connection.roles.delete(params)
111
-
112
- puts "\n"
113
- ui.warn("Deleted server #{server.name}")
114
- end
115
-
116
- def show_server(name)
117
- role = connection.roles.find name
118
-
119
- puts ""
120
- if role
121
- details = []
122
- details << ui.color("Role name", :bold, :cyan)
123
- details << role.name
124
- details << ui.color("Status", :bold, :cyan)
125
- details << role.status
126
- details << ui.color("Size", :bold, :cyan)
127
- details << role.size
128
- details << ui.color("Hosted service name", :bold, :cyan)
129
- details << role.hostedservicename
130
- details << ui.color("Deployment name", :bold, :cyan)
131
- details << role.deployname
132
- details << ui.color("Host name", :bold, :cyan)
133
- details << role.hostname
134
- unless role.sshport.nil?
135
- details << ui.color("SSH port", :bold, :cyan)
136
- details << role.sshport
137
- end
138
- unless role.winrmport.nil?
139
- details << ui.color("WinRM port", :bold, :cyan)
140
- details << role.winrmport
141
- end
142
- details << ui.color("Public IP", :bold, :cyan)
143
- details << role.publicipaddress.to_s
144
-
145
- unless role.thumbprint.empty?
146
- details << ui.color("Thumbprint", :bold, :cyan)
147
- details << role.thumbprint
148
- end
149
- puts ui.list(details, :columns_across, 2)
150
- if role.tcpports.length > 0 || role.udpports.length > 0
151
- details.clear
152
- details << ui.color("Ports open", :bold, :cyan)
153
- details << ui.color("Local port", :bold, :cyan)
154
- details << ui.color("IP", :bold, :cyan)
155
- details << ui.color("Public port", :bold, :cyan)
156
- if role.tcpports.length > 0
157
- role.tcpports.each do |port|
158
- details << "tcp"
159
- details << port["LocalPort"]
160
- details << port["Vip"]
161
- details << port["PublicPort"]
162
- end
163
- end
164
- if role.udpports.length > 0
165
- role.udpports.each do |port|
166
- details << "udp"
167
- details << port["LocalPort"]
168
- details << port["Vip"]
169
- details << port["PublicPort"]
170
- end
171
- end
172
- puts ui.list(details, :columns_across, 4)
173
- end
174
- else
175
- puts "No VM found"
176
- end
177
-
178
- rescue => error
179
- puts "#{error.class} and #{error.message}"
180
- end
181
-
182
- def list_internal_lb
183
- lbs = connection.lbs.all
184
- cols = %w{Name Service Subnet VIP}
185
- rows = []
186
- lbs.each do |lb|
187
- cols.each { |col| rows << lb.send(col.downcase).to_s }
188
- end
189
- display_list(ui, cols, rows)
190
- end
191
-
192
- def create_internal_lb(params = {})
193
- connection.lbs.create(params)
194
- end
195
-
196
- def list_vnets
197
- vnets = connection.vnets.all
198
- cols = ["Name", "Affinity Group", "State"]
199
- rows = []
200
- vnets.each do |vnet|
201
- %w{name affinity_group state}.each { |col| rows << vnet.send(col).to_s }
202
- end
203
- display_list(ui, cols, rows)
204
- end
205
-
206
- def create_vnet(params = {})
207
- connection.vnets.create(params)
208
- end
209
-
210
- def list_affinity_groups
211
- affinity_groups = connection.ags.all
212
- cols = %w{Name Location Description}
213
- rows = []
214
- affinity_groups.each do |affinity_group|
215
- cols.each { |col| rows << affinity_group.send(col.downcase).to_s }
216
- end
217
- display_list(ui, cols, rows)
218
- end
219
-
220
- def create_affinity_group(params = {})
221
- connection.ags.create(params)
222
- end
223
-
224
- def create_server(params = {})
225
- remove_hosted_service_on_failure = params[:azure_dns_name]
226
- if connection.hosts.exists?(params[:azure_dns_name])
227
- remove_hosted_service_on_failure = nil
228
- end
229
-
230
- # If Storage Account is not specified, check if the geographic location has one to re-use
231
- if not params[:azure_storage_account]
232
- storage_accts = connection.storageaccounts.all
233
- storage = storage_accts.find { |storage_acct| storage_acct.location.to_s == params[:azure_service_location] }
234
- unless storage
235
- params[:azure_storage_account] = [strip_non_ascii(params[:azure_vm_name]), random_string].join.downcase
236
- remove_storage_service_on_failure = params[:azure_storage_account]
237
- else
238
- remove_storage_service_on_failure = nil
239
- params[:azure_storage_account] = storage.name.to_s
240
- end
241
- else
242
- if connection.storageaccounts.exists?(params[:azure_storage_account])
243
- remove_storage_service_on_failure = nil
244
- else
245
- remove_storage_service_on_failure = params[:azure_storage_account]
246
- end
247
- end
248
-
249
- begin
250
- connection.deploys.create(params)
251
- rescue Exception => e
252
- Chef::Log.error("Failed to create the server -- exception being rescued: #{e}")
253
- backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
254
- Chef::Log.debug("#{backtrace_message}")
255
- cleanup_and_exit(remove_hosted_service_on_failure, remove_storage_service_on_failure)
256
- end
257
- end
258
-
259
- def cleanup_and_exit(remove_hosted_service_on_failure, remove_storage_service_on_failure)
260
- Chef::Log.warn("Cleaning up resources...")
261
-
262
- if remove_hosted_service_on_failure
263
- ret_val = connection.hosts.delete(remove_hosted_service_on_failure)
264
- ret_val.content.empty? ? Chef::Log.warn("Deleted created DNS: #{remove_hosted_service_on_failure}.") : Chef::Log.warn("Deletion failed for created DNS:#{remove_hosted_service_on_failure}. " + ret_val.text)
265
- end
266
-
267
- if remove_storage_service_on_failure
268
- ret_val = connection.storageaccounts.delete(remove_storage_service_on_failure)
269
- ret_val.content.empty? ? Chef::Log.warn("Deleted created Storage Account: #{remove_storage_service_on_failure}.") : Chef::Log.warn("Deletion failed for created Storage Account: #{remove_storage_service_on_failure}. " + ret_val.text)
270
- end
271
- exit 1
272
- end
273
-
274
- def get_role_server(dns_name, vm_name)
275
- deploy = connection.deploys.queryDeploy(dns_name)
276
- deploy.find_role(vm_name)
277
- end
278
-
279
- def get_extension(name, publisher)
280
- connection.query_azure("resourceextensions/#{publisher}/#{name}")
281
- end
282
-
283
- def deployment_name(dns_name)
284
- connection.deploys.get_deploy_name_for_hostedservice(dns_name)
285
- end
286
-
287
- def deployment(path)
288
- connection.query_azure(path)
289
- end
290
-
291
- def valid_image?(name)
292
- connection.images.exists?(name)
293
- end
294
-
295
- def vm_image?(name)
296
- connection.images.is_vm_image(name)
297
- end
298
-
299
- def add_extension(name, params = {})
300
- ui.info "Started with Chef Extension deployment on the server #{name}..."
301
- connection.roles.update(name, params)
302
- ui.info "\nSuccessfully deployed Chef Extension on the server #{name}."
303
- rescue Exception => e
304
- Chef::Log.error("Failed to add extension to the server -- exception being rescued: #{e}")
305
- backtrace_message = "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
306
- Chef::Log.debug("#{backtrace_message}")
307
- end
308
- end
309
- end
310
- end
@@ -1,99 +0,0 @@
1
- #
2
- # Author:: Jeff Mendoza (jeffmendoza@live.com)
3
- # Copyright:: Copyright (c) Chef Software Inc.
4
- # License:: Apache License, Version 2.0
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
- module Azure
20
- class AGs
21
- def initialize(connection)
22
- @connection = connection
23
- end
24
-
25
- def load
26
- @ags ||= begin
27
- @ags = {}
28
- response = @connection.query_azure("affinitygroups",
29
- "get",
30
- "",
31
- "",
32
- true,
33
- false)
34
- response.css("AffinityGroup").each do |ag|
35
- item = AG.new(@connection).parse(ag)
36
- @ags[item.name] = item
37
- end
38
- @ags
39
- end
40
- end
41
-
42
- def all
43
- load.values
44
- end
45
-
46
- def exists?(name)
47
- load.key?(name)
48
- end
49
-
50
- def find(name)
51
- load[name]
52
- end
53
-
54
- def create(params)
55
- ag = AG.new(@connection)
56
- ag.create(params)
57
- end
58
- end
59
- end
60
-
61
- module Azure
62
- class AG
63
- attr_accessor :name, :label, :description, :location
64
-
65
- def initialize(connection)
66
- @connection = connection
67
- end
68
-
69
- def parse(image)
70
- @name = image.at_css("Name").content
71
- @label = image.at_css("Label").content
72
- @description = image.at_css("Description").content if
73
- image.at_css("Description")
74
- @location = image.at_css("Location").content if image.at_css("Location")
75
- self
76
- end
77
-
78
- def create(params)
79
- builder = Nokogiri::XML::Builder.new(encoding: "utf-8") do |xml|
80
- xml.CreateAffinityGroup(
81
- xmlns: "http://schemas.microsoft.com/windowsazure"
82
- ) do
83
- xml.Name params[:azure_ag_name]
84
- xml.Label Base64.strict_encode64(params[:azure_ag_name])
85
- unless params[:azure_ag_desc].nil?
86
- xml.Description params[:azure_ag_desc]
87
- end
88
- xml.Location params[:azure_location]
89
- end
90
- end
91
- @connection.query_azure("affinitygroups",
92
- "post",
93
- builder.to_xml,
94
- "",
95
- true,
96
- false)
97
- end
98
- end
99
- end
@@ -1,235 +0,0 @@
1
- #
2
- # Author:: Mukta Aphale (mukta.aphale@clogeny.com)
3
- # Copyright:: Copyright (c) Chef Software Inc.
4
- # License:: Apache License, Version 2.0
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
- module Azure
20
- class Certificates
21
- def initialize(connection)
22
- @connection = connection
23
- end
24
-
25
- def create(params)
26
- certificate = Certificate.new(@connection)
27
- certificate.create(params)
28
- end
29
-
30
- def add(certificate_data, certificate_password, certificate_format, dns_name)
31
- certificate = Certificate.new(@connection)
32
- certificate.add_certificate certificate_data, certificate_password, certificate_format, dns_name
33
- end
34
-
35
- def create_ssl_certificate(azure_dns_name)
36
- cert_params = { output_file: "winrm", key_length: 2048, cert_validity: 24,
37
- azure_dns_name: azure_dns_name }
38
- certificate = Certificate.new(@connection)
39
- thumbprint = certificate.create_ssl_certificate(cert_params)
40
- end
41
-
42
- def get_certificate(dns_name, fingerprint)
43
- certificate = Certificate.new(@connection)
44
- certificate.get_certificate(dns_name, fingerprint)
45
- end
46
- end
47
- end
48
-
49
- module Azure
50
- class Certificate
51
- attr_accessor :connection
52
- attr_accessor :cert_data, :fingerprint, :certificate_version
53
- def initialize(connection)
54
- @connection = connection
55
- @certificate_version = 2 # cf. RFC 5280 - to make it a "v3" certificate
56
- end
57
-
58
- def create(params)
59
- # If RSA private key has been specified, then generate an x 509 certificate from the
60
- # public part of the key
61
- @cert_data = generate_public_key_certificate_data({ ssh_key: params[:ssh_identity_file],
62
- ssh_key_passphrase: params[:identity_file_passphrase] })
63
- add_certificate @cert_data, "knifeazure", "pfx", params[:azure_dns_name]
64
-
65
- # Return the fingerprint to be used while adding role
66
- @fingerprint
67
- end
68
-
69
- def generate_public_key_certificate_data(params)
70
- # Generate OpenSSL RSA key from the mentioned ssh key path (and passphrase)
71
- key = OpenSSL::PKey::RSA.new(File.read(params[:ssh_key]), params[:ssh_key_passphrase])
72
- # Generate X 509 certificate
73
- ca = OpenSSL::X509::Certificate.new
74
- ca.version = @certificate_version
75
- ca.serial = Random.rand(65534) + 1 # 2 digit byte range random number for better security aspect
76
- ca.subject = OpenSSL::X509::Name.parse "/DC=org/DC=knife-plugin/CN=Opscode CA"
77
- ca.issuer = ca.subject # root CA's are "self-signed"
78
- ca.public_key = key.public_key # Assign the ssh-key's public part to the certificate
79
- ca.not_before = Time.now
80
- ca.not_after = ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity
81
- ef = OpenSSL::X509::ExtensionFactory.new
82
- ef.subject_certificate = ca
83
- ef.issuer_certificate = ca
84
- ca.add_extension(ef.create_extension("basicConstraints", "CA:TRUE", true))
85
- ca.add_extension(ef.create_extension("keyUsage", "keyCertSign, cRLSign", true))
86
- ca.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false))
87
- ca.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false))
88
- ca.sign(key, OpenSSL::Digest::SHA256.new)
89
- # Generate the SHA1 fingerprint of the der format of the X 509 certificate
90
- @fingerprint = OpenSSL::Digest::SHA1.new(ca.to_der)
91
- # Create the pfx format of the certificate
92
- pfx = OpenSSL::PKCS12.create("knifeazure", "knife-azure-pfx", key, ca)
93
- # Encode the pfx format - upload this certificate
94
- Base64.strict_encode64(pfx.to_der)
95
- end
96
-
97
- def add_certificate(certificate_data, certificate_password, certificate_format, dns_name)
98
- # Generate XML to call the API
99
- # Add certificate to the hosted service
100
- builder = Nokogiri::XML::Builder.new do |xml|
101
- xml.CertificateFile("xmlns" => "http://schemas.microsoft.com/windowsazure") do
102
- xml.Data certificate_data
103
- xml.CertificateFormat certificate_format
104
- xml.Password certificate_password
105
- end
106
- end
107
- # Windows Azure API call
108
- @connection.query_azure("hostedservices/#{dns_name}/certificates", "post", builder.to_xml)
109
-
110
- # Check if certificate is available else raise error
111
- for attempt in 0..4
112
- Chef::Log.info "Waiting to get certificate ..."
113
- res = get_certificate(dns_name, @fingerprint)
114
- break unless res.empty?
115
- if attempt == 4
116
- raise "The certificate with thumbprint #{fingerprint} was not found."
117
- else
118
- sleep 5
119
- end
120
- end
121
- end
122
-
123
- def get_certificate(dns_name, fingerprint)
124
- @connection.query_azure("hostedservices/#{dns_name}/certificates/sha1-#{fingerprint}", "get").search("Certificate")
125
- end
126
-
127
- ######## SSL certificate generation for knife-azure ssl bootstrap ######
128
- def create_ssl_certificate(cert_params)
129
- file_path = cert_params[:output_file].sub(/\.(\w+)$/, "")
130
- path = prompt_for_file_path
131
- file_path = File.join(path, file_path) unless path.empty?
132
- cert_params[:domain] = prompt_for_domain
133
-
134
- rsa_key = generate_keypair cert_params[:key_length]
135
- cert = generate_certificate(rsa_key, cert_params)
136
- write_certificate_to_file cert, file_path, rsa_key, cert_params
137
- puts "*" * 70
138
- puts "Generated Certificates:"
139
- puts "- #{file_path}.pfx - PKCS12 format keypair. Contains both the public and private keys, usually used on the server."
140
- puts "- #{file_path}.b64 - Base64 encoded PKCS12 keypair. Contains both the public and private keys, for upload to the Azure REST API."
141
- puts "- #{file_path}.pem - Base64 encoded public certificate only. Required by the client to connect to the server."
142
- puts "Certificate Thumbprint: #{@thumbprint.to_s.upcase}"
143
- puts "*" * 70
144
-
145
- config[:ca_trust_file] = file_path + ".pem" if config[:ca_trust_file].nil?
146
- cert_data = File.read (file_path + ".b64")
147
- add_certificate cert_data, @winrm_cert_passphrase, "pfx", cert_params[:azure_dns_name]
148
- @thumbprint
149
- end
150
-
151
- def generate_keypair(key_length)
152
- OpenSSL::PKey::RSA.new(key_length.to_i)
153
- end
154
-
155
- def prompt_for_passphrase
156
- passphrase = ""
157
- begin
158
- print "Passphrases do not match. Try again.\n" unless passphrase.empty?
159
- print "Enter certificate passphrase (empty for no passphrase):"
160
- passphrase = STDIN.gets
161
- return passphrase.strip if passphrase == "\n"
162
-
163
- print "Enter same passphrase again:"
164
- confirm_passphrase = STDIN.gets
165
- end until passphrase == confirm_passphrase
166
- passphrase.strip
167
- end
168
-
169
- def prompt_for_file_path
170
- file_path = ""
171
- counter = 0
172
- begin
173
- print "Invalid location! \n" unless file_path.empty?
174
- print 'Enter the file path for certificates e.g. C:\Windows (empty for current location):'
175
- file_path = STDIN.gets
176
- stripped_file_path = file_path.strip
177
- return stripped_file_path if file_path == "\n"
178
-
179
- counter += 1
180
- exit(1) if counter == 3
181
- end until File.directory?(stripped_file_path)
182
- stripped_file_path
183
- end
184
-
185
- def prompt_for_domain
186
- counter = 0
187
- begin
188
- print "Enter the domain (mandatory):"
189
- domain = STDIN.gets
190
- domain = domain.strip
191
- counter += 1
192
- exit(1) if counter == 3
193
- end until !domain.empty?
194
- domain
195
- end
196
-
197
- def generate_certificate(rsa_key, cert_params)
198
- @hostname = "*"
199
- if cert_params[:domain]
200
- @hostname = "*." + cert_params[:domain]
201
- end
202
-
203
- # Create a self-signed X509 certificate from the rsa_key (unencrypted)
204
- cert = OpenSSL::X509::Certificate.new
205
- cert.version = 2
206
- cert.serial = Random.rand(65534) + 1 # 2 digit byte range random number for better security aspect
207
-
208
- cert.subject = OpenSSL::X509::Name.parse "/CN=#{@hostname}"
209
- cert.issuer = cert.subject
210
- cert.public_key = rsa_key.public_key
211
- cert.not_before = Time.now
212
- cert.not_after = cert.not_before + 2 * 365 * cert_params[:cert_validity].to_i * 60 * 60 # 2 years validity
213
- ef = OpenSSL::X509::ExtensionFactory.new
214
- ef.subject_certificate = cert
215
- ef.issuer_certificate = cert
216
- cert.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false))
217
- cert.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false))
218
- cert.add_extension(ef.create_extension("extendedKeyUsage", "1.3.6.1.5.5.7.3.1", false))
219
- cert.sign(rsa_key, OpenSSL::Digest::SHA1.new)
220
- @thumbprint = OpenSSL::Digest::SHA1.new(cert.to_der)
221
- cert
222
- end
223
-
224
- def write_certificate_to_file(cert, file_path, rsa_key, cert_params)
225
- File.open(file_path + ".pem", "wb") { |f| f.print cert.to_pem }
226
- @winrm_cert_passphrase = prompt_for_passphrase unless @winrm_cert_passphrase
227
- pfx = OpenSSL::PKCS12.create("#{cert_params[:winrm_cert_passphrase]}", "winrmcert", rsa_key, cert)
228
- File.open(file_path + ".pfx", "wb") { |f| f.print pfx.to_der }
229
- File.open(file_path + ".b64", "wb") { |f| f.print Base64.strict_encode64(pfx.to_der) }
230
- end
231
-
232
- ########## SSL certificate generation ends ###########
233
-
234
- end
235
- end