anchor-pki 0.6.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/Gemfile.lock +45 -21
- data/README.md +3 -5
- data/lib/anchor/auto_cert/configuration.rb +43 -218
- data/lib/anchor/auto_cert/railtie.rb +4 -63
- data/lib/anchor/auto_cert.rb +0 -16
- data/lib/anchor/pem_bundle.rb +2 -0
- data/lib/anchor/version.rb +1 -1
- data/lib/anchor.rb +7 -1
- data/lib/puma/dsl.rb +14 -9
- data/lib/puma/plugin/auto_cert.rb +108 -80
- metadata +4 -29
- data/lib/anchor/auto_cert/identifier_policy.rb +0 -71
- data/lib/anchor/auto_cert/managed_certificate.rb +0 -77
- data/lib/anchor/auto_cert/manager.rb +0 -260
- data/lib/anchor/auto_cert/policy_check/for_hostname.rb +0 -40
- data/lib/anchor/auto_cert/policy_check/for_ipaddr.rb +0 -48
- data/lib/anchor/auto_cert/policy_check/for_wildcard_hostname.rb +0 -57
- data/lib/anchor/auto_cert/policy_check.rb +0 -37
- data/lib/anchor/auto_cert/registry.rb +0 -63
- data/lib/anchor/auto_cert/renewal_busy_wait.rb +0 -40
- data/lib/anchor/auto_cert/terms_of_service_acceptor.rb +0 -34
- data/lib/anchor/disk_store.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 199d953aecf7e0a21ec2d40b4b910932dce98194b02dad0ccb5a19a8edca7dfc
|
4
|
+
data.tar.gz: 75eebd2d66d21913ec9299be8f6a11ba04a53bdb6f63554258644b18d5495f56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f0b100133cdbd56308538a5c3085062221d3e9d7caa154aebe7fa61661ac59713f8e14829ced0dba6731c6fbff20a47d5382e6062e164e7ac85cd05ea94c406
|
7
|
+
data.tar.gz: 6424e2cb19604b4a78a673109fc1ffc1bc4ee62de8a036fdacc36030b23d67f320f7142bc62f4fdae7b3b3864d2ab1cbdb950548460b7bf01178a2a828dea7b7
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.8.0] - 2024-03-04
|
4
|
+
|
5
|
+
- fix 0.7 regression such that configuration once again considers ENV values
|
6
|
+
|
7
|
+
## [0.7.0] - 2024-01-11
|
8
|
+
|
9
|
+
- inherit from the puma-acme plugin in auto\_cert plugin
|
10
|
+
- remove extraneous config & environment settings
|
11
|
+
|
3
12
|
## [0.6.3] - 2024-01-10
|
4
13
|
|
5
14
|
- fixed release (0.6.2 didn't contain the expected changes)
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
anchor-pki (0.
|
5
|
-
acme
|
6
|
-
pstore (~> 0.1)
|
4
|
+
anchor-pki (0.8.0)
|
5
|
+
puma-acme (~> 0.1)
|
7
6
|
|
8
7
|
GEM
|
9
8
|
remote: https://rubygems.org/
|
10
9
|
specs:
|
11
|
-
acme-client (2.0.
|
10
|
+
acme-client (2.0.17)
|
12
11
|
faraday (>= 1.0, < 3.0.0)
|
13
12
|
faraday-retry (>= 1.0, < 3.0.0)
|
14
13
|
addressable (2.8.4)
|
@@ -17,40 +16,57 @@ GEM
|
|
17
16
|
base64 (0.2.0)
|
18
17
|
crack (0.4.5)
|
19
18
|
rexml
|
20
|
-
diff-lcs (1.5.
|
19
|
+
diff-lcs (1.5.1)
|
21
20
|
docile (1.4.0)
|
22
|
-
faraday (2.
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
faraday-net_http (3.0.2)
|
21
|
+
faraday (2.9.0)
|
22
|
+
faraday-net_http (>= 2.0, < 3.2)
|
23
|
+
faraday-net_http (3.1.0)
|
24
|
+
net-http
|
27
25
|
faraday-retry (2.2.0)
|
28
26
|
faraday (~> 2.0)
|
29
27
|
hashdiff (1.0.1)
|
30
28
|
json (2.6.3)
|
31
29
|
minitest (5.18.0)
|
30
|
+
mustermann (3.0.0)
|
31
|
+
ruby2_keywords (~> 0.0.1)
|
32
|
+
net-http (0.4.1)
|
33
|
+
uri
|
34
|
+
nio4r (2.7.0)
|
32
35
|
parallel (1.23.0)
|
33
36
|
parser (3.2.2.1)
|
34
37
|
ast (~> 2.4.1)
|
35
38
|
pstore (0.1.3)
|
36
39
|
public_suffix (5.0.1)
|
40
|
+
puma (6.4.2)
|
41
|
+
nio4r (~> 2.0)
|
42
|
+
puma-acme (0.1.3)
|
43
|
+
acme-client (~> 2.0.13)
|
44
|
+
pstore (~> 0.1)
|
45
|
+
puma (~> 6.0)
|
46
|
+
sinatra (~> 4.0)
|
47
|
+
rack (3.0.9.1)
|
48
|
+
rack-protection (4.0.0)
|
49
|
+
base64 (>= 0.1.0)
|
50
|
+
rack (>= 3.0.0, < 4)
|
51
|
+
rack-session (2.0.0)
|
52
|
+
rack (>= 3.0.0)
|
37
53
|
rainbow (3.1.1)
|
38
54
|
rake (13.1.0)
|
39
55
|
regexp_parser (2.8.0)
|
40
56
|
rexml (3.2.5)
|
41
|
-
rspec (3.
|
42
|
-
rspec-core (~> 3.
|
43
|
-
rspec-expectations (~> 3.
|
44
|
-
rspec-mocks (~> 3.
|
45
|
-
rspec-core (3.
|
46
|
-
rspec-support (~> 3.
|
47
|
-
rspec-expectations (3.
|
57
|
+
rspec (3.13.0)
|
58
|
+
rspec-core (~> 3.13.0)
|
59
|
+
rspec-expectations (~> 3.13.0)
|
60
|
+
rspec-mocks (~> 3.13.0)
|
61
|
+
rspec-core (3.13.0)
|
62
|
+
rspec-support (~> 3.13.0)
|
63
|
+
rspec-expectations (3.13.0)
|
48
64
|
diff-lcs (>= 1.2.0, < 2.0)
|
49
|
-
rspec-support (~> 3.
|
50
|
-
rspec-mocks (3.
|
65
|
+
rspec-support (~> 3.13.0)
|
66
|
+
rspec-mocks (3.13.0)
|
51
67
|
diff-lcs (>= 1.2.0, < 2.0)
|
52
|
-
rspec-support (~> 3.
|
53
|
-
rspec-support (3.
|
68
|
+
rspec-support (~> 3.13.0)
|
69
|
+
rspec-support (3.13.1)
|
54
70
|
rubocop (1.51.0)
|
55
71
|
json (~> 2.3)
|
56
72
|
parallel (~> 1.10)
|
@@ -79,7 +95,15 @@ GEM
|
|
79
95
|
simplecov_json_formatter (~> 0.1)
|
80
96
|
simplecov-html (0.12.3)
|
81
97
|
simplecov_json_formatter (0.1.4)
|
98
|
+
sinatra (4.0.0)
|
99
|
+
mustermann (~> 3.0)
|
100
|
+
rack (>= 3.0.0, < 4)
|
101
|
+
rack-protection (= 4.0.0)
|
102
|
+
rack-session (>= 2.0.0, < 3)
|
103
|
+
tilt (~> 2.0)
|
104
|
+
tilt (2.3.0)
|
82
105
|
unicode-display_width (2.4.2)
|
106
|
+
uri (0.13.0)
|
83
107
|
vcr (6.1.0)
|
84
108
|
webmock (3.18.1)
|
85
109
|
addressable (>= 2.8.0)
|
data/README.md
CHANGED
@@ -8,15 +8,13 @@ The Following environment variables are available to configure the default
|
|
8
8
|
[`AutoCert::Manager`](./lib/anchor/auto_cert/manager.rb).
|
9
9
|
|
10
10
|
* `HTTPS_PORT` - the TCP numerical port to bind SSL to.
|
11
|
-
* `
|
12
|
-
* `ACME_CONTACT` - URL to contact in case of issues with the account
|
11
|
+
* `SERVER_NAME`/`SERVER_NAMES` - A comma separated list of hostnames for provisioning certs
|
13
12
|
* `ACME_DIRECTORY_URL` - the ACME provider's directory
|
14
13
|
* `ACME_HMAC_KEY` - your External Account Binding (EAB) HMAC_KEY for authenticating with the ACME directory above
|
15
14
|
* `ACME_KID` - your External Account Binding (EAB) KID for authenticating with the ACME directory above with an
|
15
|
+
* `ACME_CONTACT` - **optional** URL to contact in case of issues with the account
|
16
16
|
* `ACME_RENEW_BEFORE_SECONDS` - **optional** Start a renewal this number number of seconds before the cert expires. This defaults to 30 days (2592000 seconds)
|
17
17
|
* `ACME_RENEW_BEFORE_FRACTION` - **optional** Start the renewal when this fraction of a cert's valid window is left. This defaults to 0.5, which means when the cert is in the last 50% of its lifespan a renewal is attempted.
|
18
|
-
* `AUTO_CERT_CHECK_EVERY` - **optional** the number of seconds to wait between checking if the certificate has expired. This defaults to 1 hour (3600 seconds)
|
19
|
-
* `AUTO_CERT_NAME` - **optional** the name to use to lookup the default `AutoCert::Configuration` in the `AutoCert::Registry`. This is `default` by default
|
20
18
|
|
21
19
|
If both `ACME_RENEW_BEFORE_SECONDS` and `ACME_RENEW_BEFORE_FRACTION` are set,
|
22
20
|
the one that causes the renewal to take place earlier is used.
|
@@ -39,7 +37,7 @@ Currently the `AutoCert::Manager` will use whichever is earlier.
|
|
39
37
|
|
40
38
|
```sh
|
41
39
|
HTTPS_PORT=44300
|
42
|
-
|
40
|
+
SERVER_NAMES=my.lcl.host,*.my.lcl.host
|
43
41
|
ACME_DIRECTORY_URL=https://acme-v02.api.letsencrypt.org/directory
|
44
42
|
ACME_KID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
45
43
|
ACME_HMAC_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
@@ -1,236 +1,61 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Anchor
|
4
|
+
# This module is here in order to communicate plugin configuration options
|
5
|
+
# to the plugin since the plugin is created dynamically and it is loaded and
|
6
|
+
# initialized without any configuration options.
|
4
7
|
module AutoCert
|
8
|
+
config_keys = %i[
|
9
|
+
algorithm
|
10
|
+
cache
|
11
|
+
cache_dir
|
12
|
+
contact
|
13
|
+
directory
|
14
|
+
eab_kid
|
15
|
+
eab_hmac_key
|
16
|
+
enabled
|
17
|
+
mode
|
18
|
+
port
|
19
|
+
renew_at
|
20
|
+
renew_interval
|
21
|
+
server_name
|
22
|
+
server_names
|
23
|
+
tos_agreed
|
24
|
+
]
|
25
|
+
|
5
26
|
# AutoCert Configuration provides a way to configure the AutoCert Manager.
|
6
27
|
#
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
:contact,
|
21
|
-
:directory_url,
|
22
|
-
:external_account_binding,
|
23
|
-
:renew_before_fraction,
|
24
|
-
:renew_before_seconds,
|
25
|
-
:tos_acceptors,
|
26
|
-
:work_dir
|
27
|
-
|
28
|
-
# rubocop:disable Metrics/ParameterLists
|
29
|
-
# Data defined classes have all required parameters in the initializer, so
|
30
|
-
# override the default initializer to allow for optional parameters and
|
31
|
-
# to pull in the defaults form the environment
|
32
|
-
#
|
33
|
-
def initialize(name:,
|
34
|
-
allow_identifiers: nil,
|
35
|
-
cache_dir: nil,
|
36
|
-
check_every_seconds: nil,
|
37
|
-
contact: nil,
|
38
|
-
directory_url: nil,
|
39
|
-
external_account_binding: nil,
|
40
|
-
renew_before_fraction: nil,
|
41
|
-
renew_before_seconds: nil,
|
42
|
-
tos_acceptors: nil,
|
43
|
-
work_dir: nil)
|
44
|
-
|
45
|
-
@name = name
|
46
|
-
|
47
|
-
@allow_identifiers = allow_identifiers
|
48
|
-
@cache_dir = cache_dir
|
49
|
-
@check_every_seconds = check_every_seconds
|
50
|
-
@contact = contact
|
51
|
-
@directory_url = directory_url
|
52
|
-
@external_account_binding = external_account_binding
|
53
|
-
@renew_before_fraction = renew_before_fraction
|
54
|
-
@renew_before_seconds = renew_before_seconds
|
55
|
-
@tos_acceptors = tos_acceptors
|
56
|
-
@work_dir = work_dir
|
57
|
-
end
|
58
|
-
# rubocop:enable Metrics/ParameterLists
|
59
|
-
|
60
|
-
def account
|
61
|
-
{
|
62
|
-
contact: contact,
|
63
|
-
external_account_binding: external_account_binding
|
64
|
-
}
|
65
|
-
end
|
66
|
-
|
67
|
-
# Enabled just means that the configuration is valid
|
68
|
-
def enabled?
|
69
|
-
validate!
|
70
|
-
true
|
71
|
-
rescue ConfigurationError => _e
|
72
|
-
false
|
73
|
-
end
|
74
|
-
|
75
|
-
def validate!
|
76
|
-
@allow_identifiers = prepare_allow_identifiers(@allow_identifiers)
|
77
|
-
@cache_dir = prepare_directory(dir: @cache_dir, property: 'cache_dir')
|
78
|
-
@check_every_seconds = prepare_check_every_seconds(@check_every_seconds)
|
79
|
-
@contact = prepare_contact(@contact)
|
80
|
-
@directory_url = prepare_directory_url(@directory_url)
|
81
|
-
@external_account_binding = prepare_external_account_binding(@external_account_binding)
|
82
|
-
@renew_before_fraction = prepare_renew_before_fraction(@renew_before_fraction)
|
83
|
-
@renew_before_seconds = prepare_renew_before_seconds(@renew_before_seconds)
|
84
|
-
@tos_acceptors = prepare_tos_acceptors(@tos_acceptors)
|
85
|
-
@work_dir = prepare_directory(dir: @work_dir, property: 'work_dir')
|
86
|
-
self
|
87
|
-
end
|
88
|
-
|
89
|
-
# Return the fallback identifer for this configuration
|
90
|
-
|
91
|
-
# look at all the identifiers, strip a leading wildcard off of all of
|
92
|
-
# them and then pick the one that has the fewest '.' in it, if there are
|
93
|
-
# ties for fewest, pick the first one in the list of ties. A minimum of
|
94
|
-
# 2 '.' is required.
|
95
|
-
#
|
96
|
-
def fallback_identifier
|
97
|
-
de_wildcarded = allow_identifiers.map { |i| i.sub(/^\*\./, '') }
|
98
|
-
not_tld = de_wildcarded.select { |i| i.count('.') >= 2 }
|
99
|
-
ordered = not_tld.sort_by { |i| i.count('.') }
|
100
|
-
ordered[0]
|
101
|
-
end
|
102
|
-
|
103
|
-
private
|
104
|
-
|
105
|
-
def prepare_allow_identifiers(allow_identifiers)
|
106
|
-
prepared = case allow_identifiers
|
107
|
-
when Array
|
108
|
-
allow_identifiers
|
109
|
-
when String
|
110
|
-
allow_identifiers.split(',')
|
111
|
-
when nil
|
112
|
-
ENV.fetch('ACME_ALLOW_IDENTIFIERS', nil)&.split(',')
|
113
|
-
end
|
114
|
-
|
115
|
-
if prepared.nil? || prepared.empty?
|
116
|
-
raise ConfigurationError,
|
117
|
-
"The '#{name}' #{self.class} instance has a misconfigured " \
|
118
|
-
'`allow_identifiers` value. Set it to a string, or an array of strings, ' \
|
119
|
-
'or set the ACME_ALLOW_IDENTIFIERS environment variable ' \
|
120
|
-
'to a comma separated list of identifiers.'
|
28
|
+
Configuration = Struct.new(*config_keys, keyword_init: true) do
|
29
|
+
alias_method :allow_identifiers=, :server_names=
|
30
|
+
alias_method :directory_url=, :directory=
|
31
|
+
|
32
|
+
def initialize(opts = {})
|
33
|
+
opts[:directory] ||= envs(:directory)
|
34
|
+
opts[:eab_kid] ||= envs(:eab_kid)
|
35
|
+
opts[:eab_hmac_key] ||= envs(:eab_hmac_key)
|
36
|
+
opts[:server_names] ||= envs(:server_names)&.split(',')
|
37
|
+
|
38
|
+
if (eab = opts.delete(:external_account_binding))
|
39
|
+
opts[:eab_kid] = eab[:kid]
|
40
|
+
opts[:eab_hmac_key] = eab[:hmac_key]
|
121
41
|
end
|
122
42
|
|
123
|
-
|
43
|
+
super(opts)
|
124
44
|
end
|
125
45
|
|
126
|
-
def
|
127
|
-
|
128
|
-
'`check_every_seconds` value. It must be set to an integer > 0, ' \
|
129
|
-
'or set the AUTO_CERT_CHECK_EVERY environment variable.'
|
130
|
-
|
131
|
-
candidates = [
|
132
|
-
check_every_seconds,
|
133
|
-
ENV.fetch('AUTO_CERT_CHECK_EVERY', nil),
|
134
|
-
DEFAULT_CHECK_EVERY_SECONDS
|
135
|
-
]
|
136
|
-
|
137
|
-
ensure_positive_integer(candidates, message)
|
46
|
+
def server_name=(name)
|
47
|
+
self.server_names = [name]
|
138
48
|
end
|
139
49
|
|
140
|
-
def
|
141
|
-
|
142
|
-
|
143
|
-
contact
|
144
|
-
end
|
145
|
-
|
146
|
-
def prepare_directory_url(directory_url)
|
147
|
-
message = "The '#{name}' #{self.class} instance has a misconfigured `directory_url` value. " \
|
148
|
-
'It must be set to a string, or set the ACME_DIRECTORY_URL environment variable.'
|
149
|
-
|
150
|
-
directory_url ||= ENV.fetch('ACME_DIRECTORY_URL', nil)
|
151
|
-
|
152
|
-
raise ConfigurationError, message if directory_url.nil?
|
153
|
-
|
154
|
-
directory_url
|
50
|
+
def external_account_binding=(eab)
|
51
|
+
self.eab_kid = eab[:kid]
|
52
|
+
self.eab_hmac_key = eab[:hmac_key]
|
155
53
|
end
|
156
54
|
|
157
|
-
|
158
|
-
kid = ENV.fetch('ACME_KID', nil)
|
159
|
-
hmac_key = ENV.fetch('ACME_HMAC_KEY', nil)
|
160
|
-
|
161
|
-
if external_account_binding && external_account_binding[:kid] && external_account_binding[:hmac_key]
|
162
|
-
return external_account_binding
|
163
|
-
end
|
164
|
-
|
165
|
-
{ kid: kid, hmac_key: hmac_key }
|
166
|
-
end
|
167
|
-
|
168
|
-
def prepare_renew_before_seconds(renew_before_seconds)
|
169
|
-
message = "The '#{name}' #{self.class} instance has a misconfigured " \
|
170
|
-
'`before_seconds` value. It must be set to an integer > 0, ' \
|
171
|
-
'or set the ACME_RENEW_BEFORE_SECONDS environment variable.'
|
172
|
-
|
173
|
-
candidates = [
|
174
|
-
renew_before_seconds,
|
175
|
-
ENV.fetch('ACME_RENEW_BEFORE_SECONDS', nil),
|
176
|
-
DEFAULT_RENEW_BEFORE_SECONDS
|
177
|
-
]
|
178
|
-
ensure_positive_integer(candidates, message)
|
179
|
-
end
|
180
|
-
|
181
|
-
def prepare_renew_before_fraction(renew_before_fraction)
|
182
|
-
message = "The '#{name}' #{self.class} instance has a misconfigured " \
|
183
|
-
'`before_fraction` value. It must be set to a float > 0 and < 1, ' \
|
184
|
-
'or set the ACME_RENEW_BEFORE_FRACTION environment variable.'
|
185
|
-
|
186
|
-
candidates = [
|
187
|
-
renew_before_fraction,
|
188
|
-
ENV.fetch('ACME_RENEW_BEFORE_FRACTION', nil),
|
189
|
-
DEFAULT_RENEW_BEFORE_FRACTION
|
190
|
-
]
|
191
|
-
|
192
|
-
candidates.each do |candidate|
|
193
|
-
next if candidate.nil?
|
194
|
-
|
195
|
-
as_float = candidate.to_f
|
196
|
-
return as_float if (0..1).cover?(as_float)
|
197
|
-
end
|
198
|
-
|
199
|
-
# this should really never happen as DEFAULT_RENEW_BEFORE_FRACTION is
|
200
|
-
# valid
|
201
|
-
raise ConfigurationError, message
|
202
|
-
end
|
203
|
-
|
204
|
-
def prepare_tos_acceptors(tos_acceptors)
|
205
|
-
Array(tos_acceptors)
|
206
|
-
end
|
207
|
-
|
208
|
-
def prepare_directory(dir:, property:)
|
209
|
-
return nil if dir.nil?
|
210
|
-
|
211
|
-
dir = Pathname.new(dir) unless dir.is_a?(Pathname)
|
212
|
-
message = "The '#{name}' #{self.class} instance has a misconfigured " \
|
213
|
-
"`#{property}` value, it resolves to (#{dir}). " \
|
214
|
-
'It must be set to a directory, or a path that can be created.'
|
215
|
-
|
216
|
-
begin
|
217
|
-
dir.mkpath
|
218
|
-
rescue StandardError => _e
|
219
|
-
raise ConfigurationError, message
|
220
|
-
end
|
221
|
-
|
222
|
-
dir
|
223
|
-
end
|
224
|
-
|
225
|
-
def ensure_positive_integer(candidates, message)
|
226
|
-
candidates.each do |candidate|
|
227
|
-
next if candidate.nil?
|
228
|
-
|
229
|
-
as_int = candidate.to_i
|
230
|
-
return as_int if as_int.positive?
|
231
|
-
end
|
55
|
+
private
|
232
56
|
|
233
|
-
|
57
|
+
def envs(key)
|
58
|
+
Anchor::ENV_VARS[key].map { |k| ENV.fetch(k, nil) }.compact.first
|
234
59
|
end
|
235
60
|
end
|
236
61
|
end
|
@@ -4,36 +4,16 @@ module Anchor
|
|
4
4
|
module AutoCert
|
5
5
|
# AutoCert Railtie
|
6
6
|
class Railtie < Rails::Railtie
|
7
|
-
name = ENV.fetch('AUTO_CERT_NAME', 'anchor')
|
8
|
-
|
9
7
|
# Initialize the configuration with a blank configuration, ensuring
|
10
8
|
# the configuration exists, even if it is not used.
|
11
|
-
config.auto_cert = ::Anchor::AutoCert::Configuration.new
|
12
|
-
|
13
|
-
# Make sure the auto cert configuration is valid before the app boots
|
14
|
-
# This will run after every code reload in development and after boot in
|
15
|
-
# production
|
16
|
-
config.to_prepare do
|
17
|
-
if Rails.configuration.auto_cert.enabled?
|
18
|
-
Rails.configuration.auto_cert.validate!
|
19
|
-
|
20
|
-
# register the configuration under its name so that it can
|
21
|
-
# be discovered by other parts of the application
|
22
|
-
auto_cert_config = Rails.configuration.auto_cert
|
23
|
-
unless ::Anchor::AutoCert::Registry.key?(auto_cert_config.name)
|
24
|
-
::Anchor::AutoCert::Registry.store(auto_cert_config.name, auto_cert_config)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
9
|
+
config.auto_cert = ::Anchor::AutoCert::Configuration.new
|
28
10
|
|
29
11
|
# this needs to be after the load_config_initializers so that the
|
30
12
|
# application can override the :rails auto_cert configuration
|
31
13
|
#
|
32
|
-
initializer 'auto_cert.configure_rails_initialization', after: :load_config_initializers do |app|
|
33
|
-
auto_cert_config = Railtie.determine_configuration(app)
|
34
|
-
app.config.auto_cert = auto_cert_config
|
35
14
|
|
36
|
-
|
15
|
+
initializer 'auto_cert.configure_rails_initialization', after: :load_config_initializers do |app|
|
16
|
+
# Update the app.config.hosts with the server_names if we are NOT
|
37
17
|
# in the test environment.
|
38
18
|
#
|
39
19
|
# In the test environment `config.hosts` is normally empty, and as a
|
@@ -41,10 +21,7 @@ module Anchor
|
|
41
21
|
# to the `config.hosts` then HostAuthorization will be used, and tests
|
42
22
|
# will break.
|
43
23
|
unless Rails.env.test?
|
44
|
-
|
45
|
-
auto_cert_config&.validate! if Rails.configuration.auto_cert.enabled?
|
46
|
-
|
47
|
-
auto_cert_config&.allow_identifiers&.each do |identifier|
|
24
|
+
app.config.auto_cert[:server_names]&.each do |identifier|
|
48
25
|
# need to convert an identifier into a host matcher, which is just
|
49
26
|
# strip off a leading '*' if it exists so that all subdomains match.
|
50
27
|
#
|
@@ -54,42 +31,6 @@ module Anchor
|
|
54
31
|
end
|
55
32
|
end
|
56
33
|
end
|
57
|
-
|
58
|
-
def self.determine_configuration(app)
|
59
|
-
auto_cert_config = app.config.auto_cert
|
60
|
-
|
61
|
-
# If no configuration is set, then try to lookup one under the :anchor
|
62
|
-
# key or create a default one.
|
63
|
-
begin
|
64
|
-
name = ENV.fetch('AUTO_CERT_NAME', 'anchor')
|
65
|
-
auto_cert_config ||= ::Anchor::AutoCert::Registry.fetch(name)
|
66
|
-
rescue KeyError
|
67
|
-
auto_cert_config = Railtie.try_to_create_default_configuration
|
68
|
-
end
|
69
|
-
|
70
|
-
return nil unless auto_cert_config
|
71
|
-
|
72
|
-
# Set some reasonable defaults for a scratch locations if they are not
|
73
|
-
# set explicitly.
|
74
|
-
acme_scratch_dir = app.root / 'tmp' / 'acme'
|
75
|
-
acme_scratch_dir.mkpath
|
76
|
-
auto_cert_config.cache_dir ||= (acme_scratch_dir / 'cache')
|
77
|
-
auto_cert_config.work_dir ||= (acme_scratch_dir / 'work')
|
78
|
-
|
79
|
-
auto_cert_config
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.try_to_create_default_configuration
|
83
|
-
name = ENV.fetch('AUTO_CERT_NAME', 'anchor')
|
84
|
-
# If it doesn't exist, create a new one - now this may raise an error
|
85
|
-
# if the configuration is not setup correctly
|
86
|
-
::Anchor::AutoCert::Configuration.new(name: name)
|
87
|
-
rescue ConfigurationError => e
|
88
|
-
# its fine to not have a configuration, just log the error and move on
|
89
|
-
msg = "[AutoCert] Unable to create the '#{name}' configuration : #{e.message}"
|
90
|
-
Rails.logger.error(msg)
|
91
|
-
nil
|
92
|
-
end
|
93
34
|
end
|
94
35
|
end
|
95
36
|
end
|
data/lib/anchor/auto_cert.rb
CHANGED
@@ -1,21 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Anchor
|
4
|
-
module AutoCert
|
5
|
-
class Error < StandardError; end
|
6
|
-
class IdentifierNotAllowedError < Error; end
|
7
|
-
class ConfigurationError < Error; end
|
8
|
-
class UnknownPolicyCheckError < Error; end
|
9
|
-
class UnknownAlgorithmError < Error; end
|
10
|
-
class UnknownKeyFormatError < Error; end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
require_relative 'auto_cert/terms_of_service_acceptor'
|
14
3
|
require_relative 'auto_cert/configuration'
|
15
|
-
require_relative 'auto_cert/manager'
|
16
|
-
require_relative 'auto_cert/managed_certificate'
|
17
|
-
require_relative 'auto_cert/identifier_policy'
|
18
|
-
require_relative 'auto_cert/registry'
|
19
|
-
require_relative 'auto_cert/renewal_busy_wait'
|
20
4
|
|
21
5
|
require_relative 'auto_cert/railtie' if defined?(Rails::Railtie)
|
data/lib/anchor/pem_bundle.rb
CHANGED
data/lib/anchor/version.rb
CHANGED
data/lib/anchor.rb
CHANGED
@@ -6,6 +6,13 @@ require 'openssl'
|
|
6
6
|
# Anchor module is the top-level namespace for the Anchor PKI client.
|
7
7
|
#
|
8
8
|
module Anchor
|
9
|
+
ENV_VARS = {
|
10
|
+
directory: %w[ACME_DIRECTORY ACME_DIRECTORY_URL],
|
11
|
+
eab_kid: %w[ACME_KID ACME_EAB_KID],
|
12
|
+
eab_hmac_key: %w[ACME_HMAC_KEY ACME_EAB_HMAC_KEY],
|
13
|
+
server_names: %w[ACME_SERVER_NAME ACME_SERVER_NAMES SERVER_NAME SERVER_NAMES ACME_ALLOW_IDENTIFIERS]
|
14
|
+
}.freeze
|
15
|
+
|
9
16
|
def self.add_cert(pem)
|
10
17
|
(@certs ||= []) << OpenSSL::X509::Certificate.new(pem)
|
11
18
|
end
|
@@ -23,4 +30,3 @@ require_relative 'anchor/version'
|
|
23
30
|
require_relative 'anchor/auto_cert'
|
24
31
|
require_relative 'anchor/oid'
|
25
32
|
require_relative 'anchor/pem_bundle'
|
26
|
-
require_relative 'anchor/disk_store'
|
data/lib/puma/dsl.rb
CHANGED
@@ -6,23 +6,28 @@
|
|
6
6
|
#
|
7
7
|
|
8
8
|
require 'puma/dsl'
|
9
|
+
require 'puma/acme/dsl'
|
9
10
|
|
10
11
|
module Puma
|
11
12
|
# Extend the ::Puma::DSL module with the configuration options we want
|
12
13
|
class DSL
|
13
|
-
def auto_cert_name(name = nil)
|
14
|
-
@options[:auto_cert_name] = name if name
|
15
|
-
@options[:auto_cert_name]
|
16
|
-
end
|
17
|
-
|
18
14
|
def auto_cert_port(port = nil)
|
19
15
|
@options[:auto_cert_port] = port if port
|
20
16
|
@options[:auto_cert_port]
|
21
17
|
end
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
alias auto_cert_algorithm acme_algorithm
|
20
|
+
alias auto_cert_cache acme_cache
|
21
|
+
alias auto_cert_cache_dir acme_cache_dir
|
22
|
+
alias auto_cert_contact acme_contact
|
23
|
+
alias auto_cert_directory acme_directory
|
24
|
+
alias auto_cert_eab_kid acme_eab_kid
|
25
|
+
alias auto_cert_eab_hmac_key acme_eab_hmac_key
|
26
|
+
alias auto_cert_mode acme_mode
|
27
|
+
alias auto_cert_renew_at acme_renew_at
|
28
|
+
alias auto_cert_renew_interval acme_renew_interval
|
29
|
+
alias auto_cert_server_name acme_server_name
|
30
|
+
alias auto_cert_server_names acme_server_names
|
31
|
+
alias auto_cert_tos_agreed acme_tos_agreed
|
27
32
|
end
|
28
33
|
end
|