Skip to content

Commit 9da1121

Browse files
committed
ACME: allow "acme_certificate server_name ...".
The parameter allows fetching the list of identifiers from the server_name directive in the same server block.
1 parent 05dafc9 commit 9da1121

File tree

3 files changed

+67
-5
lines changed

3 files changed

+67
-5
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ Add the moduel to the nginx configuration and configure as described below.
4949

5050
## Example Configuration
5151

52-
5352
```nginx
5453
resolver 127.0.0.1;
5554
@@ -64,7 +63,7 @@ acme_shared_zone 1M;
6463
server {
6564
server_name .example.test;
6665
67-
acme_certificate .example.test
66+
acme_certificate server_name
6867
issuer=example;
6968
7069
ssl_certificate $acme_certificate;
@@ -209,14 +208,22 @@ challenge data for all the configured certificate issuers.
209208

210209
### acme_certificate
211210

212-
**Syntax:** acme_certificate `identifier` ... `issuer` = `issuer_name` [ `key` = `alg[:size]` | `file` ]
211+
**Syntax:** acme_certificate `server_name` | `identifier` ... `issuer` = `issuer_name` [ `key` = `alg[:size]` | `file` ]
213212

214213
**Default:** -
215214

216215
**Context:** server
217216

218217
Defines a certificate with the list of `identifier`s requested from
219218
issuer `issuer_name`.
219+
220+
The `server_name` parameter allows taking the list of identifiers from the
221+
[server_name] directive in the same `server` block instead of specifying names
222+
explicitly. Not all the values accepted by [server_name] are valid certificate
223+
identifiers: regular expressions and wildcards are not supported.
224+
225+
[server_name]: https://nginx.org/en/docs/http/ngx_http_core_module.html#server_name
226+
220227
The `key` parameter sets the type of generated private key or a
221228
path to an existing file. Supported key algorithms and sizes:
222229
`ecdsa:256` (default), `ecdsa:384`,

src/conf.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ pub struct AcmeServerConfig {
3939
// A single sertificate per server is supported for now.
4040
// With multiple certs we will have to implement certificate selection.
4141
pub order: Option<CertificateOrder<ngx_str_t, Pool>>,
42+
/// Read identifiers set by "server_name" in the server block.
43+
pub server_name: bool,
4244
}
4345

4446
pub static mut NGX_HTTP_ACME_COMMANDS: [ngx_command_t; 4] = [
@@ -277,12 +279,17 @@ extern "C" fn cmd_add_certificate(
277279
continue;
278280
}
279281

282+
if value.as_bytes() == b"server_name" {
283+
ascf.server_name = true;
284+
continue;
285+
}
286+
280287
if let Err(err) = order.try_add_identifier(value) {
281288
return cf.error(args[0], &err);
282289
}
283290
}
284291

285-
if order.identifiers.is_empty() {
292+
if order.identifiers.is_empty() && !ascf.server_name {
286293
return c"no identifiers".as_ptr().cast_mut();
287294
}
288295

@@ -443,6 +450,25 @@ impl AcmeMainConfig {
443450
continue;
444451
};
445452

453+
// At this point, the server names list should be fully initialized.
454+
if ascf.server_name {
455+
let server_names = unsafe { cscfp.server_names.as_slice() };
456+
457+
if let Err(err) = order.add_server_names(cf, server_names) {
458+
ngx_log_error!(NGX_LOG_EMERG, cf.log, "\"acme_certificate\": {err}");
459+
return Err(Status::NGX_ERROR);
460+
}
461+
462+
if order.identifiers.is_empty() {
463+
ngx_log_error!(
464+
NGX_LOG_EMERG,
465+
cf.log,
466+
"\"acme_certificate\": no identifiers found in \"server_name\""
467+
);
468+
return Err(Status::NGX_ERROR);
469+
}
470+
}
471+
446472
if let Some(issuer) = self.issuer_mut(&ascf.issuer) {
447473
issuer.add_certificate_order(cf, order)?;
448474
} else {

src/conf/order.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ use core::hash::{self, Hash, Hasher};
33
use core::net::IpAddr;
44
use core::str::Utf8Error;
55

6-
use nginx_sys::ngx_str_t;
6+
use nginx_sys::{ngx_conf_t, ngx_http_server_name_t, ngx_str_t};
77
use ngx::allocator::{AllocError, Allocator, TryCloneIn};
88
use ngx::collections::Vec;
99
use ngx::core::{NgxString, Pool, Status};
10+
use ngx::ngx_log_error;
1011
use siphasher::sip::SipHasher;
1112
use thiserror::Error;
1213

@@ -147,6 +148,34 @@ impl CertificateOrder<ngx_str_t, Pool> {
147148
Ok(())
148149
}
149150

151+
pub fn add_server_names(
152+
&mut self,
153+
cf: &mut ngx_conf_t,
154+
server_names: &[ngx_http_server_name_t],
155+
) -> Result<(), IdentifierError> {
156+
for server_name in server_names {
157+
if !server_name.regex.is_null() {
158+
ngx_log_error!(
159+
nginx_sys::NGX_LOG_WARN,
160+
cf.log,
161+
"\"acme_certificate\": unsupported regular expression in server_name: {}",
162+
server_name.name
163+
);
164+
continue;
165+
}
166+
167+
// A valid server_name entry that we want to ignore.
168+
// We'll fail properly later if that's the only entry.
169+
if server_name.name.is_empty() {
170+
continue;
171+
}
172+
173+
self.try_add_identifier(&server_name.name)?;
174+
}
175+
176+
Ok(())
177+
}
178+
150179
pub fn try_add_identifier(&mut self, value: &ngx_str_t) -> Result<(), IdentifierError> {
151180
if value.is_empty() {
152181
return Err(IdentifierError::Empty);

0 commit comments

Comments
 (0)