Browse Source

Allow to specify a unique name for each certificate

pull/41/head
Rodolphe Breard 4 years ago
parent
commit
426fb63c50
  1. 1
      CHANGELOG.md
  2. 4
      acmed/src/certificate.rs
  3. 61
      acmed/src/config.rs
  4. 9
      acmed/src/main_event_loop.rs
  5. 9
      man/en/acmed.toml.5

1
CHANGELOG.md

@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Add proxy support through the `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables. - Add proxy support through the `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY` environment variables.
- Allow to specify a unique name for each certificate.
### Changed ### Changed
- The minimal required Rust version is 1.42.0. - The minimal required Rust version is 1.42.0.

4
acmed/src/certificate.rs

@ -22,15 +22,13 @@ pub struct Certificate {
pub hooks: Vec<Hook>, pub hooks: Vec<Hook>,
pub crt_name: String, pub crt_name: String,
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub id: usize,
pub renew_delay: Duration, pub renew_delay: Duration,
pub file_manager: FileManager, pub file_manager: FileManager,
} }
impl fmt::Display for Certificate { impl fmt::Display for Certificate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: set a more "funky" id
write!(f, "crt-{:x}", self.id)
write!(f, "{}", self.crt_name)
} }
} }

61
acmed/src/config.rs

@ -176,15 +176,15 @@ impl Config {
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct GlobalOptions { pub struct GlobalOptions {
pub accounts_directory: Option<String>, pub accounts_directory: Option<String>,
pub certificates_directory: Option<String>,
pub cert_file_group: Option<String>,
pub cert_file_mode: Option<u32>, pub cert_file_mode: Option<u32>,
pub cert_file_user: Option<String>, pub cert_file_user: Option<String>,
pub cert_file_group: Option<String>,
pub pk_file_mode: Option<u32>,
pub pk_file_user: Option<String>,
pub pk_file_group: Option<String>,
pub certificates_directory: Option<String>,
#[serde(default)] #[serde(default)]
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub pk_file_group: Option<String>,
pub pk_file_mode: Option<u32>,
pub pk_file_user: Option<String>,
pub renew_delay: Option<String>, pub renew_delay: Option<String>,
pub root_certificates: Option<Vec<String>>, pub root_certificates: Option<Vec<String>>,
} }
@ -202,12 +202,12 @@ impl GlobalOptions {
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Endpoint { pub struct Endpoint {
pub name: String, pub name: String,
pub url: String,
pub tos_agreed: bool,
#[serde(default)] #[serde(default)]
pub rate_limits: Vec<String>, pub rate_limits: Vec<String>,
pub renew_delay: Option<String>, pub renew_delay: Option<String>,
pub root_certificates: Option<Vec<String>>, pub root_certificates: Option<Vec<String>>,
pub tos_agreed: bool,
pub url: String,
} }
impl Endpoint { impl Endpoint {
@ -262,16 +262,16 @@ pub struct RateLimit {
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Hook { pub struct Hook {
pub name: String,
#[serde(rename = "type")]
pub hook_type: Vec<HookType>,
pub cmd: String,
pub allow_failure: Option<bool>,
pub args: Option<Vec<String>>, pub args: Option<Vec<String>>,
pub cmd: String,
pub name: String,
pub stderr: Option<String>,
pub stdin: Option<String>, pub stdin: Option<String>,
pub stdin_str: Option<String>, pub stdin_str: Option<String>,
pub stdout: Option<String>, pub stdout: Option<String>,
pub stderr: Option<String>,
pub allow_failure: Option<bool>,
#[serde(rename = "type")]
pub hook_type: Vec<HookType>,
} }
#[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize)] #[derive(Clone, Debug, Eq, Hash, PartialEq, Deserialize)]
@ -299,8 +299,8 @@ pub enum HookType {
#[derive(Deserialize)] #[derive(Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Group { pub struct Group {
pub name: String,
pub hooks: Vec<String>, pub hooks: Vec<String>,
pub name: String,
} }
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
@ -340,14 +340,14 @@ impl ExternalAccount {
#[derive(Clone, Debug, Deserialize)] #[derive(Clone, Debug, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Account { pub struct Account {
pub name: String,
pub contacts: Vec<AccountContact>, pub contacts: Vec<AccountContact>,
pub key_type: Option<String>,
pub signature_algorithm: Option<String>,
pub hooks: Option<Vec<String>>,
pub external_account: Option<ExternalAccount>,
#[serde(default)] #[serde(default)]
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub external_account: Option<ExternalAccount>,
pub hooks: Option<Vec<String>>,
pub key_type: Option<String>,
pub name: String,
pub signature_algorithm: Option<String>,
} }
impl Account { impl Account {
@ -407,21 +407,20 @@ impl AccountContact {
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Certificate { pub struct Certificate {
pub account: String, pub account: String,
pub csr_digest: Option<String>,
pub directory: Option<String>,
pub endpoint: String, pub endpoint: String,
pub identifiers: Vec<Identifier>,
#[serde(default)] #[serde(default)]
pub subject_attributes: SubjectAttributes,
pub env: HashMap<String, String>,
pub file_name_format: Option<String>,
pub hooks: Vec<String>,
pub identifiers: Vec<Identifier>,
pub key_type: Option<String>, pub key_type: Option<String>,
pub csr_digest: Option<String>,
pub kp_reuse: Option<bool>, pub kp_reuse: Option<bool>,
pub directory: Option<String>,
pub name: Option<String>, pub name: Option<String>,
pub name_format: Option<String>,
pub formats: Option<Vec<String>>,
pub hooks: Vec<String>,
#[serde(default)]
pub env: HashMap<String, String>,
pub renew_delay: Option<String>, pub renew_delay: Option<String>,
#[serde(default)]
pub subject_attributes: SubjectAttributes,
} }
impl Certificate { impl Certificate {
@ -465,12 +464,12 @@ impl Certificate {
id.to_string() id.to_string()
} }
}; };
let name = name.replace("*", "_").replace(":", "_");
let name = name.replace("*", "_").replace(":", "_").replace("/", "_");
Ok(name) Ok(name)
} }
pub fn get_crt_name_format(&self) -> String { pub fn get_crt_name_format(&self) -> String {
match &self.name_format {
match &self.file_name_format {
Some(n) => n.to_string(), Some(n) => n.to_string(),
None => crate::DEFAULT_CERT_FORMAT.to_string(), None => crate::DEFAULT_CERT_FORMAT.to_string(),
} }
@ -534,9 +533,9 @@ impl Certificate {
pub struct Identifier { pub struct Identifier {
pub challenge: String, pub challenge: String,
pub dns: Option<String>, pub dns: Option<String>,
pub ip: Option<String>,
#[serde(default)] #[serde(default)]
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub ip: Option<String>,
} }
impl<'de> Deserialize<'de> for Identifier { impl<'de> Deserialize<'de> for Identifier {

9
acmed/src/main_event_loop.rs

@ -89,12 +89,16 @@ impl MainEventLoop {
accounts.insert(acc.name.clone(), account); accounts.insert(acc.name.clone(), account);
} }
let mut certs = Vec::new();
let mut certs: Vec<Certificate> = Vec::new();
let mut endpoints = HashMap::new(); let mut endpoints = HashMap::new();
for (i, crt) in cnf.certificate.iter().enumerate() {
for crt in cnf.certificate.iter() {
let endpoint = crt.get_endpoint(&cnf, root_certs)?; let endpoint = crt.get_endpoint(&cnf, root_certs)?;
let endpoint_name = endpoint.name.clone(); let endpoint_name = endpoint.name.clone();
let crt_name = crt.get_crt_name()?; let crt_name = crt.get_crt_name()?;
if certs.iter().any(|c| c.crt_name == crt_name) {
let msg = format!("{}: duplicate certificate name", crt_name);
return Err(msg.into());
}
let key_type = crt.get_key_type()?; let key_type = crt.get_key_type()?;
let hooks = crt.get_hooks(&cnf)?; let hooks = crt.get_hooks(&cnf)?;
let fm = FileManager { let fm = FileManager {
@ -132,7 +136,6 @@ impl MainEventLoop {
.collect(), .collect(),
crt_name, crt_name,
env: crt.env.to_owned(), env: crt.env.to_owned(),
id: i + 1,
renew_delay: crt.get_renew_delay(&cnf)?, renew_delay: crt.get_renew_delay(&cnf)?,
file_manager: fm, file_manager: fm,
}; };

9
man/en/acmed.toml.5

@ -153,6 +153,15 @@ rsa4096
.El .El
.It Ic kp_reuse Ar boolean .It Ic kp_reuse Ar boolean
Set whether or not the private key should be reused when renewing the certificate. Default is false. Set whether or not the private key should be reused when renewing the certificate. Default is false.
.It Ic name
Name of the certificate. Must be unique. Will be used in logs and in the associated file's name. The
.Sq * ,
.So
:
.Sc
and
.Sq /
characters will be replaced by an underscore. Default is the first identifier.
.It Cm renew_delay Ar string .It Cm renew_delay Ar string
Period of time between the certificate renewal and its expiration date. The format is described in the Period of time between the certificate renewal and its expiration date. The format is described in the
.Sx TIME PERIODS .Sx TIME PERIODS

Loading…
Cancel
Save