reqsign_aws_core/provide_credential/
assume_role.rs1use std::fmt::{Debug, Formatter};
19
20use reqsign_core::{Context, ProvideCredential, Result, Signer};
21
22use crate::Credential;
23use crate::assume_role::{AssumeRoleGrant, AssumeRoleOperation};
24use crate::provide_credential::utils::sts_endpoint;
25
26pub struct AssumeRoleCredentialProvider {
32 grant: AssumeRoleGrant,
33 duration_seconds: Option<u32>,
34 region: Option<String>,
35 use_regional_sts_endpoint: bool,
36 sts_signer: Signer<Credential>,
37}
38
39impl Debug for AssumeRoleCredentialProvider {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("AssumeRoleCredentialProvider")
42 .finish_non_exhaustive()
43 }
44}
45
46impl AssumeRoleCredentialProvider {
47 pub fn new(role_arn: String, sts_signer: Signer<Credential>) -> Self {
49 Self {
50 grant: AssumeRoleGrant::new(role_arn, "reqsign"),
51 duration_seconds: Some(3_600),
52 region: None,
53 use_regional_sts_endpoint: false,
54 sts_signer,
55 }
56 }
57
58 pub fn with_role_session_name(mut self, name: String) -> Self {
60 self.grant.role_session_name = name;
61 self
62 }
63
64 pub fn with_external_id(mut self, id: String) -> Self {
66 self.grant.external_id = Some(id);
67 self
68 }
69
70 pub fn with_duration_seconds(mut self, seconds: u32) -> Self {
72 self.duration_seconds = Some(seconds);
73 self
74 }
75
76 pub fn with_policy(mut self, policy: String) -> Self {
78 self.grant.policy = Some(policy);
79 self
80 }
81
82 pub fn with_policy_arns(mut self, policy_arns: Vec<String>) -> Self {
84 self.grant.policy_arns = policy_arns;
85 self
86 }
87
88 pub fn with_tags(mut self, tags: Vec<(String, String)>) -> Self {
90 self.grant.tags = tags;
91 self
92 }
93
94 pub fn with_region(mut self, region: String) -> Self {
96 self.region = Some(region);
97 self
98 }
99
100 pub fn with_regional_sts_endpoint(mut self) -> Self {
102 self.use_regional_sts_endpoint = true;
103 self
104 }
105
106 pub fn with_mfa_serial(mut self, serial_number: String) -> Self {
108 self.grant.serial_number = Some(serial_number);
109 self
110 }
111
112 pub fn with_mfa_code(mut self, token_code: String) -> Self {
114 self.grant.token_code = Some(token_code);
115 self
116 }
117
118 pub fn from_env(ctx: &Context, sts_signer: Signer<Credential>) -> Option<Self> {
120 let role_arn = ctx.env_var("AWS_ROLE_ARN")?;
121 let mut provider = Self::new(role_arn, sts_signer);
122
123 if let Some(name) = ctx.env_var("AWS_ROLE_SESSION_NAME") {
124 provider = provider.with_role_session_name(name);
125 }
126 if let Some(id) = ctx.env_var("AWS_EXTERNAL_ID") {
127 provider = provider.with_external_id(id);
128 }
129 if let Some(region) = ctx.env_var("AWS_REGION") {
130 provider = provider.with_region(region);
131 }
132 if ctx.env_var("AWS_STS_REGIONAL_ENDPOINTS").as_deref() == Some("regional") {
133 provider = provider.with_regional_sts_endpoint();
134 }
135
136 Some(provider)
137 }
138}
139
140impl ProvideCredential for AssumeRoleCredentialProvider {
141 type Credential = Credential;
142
143 async fn provide_credential(&self, ctx: &Context) -> Result<Option<Self::Credential>> {
144 match self.region.as_deref() {
145 Some(region) => self.grant.validate_for_region(region)?,
146 None => self.grant.validate_for_partition("aws")?,
147 }
148 let endpoint = sts_endpoint(self.region.as_deref(), self.use_regional_sts_endpoint)?;
149 let operation = AssumeRoleOperation::new(endpoint, &self.grant, self.duration_seconds)?;
150 operation.execute(ctx, &self.sts_signer).await.map(Some)
151 }
152}