Sealing: Encryption of Secrets #1
12 changed files with 44 additions and 206 deletions
|
|
@ -1,13 +1,13 @@
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
|
||||||
use crate::storage::DatabaseDriver;
|
use crate::storage::DbPool;
|
||||||
|
|
||||||
// route prefix: `/auth/token/`
|
// route prefix: `/auth/token/`
|
||||||
// mod token;
|
// mod token;
|
||||||
|
|
||||||
// use self::token::token_auth_router;
|
// use self::token::token_auth_router;
|
||||||
|
|
||||||
pub fn auth_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn auth_router(pool: DbPool) -> Router<DbPool> {
|
||||||
Router::new().with_state(pool)
|
Router::new().with_state(pool)
|
||||||
// .nest("/token", token_auth_router())
|
// .nest("/token", token_auth_router())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,14 @@ impl HttpError {
|
||||||
HttpError::new(status_code, vec![error.to_string(); 1])
|
HttpError::new(status_code, vec![error.to_string(); 1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Custom serialization function for `secret_data`
|
||||||
|
pub fn serialize_reject_none<S>(value: &Option<String>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
match value {
|
||||||
|
Some(data) => serializer.serialize_str(data),
|
||||||
|
None => Err(serde::ser::Error::custom("`secret_data` must not be None during serialization!")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ use axum::{
|
||||||
use log::*;
|
use log::*;
|
||||||
use tower::Service;
|
use tower::Service;
|
||||||
|
|
||||||
use crate::{common::HttpError, storage::DatabaseDriver};
|
use crate::{common::HttpError, storage::DbPool};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
/// State to be used to store the database pool
|
/// State to be used to store the database pool
|
||||||
/// and the routers for each engine
|
/// and the routers for each engine
|
||||||
struct EngineMapperState {
|
struct EngineMapperState {
|
||||||
pool: DatabaseDriver,
|
pool: DbPool,
|
||||||
kv_v2: Router,
|
kv_v2: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,7 +24,7 @@ struct EngineMapperState {
|
||||||
struct EnginePath(String);
|
struct EnginePath(String);
|
||||||
|
|
||||||
/// Secret engine router
|
/// Secret engine router
|
||||||
pub fn secrets_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn secrets_router(pool: DbPool) -> Router<DbPool> {
|
||||||
// State containing the pool and engine routers
|
// State containing the pool and engine routers
|
||||||
let state = EngineMapperState {
|
let state = EngineMapperState {
|
||||||
pool: pool.clone(),
|
pool: pool.clone(),
|
||||||
|
|
@ -81,7 +81,7 @@ fn unknown_engine(engine_type: String) -> impl IntoResponse {
|
||||||
|
|
||||||
/// Returns the mount path and engine type for the request,
|
/// Returns the mount path and engine type for the request,
|
||||||
/// if the mount path is registed at the database
|
/// if the mount path is registed at the database
|
||||||
async fn map_mount_points(req: &Uri, pool: &DatabaseDriver) -> Option<(String, String)> {
|
async fn map_mount_points(req: &Uri, pool: &DbPool) -> Option<(String, String)> {
|
||||||
let mut mount_path_fragments: Vec<&str> = req.path().split('/').collect();
|
let mut mount_path_fragments: Vec<&str> = req.path().split('/').collect();
|
||||||
|
|
||||||
// Find longest matching existing mount path for the request
|
// Find longest matching existing mount path for the request
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,13 @@ mod meta;
|
||||||
// #[cfg(test)]
|
// #[cfg(test)]
|
||||||
// mod tests;
|
// mod tests;
|
||||||
|
|
||||||
use crate::storage::DatabaseDriver;
|
use crate::storage::DbPool;
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
extract::{Path, State},
|
|
||||||
routing::*,
|
routing::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn kv_router(pool: DatabaseDriver) -> Router {
|
pub fn kv_router(pool: DbPool) -> Router {
|
||||||
Router::new()
|
Router::new()
|
||||||
.route("/config", get(get_config))
|
.route("/config", get(get_config))
|
||||||
.route("/config", post(post_config))
|
.route("/config", post(post_config))
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
use super::structs::KvV2WriteRequest;
|
use super::structs::KvV2WriteRequest;
|
||||||
use crate::{
|
use crate::{
|
||||||
DatabaseDriver,
|
common::HttpError, engines::{
|
||||||
common::HttpError,
|
kv::structs::{KvSecretData, KvSecretRes, KvV2WriteResponse, Wrapper}, EnginePath
|
||||||
engines::{
|
}, DbPool
|
||||||
EnginePath,
|
|
||||||
kv::structs::{KvSecretData, KvSecretRes, KvV2WriteResponse, Wrapper},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use axum::{
|
use axum::{
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
|
|
@ -26,7 +23,7 @@ pub struct GetDataQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_data(
|
pub async fn get_data(
|
||||||
State(pool): State<DatabaseDriver>,
|
State(pool): State<DbPool>,
|
||||||
Query(params): Query<GetDataQuery>,
|
Query(params): Query<GetDataQuery>,
|
||||||
Path(path): Path<String>,
|
Path(path): Path<String>,
|
||||||
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
||||||
|
|
@ -66,7 +63,7 @@ pub async fn get_data(
|
||||||
}
|
}
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
sqlx::Error::RowNotFound => {
|
sqlx::Error::RowNotFound => {
|
||||||
error!("Row not found {:?}", e);
|
warn!("Secret not found (could be correct behavior) {:?}", e);
|
||||||
Ok(HttpError::simple(
|
Ok(HttpError::simple(
|
||||||
StatusCode::NOT_FOUND,
|
StatusCode::NOT_FOUND,
|
||||||
"Secret not found within kv2 engine",
|
"Secret not found within kv2 engine",
|
||||||
|
|
@ -78,16 +75,15 @@ pub async fn get_data(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn post_data(
|
pub async fn post_data(
|
||||||
State(pool): State<DatabaseDriver>,
|
State(pool): State<DbPool>,
|
||||||
Path(kv_path): Path<String>,
|
Path(kv_path): Path<String>,
|
||||||
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
||||||
Json(secret): Json<KvV2WriteRequest>,
|
Json(secret): Json<KvV2WriteRequest>,
|
||||||
) -> Result<Response, ()> {
|
) -> Result<Response, ()> {
|
||||||
log::debug!(
|
debug!(
|
||||||
"Engine: {}, Secret: {}, Content: {}, Version: {:?}, path: {}",
|
"Engine: {}, Secret: {}, Version: {:?}, path: {}",
|
||||||
engine_path,
|
engine_path,
|
||||||
kv_path,
|
kv_path,
|
||||||
secret.data,
|
|
||||||
secret.version, //.unwrap_or(0),
|
secret.version, //.unwrap_or(0),
|
||||||
kv_path
|
kv_path
|
||||||
);
|
);
|
||||||
|
|
@ -117,8 +113,6 @@ pub async fn post_data(
|
||||||
|
|
||||||
tx.commit().await.expect("FAILED TO WRITE TX!");
|
tx.commit().await.expect("FAILED TO WRITE TX!");
|
||||||
|
|
||||||
warn!("test: {res_m:?} {res_r:?} {}", res_r.version_number);
|
|
||||||
|
|
||||||
let res = KvV2WriteResponse {
|
let res = KvV2WriteResponse {
|
||||||
created_time: created_time.into(),
|
created_time: created_time.into(),
|
||||||
custom_metadata: None,
|
custom_metadata: None,
|
||||||
|
|
@ -134,11 +128,11 @@ pub async fn post_data(
|
||||||
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-latest-version-of-secret
|
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-latest-version-of-secret
|
||||||
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-secret-versions
|
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-secret-versions
|
||||||
pub async fn delete_data(
|
pub async fn delete_data(
|
||||||
State(pool): State<DatabaseDriver>,
|
State(pool): State<DbPool>,
|
||||||
Path(path): Path<String>,
|
Path(path): Path<String>,
|
||||||
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
||||||
) -> Result<Response, Response> {
|
) -> Result<Response, Response> {
|
||||||
log::debug!("Secret: {}, path: {}", path, path);
|
debug!("Secret: {}, path: {}", path, path);
|
||||||
|
|
||||||
let del_time = UtcDateTime::now().unix_timestamp();
|
let del_time = UtcDateTime::now().unix_timestamp();
|
||||||
|
|
||||||
|
|
@ -186,7 +180,7 @@ pub async fn delete_data(
|
||||||
error!(
|
error!(
|
||||||
"Strange - a version to be deleted has been found but could not be found to set deletion.\n\t{e:?}"
|
"Strange - a version to be deleted has been found but could not be found to set deletion.\n\t{e:?}"
|
||||||
);
|
);
|
||||||
// Not commited transactions will be aborted upon drop
|
// Not committed transactions will be aborted upon drop
|
||||||
// tx.rollback().await.unwrap();
|
// tx.rollback().await.unwrap();
|
||||||
return Err(HttpError::simple(
|
return Err(HttpError::simple(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
|
@ -204,7 +198,7 @@ pub async fn delete_data(
|
||||||
|
|
||||||
// Not
|
// Not
|
||||||
pub async fn patch_data(
|
pub async fn patch_data(
|
||||||
State(pool): State<DatabaseDriver>,
|
State(pool): State<DbPool>,
|
||||||
Path(kv_path): Path<String>,
|
Path(kv_path): Path<String>,
|
||||||
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
Extension(EnginePath(engine_path)): Extension<EnginePath>,
|
||||||
Json(secret): Json<KvV2WriteRequest>,
|
Json(secret): Json<KvV2WriteRequest>,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::storage::DatabaseDriver;
|
use crate::storage::DbPool;
|
||||||
use axum::extract::{Path, State};
|
use axum::extract::{Path, State};
|
||||||
|
|
||||||
pub async fn delete_path() -> &'static str {
|
pub async fn delete_path() -> &'static str {
|
||||||
|
|
@ -14,7 +14,7 @@ pub async fn get_meta() -> &'static str {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn post_meta(
|
pub async fn post_meta(
|
||||||
State(pool): State<DatabaseDriver>,
|
State(pool): State<DbPool>,
|
||||||
Path((mount_path, kv_path)): Path<(String, String)>,
|
Path((mount_path, kv_path)): Path<(String, String)>,
|
||||||
body: String,
|
body: String,
|
||||||
) -> &'static str {
|
) -> &'static str {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ use time::{OffsetDateTime, UtcDateTime, serde::rfc3339};
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
/// For SQLite support
|
|
||||||
pub struct KvSecretData {
|
pub struct KvSecretData {
|
||||||
pub secret_data: String,
|
pub secret_data: String,
|
||||||
#[serde(with = "rfc3339")]
|
#[serde(with = "rfc3339")]
|
||||||
|
|
@ -43,7 +42,6 @@ pub struct Wrapper<T> {
|
||||||
pub data: T,
|
pub data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct KvSecretRes {
|
pub struct KvSecretRes {
|
||||||
/// Map (required)
|
/// Map (required)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
|
||||||
use crate::storage::DatabaseDriver;
|
use crate::storage::DbPool;
|
||||||
|
|
||||||
pub fn identity_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn identity_router(pool: DbPool) -> Router<DbPool> {
|
||||||
Router::new().with_state(pool)
|
Router::new().with_state(pool)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use axum::{
|
||||||
};
|
};
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::{env, net::SocketAddr, str::FromStr};
|
use std::{env, net::SocketAddr, str::FromStr};
|
||||||
use storage::DatabaseDriver;
|
use storage::DbPool;
|
||||||
use tokio::{net::TcpListener, signal};
|
use tokio::{net::TcpListener, signal};
|
||||||
|
|
||||||
use crate::common::HttpError;
|
use crate::common::HttpError;
|
||||||
|
|
@ -70,7 +70,7 @@ async fn set_default_content_type_json(
|
||||||
Ok(next.run(req).await)
|
Ok(next.run(req).await)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn shutdown_signal(pool: DatabaseDriver) {
|
async fn shutdown_signal(pool: DbPool) {
|
||||||
let ctrl_c = async {
|
let ctrl_c = async {
|
||||||
signal::ctrl_c()
|
signal::ctrl_c()
|
||||||
.await
|
.await
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
|
pub mod sealing;
|
||||||
|
|
||||||
use std::{fs::File, path::Path};
|
use std::{fs::File, path::Path};
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use sqlx::{sqlite::SqlitePoolOptions, Pool, Sqlite};
|
use sqlx::{sqlite::SqlitePoolOptions, Pool, Sqlite};
|
||||||
|
|
||||||
pub(crate) type DatabaseDriver = Pool<Sqlite>;
|
pub(crate) type DbType = Sqlite;
|
||||||
|
pub(crate) type DbPool = Pool<DbType>;
|
||||||
|
|
||||||
pub async fn create_pool(db_url: String) -> DatabaseDriver {
|
pub async fn create_pool(db_url: String) -> DbPool {
|
||||||
// Create SQLite database file if it does not exist
|
// Create SQLite database file if it does not exist
|
||||||
if db_url.starts_with("sqlite:") && db_url != ("sqlite::memory:") {
|
if db_url.starts_with("sqlite:") && db_url != ("sqlite::memory:") {
|
||||||
let path = db_url.replace("sqlite:", "");
|
let path = db_url.replace("sqlite:", "");
|
||||||
|
|
|
||||||
|
|
@ -1,167 +0,0 @@
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use base::create_mock_meta;
|
|
||||||
#[test]
|
|
||||||
fn test_update_secret() {
|
|
||||||
let db: sled::Db = sled::open("sled_db").unwrap();
|
|
||||||
update_secret(&db, "foo", TempSecret{version: -99, content: "cool".to_string()});
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_get_secret() {
|
|
||||||
let db: sled::Db = sled::open("sled_db").unwrap();
|
|
||||||
get_secret(&db, "foo");
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_delete_secret(){
|
|
||||||
let db: sled::Db = sled::open("sled_db").unwrap();
|
|
||||||
delete_secret(&db, "foo");
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn test_meta(){
|
|
||||||
let db: sled::Db = sled::open("sled_db").unwrap();
|
|
||||||
println!("writing metadata:");
|
|
||||||
update_secret_meta(&db, "metatest", create_mock_meta());
|
|
||||||
println!("getting metadata:");
|
|
||||||
get_secretmeta(&db, "metatest");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
use sled::Db;
|
|
||||||
use base::{deserialize_metadata_struct, deserialize_secret_struct, serialize_metadata_json, serialize_secret_json, SecretMeta, TempSecret};
|
|
||||||
|
|
||||||
/// [TODO] Currently no proper versioning
|
|
||||||
/// inserts a secret. If there was already a secret in the given path, the version is incremented
|
|
||||||
fn update_secret(db: &Db, path: &str, mut secret: TempSecret) {
|
|
||||||
match get_secret(db, path) {
|
|
||||||
Some(old_secret) => {
|
|
||||||
// case secret found. TODO save it somewhere for versioning
|
|
||||||
secret.version = old_secret.version + 1;
|
|
||||||
#[cfg(test)]
|
|
||||||
print!("something was found. new version {} \n", secret.version)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// case new secret
|
|
||||||
secret.version = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if let secret_json = serialize_secret_json(&secret) {
|
|
||||||
// let _res = db.insert(path, secret_json); // maybe this can be handled cleaner
|
|
||||||
match serialize_secret_json(&secret) {
|
|
||||||
Ok(secret_json) => {
|
|
||||||
#[cfg(test)]
|
|
||||||
println!("String: {:?}", secret_json.clone());
|
|
||||||
let as_ivec = sled::IVec::from(secret_json.into_bytes()); // maybe outsource this in a fn later
|
|
||||||
#[cfg(test)]
|
|
||||||
println!("ivec: {:?}", as_ivec);
|
|
||||||
match db.insert(path, as_ivec) {
|
|
||||||
Ok(_) => println!("Secret inserted"),
|
|
||||||
Err(e) => eprintln!("Failed to insert secret: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => eprintln!("Failed to serialize secret: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// !TODO eliminate redundancy: refactor get and update functions to accept generic types!
|
|
||||||
|
|
||||||
// read and return a secret from the DB
|
|
||||||
//if there is no secret, return None
|
|
||||||
fn get_secret(db: &Db, path: &str) -> Option<TempSecret>{
|
|
||||||
let raw_secret;
|
|
||||||
match db.get(path) {
|
|
||||||
Ok(Some(ivec)) => {
|
|
||||||
raw_secret = ivec;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Error on retrieving secret: {}", e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Ok(None) => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// outsource this in a fn later. TODO maybe deal with unwrap
|
|
||||||
let as_str = String::from_utf8(raw_secret.to_vec()).unwrap();
|
|
||||||
match deserialize_secret_struct(&as_str) {
|
|
||||||
Ok(secret) => {
|
|
||||||
#[cfg(test)]
|
|
||||||
println!("got some secret: {:?}", secret);
|
|
||||||
return Some(secret);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("error on secret deserialization: {}", e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO write abstract get_something fn
|
|
||||||
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#read-secret-metadata
|
|
||||||
fn get_secretmeta(db: &Db, path: &str) -> Option<SecretMeta>{
|
|
||||||
let raw_metadata;
|
|
||||||
match db.get(path) {
|
|
||||||
Ok(Some(ivec)) => {
|
|
||||||
raw_metadata = ivec;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Error on retrieving metadata: {}", e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Ok(None) => {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let as_str = String::from_utf8(raw_metadata.to_vec()).unwrap();
|
|
||||||
match deserialize_metadata_struct(&as_str) {
|
|
||||||
Ok(meta) => {
|
|
||||||
#[cfg(test)]
|
|
||||||
println!("got some metadata: {:?}", meta);
|
|
||||||
return Some(meta);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("error on secret deserialization: {}", e);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// currently early version (copied from update_secret)
|
|
||||||
fn update_secret_meta(db: &Db, path: &str, mut meta: SecretMeta) {
|
|
||||||
match get_secretmeta(db, path) {
|
|
||||||
Some(meta) => {
|
|
||||||
// case secret found. TODO save it somewhere for versioning
|
|
||||||
#[cfg(test)]
|
|
||||||
print!("something was found. new version {:?} \n", meta)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
match serialize_metadata_json(&meta) {
|
|
||||||
Ok(meta_json) => {
|
|
||||||
#[cfg(test)]
|
|
||||||
println!("String: {:?}", meta_json.clone());
|
|
||||||
let as_ivec = sled::IVec::from(meta_json.into_bytes()); // maybe outsource this in a fn later
|
|
||||||
#[cfg(test)]
|
|
||||||
println!("ivec: {:?}", as_ivec);
|
|
||||||
match db.insert(path, as_ivec) {
|
|
||||||
Ok(_) => println!("Metadata inserted"),
|
|
||||||
Err(e) => eprintln!("Failed to insert meta: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => eprintln!("Failed to serialize meta: {}", e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// TODO soft delete the secret version at path. can be undone with undelete_secret
|
|
||||||
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-latest-version-of-secret
|
|
||||||
// https://developer.hashicorp.com/vault/api-docs/secret/kv/kv-v2#delete-secret-versions
|
|
||||||
|
|
||||||
/// hard delete secret at path
|
|
||||||
fn delete_secret(db: &Db, path: &str) {
|
|
||||||
let rem = db.remove(path);
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use axum::Router;
|
use axum::Router;
|
||||||
|
|
||||||
use crate::storage::DatabaseDriver;
|
use crate::storage::DbPool;
|
||||||
|
|
||||||
/// System routes
|
/// System routes
|
||||||
pub fn sys_router(pool: DatabaseDriver) -> Router<DatabaseDriver> {
|
pub fn sys_router(pool: DbPool) -> Router<DbPool> {
|
||||||
Router::new().with_state(pool)
|
Router::new().with_state(pool)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue