diff --git a/Cargo.lock b/Cargo.lock index b6a9b73..cc8e1fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,7 +104,6 @@ dependencies = [ "serde_urlencoded", "thiserror", "tokio", - "tokio-stream", "tokio-util", "url", "winapi", @@ -197,9 +196,11 @@ dependencies = [ "futures", "log", "reqwest", + "rustls 0.22.1", "serde", "serde_json", "tokio", + "webpki-roots 0.26.0", ] [[package]] @@ -240,33 +241,12 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -365,6 +345,17 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.28.1" @@ -479,16 +470,17 @@ dependencies = [ ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-rustls" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ - "bytes", + "futures-util", + "http", "hyper", - "native-tls", + "rustls 0.21.10", "tokio", - "tokio-native-tls", + "tokio-rustls", ] [[package]] @@ -591,12 +583,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.151" @@ -657,24 +643,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "num-traits" version = "0.2.17" @@ -709,50 +677,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "openssl" -version = "0.10.62" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" -dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -814,12 +738,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" - [[package]] name = "powerfmt" version = "0.2.0" @@ -897,21 +815,22 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-tls", + "hyper-rustls", "ipnet", "js-sys", "log", "mime", - "native-tls", "once_cell", "percent-encoding", "pin-project-lite", + "rustls 0.21.10", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "system-configuration", "tokio", - "tokio-native-tls", + "tokio-rustls", "tokio-util", "tower-service", "url", @@ -919,9 +838,24 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots 0.25.3", "winreg", ] +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -942,47 +876,87 @@ dependencies = [ ] [[package]] -name = "ryu" -version = "1.0.16" +name = "rustls" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] [[package]] -name = "schannel" -version = "0.1.23" +name = "rustls" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "fe6b63262c9fcac8659abfaa96cac103d28166d3ff3eaf8f412e19f3ae9e5a48" dependencies = [ - "windows-sys 0.52.0", + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.1", + "subtle", + "zeroize", ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "rustls-pemfile" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] [[package]] -name = "security-framework" -version = "2.9.2" +name = "rustls-pki-types" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", + "ring", + "untrusted", ] [[package]] -name = "security-framework-sys" -version = "2.9.1" +name = "rustls-webpki" +version = "0.102.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "ef4ca26037c909dedb327b48c3327d0ba91d3dd3c4e05dad328f210ffb68e95b" dependencies = [ - "core-foundation-sys", - "libc", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", ] [[package]] @@ -1089,6 +1063,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "2.0.48" @@ -1121,19 +1107,6 @@ dependencies = [ "libc", ] -[[package]] -name = "tempfile" -version = "3.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.52.0", -] - [[package]] name = "termcolor" version = "1.4.0" @@ -1238,23 +1211,12 @@ dependencies = [ ] [[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" +name = "tokio-rustls" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "futures-core", - "pin-project-lite", + "rustls 0.21.10", "tokio", ] @@ -1324,6 +1286,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.0" @@ -1335,12 +1303,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "want" version = "0.3.1" @@ -1445,6 +1407,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + +[[package]] +name = "webpki-roots" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de2cfda980f21be5a7ed2eadb3e6fe074d56022bea2cdeb1a62eb220fc04188" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1626,3 +1603,9 @@ dependencies = [ "cfg-if", "windows-sys 0.48.0", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 1c01f96..3e88d2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,12 +11,14 @@ keywords = ["doppler", "docker swarm", "secrets", "configuration"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bollard = { version = "0.15.0", features = ["tokio-stream"] } +bollard = { version = "0.15.0" } bytes = "1.5.0" env_logger = "0.10.1" futures = "0.3.30" log = "0.4.20" -reqwest = { version = "0.11.23", features = ["stream", "json"] } +reqwest = { version = "0.11.23", default-features = false, features = ["stream", "rustls-tls", "rustls-tls-webpki-roots"] } +rustls = "0.22.1" serde = { version = "1.0.194", features = ["derive"] } serde_json = "1.0.110" tokio = { version = "1.35.1", features = ["full"] } +webpki-roots = "0.26.0" diff --git a/src/config.rs b/src/config.rs index f523855..84ae0b3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -16,11 +16,11 @@ pub fn read_config() -> Result { let config_file = std::env::args().nth(1).ok_or("no config file specified")?; let data = std::fs::read_to_string(&config_file) - .map_err(|e| format!("failed to read config file {}: {}", &config_file, e))?; + .map_err(|e| format!("Failed to read config file {}: {}", &config_file, e))?; let config = serde_json::from_str(&data) .map_err(Error::from) - .map_err(|e| format!("failed to parse config file {}: {}", &config_file, e))?; + .map_err(|e| format!("Failed to parse config file {}: {}", &config_file, e))?; Ok(config) } diff --git a/src/docker.rs b/src/docker.rs index e29f63d..682d761 100644 --- a/src/docker.rs +++ b/src/docker.rs @@ -32,9 +32,15 @@ pub async fn update_service( .inspect_service(service_name, None::) .await?; - let current_version = current_service.version.unwrap().index.unwrap(); + let current_version = current_service + .version + .ok_or_else(|| format!("[{}] Cannot get docker service version", service_name))? + .index + .ok_or_else(|| format!("[{}] Cannot get docker service version index", service_name))?; - let mut current_spec = current_service.spec.unwrap(); + let mut current_spec = current_service + .spec + .ok_or_else(|| format!("[{}] Cannot get docker service spec", service_name))?; // Update the existing ServiceSpec with new environment variables current_spec.name = Some(service_name.to_string()); diff --git a/src/secrets.rs b/src/secrets.rs index abeeb86..d0a55b6 100644 --- a/src/secrets.rs +++ b/src/secrets.rs @@ -1,18 +1,25 @@ use crate::error::Error; -pub async fn fetch_secrets(http: &reqwest::Client, token: &str) -> Result, Error> { +pub async fn fetch_secrets( + http: &reqwest::Client, + doppler_token: &str, +) -> Result, Error> { let response = http .get("https://api.doppler.com/v3/configs/config/secrets/download?format=docker") - .bearer_auth(token) + .bearer_auth(doppler_token) .send() .await - .expect("request failed"); + .map_err(|e| format!("{e}"))?; if response.status() != 200 { - return Err(format!("failed to fetch secrets: {}", response.status()).into()); + return Err(format!("HTTP Status {}", response.status()).into()); } - let body = response.text().await.expect("failed to get response body"); + let body = response + .text() + .await + .map_err(|e| format!("Cannot read response body: {}", e))?; + let mut secrets: Vec = body.lines().map(|line| line.to_owned()).collect(); secrets.sort(); diff --git a/src/watch.rs b/src/watch.rs index e9bf365..bd202dd 100644 --- a/src/watch.rs +++ b/src/watch.rs @@ -24,8 +24,12 @@ pub fn parse_watch_event(raw_payload: &Bytes) -> Result { return Err("invalid event".into()); } - let event: EventPayload = serde_json::from_slice(&raw_payload[20..]) - .map_err(|e| format!("failed to parse event payload: {e}"))?; + let event: EventPayload = serde_json::from_slice(&raw_payload[20..]).map_err(|e| { + format!( + "Failed to parse event payload: {}. Payload: {:?}", + e, raw_payload + ) + })?; Ok(event.event_type) } diff --git a/src/worker.rs b/src/worker.rs index 94e5886..2152f3d 100644 --- a/src/worker.rs +++ b/src/worker.rs @@ -33,40 +33,64 @@ impl Worker { } pub async fn run(&self) { - log::info!("Fetching secrets for {}", &self.watcher.name); + log::info!("[{}] Fetching secrets...", &self.watcher.name); - self.sync_secrets().await; - self.watch_for_updates().await; + for _ in 1..5 { + match self.sync_secrets().await { + Ok(_) => { + break; + } + Err(e) => { + log::error!("[{}] Failed to sync secrets: {}", &self.watcher.name, e); + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + } + } + + loop { + if let Err(e) = self.watch_for_updates().await { + log::error!( + "[{}] Failed to watch for updates: {}", + &self.watcher.name, + e + ); + tokio::time::sleep(std::time::Duration::from_secs(5)).await; + } + } } - pub async fn sync_secrets(&self) { + pub async fn sync_secrets(&self) -> crate::result::Result<()> { let doppler_secrets = fetch_secrets(&self.http, &self.watcher.doppler_token) .await - .unwrap(); + .map_err(|e| format!("Failed to fetch secrets: {}", e))?; for service in &self.watcher.docker_services { - let docker_secrets = crate::docker::get_current_env_vars(service).await.unwrap(); + let docker_secrets = crate::docker::get_current_env_vars(service) + .await + .map_err(|e| format!("[{}] Failed to get current env vars: {}", service, e))?; if should_update_docker_service(&doppler_secrets, &docker_secrets) { crate::docker::update_service(service, doppler_secrets.clone()) .await - .unwrap(); + .map_err(|e| format!("[{}] Failed to update docker service: {}", service, e))?; - log::info!("Updated {}", service); + log::info!("[{}] [{}] Service updated", &self.watcher.name, service); } else { - log::info!("No changes detected for {}", service); + log::info!("[{}] [{}] No changes detected", &self.watcher.name, service); } } + + Ok(()) } - pub async fn watch_for_updates(&self) { + pub async fn watch_for_updates(&self) -> crate::result::Result<()> { let response = self .http .get("https://api.doppler.com/v3/configs/config/secrets/watch?include_dynamic_secrets=false&include_managed_secrets=false") .bearer_auth(&self.watcher.doppler_token) .send() .await - .expect("request failed"); + .map_err(|e| format!("[{}] Failed to watch for updates: {}", &self.watcher.name, e))?; let mut stream = response.bytes_stream(); while let Some(Ok(item)) = stream.next().await { @@ -75,8 +99,10 @@ impl Worker { }; if WatchEvent::SecretsUpdate == event { - self.sync_secrets().await; + self.sync_secrets().await?; } } + + Ok(()) } }