certmaker 0.0.1

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.
Files changed (5) hide show
  1. data/LICENSE +23 -0
  2. data/README.md +66 -0
  3. data/bin/certmaker +339 -0
  4. data/samples/config.yml +3 -0
  5. metadata +57 -0
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Portions copyright (c) 2011 Declan McGrath
2
+ Portions copyright (c) 2011 ToothSuite
3
+
4
+ MIT License
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Certmaker: a gem to create and deploy SSL certificates to cloud platforms
2
+
3
+ ### Installation
4
+ gem install certmaker
5
+
6
+ ### Before you start
7
+ This project is at an early stage. It is 100% usable for people who use Namecheap's Comodo PositiveSSL certs. It is particularly useful for those who then use those certs on Heroku - as this gem does the heavy lifting of bundling in keys, removing passwords and combining intermediate certifiate chains as required by Heroku. If you use something other than this configuration then we'd love to extend the role of this gem so drop us a line and we can work together to try and remove the pain of getting SSL certs setup for your application. It really shouldn't be this difficult. The main motivation behind this gem is to make the process easy to repeat - so that the next time you want to setup an SSL cert you don't have to jump through the hoops of remembering what files to combine and in what order.
8
+
9
+ ### Usage
10
+ The typical usage is to create a private key locally and a CSR
11
+
12
+ certmaker create your.secure.domain
13
+
14
+ You then keep the private key safe and use the CSR to request an SSL cert from your SSL Certificate provider
15
+
16
+ For some platforms the cert you receive from your SSL Certificate provider is all you need to get going.
17
+
18
+ For other platforms (eg. heroku) you need to do a little more, such as combining together your key, certifice, intermediate cert chain as well as removing passwords.
19
+
20
+ For heroku you just save the SSL cert zip in designated directory and run the commands...
21
+
22
+ certmaker unpack_namecheap your.secure.domain
23
+ certmaker heroku_wizard your.secure.domain
24
+
25
+ ... to do all that is necessary (currently we only can vouch for this process working with namecheap.com Comodo PositiveSSL certs as it all we have tested with). This will do the necessary transformations and then prompt you to upload the finished SSL cert to your heroku app.
26
+
27
+ We also provide the following commands
28
+
29
+ certmaker unpack_namecheap your.secure.domain
30
+ certmaker combine_key your.secure.domain # can take an optional --certfilename parameter
31
+ certmaker remove_passphrases your.secure.domain
32
+ certmaker append_chain your.secure.domain
33
+ certmaker check_chain your.secure.domain
34
+ certmaker upload_to_heroku your.secure.domain
35
+
36
+ All your keys, certs and other details are stored under a .certmaker directory in your home directory. You need to have a little understanding of the directory stucture to know where to find things. Each cert you generate will live in its own directory under .certmaker/certs/
37
+
38
+ For example...
39
+
40
+ /home/user/.certmaker/
41
+ `-- certs
42
+ `-- www_sample_com_ssl
43
+ |-- 1_my_key_and_csr
44
+ | |-- www.sample.com.csr
45
+ | `-- www.sample.com.key
46
+ |-- 2_ssl_provider_artifacts
47
+ | `-- zips
48
+ |-- 3_key_cert_combo
49
+ |-- 4_key_cert_nopass
50
+ |-- 5_key_cert_no_pass_chained
51
+ `-- config.yml
52
+
53
+ ... your private key and CSR will be under 1_my_key_and_csr
54
+
55
+ Note: The first time you run a command such as 'certmaker create your.secure.domain' for a new subdomain you will be prompted to create a config.yml file under the individual cert directory. Currently this config file is only used to supply the 'ordered_chain_filenames' setting. This allows you to define the order in which intermediate certs are chained together (yes, this all does sound unnecessarily confusing!).
56
+
57
+ The 2_ssl_provider_artifacts directory is used to store the cert and other bits send on by your SSL certificate provider after you have successfully applied for a cert (zip files should be stored in the zips folder).
58
+
59
+ The 3_key_cert_combo is used to store files that combine a private key and a cert. The 4_key_cert_nopass directory transforms the contents of the previous directory so that any password has been remove from the files. This is often required so that cloud servers can automatically restart your app without needing to supply a password. Finally the 5_key_cert_no_pass_chained transforms the files a little more - ultimately it contains the final version of the cert by adding the intermediate chain. So by this stage we should have our SSL cert (with the key combined, any passwords removed and the intermediate chain added). Phew!
60
+
61
+ ###Credits
62
+ Thanks to the following resources which laid the the foundation for this gem
63
+ * [Generating and adding a cert to Heroku](http://blog.dynamic50.com/2011/02/15/ssl-on-wildcard-domains-on-heroku-using-godaddy/)
64
+ * [How to build the intermediate cert chain for a Comodo cert](http://ryan.mcgeary.org/2011/09/16/how-to-add-a-dnsimple-ssl-certificate-to-heroku/)
65
+ * [How to verify a certificate chain file](http://backreference.org/2010/03/06/check-certificate-chain-file/)
66
+ * [How to debug SSL](http://sysadvent.blogspot.com/2010/12/day-3-debugging-ssltls-with-openssl1.html)
data/bin/certmaker ADDED
@@ -0,0 +1,339 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'fileutils'
5
+ require 'yaml'
6
+ require 'getoptlong'
7
+
8
+ PROGRAM_NAME = 'certmaker'
9
+
10
+ opts = GetoptLong.new(
11
+ [ "--certfilename", "-c", GetoptLong::OPTIONAL_ARGUMENT ],
12
+ [ "--usage", "-u", GetoptLong::NO_ARGUMENT ],
13
+ [ "--version", "-v", GetoptLong::NO_ARGUMENT ]
14
+ )
15
+
16
+ def latest_documentation_info
17
+ "Please see https://github.com/theirishpenguin/certmaker\n" +
18
+ "for the latest instructions."
19
+ end
20
+
21
+ begin
22
+ opts.each do |opt, arg|
23
+ case opt
24
+ when "--certfilename"
25
+ @certfilename = arg
26
+ when "--usage"
27
+ puts "certmake command SUB_DOMAIN [--certfilename=foo.crt]\n\n" +
28
+ latest_documentation_info
29
+ exit 0
30
+ when "--version"
31
+ puts "certmake v0.0.1"
32
+ exit 0
33
+ end
34
+ end
35
+
36
+ rescue
37
+ raise # TODO: Handle errors
38
+ end
39
+
40
+ @exe_filepath = File.expand_path(__FILE__)
41
+ @command = ARGV[0]
42
+
43
+ @commands = ['create', 'unpack_namecheap', 'combine_key', 'remove_passphrases', 'append_chain', 'check_chain', 'upload_to_heroku', 'heroku_wizard'] # 'assemble_chain'
44
+
45
+ unless @commands.include? @command
46
+ puts "
47
+ You tried to run an invalid command (#{@command}). Valid commands are:
48
+
49
+ #{@commands.map{|com| " #{PROGRAM_NAME} #{com}"}.join("\n")}
50
+
51
+ #{latest_documentation_info}
52
+ "
53
+ exit 1
54
+ end
55
+
56
+ @common_name = ARGV[1]
57
+
58
+ if @common_name.to_s.empty?
59
+ puts "Please supply the exact URL you wish to generate the a cert for as a parameter"
60
+ exit 1
61
+ end
62
+
63
+ def underscored_name
64
+ @common_name.gsub('.') {'_'}
65
+ end
66
+
67
+ def init
68
+ @dot_dir = "#{ENV['HOME']}/.certmaker"
69
+ @certificates_dir = "#{@dot_dir}/certs"
70
+ FileUtils.mkdir_p @certificates_dir
71
+
72
+ @cert_dir = "#{@certificates_dir}/#{underscored_name}_ssl"
73
+ FileUtils.mkdir_p @cert_dir
74
+ FileUtils.cd @cert_dir
75
+
76
+ @config_filepath = "#{@cert_dir}/config.yml"
77
+ end
78
+
79
+ def load_config
80
+ if File.exist? @config_filepath
81
+ @config = YAML::load(File.open(@config_filepath))
82
+ else
83
+ puts "
84
+ Please create a config file at
85
+ #{@config_filepath}
86
+
87
+ Here is a sample:
88
+
89
+ #{sample_config_text}
90
+ "
91
+ exit 1
92
+ end
93
+ end
94
+
95
+ def sample_config_filepath
96
+ "#{File.dirname(@exe_filepath)}/../samples/config.yml"
97
+ end
98
+
99
+ def sample_config_text
100
+
101
+ "
102
+ # START OF CONFIG FILE
103
+ # ---------------------------------------
104
+ #{File.read(sample_config_filepath).chomp}
105
+ # ---------------------------------------
106
+ # END OF CONFIG FILE
107
+ "
108
+ end
109
+
110
+ def create_wip_dirs
111
+ # Each directory is a sequential step in the obtaining of the cert
112
+ # Note: All directories are important, arguably dir 1 is the most important
113
+ # as it contains your private key (never lose this!)
114
+ @dir1 ="#{@cert_dir}/1_my_key_and_csr"
115
+ @dir2 = "#{@cert_dir}/2_ssl_provider_artifacts"
116
+ @dir2_zips = "#{@dir2}/zips"
117
+ @dir3 = "#{@cert_dir}/3_key_cert_combo"
118
+ @dir4 = "#{@cert_dir}/4_key_cert_nopass"
119
+ @dir5 = "#{@cert_dir}/5_key_cert_no_pass_chained"
120
+
121
+ [@dir1, @dir2_zips, @dir3, @dir4, @dir5].each do |dir|
122
+ FileUtils.mkdir_p dir
123
+ end
124
+
125
+ end
126
+
127
+ def private_key_filepath
128
+ "#{@dir1}/#{@common_name}.key"
129
+ end
130
+
131
+ def private_key_nopass_filepath
132
+ "#{@dir4}/#{@common_name}.nopass.key"
133
+ end
134
+
135
+ def csr_filepath
136
+ "#{@dir1}/#{@common_name}.csr"
137
+ end
138
+
139
+ def crt_filepath
140
+ if @certfilename
141
+ "#{@dir2}/#{@certfilename}"
142
+ else
143
+ "#{@dir2}/#{underscored_name}.crt"
144
+ end
145
+ end
146
+
147
+ def key_cert_combo_filepath
148
+ "#{@dir3}/#{underscored_name}.pem"
149
+ end
150
+
151
+ def key_cert_combo_nopass_filepath
152
+ "#{@dir4}/#{underscored_name}.nopass.pem"
153
+ end
154
+
155
+ def key_cert_combo_nopass_chained_filepath
156
+ "#{@dir5}/#{underscored_name}_chained.nopass.pem"
157
+ end
158
+
159
+ def generate_private_key
160
+ `openssl genrsa -out #{private_key_filepath} 2048`
161
+ end
162
+
163
+ def generate_csr
164
+ `openssl req -new -key #{private_key_filepath} -out #{csr_filepath}`
165
+ end
166
+
167
+ def display_csr_instructions
168
+ puts "
169
+ Here's an example of values for your csr when asked.
170
+
171
+ NB: Don't create a challenge passphrase or any other optional
172
+ fields when asked.
173
+
174
+ Country Name (2 letter code) [AU]:IE
175
+ State or Province Name (full name) [Some-State]:Leinster
176
+ Locality Name (eg, city) []:Dublin
177
+ Organization Name (eg, company) [Internet Widgits Pty Ltd]:EXAMPLE CORP LIMITED
178
+ Organizational Unit Name (eg, section) []:Engineering
179
+ Common Name (eg, YOUR name) []:www.example.com
180
+ Email Address []:support@example.com
181
+
182
+ "
183
+ end
184
+
185
+ def create
186
+ generate_private_key
187
+ display_csr_instructions
188
+ generate_csr
189
+ display_make_summary
190
+ end
191
+
192
+ def continue_prompt
193
+ puts 'Press any key to continue or Ctrl-C to exit.'
194
+ dummy = STDIN.gets.chomp
195
+ end
196
+
197
+
198
+ def display_make_summary
199
+ puts "
200
+ A private key (.key file) and a CSR (.csr file) has been generated for you.
201
+
202
+ The private key file is at
203
+ #{private_key_filepath}
204
+
205
+ You need to keep the private key safe, as you cannot recover from losing it.
206
+
207
+ You will now use the CSR to create your certificate, which is at
208
+ #{csr_filepath}
209
+
210
+ Visit your SSL retailers website and request, renew or reissue a SSL certificate.
211
+
212
+ You will be asked for a CSR key when applying for a cert. Copy and paste the contents of the CSR file into the SSL cert application form.
213
+
214
+ Notes on applying for an SSL cert
215
+ * If you are asked to specify your webserver type and you are not sure what to say you can usually choose the most general option available (eg. other).
216
+ * Your SSL Cert retailer will ask you to verify domain ownership of #{@common_name}
217
+ * Your SSL Cert retailer will finally issue you the SSL certs
218
+ * The certs make come in a zip file(s). Files with'_pkcs7' in the name are for Windows servers
219
+ * Often, intermediate cert chains are provided as an extra with your cert. They need to be installed with your cert. The actual cert itself is usual the file with your domain name in it
220
+
221
+ If you receive zip files of certs, you can download them to #{@dir2_zips} and run the command:
222
+
223
+ #{PROGRAM_NAME} unpack_namecheap #{@common_name}
224
+
225
+ If your certs don't come in a zip file or your prefer to extract them manually before continuing, then you can download them to #{@dir2}
226
+
227
+ Once unpacked, you now have obtained your certs. Next up you can do any of the following as needed
228
+
229
+ #{PROGRAM_NAME} heroku_wizard #{@common_name}
230
+ #{PROGRAM_NAME} combine_key #{@common_name}
231
+ #{PROGRAM_NAME} remove_passphrases #{@common_name}
232
+ #{PROGRAM_NAME} append_chain #{@common_name}
233
+ #{PROGRAM_NAME} check_chain #{@common_name}
234
+ #{PROGRAM_NAME} upload_to_heroku #{@common_name}
235
+
236
+ "
237
+ end
238
+
239
+ def unpack_namecheap
240
+ # Pre-requisite
241
+ if `which unzip`.length == 0
242
+ puts "Please first install unzip (eg. on Ubuntu use 'sudo apt-get install unzip')"
243
+ exit 1
244
+ end
245
+
246
+ FileUtils.cd @dir2
247
+ `unzip -j zips/#{underscored_name}.zip`
248
+ end
249
+
250
+
251
+ def combine_private_key_and_cert
252
+ instruct "Combining your private key with your combined cert"
253
+
254
+ `cat #{crt_filepath} #{private_key_filepath} > #{key_cert_combo_filepath}`
255
+ end
256
+
257
+ def remove_passphrases
258
+ instruct "Removing passphrase"
259
+
260
+ puts `openssl rsa -in #{key_cert_combo_filepath} -out #{key_cert_combo_nopass_filepath}`
261
+
262
+ puts `openssl x509 -in #{key_cert_combo_filepath} >> #{key_cert_combo_nopass_filepath}`
263
+
264
+ puts `openssl rsa -in #{private_key_filepath} -out #{private_key_nopass_filepath}`
265
+ end
266
+
267
+ def chain_files_in_order
268
+ @config['ordered_chain_filenames'].map{ |filename|
269
+ "#{@dir2}/#{filename}"
270
+ }.join(' ')
271
+ end
272
+
273
+ def append_chain
274
+ instruct "Appending intermediate chain to cert"
275
+
276
+ `cat #{key_cert_combo_nopass_filepath} #{chain_files_in_order} > #{key_cert_combo_nopass_chained_filepath}`
277
+ end
278
+
279
+ def check_chain
280
+
281
+ # Pre-requisite
282
+ if `which perl`.length == 0
283
+ puts "Please install perl."
284
+ exit 1
285
+ end
286
+
287
+ instruct "Checking chain. The issuer of the first should be the subject of the second. And so on. Is that how the following output looks"
288
+
289
+ puts `perl -n0777e 'map { print "---\n"; open(CMD, "| openssl x509 -noout -subject -issuer"); print CMD; close(CMD) } /^-----BEGIN.*?^-----END.*?\n/gsm' #{key_cert_combo_nopass_chained_filepath}`
290
+ end
291
+
292
+ def upload_to_heroku
293
+
294
+ puts "What is your heroku app name?"
295
+ app_name = STDIN.gets.chomp
296
+
297
+ cmd = "heroku ssl:add #{key_cert_combo_nopass_chained_filepath} #{private_key_nopass_filepath} --app #{app_name}"
298
+
299
+ puts "
300
+ If you want to upload the key certificate to heroku for your app, this will run the command
301
+
302
+ #{cmd}
303
+
304
+ "
305
+
306
+ continue_prompt
307
+
308
+ puts `#{cmd}`
309
+ end
310
+
311
+ def instruct(instruction)
312
+ puts "\n#{instruction}...\n"
313
+ end
314
+
315
+ init
316
+ load_config
317
+ create_wip_dirs
318
+ case @command
319
+ when 'create'
320
+ create
321
+ when 'unpack_namecheap'
322
+ unpack_namecheap
323
+ when 'combine_key'
324
+ combine_private_key_and_cert
325
+ when 'remove_passphrases'
326
+ remove_passphrases
327
+ when 'heroku_wizard'
328
+ combine_private_key_and_cert
329
+ remove_passphrases
330
+ append_chain
331
+ upload_to_heroku
332
+ when 'append_chain'
333
+ append_chain
334
+ when 'check_chain'
335
+ check_chain
336
+ when 'upload_to_heroku'
337
+ upload_to_heroku
338
+ end
339
+
@@ -0,0 +1,3 @@
1
+ ordered_chain_filenames:
2
+ # eg. For Namecheap
3
+ # ordered_chain_filenames: [PositiveSSLCA.crt, UTNAddTrustServerCA.crt, AddTrustExternalCARoot.crt]
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: certmaker
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Declan McGrath
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-11-18 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: Easy way to make SSL Certs suitable for cloud platforms
17
+ email: declan@toothsuite.com
18
+ executables:
19
+ - certmaker
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - bin/certmaker
26
+ - samples/config.yml
27
+ - LICENSE
28
+ - README.md
29
+ homepage: http://rubygems.org/gems/certmaker
30
+ licenses: []
31
+
32
+ post_install_message:
33
+ rdoc_options: []
34
+
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: "0"
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.7.2
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Make SSL Certs suitable for cloud platforms
56
+ test_files: []
57
+