puma-acme 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +29 -12
- data/LICENSE.txt +1 -1
- data/README.md +33 -40
- data/lib/puma/acme/plugin.rb +16 -16
- data/lib/puma/acme/version.rb +1 -1
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 627c59d3385c6bd13e5a80e2eabade6fdc7c979d84594ce19223972588c6ab3d
|
4
|
+
data.tar.gz: faebef3c6288f8d1a4588999ae4bf7d6561a6cb23981333b212b426d32562bb0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95128f3fcff6e220ce51ca8678aa530e5ef7b53b79b60b680c4d2c7f9e466535d3599c89e155efc85d5cc5f0998034f029e2c170c92b7a9586416d66738a617a
|
7
|
+
data.tar.gz: ff84a445f469fcbbd51334b725a30a5840cc1d0a2f3914b89ac72fd8b496d7881c5e8f6f7b577ae763502ade3f29034161ba4acaabfecac59268205c026f3e0a
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,58 +1,75 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
puma-acme (0.1.
|
4
|
+
puma-acme (0.1.1)
|
5
5
|
acme-client (~> 2.0.13)
|
6
6
|
pstore (~> 0.1)
|
7
|
-
puma (~> 6
|
7
|
+
puma (~> 5.6)
|
8
8
|
sinatra (~> 3.1)
|
9
9
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
acme-client (2.0.
|
13
|
+
acme-client (2.0.16)
|
14
14
|
faraday (>= 1.0, < 3.0.0)
|
15
15
|
faraday-retry (>= 1.0, < 3.0.0)
|
16
|
+
addressable (2.8.6)
|
17
|
+
public_suffix (>= 2.0.2, < 6.0)
|
16
18
|
base64 (0.2.0)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
byebug (11.1.3)
|
20
|
+
crack (0.4.5)
|
21
|
+
rexml
|
22
|
+
faraday (2.9.0)
|
23
|
+
faraday-net_http (>= 2.0, < 3.2)
|
24
|
+
faraday-net_http (3.1.0)
|
25
|
+
net-http
|
22
26
|
faraday-retry (2.2.0)
|
23
27
|
faraday (~> 2.0)
|
28
|
+
hashdiff (1.1.0)
|
24
29
|
http.rb (0.12.0)
|
25
30
|
minitest (5.20.0)
|
26
31
|
minitest-mock_expectations (1.2.0)
|
27
32
|
mustermann (3.0.0)
|
28
33
|
ruby2_keywords (~> 0.0.1)
|
34
|
+
net-http (0.4.1)
|
35
|
+
uri
|
29
36
|
nio4r (2.7.0)
|
30
37
|
pstore (0.1.3)
|
31
|
-
|
38
|
+
public_suffix (5.0.4)
|
39
|
+
puma (5.6.8)
|
32
40
|
nio4r (~> 2.0)
|
33
41
|
rack (2.2.8)
|
34
|
-
rack-protection (3.
|
42
|
+
rack-protection (3.2.0)
|
43
|
+
base64 (>= 0.1.0)
|
35
44
|
rack (~> 2.2, >= 2.2.4)
|
36
45
|
rake (13.1.0)
|
46
|
+
rexml (3.2.6)
|
37
47
|
ruby2_keywords (0.0.5)
|
38
|
-
sinatra (3.
|
48
|
+
sinatra (3.2.0)
|
39
49
|
mustermann (~> 3.0)
|
40
50
|
rack (~> 2.2, >= 2.2.4)
|
41
|
-
rack-protection (= 3.
|
51
|
+
rack-protection (= 3.2.0)
|
42
52
|
tilt (~> 2.0)
|
43
53
|
tilt (2.3.0)
|
54
|
+
uri (0.13.0)
|
44
55
|
vcr (6.2.0)
|
56
|
+
webmock (3.19.1)
|
57
|
+
addressable (>= 2.8.0)
|
58
|
+
crack (>= 0.3.2)
|
59
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
45
60
|
|
46
61
|
PLATFORMS
|
47
62
|
arm64-darwin-23
|
48
63
|
|
49
64
|
DEPENDENCIES
|
65
|
+
byebug
|
50
66
|
http.rb (~> 0.12)
|
51
67
|
minitest (~> 5.14)
|
52
68
|
minitest-mock_expectations (~> 1.2)
|
53
69
|
puma-acme!
|
54
70
|
rake (~> 13.0)
|
55
71
|
vcr (~> 6.1)
|
72
|
+
webmock (~> 3.19)
|
56
73
|
|
57
74
|
BUNDLED WITH
|
58
75
|
2.3.26
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c)
|
3
|
+
Copyright (c) 2024 Anchor Security, Inc.
|
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
|
data/README.md
CHANGED
@@ -1,28 +1,24 @@
|
|
1
1
|
# puma-acme
|
2
2
|
|
3
|
-
A [Puma](https://puma.io/) plugin for
|
4
|
-
[ACME](https://www.rfc-editor.org/rfc/rfc8555.html).
|
3
|
+
A [Puma](https://puma.io/) plugin for adding HTTPS support to a Puma server
|
4
|
+
with SSL certs via [ACME](https://www.rfc-editor.org/rfc/rfc8555.html).
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
provisioning. A rack handler for
|
6
|
+
To use, configure the server name(s), accept the TOS, and add a bind directive.
|
7
|
+
The plugin will handle ACME account creation, order handling, challenge
|
8
|
+
responses, and certificate provisioning. A
|
10
9
|
[HTTP-01](https://letsencrypt.org/docs/challenge-types/#http-01-challenge)
|
11
|
-
|
12
|
-
challenges.
|
10
|
+
rack handler also allows non-SSL addresses to automatically answer challenges.
|
13
11
|
|
14
|
-
On first boot, the server will
|
15
|
-
|
16
|
-
|
17
|
-
and binds to the SSL port.
|
12
|
+
On first boot, the server will start without SSL and run the ACME workflow in a
|
13
|
+
background thread. When the workflow finishes, the server will gracefully
|
14
|
+
restart and bind to the SSL port.
|
18
15
|
|
19
16
|
If the configured cache contains an unexpired certificate that matches the
|
20
17
|
algorithm and server name(s), it will use the cert to bind a listener at server
|
21
18
|
boot.
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
directive for details.
|
20
|
+
Setting a renewal interval based on the remaining time as a duration or a
|
21
|
+
fraction will enable automatic renewal. See `acme_renew_at` for details.
|
26
22
|
|
27
23
|
Supports standalone and cluster mode, along with graceful & rolling restarts.
|
28
24
|
|
@@ -45,7 +41,7 @@ config.bind 'tcp://0.0.0.0:80'
|
|
45
41
|
|
46
42
|
plugin :acme
|
47
43
|
|
48
|
-
acme_server_name 'puma-acme.example.org'
|
44
|
+
acme_server_name 'puma-acme.example.org'
|
49
45
|
acme_tos_agreed true
|
50
46
|
|
51
47
|
config.bind 'acme://0.0.0.0:443'
|
@@ -60,22 +56,21 @@ advanced:
|
|
60
56
|
# Recommended for account recovery and revocation.
|
61
57
|
acme_contact 'mailto:acme-user@exmaple.org'
|
62
58
|
|
63
|
-
# Specify
|
59
|
+
# Specify server names (SAN extension).
|
64
60
|
acme_server_names 'puma-acme.example.org', 'www.puma-acme.example.org'
|
65
61
|
|
66
62
|
# Enable automatic renewal based on an amount of time or fraction of life
|
67
|
-
# remaining. For an amount of time, use
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# certificate lifetime.
|
63
|
+
# remaining. For an amount of time, use Integer seconds, for example the value
|
64
|
+
# 2592000 will set renewal to 30 days before certificate expiry. For a fraction
|
65
|
+
# of life remaining, use a Float between 0 and 1, for example the value 0.75
|
66
|
+
# will set renewal at 75% of the way through the certificate lifetime.
|
72
67
|
acme_renew_at 0.75
|
73
68
|
|
74
|
-
# URL of ACME server's directory URL,
|
69
|
+
# URL of ACME server's directory URL, defaults to LetsEncrypt.
|
75
70
|
acme_directory 'https://acme.example.org/directory'
|
76
71
|
|
77
|
-
# Accept the Terms of Service (TOS) of an ACME server
|
78
|
-
#
|
72
|
+
# Accept the Terms of Service (TOS) of an ACME server with the server's
|
73
|
+
# directory URL as a string or true to accept any server's TOS.
|
79
74
|
acme_tos_agreed 'https://acme.example.org/directory'
|
80
75
|
|
81
76
|
# External Account Binding (EAB) token KID & secret HMAC key for the ACME
|
@@ -83,29 +78,27 @@ acme_tos_agreed 'https://acme.example.org/directory'
|
|
83
78
|
acme_eab_kid ENV['ACME_KID']
|
84
79
|
acme_eab_hmac_key ENV['ACME_HMAC_KEY']
|
85
80
|
|
86
|
-
# Encryption key algorithm, :ecdsa
|
81
|
+
# Encryption key algorithm, either :ecdsa or :rsa, defaults to :ecdsa.
|
87
82
|
acme_algorithm :ecdsa
|
88
83
|
|
89
|
-
# Provision mode, :background
|
90
|
-
#
|
91
|
-
#
|
92
|
-
# Foreground mode blocks all binding listeners until a certificate
|
93
|
-
#
|
94
|
-
acme_mode :background
|
84
|
+
# Provision mode, either :background or :foreground, defaults to :background.
|
85
|
+
# Background mode provisions certificates in a background thread without
|
86
|
+
# blocking binding or request serving for non-acme listeners.
|
87
|
+
# Foreground mode blocks all binding listeners until a certificate
|
88
|
+
# provisions, compatible only with zero-challenge ACME flow.
|
89
|
+
acme_mode :background
|
95
90
|
|
96
|
-
# Store account, order, and
|
97
|
-
#
|
91
|
+
# ActiveSupport::Cache::Store compatible cache to store account, order, and
|
92
|
+
# certificate data. Defaults to a local filesystem based cache.
|
98
93
|
acme_cache Rails.cache
|
99
94
|
|
100
|
-
# Path to the cache directory for the default cache, 'tmp/acme'
|
95
|
+
# Path to the cache directory for the default cache, defaults to 'tmp/acme'.
|
101
96
|
acme_cache_dir 'tmp/acme'
|
102
97
|
|
103
|
-
# Time to wait in seconds before
|
104
|
-
# is the default.
|
98
|
+
# Time to wait in seconds before rechecking order status, defaults to 1 second.
|
105
99
|
acme_poll_interval 1
|
106
100
|
|
107
|
-
# Time to wait in seconds before checking for
|
108
|
-
# hour.
|
101
|
+
# Time to wait in seconds before checking for renewal, defaults to 1 hour.
|
109
102
|
acme_renew_interval 60 * 60
|
110
103
|
```
|
111
104
|
|
@@ -117,5 +110,5 @@ acme_renew_interval 60 * 60
|
|
117
110
|
|
118
111
|
## License
|
119
112
|
|
120
|
-
|
113
|
+
puma-acme is available as open source under the terms of the [MIT
|
121
114
|
License](http://opensource.org/licenses/MIT).
|
data/lib/puma/acme/plugin.rb
CHANGED
@@ -41,11 +41,11 @@ module Puma
|
|
41
41
|
manager: @manager
|
42
42
|
)
|
43
43
|
|
44
|
-
@
|
44
|
+
@logger = launcher.respond_to?(:log_writer) ? launcher.log_writer : launcher.events
|
45
45
|
|
46
46
|
cert = @manager.cert!(identifiers: identifiers, algorithm: algorithm)
|
47
47
|
if cert.usable?
|
48
|
-
@
|
48
|
+
@logger.debug 'Acme: cert already provisioned'
|
49
49
|
|
50
50
|
bind_to(launcher, cert)
|
51
51
|
|
@@ -57,17 +57,17 @@ module Puma
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
elsif mode == :background
|
60
|
-
@
|
60
|
+
@logger.log 'Puma background provisioning cert via puma-acme plugin...'
|
61
61
|
|
62
62
|
in_background do
|
63
63
|
provision(cert, poll_interval: poll_interval)
|
64
64
|
|
65
|
-
@
|
65
|
+
@logger.log 'Puma restarting after provisioning cert via puma-acme plugin...'
|
66
66
|
|
67
67
|
launcher.restart
|
68
68
|
end
|
69
69
|
elsif mode == :foreground
|
70
|
-
@
|
70
|
+
@logger.log 'Puma foreground provisioning cert via puma-acme plugin...'
|
71
71
|
|
72
72
|
provision(cert, poll_interval: poll_interval)
|
73
73
|
bind_to(launcher, cert)
|
@@ -92,7 +92,7 @@ module Puma
|
|
92
92
|
'cert_pem' => cert.cert_pem
|
93
93
|
}
|
94
94
|
|
95
|
-
ctx = MiniSSL::ContextBuilder.new(params, @
|
95
|
+
ctx = MiniSSL::ContextBuilder.new(params, @logger).context
|
96
96
|
|
97
97
|
launcher.binder.before_parse_hook do
|
98
98
|
@acme_binds.each do |str|
|
@@ -100,16 +100,16 @@ module Puma
|
|
100
100
|
|
101
101
|
if (fd = launcher.binder.inherited_fds.delete(str))
|
102
102
|
io = launcher.binder.inherit_ssl_listener(fd, ctx)
|
103
|
-
@
|
103
|
+
@logger.log "* Inherited #{str}"
|
104
104
|
elsif (fd = launcher.binder.activated_sockets.delete([:acme, uri.host, uri.port]))
|
105
105
|
io = launcher.binder.inherit_ssl_listener(fd, ctx)
|
106
|
-
@
|
106
|
+
@logger.log "* Activated #{str}"
|
107
107
|
else
|
108
108
|
io = launcher.binder.add_ssl_listener(uri.host, uri.port, ctx)
|
109
109
|
end
|
110
110
|
|
111
111
|
cert.identifiers.each do |identifier|
|
112
|
-
@
|
112
|
+
@logger.log "* Listening on ssl://#{uri.host}:#{uri.port} for https://#{identifier.value} (puma-acme)"
|
113
113
|
end
|
114
114
|
|
115
115
|
launcher.binder.listeners << [str, io]
|
@@ -119,13 +119,13 @@ module Puma
|
|
119
119
|
|
120
120
|
def provision(cert, poll_interval:)
|
121
121
|
unless @manager.account
|
122
|
-
@
|
122
|
+
@logger.debug 'Acme: creating account'
|
123
123
|
|
124
124
|
@manager.account!
|
125
125
|
end
|
126
126
|
|
127
127
|
if cert.order.nil?
|
128
|
-
@
|
128
|
+
@logger.debug 'Acme: creating order'
|
129
129
|
@manager.order!(cert)
|
130
130
|
else
|
131
131
|
@manager.reload!(cert)
|
@@ -134,23 +134,23 @@ module Puma
|
|
134
134
|
loop do
|
135
135
|
case cert.order.status.to_sym
|
136
136
|
when :valid
|
137
|
-
@
|
137
|
+
@logger.debug 'Acme: downloading cert'
|
138
138
|
|
139
139
|
@manager.download!(cert)
|
140
140
|
|
141
141
|
return
|
142
142
|
when :processing, :pending
|
143
|
-
@
|
143
|
+
@logger.debug "Acme: waiting on #{cert.order.status} order"
|
144
144
|
|
145
145
|
sleep poll_interval
|
146
146
|
|
147
147
|
@manager.reload!(cert)
|
148
148
|
when :ready
|
149
|
-
@
|
149
|
+
@logger.debug 'Acme: finalizing ready order'
|
150
150
|
|
151
151
|
@manager.finalize!(cert)
|
152
152
|
when :invalid
|
153
|
-
@
|
153
|
+
@logger.debug 'Acme: invalid order, re-ordering'
|
154
154
|
|
155
155
|
@manager.order!(cert)
|
156
156
|
end
|
@@ -171,7 +171,7 @@ module Puma
|
|
171
171
|
|
172
172
|
next unless cert.renewable?(renew_at)
|
173
173
|
|
174
|
-
@
|
174
|
+
@logger.debug 'Acme: creating renewal order'
|
175
175
|
|
176
176
|
@manager.order!(cert)
|
177
177
|
|
data/lib/puma/acme/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puma-acme
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anchor Security, Inc
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acme-client
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '6
|
47
|
+
version: '5.6'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '6
|
54
|
+
version: '5.6'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: sinatra
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '6.1'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: webmock
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '3.19'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '3.19'
|
139
153
|
description: A Puma webserver plugin for automatic access to certificates from Let's
|
140
154
|
Encrypt and any other ACME-based CA.
|
141
155
|
email:
|
@@ -183,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
183
197
|
- !ruby/object:Gem::Version
|
184
198
|
version: '0'
|
185
199
|
requirements: []
|
186
|
-
rubygems_version: 3.
|
200
|
+
rubygems_version: 3.4.10
|
187
201
|
signing_key:
|
188
202
|
specification_version: 4
|
189
203
|
summary: Puma plugin for ACME.
|