diff options
author | Alex Auvolat <alex@adnab.me> | 2023-06-14 16:56:15 +0200 |
---|---|---|
committer | Alex Auvolat <alex@adnab.me> | 2023-06-14 16:56:15 +0200 |
commit | 7895f99d3afc6e97f62f52abe06a6ee8d0f0617f (patch) | |
tree | 54918eaff3880d013d59b77db2091c56c5f45fb7 /src/api | |
parent | 4a82f6380e6a7d7c841477fc914fd96e6c09adad (diff) | |
download | garage-7895f99d3afc6e97f62f52abe06a6ee8d0f0617f.tar.gz garage-7895f99d3afc6e97f62f52abe06a6ee8d0f0617f.zip |
admin and cli: hide secret keys unless asked
Diffstat (limited to 'src/api')
-rw-r--r-- | src/api/admin/api_server.rs | 9 | ||||
-rw-r--r-- | src/api/admin/key.rs | 34 | ||||
-rw-r--r-- | src/api/admin/router.rs | 14 | ||||
-rw-r--r-- | src/api/helpers.rs | 4 |
4 files changed, 43 insertions, 18 deletions
diff --git a/src/api/admin/api_server.rs b/src/api/admin/api_server.rs index b0dfdfb7..6819e28e 100644 --- a/src/api/admin/api_server.rs +++ b/src/api/admin/api_server.rs @@ -242,8 +242,13 @@ impl ApiHandler for AdminApiServer { Endpoint::RevertClusterLayout => handle_revert_cluster_layout(&self.garage, req).await, // Keys Endpoint::ListKeys => handle_list_keys(&self.garage).await, - Endpoint::GetKeyInfo { id, search } => { - handle_get_key_info(&self.garage, id, search).await + Endpoint::GetKeyInfo { + id, + search, + show_secret_key, + } => { + let show_secret_key = show_secret_key.map(|x| x == "true").unwrap_or(false); + handle_get_key_info(&self.garage, id, search, show_secret_key).await } Endpoint::CreateKey => handle_create_key(&self.garage, req).await, Endpoint::ImportKey => handle_import_key(&self.garage, req).await, diff --git a/src/api/admin/key.rs b/src/api/admin/key.rs index 664fde4c..0d1f799b 100644 --- a/src/api/admin/key.rs +++ b/src/api/admin/key.rs @@ -10,7 +10,7 @@ use garage_model::garage::Garage; use garage_model::key_table::*; use crate::admin::error::*; -use crate::helpers::{json_ok_response, parse_json_body}; +use crate::helpers::{is_default, json_ok_response, parse_json_body}; pub async fn handle_list_keys(garage: &Arc<Garage>) -> Result<Response<Body>, Error> { let res = garage @@ -44,6 +44,7 @@ pub async fn handle_get_key_info( garage: &Arc<Garage>, id: Option<String>, search: Option<String>, + show_secret_key: bool, ) -> Result<Response<Body>, Error> { let key = if let Some(id) = id { garage.key_helper().get_existing_key(&id).await? @@ -56,7 +57,7 @@ pub async fn handle_get_key_info( unreachable!(); }; - key_info_results(garage, key).await + key_info_results(garage, key, show_secret_key).await } pub async fn handle_create_key( @@ -68,7 +69,7 @@ pub async fn handle_create_key( let key = Key::new(req.name.as_deref().unwrap_or("Unnamed key")); garage.key_table.insert(&key).await?; - key_info_results(garage, key).await + key_info_results(garage, key, true).await } #[derive(Deserialize)] @@ -88,10 +89,14 @@ pub async fn handle_import_key( return Err(Error::KeyAlreadyExists(req.access_key_id.to_string())); } - let imported_key = Key::import(&req.access_key_id, &req.secret_access_key, &req.name); + let imported_key = Key::import( + &req.access_key_id, + &req.secret_access_key, + req.name.as_deref().unwrap_or("Imported key"), + ); garage.key_table.insert(&imported_key).await?; - key_info_results(garage, imported_key).await + key_info_results(garage, imported_key, false).await } #[derive(Deserialize)] @@ -99,7 +104,7 @@ pub async fn handle_import_key( struct ImportKeyRequest { access_key_id: String, secret_access_key: String, - name: String, + name: Option<String>, } pub async fn handle_update_key( @@ -129,7 +134,7 @@ pub async fn handle_update_key( garage.key_table.insert(&key).await?; - key_info_results(garage, key).await + key_info_results(garage, key, false).await } #[derive(Deserialize)] @@ -152,7 +157,11 @@ pub async fn handle_delete_key(garage: &Arc<Garage>, id: String) -> Result<Respo .body(Body::empty())?) } -async fn key_info_results(garage: &Arc<Garage>, key: Key) -> Result<Response<Body>, Error> { +async fn key_info_results( + garage: &Arc<Garage>, + key: Key, + show_secret: bool, +) -> Result<Response<Body>, Error> { let mut relevant_buckets = HashMap::new(); let key_state = key.state.as_option().unwrap(); @@ -181,7 +190,11 @@ async fn key_info_results(garage: &Arc<Garage>, key: Key) -> Result<Response<Bod let res = GetKeyInfoResult { name: key_state.name.get().clone(), access_key_id: key.key_id.clone(), - secret_access_key: key_state.secret_key.clone(), + secret_access_key: if show_secret { + Some(key_state.secret_key.clone()) + } else { + None + }, permissions: KeyPerm { create_bucket: *key_state.allow_create_bucket.get(), }, @@ -227,7 +240,8 @@ async fn key_info_results(garage: &Arc<Garage>, key: Key) -> Result<Response<Bod struct GetKeyInfoResult { name: String, access_key_id: String, - secret_access_key: String, + #[serde(skip_serializing_if = "is_default")] + secret_access_key: Option<String>, permissions: KeyPerm, buckets: Vec<KeyInfoBucketResult>, } diff --git a/src/api/admin/router.rs b/src/api/admin/router.rs index 077509e3..97ad6f76 100644 --- a/src/api/admin/router.rs +++ b/src/api/admin/router.rs @@ -35,6 +35,7 @@ pub enum Endpoint { GetKeyInfo { id: Option<String>, search: Option<String>, + show_secret_key: Option<String>, }, DeleteKey { id: String, @@ -104,11 +105,11 @@ impl Endpoint { POST ("/v0/layout/apply" | "/v1/layout/apply") => ApplyClusterLayout, POST ("/v0/layout/revert" | "/v1/layout/revert") => RevertClusterLayout, // API key endpoints - GET ("/v0/key" | "/v1/key") if id => GetKeyInfo (query_opt::id, query_opt::search), - GET ("/v0/key" | "/v1/key") if search => GetKeyInfo (query_opt::id, query_opt::search), - POST ("/v0/key" | "/v1/key") if id => UpdateKey (query::id), - POST ("/v0/key" | "/v1/key") => CreateKey, - POST ("/v0/key/import" | "/v1/key/import") => ImportKey, + GET "/v1/key" if id => GetKeyInfo (query_opt::id, query_opt::search, query_opt::show_secret_key), + GET "/v1/key" if search => GetKeyInfo (query_opt::id, query_opt::search, query_opt::show_secret_key), + POST "/v1/key" if id => UpdateKey (query::id), + POST "/v1/key" => CreateKey, + POST "/v1/key/import" => ImportKey, DELETE ("/v0/key" | "/v1/key") if id => DeleteKey (query::id), GET ("/v0/key" | "/v1/key") => ListKeys, // Bucket endpoints @@ -153,6 +154,7 @@ generateQueryParameters! { "search" => search, "globalAlias" => global_alias, "alias" => alias, - "accessKeyId" => access_key_id + "accessKeyId" => access_key_id, + "showSecretKey" => show_secret_key ] } diff --git a/src/api/helpers.rs b/src/api/helpers.rs index 642dbc42..1d55ebd5 100644 --- a/src/api/helpers.rs +++ b/src/api/helpers.rs @@ -152,6 +152,10 @@ pub fn json_ok_response<T: Serialize>(res: &T) -> Result<Response<Body>, Error> .body(Body::from(resp_json))?) } +pub fn is_default<T: Default + PartialEq>(v: &T) -> bool { + *v == T::default() +} + #[cfg(test)] mod tests { use super::*; |