amarillo 0.3.2 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/amarillo +34 -9
- data/lib/amarillo/environment.rb +4 -1
- data/lib/amarillo.rb +76 -25
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5229f8188b6086ad5c09326cc438d8375703602036e50534cbb69d684a2ec9e7
|
4
|
+
data.tar.gz: b1a7005a37527eb00fd44dbc45cfa0ea3e232f90bbd8ad004f712bb74d8be0a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b167194f5fbb58f945fb5674d9466473cf9777a04536cbb709bdf7e75e018666c7421beb28dfc300ad49c5e522f2250339f8b92c882273608525084708caa088
|
7
|
+
data.tar.gz: 1e40be3bb8babc91470dca9588c51467cd572e99dada1d9e716f4cbe57e669c0731956a3e36598c35a37a9a015369b88b01cb7ffe604442463d6b884dd1d907d
|
data/bin/amarillo
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2022 iAchieved.it LLC
|
4
4
|
#
|
5
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -35,12 +35,16 @@ OptionParser.new do |opts|
|
|
35
35
|
options[:list] = l
|
36
36
|
end
|
37
37
|
|
38
|
-
opts.on("-d", "--delete", "Delete certificate") do |d|
|
38
|
+
opts.on("-d", "--delete COMMONNAME", "Delete certificate specified by COMMONNAME") do |d|
|
39
39
|
options[:delete] = d
|
40
40
|
end
|
41
41
|
|
42
|
-
opts.on("-r", "--renew", "Renew certificates") do |r|
|
43
|
-
|
42
|
+
opts.on("-r", "--renew [COMMONNAME]", "Renew specific or all certificates") do |r|
|
43
|
+
if r
|
44
|
+
options[:renew] = r
|
45
|
+
else
|
46
|
+
options[:renew] = 'all'
|
47
|
+
end
|
44
48
|
end
|
45
49
|
|
46
50
|
opts.on("-z", "--zone ZONE", "Hosted zone") do |z|
|
@@ -55,6 +59,14 @@ OptionParser.new do |opts|
|
|
55
59
|
options[:name] = n
|
56
60
|
end
|
57
61
|
|
62
|
+
opts.on("-k", "--keytype KEYTYPE", "Valid key types: ") do |k|
|
63
|
+
options[:keytype] = k
|
64
|
+
end
|
65
|
+
|
66
|
+
opts.on("-s", "--script SCRIPT", "A script or command to execute after a successful certificate creation or renewal") do |s|
|
67
|
+
options[:script] = s
|
68
|
+
end
|
69
|
+
|
58
70
|
opts.on("-a", "--amarillo-home AMARILLO_HOME", "Home directory for configuration, keys, and certificates") do |o|
|
59
71
|
options[:amarillo_home] = a
|
60
72
|
end
|
@@ -103,8 +115,8 @@ else
|
|
103
115
|
email = options[:email]
|
104
116
|
end
|
105
117
|
|
106
|
-
if options[:name].nil? and options[:renew].nil? and options[:list].nil? then
|
107
|
-
puts "Usage: amarillo --name COMMONNAME [--zone ZONE] [--email EMAIL] [--amarillo-home AMARILLO_HOME]"
|
118
|
+
if options[:name].nil? and options[:renew].nil? and options[:list].nil? and options[:delete].nil? then
|
119
|
+
puts "Usage: amarillo [--name COMMONNAME|--renew|--renew COMMONNAME] [--zone ZONE] [--email EMAIL] [--amarillo-home AMARILLO_HOME]"
|
108
120
|
exit -1
|
109
121
|
else
|
110
122
|
name = options[:name]
|
@@ -119,13 +131,26 @@ end
|
|
119
131
|
y = Amarillo.new amarillo_home
|
120
132
|
|
121
133
|
if options[:renew] then
|
122
|
-
|
134
|
+
|
135
|
+
if options[:renew] != 'all' then
|
136
|
+
y.renewCertificate options[:renew]
|
137
|
+
else
|
138
|
+
y.renewCertificates
|
139
|
+
end
|
140
|
+
|
123
141
|
elsif options[:list] then
|
124
142
|
y.listCertificates
|
125
143
|
elsif options[:delete] then
|
126
|
-
y.deleteCertificate
|
144
|
+
y.deleteCertificate options[:delete]
|
127
145
|
else
|
128
|
-
|
146
|
+
config = {
|
147
|
+
"zone" => zone,
|
148
|
+
"commonName" => name,
|
149
|
+
"email" => email,
|
150
|
+
"key_type" => options[:keytype],
|
151
|
+
"script" => options[:script]
|
152
|
+
}
|
153
|
+
y.requestCertificate certConfig: config
|
129
154
|
end
|
130
155
|
|
131
156
|
|
data/lib/amarillo/environment.rb
CHANGED
@@ -105,7 +105,10 @@ HEREDOC
|
|
105
105
|
"email" => email,
|
106
106
|
"zone" => zone,
|
107
107
|
"nameservers" => ['208.67.222.222', '9.9.9.9'],
|
108
|
-
"key_type" => 'ec,secp384r1'
|
108
|
+
"key_type" => 'ec,secp384r1',
|
109
|
+
"owner" => 'root',
|
110
|
+
"group" => 'root',
|
111
|
+
"key_mode" => 0660
|
109
112
|
}}
|
110
113
|
File.write(@configFile, config.to_yaml)
|
111
114
|
else
|
data/lib/amarillo.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Inspired by Pete Keen's (pete@petekeen.net) post
|
4
4
|
# https://www.petekeen.net/lets-encrypt-without-certbot
|
5
5
|
#
|
6
|
-
# Copyright
|
6
|
+
# Copyright 2022 iAchieved.it LLC
|
7
7
|
#
|
8
8
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
9
9
|
# of this software and associated documentation files (the "Software"), to deal
|
@@ -86,7 +86,17 @@ class Amarillo
|
|
86
86
|
|
87
87
|
end
|
88
88
|
|
89
|
-
def requestCertificate(
|
89
|
+
def requestCertificate(configPath: nil, certConfig: nil)
|
90
|
+
|
91
|
+
if configPath
|
92
|
+
certConfig = YAML.load(File.read(configPath))
|
93
|
+
end
|
94
|
+
|
95
|
+
commonName = certConfig["commonName"]
|
96
|
+
email = certConfig["email"]
|
97
|
+
zone = certConfig["zone"]
|
98
|
+
key_type = certConfig["key_type"]
|
99
|
+
script = certConfig["script"]
|
90
100
|
|
91
101
|
@zone = zone
|
92
102
|
|
@@ -139,11 +149,16 @@ class Amarillo
|
|
139
149
|
|
140
150
|
@route53.change_resource_record_sets(options)
|
141
151
|
|
152
|
+
at_exit do
|
153
|
+
self.cleanup label, record_type, challengeValue
|
154
|
+
end
|
155
|
+
|
156
|
+
|
142
157
|
nameservers = @environment.get_zone_nameservers
|
143
158
|
|
144
159
|
@logger.info "Waiting for DNS record to propagate"
|
145
160
|
while !check_dns(commonName, nameservers, challengeValue)
|
146
|
-
sleep
|
161
|
+
sleep 5
|
147
162
|
@logger.info "Still waiting..."
|
148
163
|
end
|
149
164
|
|
@@ -152,20 +167,13 @@ class Amarillo
|
|
152
167
|
@logger.info "Requesting validation..."
|
153
168
|
authorization.dns.reload
|
154
169
|
while authorization.dns.status == 'pending'
|
155
|
-
sleep
|
170
|
+
sleep 5
|
156
171
|
@logger.info "DNS status: #{authorization.dns.status}"
|
157
172
|
authorization.dns.reload
|
158
173
|
end
|
159
174
|
|
160
175
|
@logger.info "Generating key"
|
161
176
|
|
162
|
-
# Create certificate yml
|
163
|
-
certConfig = {
|
164
|
-
"commonName" => commonName,
|
165
|
-
"email" => email,
|
166
|
-
"zone" => zone
|
167
|
-
}
|
168
|
-
|
169
177
|
if key_type
|
170
178
|
certConfig["key_type"] = key_type
|
171
179
|
else
|
@@ -178,16 +186,22 @@ class Amarillo
|
|
178
186
|
if type == 'ec' then
|
179
187
|
certPrivateKey = OpenSSL::PKey::EC.new(args).generate_key
|
180
188
|
elsif type == 'rsa' then
|
181
|
-
|
189
|
+
if args.to_i > 0
|
190
|
+
certPrivateKey = OpenSSL::PKey::RSA.new(args.to_i)
|
191
|
+
else
|
192
|
+
@logger.error("Invalid RSA key size: #{args}")
|
193
|
+
end
|
182
194
|
end
|
183
195
|
|
184
196
|
@logger.info "Requesting certificate..."
|
185
197
|
csr = Acme::Client::CertificateRequest.new private_key: certPrivateKey,
|
186
198
|
names: [commonName]
|
187
199
|
|
188
|
-
while order.status
|
200
|
+
while order.status != 'ready'
|
189
201
|
sleep(1)
|
202
|
+
@logger.info "Order status: #{order.status}"
|
190
203
|
order.reload
|
204
|
+
raise if order.status == 'invalid'
|
191
205
|
end
|
192
206
|
|
193
207
|
@logger.info "Order status: #{order.status}"
|
@@ -196,7 +210,7 @@ class Amarillo
|
|
196
210
|
order.finalize(csr: csr)
|
197
211
|
rescue
|
198
212
|
@logger.error("Error finalizing certificate order")
|
199
|
-
|
213
|
+
raise
|
200
214
|
end
|
201
215
|
|
202
216
|
keyOutputPath = "#{@keyPath}/#{commonName}.key"
|
@@ -207,7 +221,13 @@ class Amarillo
|
|
207
221
|
File.open(keyOutputPath, "w") do |f|
|
208
222
|
f.puts certPrivateKey.to_pem.to_s
|
209
223
|
end
|
210
|
-
|
224
|
+
|
225
|
+
keyMode = @config["defaults"]["key_mode"] || 0600
|
226
|
+
if keyMode
|
227
|
+
File.chmod(keyMode, keyOutputPath)
|
228
|
+
else
|
229
|
+
File.chmod(0600, keyOutputPath)
|
230
|
+
end
|
211
231
|
|
212
232
|
@logger.info "Saving certificate to #{certOutputPath}"
|
213
233
|
|
@@ -215,10 +235,20 @@ class Amarillo
|
|
215
235
|
f.puts order.certificate
|
216
236
|
end
|
217
237
|
|
238
|
+
owner = certConfig["owner"] || @config["defaults"]["owner"] || "root"
|
239
|
+
group = certConfig["group"] || @config["defaults"]["group"] || "root"
|
240
|
+
begin
|
241
|
+
FileUtils.chown(owner, group, keyOutputPath)
|
242
|
+
rescue
|
243
|
+
@logger.info "Unable to change ownership of key file #{keyOutputPath}"
|
244
|
+
end
|
245
|
+
|
218
246
|
certConfigFile = "#{@configsPath}/#{commonName}.yml"
|
247
|
+
|
248
|
+
@logger.info "Saving certificate configuration to #{certConfigFile}"
|
219
249
|
File.write(certConfigFile, certConfig.to_yaml)
|
220
250
|
|
221
|
-
self.
|
251
|
+
self.doRenewalAction script
|
222
252
|
|
223
253
|
end
|
224
254
|
|
@@ -247,10 +277,6 @@ class Amarillo
|
|
247
277
|
@route53.change_resource_record_sets(options)
|
248
278
|
end
|
249
279
|
|
250
|
-
def renewCertificate(zone, commonName, email)
|
251
|
-
|
252
|
-
end
|
253
|
-
|
254
280
|
def listCertificates
|
255
281
|
|
256
282
|
rows = []
|
@@ -284,6 +310,7 @@ class Amarillo
|
|
284
310
|
|
285
311
|
end
|
286
312
|
|
313
|
+
# Renew all certificates
|
287
314
|
def renewCertificates
|
288
315
|
t = Time.now
|
289
316
|
@logger.info "Renewing certificates"
|
@@ -291,10 +318,7 @@ class Amarillo
|
|
291
318
|
Dir["#{@configsPath}/*.yml"].each do |c|
|
292
319
|
config = YAML.load(File.read(c))
|
293
320
|
|
294
|
-
cn
|
295
|
-
email = config["email"]
|
296
|
-
zone = config["zone"]
|
297
|
-
key_type = config["key_type"]
|
321
|
+
cn = config["commonName"]
|
298
322
|
|
299
323
|
certificatePath = "#{@certificatePath}/#{cn}.crt"
|
300
324
|
raw = File.read certificatePath
|
@@ -303,12 +327,39 @@ class Amarillo
|
|
303
327
|
|
304
328
|
if daysToExpiration < 30 then
|
305
329
|
@logger.info "#{cn} certificate needs to be renewed"
|
306
|
-
self.requestCertificate
|
330
|
+
self.requestCertificate configPath: c
|
307
331
|
else
|
308
332
|
@logger.info "#{cn} certificate does not need to be renewed"
|
309
333
|
end
|
310
334
|
end
|
311
335
|
end
|
336
|
+
|
337
|
+
# Renew specific certificate, implied force
|
338
|
+
def renewCertificate(commonName)
|
339
|
+
|
340
|
+
configPath = "#{@configsPath}/#{commonName}.yml"
|
341
|
+
self.requestCertificate configPath: configPath
|
342
|
+
|
343
|
+
end
|
344
|
+
|
345
|
+
def doRenewalAction(renewal_action)
|
346
|
+
|
347
|
+
if renewal_action
|
348
|
+
|
349
|
+
@logger.info "Executing certificate renewal action: #{renewal_action}"
|
350
|
+
|
351
|
+
begin
|
352
|
+
%x( #{renewal_action} )
|
353
|
+
@logger.info "Renewal action returned: #{$?}"
|
354
|
+
rescue
|
355
|
+
@logger.error("Error executing certificate renewal action")
|
356
|
+
raise
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|
360
|
+
|
361
|
+
end
|
362
|
+
|
312
363
|
end
|
313
364
|
|
314
365
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amarillo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iAchieved.it LLC
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acme-client
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '3.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '3.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: aws-sdk-core
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
requirements: []
|
112
|
-
rubygems_version: 3.
|
112
|
+
rubygems_version: 3.2.33
|
113
113
|
signing_key:
|
114
114
|
specification_version: 4
|
115
115
|
summary: Amarillo
|