Skip to content

Commit 0086f77

Browse files
authored
Merge pull request #15 from n0-computer/letsencrypt
Letsencrypt
2 parents 8ff4769 + 9ece833 commit 0086f77

File tree

6 files changed

+408
-190
lines changed

6 files changed

+408
-190
lines changed

iroh-gateway/Cargo.lock

Lines changed: 24 additions & 64 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

iroh-gateway/Cargo.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ edition = "2021"
55

66
[dependencies]
77
axum = "0.7.2"
8-
axum-server = { version = "0.6.0", features = ["tls-rustls", "tokio-rustls"] }
98
tokio = { version = "1", features = ["full"] }
109
headers = { version = "0.4" }
1110
hyper = "1"
@@ -26,4 +25,8 @@ futures = "0.3.29"
2625
lru = "0.12.1"
2726
tracing-subscriber = "0.3.18"
2827
indicatif = "0.17.7"
29-
rustls = "0.22.1"
28+
rustls = "0.21"
29+
tokio-rustls-acme = { version = "0.2.0", features = ["axum"] }
30+
hyper-util = "0.1.2"
31+
rustls-pemfile = "1.0.2"
32+
tower-service = "0.3.2"

iroh-gateway/src/args.rs

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ use std::path::PathBuf;
33

44
use clap::Parser;
55

6+
#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq)]
7+
pub enum CertMode {
8+
/// No certificates at all, we serve http.
9+
None,
10+
/// Use a self-signed certificate in the cert_path directory.
11+
Manual,
12+
/// Use a letsencrypt certificate, in staging mode.
13+
LetsEncryptStaging,
14+
/// Use a letsencrypt certificate, in production mode.
15+
LetsEncrypt,
16+
}
17+
618
#[derive(Parser, Debug)]
719
pub struct Args {
820
/// Ticket for the default node.
@@ -15,19 +27,32 @@ pub struct Args {
1527
pub default_node: Option<String>,
1628

1729
/// Http or https listen addr.
18-
///
30+
///
1931
/// Will listen on http if cert_path is not specified, https otherwise.
2032
#[clap(long, default_value = "0.0.0.0:8080")]
2133
pub addr: String,
2234

23-
/// Https certificate path.
24-
///
25-
/// If this is specified, the server will listen on https.
26-
/// The path should be a directory containing `cert.pem` and `key.pem`.
27-
#[clap(long)]
28-
pub cert_path: Option<PathBuf>,
29-
3035
/// Magic port for the node, random if not specified.
3136
#[clap(long)]
3237
pub magic_port: Option<u16>,
38+
39+
/// Certificate mode, default is none.
40+
#[clap(long, default_value = "None")]
41+
pub cert_mode: CertMode,
42+
43+
/// Hostnames for letsencrypt.
44+
#[clap(long, required_if_eq_any([("cert_mode", "LetsEncryptStaging"), ("cert_mode", "LetsEncrypt")]))]
45+
pub hostname: Vec<String>,
46+
47+
/// Contact email for letsencrypt.
48+
#[clap(long, required_if_eq_any([("cert_mode", "LetsEncryptStaging"), ("cert_mode", "LetsEncrypt")]))]
49+
pub contact: Option<String>,
50+
51+
/// Certificate path.
52+
///
53+
/// Not needed if cert_mode is None.
54+
/// In manual mode, this is the directory containing the cert.pem and key.pem files.
55+
/// In letsencrypt mode, this is the directory used by the acme acceptor.
56+
#[clap(long, required_if_eq_any([("cert_mode", "LetsEncryptStaging"), ("cert_mode", "LetsEncrypt"), ("cert_mode", "Manual")]))]
57+
pub cert_path: Option<PathBuf>,
3358
}

iroh-gateway/src/cert_util.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! Utilities for loading certificates and keys.
2+
use anyhow::{Context, Result};
3+
use std::path::Path;
4+
5+
pub fn load_certs(filename: impl AsRef<Path>) -> Result<Vec<rustls::Certificate>> {
6+
println!("loading certs from {}", filename.as_ref().display());
7+
let certfile = std::fs::File::open(filename).context("cannot open certificate file")?;
8+
let mut reader = std::io::BufReader::new(certfile);
9+
10+
let certs = rustls_pemfile::certs(&mut reader)?
11+
.iter()
12+
.map(|v| rustls::Certificate(v.clone()))
13+
.collect();
14+
15+
Ok(certs)
16+
}
17+
18+
pub fn load_secret_key(filename: impl AsRef<Path>) -> Result<rustls::PrivateKey> {
19+
println!("loading secret key from {}", filename.as_ref().display());
20+
let keyfile = std::fs::File::open(filename.as_ref()).context("cannot open secret key file")?;
21+
let mut reader = std::io::BufReader::new(keyfile);
22+
23+
loop {
24+
match rustls_pemfile::read_one(&mut reader).context("cannot parse secret key .pem file")? {
25+
Some(rustls_pemfile::Item::RSAKey(key)) => return Ok(rustls::PrivateKey(key)),
26+
Some(rustls_pemfile::Item::PKCS8Key(key)) => return Ok(rustls::PrivateKey(key)),
27+
Some(rustls_pemfile::Item::ECKey(key)) => return Ok(rustls::PrivateKey(key)),
28+
None => break,
29+
_ => {}
30+
}
31+
}
32+
33+
anyhow::bail!(
34+
"no keys found in {} (encrypted keys not supported)",
35+
filename.as_ref().display()
36+
);
37+
}

0 commit comments

Comments
 (0)