Skip to main content

rusty_cdk_core/secretsmanager/
builder.rs

1use crate::secretsmanager::{GenerateSecretString, Secret, SecretProperties, SecretRef, SecretType};
2use crate::shared::Id;
3use crate::stack::{Resource, StackBuilder};
4use crate::type_state;
5use crate::wrappers::StringForSecret;
6use serde_json::Value;
7use std::marker::PhantomData;
8
9type_state!(SecretBuilderState, StartState, SelectedSecretTypeState,);
10
11/// Builder for AWS Secrets Manager secrets.
12///
13/// See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-secretsmanager-secret.html
14/// Supports both static secret strings and automatically generated secrets.
15///
16/// # Example
17///
18/// ```rust
19/// use rusty_cdk_core::stack::StackBuilder;
20/// use rusty_cdk_core::secretsmanager::{SecretBuilder, GenerateSecretStringBuilder};
21/// use rusty_cdk_core::wrappers::*;
22/// use rusty_cdk_macros::string_for_secret;
23///
24/// let mut stack_builder = StackBuilder::new();
25///
26/// // Create a secret with a static value
27/// let secret = SecretBuilder::new("my-secret")
28///     .name(string_for_secret!("my-secret-name"))
29///     .description("My database password")
30///     .secret_string("my-password")
31///     .build(&mut stack_builder);
32///
33/// // Create a secret with auto-generated value
34/// let generated_secret_config = GenerateSecretStringBuilder::new()
35///     .password_length(32)
36///     .exclude_punctuation(true)
37///     .build();
38///
39/// let generated_secret = SecretBuilder::new("generated-secret")
40///     .generate_secret_string(generated_secret_config)
41///     .build(&mut stack_builder);
42/// ```
43pub struct SecretBuilder<T: SecretBuilderState> {
44    phantom_data: PhantomData<T>,
45    id: Id,
46    name: Option<String>,
47    description: Option<String>,
48    generate_secret_string: Option<GenerateSecretString>,
49    secret_string: Option<String>,
50}
51
52impl SecretBuilder<StartState> {
53    /// Creates a new Secrets Manager secret builder.
54    ///
55    /// # Arguments
56    /// * `id` - Unique identifier for the secret
57    pub fn new(id: &str) -> Self {
58        SecretBuilder {
59            phantom_data: Default::default(),
60            id: Id(id.to_string()),
61            name: None,
62            description: None,
63            generate_secret_string: None,
64            secret_string: None,
65        }
66    }
67
68    pub fn name(self, name: StringForSecret) -> Self {
69        Self {
70            name: Some(name.0),
71            ..self
72        }
73    }
74
75    pub fn description<T: Into<String>>(self, description: T) -> Self {
76        Self {
77            description: Some(description.into()),
78            ..self
79        }
80    }
81
82    pub fn secret_string<T: Into<String>>(self, value: T) -> SecretBuilder<SelectedSecretTypeState> {
83        SecretBuilder {
84            phantom_data: Default::default(),
85            id: self.id,
86            name: self.name,
87            description: self.description,
88            secret_string: Some(value.into()),
89            generate_secret_string: None,
90        }
91    }
92
93    pub fn generate_secret_string(self, value: GenerateSecretString) -> SecretBuilder<SelectedSecretTypeState> {
94        SecretBuilder {
95            phantom_data: Default::default(),
96            id: self.id,
97            name: self.name,
98            description: self.description,
99            generate_secret_string: Some(value),
100            secret_string: None,
101        }
102    }
103}
104
105impl SecretBuilder<SelectedSecretTypeState> {
106    pub fn build(self, stack_builder: &mut StackBuilder) -> SecretRef {
107        let resource_id = Resource::generate_id("SecretsManagerSecret");
108
109        stack_builder.add_resource(Secret {
110            id: self.id,
111            resource_id: resource_id.to_string(),
112            r#type: SecretType::SecretType,
113            properties: SecretProperties {
114                name: self.name,
115                description: self.description,
116                generate_secret_string: self.generate_secret_string,
117                secret_string: self.secret_string,
118            },
119        });
120
121        SecretRef::internal_new(resource_id)
122    }
123}
124
125type_state!(
126    GenerateSecretStringBuilderState,
127    GenerateStringStartState,
128    GenerateStringKeyState,
129    SecretStringTemplateState,
130);
131
132/// Builder for generated secret string configuration.
133///
134/// Configures how AWS Secrets Manager should automatically generate a secret value.
135pub struct GenerateSecretStringBuilder<T: GenerateSecretStringBuilderState> {
136    phantom_data: PhantomData<T>,
137    generate_string_key: Option<String>,
138    secret_string_template: Option<String>,
139    exclude_characters: Option<Vec<char>>,
140    exclude_lowercase: Option<bool>,
141    exclude_numbers: Option<bool>,
142    exclude_punctuation: Option<bool>,
143    exclude_uppercase: Option<bool>,
144    include_space: Option<bool>,
145    password_length: Option<u32>,
146    require_each_included_type: Option<bool>,
147}
148
149impl<T: GenerateSecretStringBuilderState> GenerateSecretStringBuilder<T> {
150    fn build_internal(self) -> GenerateSecretString {
151        GenerateSecretString {
152            exclude_characters: self.exclude_characters.map(|v| v.into_iter().collect()),
153            exclude_lowercase: self.exclude_lowercase,
154            exclude_numbers: self.exclude_numbers,
155            exclude_punctuation: self.exclude_punctuation,
156            exclude_uppercase: self.exclude_uppercase,
157            include_space: self.include_space,
158            password_length: self.password_length,
159            require_each_included_type: self.require_each_included_type,
160            generate_string_key: self.generate_string_key,
161            secret_string_template: self.secret_string_template,
162        }
163    }
164}
165
166impl Default for GenerateSecretStringBuilder<GenerateStringStartState> {
167    fn default() -> Self {
168        Self::new()
169    }
170}
171
172impl GenerateSecretStringBuilder<GenerateStringStartState> {
173    pub fn new() -> Self {
174        Self {
175            phantom_data: Default::default(),
176            exclude_characters: None,
177            exclude_lowercase: None,
178            exclude_numbers: None,
179            exclude_punctuation: None,
180            exclude_uppercase: None,
181            generate_string_key: None,
182            include_space: None,
183            password_length: None,
184            require_each_included_type: None,
185            secret_string_template: None,
186        }
187    }
188
189    pub fn exclude_characters(self, exclude_characters: Vec<char>) -> Self {
190        Self {
191            exclude_characters: Some(exclude_characters),
192            ..self
193        }
194    }
195    pub fn exclude_lowercase(self, exclude_lowercase: bool) -> Self {
196        Self {
197            exclude_lowercase: Some(exclude_lowercase),
198            ..self
199        }
200    }
201
202    pub fn exclude_numbers(self, exclude_numbers: bool) -> Self {
203        Self {
204            exclude_numbers: Some(exclude_numbers),
205            ..self
206        }
207    }
208
209    pub fn exclude_punctuation(self, exclude_punctuation: bool) -> Self {
210        Self {
211            exclude_punctuation: Some(exclude_punctuation),
212            ..self
213        }
214    }
215
216    pub fn exclude_uppercase(self, exclude_uppercase: bool) -> Self {
217        Self {
218            exclude_uppercase: Some(exclude_uppercase),
219            ..self
220        }
221    }
222
223    pub fn include_space(self, include_space: bool) -> Self {
224        Self {
225            include_space: Some(include_space),
226            ..self
227        }
228    }
229
230    pub fn password_length(self, password_length: u32) -> Self {
231        Self {
232            password_length: Some(password_length),
233            ..self
234        }
235    }
236
237    pub fn require_each_included_type(self, require_each_included_type: bool) -> Self {
238        Self {
239            require_each_included_type: Some(require_each_included_type),
240            ..self
241        }
242    }
243
244    pub fn generate_string_key<T: Into<String>>(self, generate_string_key: T) -> GenerateSecretStringBuilder<GenerateStringKeyState> {
245        GenerateSecretStringBuilder {
246            phantom_data: Default::default(),
247            generate_string_key: Some(generate_string_key.into()),
248            exclude_characters: self.exclude_characters,
249            exclude_lowercase: self.exclude_lowercase,
250            exclude_numbers: self.exclude_numbers,
251            exclude_punctuation: self.exclude_punctuation,
252            exclude_uppercase: self.exclude_uppercase,
253            include_space: self.include_space,
254            password_length: self.password_length,
255            require_each_included_type: self.require_each_included_type,
256            secret_string_template: None,
257        }
258    }
259
260    #[must_use]
261    pub fn build(self) -> GenerateSecretString {
262        self.build_internal()
263    }
264}
265
266impl GenerateSecretStringBuilder<GenerateStringKeyState> {
267    pub fn secret_string_template(self, secret_string_template: Value) -> GenerateSecretStringBuilder<SecretStringTemplateState> {
268        GenerateSecretStringBuilder {
269            phantom_data: Default::default(),
270            secret_string_template: Some(secret_string_template.to_string()),
271            generate_string_key: self.generate_string_key,
272            exclude_characters: self.exclude_characters,
273            exclude_lowercase: self.exclude_lowercase,
274            exclude_numbers: self.exclude_numbers,
275            exclude_punctuation: self.exclude_punctuation,
276            exclude_uppercase: self.exclude_uppercase,
277            include_space: self.include_space,
278            password_length: self.password_length,
279            require_each_included_type: self.require_each_included_type,
280        }
281    }
282}
283
284impl GenerateSecretStringBuilder<SecretStringTemplateState> {
285    #[must_use]
286    pub fn build(self) -> GenerateSecretString {
287        self.build_internal()
288    }
289}