docbox_core/secrets/
aws.rs

1use std::{collections::HashMap, fmt::Debug};
2
3use aws_sdk_secretsmanager::{
4    error::SdkError,
5    operation::{create_secret::CreateSecretError, get_secret_value::GetSecretValueError},
6};
7use serde::Deserialize;
8use thiserror::Error;
9
10use crate::aws::SecretsManagerClient;
11
12use super::{Secret, SecretManager};
13
14#[derive(Clone, Deserialize)]
15pub struct AwsSecretManagerConfig {
16    /// Collection of secrets to include
17    #[serde(default)]
18    pub secrets: HashMap<String, String>,
19    /// Optional default secret
20    #[serde(default)]
21    pub default: Option<String>,
22}
23
24impl AwsSecretManagerConfig {
25    pub fn from_env() -> anyhow::Result<Self> {
26        let default = std::env::var("DOCBOX_SECRET_MANAGER_DEFAULT").ok();
27
28        Ok(Self {
29            default,
30            secrets: Default::default(),
31        })
32    }
33}
34
35impl Debug for AwsSecretManagerConfig {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        f.debug_struct("AwsSecretManagerConfig").finish()
38    }
39}
40
41pub struct AwsSecretManager {
42    client: SecretsManagerClient,
43}
44
45impl AwsSecretManager {
46    pub fn new(client: SecretsManagerClient) -> Self {
47        Self { client }
48    }
49}
50
51#[derive(Debug, Error)]
52pub enum AwsSecretError {
53    #[error(transparent)]
54    GetSecretValue(SdkError<GetSecretValueError>),
55    #[error(transparent)]
56    CreateSecret(SdkError<CreateSecretError>),
57}
58
59impl SecretManager for AwsSecretManager {
60    async fn get_secret(&self, name: &str) -> anyhow::Result<Option<super::Secret>> {
61        let result = self
62            .client
63            .get_secret_value()
64            .secret_id(name)
65            .send()
66            .await
67            .map_err(AwsSecretError::GetSecretValue)?;
68
69        if let Some(value) = result.secret_string {
70            return Ok(Some(Secret::String(value)));
71        }
72
73        if let Some(value) = result.secret_binary {
74            return Ok(Some(Secret::Binary(value.into_inner())));
75        }
76
77        Ok(None)
78    }
79
80    async fn create_secret(&self, name: &str, value: &str) -> anyhow::Result<()> {
81        self.client
82            .create_secret()
83            .secret_string(value)
84            .name(name)
85            .send()
86            .await
87            .map_err(AwsSecretError::CreateSecret)?;
88
89        Ok(())
90    }
91}