@@ -156,6 +156,14 @@ pub struct AmazonS3Builder {
156156 container_credentials_full_uri : Option < String > ,
157157 /// Container authorization token file, see <https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html>
158158 container_authorization_token_file : Option < String > ,
159+ /// Web identity token file path for AssumeRoleWithWebIdentity
160+ web_identity_token_file : Option < String > ,
161+ /// Role ARN to assume when using web identity token
162+ role_arn : Option < String > ,
163+ /// Session name for web identity role assumption
164+ role_session_name : Option < String > ,
165+ /// Custom STS endpoint for web identity token exchange
166+ sts_endpoint : Option < String > ,
159167 /// Client options
160168 client_options : ClientOptions ,
161169 /// Credentials
@@ -319,6 +327,34 @@ pub enum AmazonS3ConfigKey {
319327 /// <https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html>
320328 ContainerAuthorizationTokenFile ,
321329
330+ /// Web identity token file path for AssumeRoleWithWebIdentity
331+ ///
332+ /// Supported keys:
333+ /// - `aws_web_identity_token_file`
334+ /// - `web_identity_token_file`
335+ WebIdentityTokenFile ,
336+
337+ /// Role ARN to assume when using web identity token
338+ ///
339+ /// Supported keys:
340+ /// - `aws_role_arn`
341+ /// - `role_arn`
342+ RoleArn ,
343+
344+ /// Session name for web identity role assumption
345+ ///
346+ /// Supported keys:
347+ /// - `aws_role_session_name`
348+ /// - `role_session_name`
349+ RoleSessionName ,
350+
351+ /// Custom STS endpoint for web identity token exchange
352+ ///
353+ /// Supported keys:
354+ /// - `aws_endpoint_url_sts`
355+ /// - `endpoint_url_sts`
356+ StsEndpoint ,
357+
322358 /// Configure how to provide `copy_if_not_exists`
323359 ///
324360 /// See [`S3CopyIfNotExists`]
@@ -381,6 +417,10 @@ impl AsRef<str> for AmazonS3ConfigKey {
381417 Self :: ContainerCredentialsRelativeUri => "aws_container_credentials_relative_uri" ,
382418 Self :: ContainerCredentialsFullUri => "aws_container_credentials_full_uri" ,
383419 Self :: ContainerAuthorizationTokenFile => "aws_container_authorization_token_file" ,
420+ Self :: WebIdentityTokenFile => "aws_web_identity_token_file" ,
421+ Self :: RoleArn => "aws_role_arn" ,
422+ Self :: RoleSessionName => "aws_role_session_name" ,
423+ Self :: StsEndpoint => "aws_endpoint_url_sts" ,
384424 Self :: SkipSignature => "aws_skip_signature" ,
385425 Self :: CopyIfNotExists => "aws_copy_if_not_exists" ,
386426 Self :: ConditionalPut => "aws_conditional_put" ,
@@ -415,6 +455,12 @@ impl FromStr for AmazonS3ConfigKey {
415455 "aws_container_credentials_relative_uri" => Ok ( Self :: ContainerCredentialsRelativeUri ) ,
416456 "aws_container_credentials_full_uri" => Ok ( Self :: ContainerCredentialsFullUri ) ,
417457 "aws_container_authorization_token_file" => Ok ( Self :: ContainerAuthorizationTokenFile ) ,
458+ "aws_web_identity_token_file" | "web_identity_token_file" => {
459+ Ok ( Self :: WebIdentityTokenFile )
460+ }
461+ "aws_role_arn" | "role_arn" => Ok ( Self :: RoleArn ) ,
462+ "aws_role_session_name" | "role_session_name" => Ok ( Self :: RoleSessionName ) ,
463+ "aws_endpoint_url_sts" | "endpoint_url_sts" => Ok ( Self :: StsEndpoint ) ,
418464 "aws_skip_signature" | "skip_signature" => Ok ( Self :: SkipSignature ) ,
419465 "aws_copy_if_not_exists" | "copy_if_not_exists" => Ok ( Self :: CopyIfNotExists ) ,
420466 "aws_conditional_put" | "conditional_put" => Ok ( Self :: ConditionalPut ) ,
@@ -458,6 +504,10 @@ impl AmazonS3Builder {
458504 /// * `AWS_DEFAULT_REGION` -> region
459505 /// * `AWS_ENDPOINT` -> endpoint
460506 /// * `AWS_SESSION_TOKEN` -> token
507+ /// * `AWS_WEB_IDENTITY_TOKEN_FILE` -> path to file containing web identity token for AssumeRoleWithWebIdentity
508+ /// * `AWS_ROLE_ARN` -> ARN of the role to assume when using web identity token
509+ /// * `AWS_ROLE_SESSION_NAME` -> optional session name for web identity role assumption (defaults to "WebIdentitySession")
510+ /// * `AWS_ENDPOINT_URL_STS` -> optional custom STS endpoint for web identity token exchange (defaults to "https://sts.{region}.amazonaws.com")
461511 /// * `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` -> <https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-iam-roles.html>
462512 /// * `AWS_CONTAINER_CREDENTIALS_FULL_URI` -> <https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html>
463513 /// * `AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE` -> <https://docs.aws.amazon.com/sdkref/latest/guide/feature-container-credentials.html>
@@ -543,6 +593,18 @@ impl AmazonS3Builder {
543593 AmazonS3ConfigKey :: ContainerAuthorizationTokenFile => {
544594 self . container_authorization_token_file = Some ( value. into ( ) ) ;
545595 }
596+ AmazonS3ConfigKey :: WebIdentityTokenFile => {
597+ self . web_identity_token_file = Some ( value. into ( ) ) ;
598+ }
599+ AmazonS3ConfigKey :: RoleArn => {
600+ self . role_arn = Some ( value. into ( ) ) ;
601+ }
602+ AmazonS3ConfigKey :: RoleSessionName => {
603+ self . role_session_name = Some ( value. into ( ) ) ;
604+ }
605+ AmazonS3ConfigKey :: StsEndpoint => {
606+ self . sts_endpoint = Some ( value. into ( ) ) ;
607+ }
546608 AmazonS3ConfigKey :: Client ( key) => {
547609 self . client_options = self . client_options . with_config ( key, value)
548610 }
@@ -612,6 +674,10 @@ impl AmazonS3Builder {
612674 AmazonS3ConfigKey :: ContainerAuthorizationTokenFile => {
613675 self . container_authorization_token_file . clone ( )
614676 }
677+ AmazonS3ConfigKey :: WebIdentityTokenFile => self . web_identity_token_file . clone ( ) ,
678+ AmazonS3ConfigKey :: RoleArn => self . role_arn . clone ( ) ,
679+ AmazonS3ConfigKey :: RoleSessionName => self . role_session_name . clone ( ) ,
680+ AmazonS3ConfigKey :: StsEndpoint => self . sts_endpoint . clone ( ) ,
615681 AmazonS3ConfigKey :: SkipSignature => Some ( self . skip_signature . to_string ( ) ) ,
616682 AmazonS3ConfigKey :: CopyIfNotExists => {
617683 self . copy_if_not_exists . as_ref ( ) . map ( ToString :: to_string)
@@ -959,21 +1025,25 @@ impl AmazonS3Builder {
9591025 std:: env:: var ( "AWS_WEB_IDENTITY_TOKEN_FILE" ) ,
9601026 std:: env:: var ( "AWS_ROLE_ARN" ) ,
9611027 ) {
962- // TODO: Replace with `AmazonS3Builder::credentials_from_env`
9631028 debug ! ( "Using WebIdentity credential provider" ) ;
9641029
965- let session_name = std:: env:: var ( "AWS_ROLE_SESSION_NAME" )
966- . unwrap_or_else ( |_| "WebIdentitySession" . to_string ( ) ) ;
1030+ let session_name = self
1031+ . role_session_name
1032+ . clone ( )
1033+ . unwrap_or_else ( || "WebIdentitySession" . to_string ( ) ) ;
9671034
968- let endpoint = format ! ( "https://sts.{region}.amazonaws.com" ) ;
1035+ let endpoint = self
1036+ . sts_endpoint
1037+ . clone ( )
1038+ . unwrap_or_else ( || format ! ( "https://sts.{region}.amazonaws.com" ) ) ;
9691039
9701040 // Disallow non-HTTPs requests
9711041 let options = self . client_options . clone ( ) . with_allow_http ( false ) ;
9721042
9731043 let token = WebIdentityProvider {
974- token_path,
1044+ token_path : token_path . clone ( ) ,
9751045 session_name,
976- role_arn,
1046+ role_arn : role_arn . clone ( ) ,
9771047 endpoint,
9781048 } ;
9791049
@@ -1611,4 +1681,56 @@ mod tests {
16111681 "expected EKS provider but got: {debug_str}"
16121682 ) ;
16131683 }
1684+
1685+ #[ test]
1686+ fn test_builder_web_identity_with_config ( ) {
1687+ let builder = AmazonS3Builder :: new ( )
1688+ . with_bucket_name ( "some-bucket" )
1689+ . with_config (
1690+ AmazonS3ConfigKey :: WebIdentityTokenFile ,
1691+ "/tmp/fake-token-file" ,
1692+ )
1693+ . with_config (
1694+ AmazonS3ConfigKey :: RoleArn ,
1695+ "arn:aws:iam::123456789012:role/test-role" ,
1696+ )
1697+ . with_config ( AmazonS3ConfigKey :: RoleSessionName , "TestSession" )
1698+ . with_config (
1699+ AmazonS3ConfigKey :: StsEndpoint ,
1700+ "https://sts.us-west-2.amazonaws.com" ,
1701+ ) ;
1702+
1703+ assert_eq ! (
1704+ builder
1705+ . get_config_value( & AmazonS3ConfigKey :: WebIdentityTokenFile )
1706+ . unwrap( ) ,
1707+ "/tmp/fake-token-file"
1708+ ) ;
1709+ assert_eq ! (
1710+ builder
1711+ . get_config_value( & AmazonS3ConfigKey :: RoleArn )
1712+ . unwrap( ) ,
1713+ "arn:aws:iam::123456789012:role/test-role"
1714+ ) ;
1715+ assert_eq ! (
1716+ builder
1717+ . get_config_value( & AmazonS3ConfigKey :: RoleSessionName )
1718+ . unwrap( ) ,
1719+ "TestSession"
1720+ ) ;
1721+ assert_eq ! (
1722+ builder
1723+ . get_config_value( & AmazonS3ConfigKey :: StsEndpoint )
1724+ . unwrap( ) ,
1725+ "https://sts.us-west-2.amazonaws.com"
1726+ ) ;
1727+
1728+ let s3 = builder. build ( ) . expect ( "should build successfully" ) ;
1729+ let creds = & s3. client . config . credentials ;
1730+ let debug_str = format ! ( "{creds:?}" ) ;
1731+ assert ! (
1732+ debug_str. contains( "TokenCredentialProvider" ) ,
1733+ "expected TokenCredentialProvider but got: {debug_str}"
1734+ ) ;
1735+ }
16141736}
0 commit comments