From 61e6df6209b3c55e4c07c6baf2fabfba23a474f1 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Mon, 6 Dec 2021 23:40:41 +0100 Subject: not much --- src/acme.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/consul.rs | 30 +++++++++++++++++++++++++++++- src/main.rs | 5 ++++- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 src/acme.rs (limited to 'src') diff --git a/src/acme.rs b/src/acme.rs new file mode 100644 index 0000000..c6dbc5b --- /dev/null +++ b/src/acme.rs @@ -0,0 +1,41 @@ +use std::collections::HashSet; + +use log::*; +use anyhow::Result; +use tokio::{sync::watch, time::sleep}; + +use acme_micro::{Error, Certificate, Directory, DirectoryUrl}; +use acme_micro::create_p384_key; + +use crate::consul::Consul; +use crate::proxy_config::ProxyConfig; + +pub async fn acme_task(mut consul: Consul, mut rx_proxy_config: watch::Receiver) { + while rx_proxy_config.changed().await.is_ok() { + let mut domains: HashSet = HashSet::new(); + + for ent in rx_proxy_config.borrow().entries.iter() { + domains.insert(ent.host.clone()); + } + info!("Ensuring we have certs for domains: {:#?}", domains); + + let results = futures::future::join_all( + domains.iter() + .map(|dom| renew_cert(dom, &consul)) + ).await; + + for (res, dom) in results.iter().zip(domains.iter()) { + if let Err(e) = res { + error!("{}: {}", dom, e); + } + } + } +} + +async fn renew_cert(dom: &str, consul: &Consul) -> Result<()> { + let dir = Directory::from_url(DirectoryUrl::LetsEncrypt)?; + let contact = vec!["mailto:alex@adnab.me".to_string()]; + let acc = dir.register_account(contact.clone())?; + // TODO + unimplemented!() +} diff --git a/src/consul.rs b/src/consul.rs index 81074f4..0f7d7c1 100644 --- a/src/consul.rs +++ b/src/consul.rs @@ -3,6 +3,8 @@ use std::collections::HashMap; use anyhow::Result; use log::*; use serde::{Deserialize, Serialize}; +use bytes::Bytes; +use reqwest::StatusCode; // ---- Watch and retrieve Consul catalog ---- @@ -28,14 +30,16 @@ pub struct ConsulNodeCatalog { pub struct Consul { client: reqwest::Client, url: String, + kv_prefix: String, idx: Option, } impl Consul { - pub fn new(url: &str) -> Self { + pub fn new(url: &str, kv_prefix: &str) -> Self { return Self { client: reqwest::Client::new(), url: url.to_string(), + kv_prefix: kv_prefix.to_string(), idx: None, }; } @@ -59,4 +63,28 @@ impl Consul { let resp: ConsulNodeCatalog = http.json().await?; return Ok(resp); } + + pub async fn kv_get(&self, key: &str) -> Result> { + let url = format!("{}/v1/kv/{}{}?raw", self.url, self.kv_prefix, key); + let http = self.client.get(&url).send().await?; + match http.status() { + StatusCode::OK => Ok(Some(http.bytes().await?)), + StatusCode::NOT_FOUND => Ok(None), + _ => Err(anyhow!("Consul request failed: {:?}", http.error_for_status())), + } + } + + pub async fn kv_put(&self, key: &str, bytes: Bytes) -> Result<()> { + let url = format!("{}/v1/kv/{}{}", self.url, self.kv_prefix, key); + let http = self.client.put(&url).body(bytes).send().await?; + http.error_for_status()?; + Ok(()) + } + + pub async fn kv_delete(&self, key: &str) -> Result<()> { + let url = format!("{}/v1/kv/{}{}", self.url, self.kv_prefix, key); + let http = self.client.delete(&url).send().await?; + http.error_for_status()?; + Ok(()) + } } diff --git a/src/main.rs b/src/main.rs index 3bd8928..3289c46 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ extern crate anyhow; mod consul; mod proxy_config; +mod acme; use log::*; @@ -11,9 +12,11 @@ async fn main() { pretty_env_logger::init(); info!("Starting Tricot"); - let consul = consul::Consul::new("http://10.42.0.21:8500"); + let consul = consul::Consul::new("http://10.42.0.21:8500", "tricot/"); let mut rx_proxy_config = proxy_config::spawn_proxy_config_task(consul.clone(), "carcajou"); + tokio::spawn(acme::acme_task(consul.clone(), rx_proxy_config.clone())); + while rx_proxy_config.changed().await.is_ok() { info!("Proxy config: {:#?}", *rx_proxy_config.borrow()); } -- cgit v1.2.3