1use crate::{Secret, SecretManager};
9use aws_config::SdkConfig;
10use aws_sdk_secretsmanager::{
11 error::SdkError,
12 operation::{
13 create_secret::CreateSecretError, delete_secret::DeleteSecretError,
14 get_secret_value::GetSecretValueError, update_secret::UpdateSecretError,
15 },
16};
17use std::fmt::Debug;
18use thiserror::Error;
19
20pub type SecretsManagerClient = aws_sdk_secretsmanager::Client;
21
22pub struct AwsSecretManager {
23 client: SecretsManagerClient,
24}
25
26impl AwsSecretManager {
27 pub fn from_sdk_config(aws_config: &SdkConfig) -> Self {
28 let client = SecretsManagerClient::new(aws_config);
29 Self::new(client)
30 }
31
32 pub fn new(client: SecretsManagerClient) -> Self {
33 Self { client }
34 }
35}
36
37#[derive(Debug, Error)]
38pub enum AwsSecretError {
39 #[error("failed to get secret value: {0}")]
40 GetSecretValue(SdkError<GetSecretValueError>),
41 #[error("failed to create secret: {0}")]
42 CreateSecret(SdkError<CreateSecretError>),
43 #[error("failed to delete secret: {0}")]
44 DeleteSecret(SdkError<DeleteSecretError>),
45 #[error("failed to update secret: {0}")]
46 UpdateSecret(SdkError<UpdateSecretError>),
47}
48
49impl SecretManager for AwsSecretManager {
50 async fn get_secret(&self, name: &str) -> anyhow::Result<Option<super::Secret>> {
51 let result = self
52 .client
53 .get_secret_value()
54 .secret_id(name)
55 .send()
56 .await
57 .map_err(AwsSecretError::GetSecretValue)?;
58
59 if let Some(value) = result.secret_string {
60 return Ok(Some(Secret::String(value)));
61 }
62
63 if let Some(value) = result.secret_binary {
64 return Ok(Some(Secret::Binary(value.into_inner())));
65 }
66
67 Ok(None)
68 }
69
70 async fn set_secret(&self, name: &str, value: &str) -> anyhow::Result<()> {
71 let err = match self
72 .client
73 .create_secret()
74 .secret_string(value)
75 .name(name)
76 .send()
77 .await
78 {
79 Ok(_) => return Ok(()),
80 Err(err) => err,
81 };
82
83 if err
85 .as_service_error()
86 .is_some_and(|value| value.is_resource_exists_exception())
87 {
88 self.client
89 .update_secret()
90 .secret_string(value)
91 .secret_id(name)
92 .send()
93 .await
94 .map_err(AwsSecretError::UpdateSecret)?;
95
96 return Ok(());
97 }
98
99 Err(AwsSecretError::CreateSecret(err).into())
100 }
101
102 async fn delete_secret(&self, name: &str) -> anyhow::Result<()> {
103 let err = match self.client.delete_secret().secret_id(name).send().await {
104 Ok(_) => return Ok(()),
105 Err(err) => err,
106 };
107
108 if err
110 .as_service_error()
111 .is_some_and(|value| value.is_resource_not_found_exception())
112 {
113 return Ok(());
114 }
115
116 Err(AwsSecretError::DeleteSecret(err).into())
117 }
118}