From 412af95149349b35db1022b881ad45c4af981b28 Mon Sep 17 00:00:00 2001 From: Adrian Heine Date: Wed, 19 Jul 2017 13:21:15 +0200 Subject: [PATCH] Use chained cert for nginx --- src/symbols/acme/chain.rs | 70 +++++++++++++++++++++++++++++ src/symbols/acme/mod.rs | 2 + src/symbols/nginx/server.rs | 2 +- src/symbols/owner.rs | 4 ++ src/symbols/tls/self_signed_cert.rs | 2 +- 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/symbols/acme/chain.rs diff --git a/src/symbols/acme/chain.rs b/src/symbols/acme/chain.rs new file mode 100644 index 0000000..145ce4d --- /dev/null +++ b/src/symbols/acme/chain.rs @@ -0,0 +1,70 @@ +use std::borrow::Cow; +use std::error::Error; +use std::fmt; +use std::fs::File as FsFile; +use std::io::Write; +use std::path::Path; + +use command_runner::CommandRunner; +use symbols::Symbol; +use resources::Resource; + +pub struct AcmeCertChain<'a> { + domain: Cow<'a, str>, + command_runner: &'a CommandRunner +} + +impl<'a> AcmeCertChain<'a> { + pub fn new(domain: Cow<'a, str>, command_runner: &'a CommandRunner) -> AcmeCertChain<'a> { + AcmeCertChain { + domain: domain, + command_runner: command_runner + } + } + + fn get_single_cert_path(&self) -> String { + format!("/etc/ssl/local_certs/{}.crt", self.domain) + } + + fn get_cert_chain_path(&self) -> String { + format!("/etc/ssl/local_certs/{}.chained.crt", self.domain) + } +} + +impl<'a> fmt::Display for AcmeCertChain<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "AcmeCertChain {}", self.domain) + } +} + +const DAYS_IN_SECONDS: u32 = 24*60*60; + +impl<'a> Symbol for AcmeCertChain<'a> { + fn target_reached(&self) -> Result> { + if !Path::new(&self.get_cert_chain_path()).exists() { + return Ok(false); + } + + let stdout = try!(self.command_runner.get_output("openssl", &["x509", "-in", &self.get_cert_chain_path(), "-noout", "-subject", "-checkend", &(30*DAYS_IN_SECONDS).to_string()])); + if stdout != format!("subject=CN = {}\nCertificate will not expire\n", self.domain).as_bytes() { + return Ok(false); + } + // FIXME: From my understanding, the -untrusted *.pem parameter shouldn't be necessary, but is necessary with openssl 1.1.0f-3 + Ok(self.command_runner.run_successfully("openssl", &["verify", "-untrusted", "/home/acme/lets_encrypt_x3_cross_signed.pem", &self.get_cert_chain_path()]).is_ok()) + } + + fn execute(&self) -> Result<(), Box> { + let output = try!(self.command_runner.get_output("cat", &[&self.get_single_cert_path(), "/home/acme/lets_encrypt_x3_cross_signed.pem"])); + let mut file = try!(FsFile::create(self.get_cert_chain_path())); + try!(file.write_all(&output)); + Ok(()) + } + + fn get_prerequisites(&self) -> Vec { + vec![ Resource::new("file", self.get_single_cert_path()) ] + } +} + +#[cfg(test)] +mod test { +} diff --git a/src/symbols/acme/mod.rs b/src/symbols/acme/mod.rs index 280a536..6c743ce 100644 --- a/src/symbols/acme/mod.rs +++ b/src/symbols/acme/mod.rs @@ -1,5 +1,7 @@ mod account_key; mod cert; +mod chain; pub use self::account_key::AcmeAccountKey; pub use self::cert::AcmeCert; +pub use self::chain::AcmeCertChain; diff --git a/src/symbols/nginx/server.rs b/src/symbols/nginx/server.rs index 19a7f33..c0da524 100644 --- a/src/symbols/nginx/server.rs +++ b/src/symbols/nginx/server.rs @@ -66,7 +66,7 @@ server {{ server_name {0}; include \"snippets/acme-challenge.conf\"; - ssl_certificate /etc/ssl/local_certs/{0}.crt; + ssl_certificate /etc/ssl/local_certs/{0}.chained.crt; ssl_certificate_key /etc/ssl/private/{0}.key; add_header Strict-Transport-Security \"max-age=31536000\"; diff --git a/src/symbols/owner.rs b/src/symbols/owner.rs index 5a8d75a..0904b94 100644 --- a/src/symbols/owner.rs +++ b/src/symbols/owner.rs @@ -3,6 +3,7 @@ use std::error::Error; use std::fmt; use std::fs; use std::os::unix::fs::MetadataExt; +use std::path::Path; use users::get_user_by_name; @@ -24,6 +25,9 @@ impl<'a, D> Owner<'a, D> where D: AsRef + fmt::Display { impl<'a, D> Symbol for Owner<'a, D> where D: AsRef + fmt::Display { fn target_reached(&self) -> Result> { + if !Path::new(self.path.as_ref()).exists() { + return Ok(false); + } let actual_uid = fs::metadata(self.path.as_ref()).unwrap().uid(); let target_uid = get_user_by_name(self.user_name.borrow()).unwrap().uid(); Ok(actual_uid == target_uid) diff --git a/src/symbols/tls/self_signed_cert.rs b/src/symbols/tls/self_signed_cert.rs index e91797a..aa3fa27 100644 --- a/src/symbols/tls/self_signed_cert.rs +++ b/src/symbols/tls/self_signed_cert.rs @@ -25,7 +25,7 @@ impl<'a> SelfSignedTlsCert<'a> { } fn get_cert_path(&self) -> String { - format!("/etc/ssl/local_certs/{}.crt", self.domain) + format!("/etc/ssl/local_certs/{}.chained.crt", self.domain) } }