From becd76c82d07545f7794f56a43ad96f2f61f42ed Mon Sep 17 00:00:00 2001 From: Frank Yang Date: Sat, 1 Oct 2022 12:50:43 +0800 Subject: [PATCH] feat(config): add vault provider Signed-off-by: Frank Yang --- Cargo.lock | 136 +++++++++++++++++++++++++++- crates/config/Cargo.toml | 2 + crates/config/src/provider.rs | 1 + crates/config/src/provider/vault.rs | 50 ++++++++++ 4 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 crates/config/src/provider/vault.rs diff --git a/Cargo.lock b/Cargo.lock index ec44c4eb1b..51b4ca948b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,6 +797,72 @@ dependencies = [ "zeroize", ] +[[package]] +name = "darling" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "derive_builder" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f91d4cfa921f1c05904dc3c57b4a32c38aed3340cce209f3a6fd1478babafc4" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68" +dependencies = [ + "derive_builder_core", + "syn", +] + [[package]] name = "dialoguer" version = "0.9.0" @@ -1527,6 +1593,12 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -2776,6 +2848,40 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "rustify" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c02e25271068de581e03ac3bb44db60165ff1a10d92b9530192ccb898bc706" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "http", + "reqwest", + "rustify_derive", + "serde", + "serde_json", + "serde_urlencoded", + "thiserror", + "tracing", + "url", +] + +[[package]] +name = "rustify_derive" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58135536c18c04f4634bedad182a3f41baf33ef811cc38a3ec7b7061c57134c8" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "serde_urlencoded", + "syn", + "synstructure", +] + [[package]] name = "rustix" version = "0.35.9" @@ -2932,9 +3038,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" +checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" dependencies = [ "serde_derive", ] @@ -2951,9 +3057,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.144" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" +checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" dependencies = [ "proc-macro2", "quote", @@ -3274,11 +3380,13 @@ dependencies = [ "async-trait", "dotenvy", "once_cell", + "serde", "spin-app", "spin-core", "thiserror", "tokio", "toml", + "vaultrs", "wit-bindgen-wasmtime", ] @@ -4131,6 +4239,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vaultrs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267f958930e08323a44c12e6c5461f3eaaa16d88785e9ec8550215b8aafc3d0b" +dependencies = [ + "async-trait", + "bytes", + "derive_builder", + "http", + "reqwest", + "rustify", + "rustify_derive", + "serde", + "serde_json", + "thiserror", + "tracing", + "url", +] + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/crates/config/Cargo.toml b/crates/config/Cargo.toml index 960dbe38a3..0509328296 100644 --- a/crates/config/Cargo.toml +++ b/crates/config/Cargo.toml @@ -13,6 +13,8 @@ spin-app = { path = "../app" } spin-core = { path = "../core" } thiserror = "1" tokio = { version = "1", features = ["rt-multi-thread"] } +vaultrs = "0.6.2" +serde = "1.0.145" [dependencies.wit-bindgen-wasmtime] git = "https://github.com/bytecodealliance/wit-bindgen" diff --git a/crates/config/src/provider.rs b/crates/config/src/provider.rs index 9f3799937a..e6dbeaadc5 100644 --- a/crates/config/src/provider.rs +++ b/crates/config/src/provider.rs @@ -6,6 +6,7 @@ use crate::Key; /// Environment variable based provider. pub mod env; +pub mod vault; /// A config provider. #[async_trait] diff --git a/crates/config/src/provider/vault.rs b/crates/config/src/provider/vault.rs new file mode 100644 index 0000000000..c38b3336f4 --- /dev/null +++ b/crates/config/src/provider/vault.rs @@ -0,0 +1,50 @@ +use anyhow::{anyhow, Result}; +use async_trait::async_trait; +use serde::{Deserialize, Serialize}; +use vaultrs::{ + client::{VaultClient, VaultClientSettingsBuilder}, + kv2, +}; + +use crate::{Key, Provider}; + +/// A config Provider that uses HashiCorp Vault. +#[derive(Debug)] +pub struct VaultProvider { + url: String, + token: String, +} + +impl VaultProvider { + pub fn new(url: impl AsRef, token: impl AsRef) -> Result { + Ok(Self { + url: url.as_ref().to_string(), + token: token.as_ref().to_string(), + }) + } +} + +#[derive(Debug, Deserialize, Serialize)] +struct Secret { + value: String, +} + +#[async_trait] +impl Provider for VaultProvider { + async fn get(&self, key: &Key) -> Result> { + let client = VaultClient::new( + VaultClientSettingsBuilder::default() + .address(&self.url) + .token(&self.token) + .build()?, + )?; + let keys = key.0.split("/").collect::>(); + if keys.len() == 1 { + return Err(anyhow!("vault key must contain the mount path")); + } + let mount = keys[0]; + let path = keys[1..].join("/"); + let secret: Secret = kv2::read(&client, mount, &path).await?; + Ok(Some(secret.value)) + } +}