aboutsummaryrefslogtreecommitdiff
path: root/src/garage/cli_v2/key.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/garage/cli_v2/key.rs')
-rw-r--r--src/garage/cli_v2/key.rs227
1 files changed, 227 insertions, 0 deletions
diff --git a/src/garage/cli_v2/key.rs b/src/garage/cli_v2/key.rs
new file mode 100644
index 00000000..ff403a9a
--- /dev/null
+++ b/src/garage/cli_v2/key.rs
@@ -0,0 +1,227 @@
+use format_table::format_table;
+
+use garage_util::error::*;
+
+use garage_api::admin::api::*;
+
+use crate::cli::structs::*;
+use crate::cli_v2::*;
+
+impl Cli {
+ pub async fn cmd_key(&self, cmd: KeyOperation) -> Result<(), Error> {
+ match cmd {
+ KeyOperation::List => self.cmd_list_keys().await,
+ KeyOperation::Info(query) => self.cmd_key_info(query).await,
+ KeyOperation::Create(query) => self.cmd_create_key(query).await,
+ KeyOperation::Rename(query) => self.cmd_rename_key(query).await,
+ KeyOperation::Delete(query) => self.cmd_delete_key(query).await,
+ KeyOperation::Allow(query) => self.cmd_allow_key(query).await,
+ KeyOperation::Deny(query) => self.cmd_deny_key(query).await,
+ KeyOperation::Import(query) => self.cmd_import_key(query).await,
+ }
+ }
+
+ pub async fn cmd_list_keys(&self) -> Result<(), Error> {
+ let keys = self.api_request(ListKeysRequest).await?;
+
+ println!("List of keys:");
+ let mut table = vec![];
+ for key in keys.0.iter() {
+ table.push(format!("\t{}\t{}", key.id, key.name));
+ }
+ format_table(table);
+
+ Ok(())
+ }
+
+ pub async fn cmd_key_info(&self, opt: KeyInfoOpt) -> Result<(), Error> {
+ let key = self
+ .api_request(GetKeyInfoRequest {
+ id: None,
+ search: Some(opt.key_pattern),
+ show_secret_key: opt.show_secret,
+ })
+ .await?;
+
+ print_key_info(&key);
+
+ Ok(())
+ }
+
+ pub async fn cmd_create_key(&self, opt: KeyNewOpt) -> Result<(), Error> {
+ let key = self
+ .api_request(CreateKeyRequest {
+ name: Some(opt.name),
+ })
+ .await?;
+
+ print_key_info(&key.0);
+
+ Ok(())
+ }
+
+ pub async fn cmd_rename_key(&self, opt: KeyRenameOpt) -> Result<(), Error> {
+ let key = self
+ .api_request(GetKeyInfoRequest {
+ id: None,
+ search: Some(opt.key_pattern),
+ show_secret_key: false,
+ })
+ .await?;
+
+ let new_key = self
+ .api_request(UpdateKeyRequest {
+ id: key.access_key_id,
+ body: UpdateKeyRequestBody {
+ name: Some(opt.new_name),
+ allow: None,
+ deny: None,
+ },
+ })
+ .await?;
+
+ print_key_info(&new_key.0);
+
+ Ok(())
+ }
+
+ pub async fn cmd_delete_key(&self, opt: KeyDeleteOpt) -> Result<(), Error> {
+ let key = self
+ .api_request(GetKeyInfoRequest {
+ id: None,
+ search: Some(opt.key_pattern),
+ show_secret_key: false,
+ })
+ .await?;
+
+ if !opt.yes {
+ println!("About to delete key {}...", key.access_key_id);
+ return Err(Error::Message(
+ "Add --yes flag to really perform this operation".to_string(),
+ ));
+ }
+
+ self.api_request(DeleteKeyRequest {
+ id: key.access_key_id.clone(),
+ })
+ .await?;
+
+ println!("Access key {} has been deleted.", key.access_key_id);
+
+ Ok(())
+ }
+
+ pub async fn cmd_allow_key(&self, opt: KeyPermOpt) -> Result<(), Error> {
+ let key = self
+ .api_request(GetKeyInfoRequest {
+ id: None,
+ search: Some(opt.key_pattern),
+ show_secret_key: false,
+ })
+ .await?;
+
+ let new_key = self
+ .api_request(UpdateKeyRequest {
+ id: key.access_key_id,
+ body: UpdateKeyRequestBody {
+ name: None,
+ allow: Some(KeyPerm {
+ create_bucket: opt.create_bucket,
+ }),
+ deny: None,
+ },
+ })
+ .await?;
+
+ print_key_info(&new_key.0);
+
+ Ok(())
+ }
+
+ pub async fn cmd_deny_key(&self, opt: KeyPermOpt) -> Result<(), Error> {
+ let key = self
+ .api_request(GetKeyInfoRequest {
+ id: None,
+ search: Some(opt.key_pattern),
+ show_secret_key: false,
+ })
+ .await?;
+
+ let new_key = self
+ .api_request(UpdateKeyRequest {
+ id: key.access_key_id,
+ body: UpdateKeyRequestBody {
+ name: None,
+ allow: None,
+ deny: Some(KeyPerm {
+ create_bucket: opt.create_bucket,
+ }),
+ },
+ })
+ .await?;
+
+ print_key_info(&new_key.0);
+
+ Ok(())
+ }
+
+ pub async fn cmd_import_key(&self, opt: KeyImportOpt) -> Result<(), Error> {
+ if !opt.yes {
+ return Err(Error::Message("This command is intended to re-import keys that were previously generated by Garage. If you want to create a new key, use `garage key new` instead. Add the --yes flag if you really want to re-import a key.".to_string()));
+ }
+
+ let new_key = self
+ .api_request(ImportKeyRequest {
+ name: Some(opt.name),
+ access_key_id: opt.key_id,
+ secret_access_key: opt.secret_key,
+ })
+ .await?;
+
+ print_key_info(&new_key.0);
+
+ Ok(())
+ }
+}
+
+fn print_key_info(key: &GetKeyInfoResponse) {
+ println!("Key name: {}", key.name);
+ println!("Key ID: {}", key.access_key_id);
+ println!(
+ "Secret key: {}",
+ key.secret_access_key.as_deref().unwrap_or("(redacted)")
+ );
+ println!("Can create buckets: {}", key.permissions.create_bucket);
+
+ println!("\nKey-specific bucket aliases:");
+ let mut table = vec![];
+ for bucket in key.buckets.iter() {
+ for la in bucket.local_aliases.iter() {
+ table.push(format!(
+ "\t{}\t{}\t{}",
+ la,
+ bucket.global_aliases.join(","),
+ bucket.id
+ ));
+ }
+ }
+ format_table(table);
+
+ println!("\nAuthorized buckets:");
+ let mut table = vec![];
+ for bucket in key.buckets.iter() {
+ let rflag = if bucket.permissions.read { "R" } else { " " };
+ let wflag = if bucket.permissions.write { "W" } else { " " };
+ let oflag = if bucket.permissions.owner { "O" } else { " " };
+ table.push(format!(
+ "\t{}{}{}\t{}\t{}\t{:.16}",
+ rflag,
+ wflag,
+ oflag,
+ bucket.global_aliases.join(","),
+ bucket.local_aliases.join(","),
+ bucket.id
+ ));
+ }
+ format_table(table);
+}