@@ -39,6 +39,7 @@ use reqsign::AwsConfig;
3939use reqsign:: AwsCredentialLoad ;
4040use reqsign:: AwsDefaultLoader ;
4141use reqsign:: AwsV4Signer ;
42+ use reqsign:: ECSCredentialProvider ;
4243use reqwest:: Url ;
4344
4445use super :: core:: * ;
@@ -402,6 +403,58 @@ impl S3Builder {
402403 self . session_token ( token)
403404 }
404405
406+ /// Set container credentials relative URI for ECS Task IAM roles.
407+ ///
408+ /// Used in ECS environments where the base metadata endpoint is known.
409+ /// Example: "/v2/credentials/my-role-name"
410+ pub fn container_credentials_relative_uri ( mut self , uri : & str ) -> Self {
411+ if !uri. is_empty ( ) {
412+ self . config . container_credentials_relative_uri = Some ( uri. to_string ( ) ) ;
413+ }
414+ self
415+ }
416+
417+ /// Set container credentials endpoint for Fargate or custom setups.
418+ ///
419+ /// Complete URL for fetching credentials. Used in Fargate environments.
420+ /// Example: "http://169.254.170.2/v2/credentials/my-role"
421+ pub fn container_credentials_endpoint ( mut self , endpoint : & str ) -> Self {
422+ if !endpoint. is_empty ( ) {
423+ self . config . container_credentials_endpoint = Some ( endpoint. to_string ( ) ) ;
424+ }
425+ self
426+ }
427+
428+ /// Set authorization token for container credentials requests.
429+ ///
430+ /// Token used for authenticating with the container credentials endpoint.
431+ pub fn container_authorization_token ( mut self , token : & str ) -> Self {
432+ if !token. is_empty ( ) {
433+ self . config . container_authorization_token = Some ( token. to_string ( ) ) ;
434+ }
435+ self
436+ }
437+
438+ /// Set path to file containing authorization token for container credentials.
439+ ///
440+ /// File should contain the authorization token for ECS credentials endpoint.
441+ pub fn container_authorization_token_file ( mut self , file_path : & str ) -> Self {
442+ if !file_path. is_empty ( ) {
443+ self . config . container_authorization_token_file = Some ( file_path. to_string ( ) ) ;
444+ }
445+ self
446+ }
447+
448+ /// Set override for the container metadata URI base endpoint.
449+ ///
450+ /// Used to override the default http://169.254.170.2 endpoint, typically for testing.
451+ pub fn container_metadata_uri_override ( mut self , uri : & str ) -> Self {
452+ if !uri. is_empty ( ) {
453+ self . config . container_metadata_uri_override = Some ( uri. to_string ( ) ) ;
454+ }
455+ self
456+ }
457+
405458 /// Disable config load so that opendal will not load config from
406459 /// environment.
407460 ///
@@ -495,6 +548,15 @@ impl S3Builder {
495548 self
496549 }
497550
551+ /// Check if ECS container credentials configuration is present
552+ fn has_ecs_config ( & self ) -> bool {
553+ self . config . container_credentials_endpoint . is_some ( )
554+ || self . config . container_credentials_relative_uri . is_some ( )
555+ || self . config . container_authorization_token . is_some ( )
556+ || self . config . container_authorization_token_file . is_some ( )
557+ || self . config . container_metadata_uri_override . is_some ( )
558+ }
559+
498560 /// Check if `bucket` is valid
499561 /// `bucket` must be not empty and if `enable_virtual_host_style` is true
500562 /// it couldn't contain dot(.) character
@@ -844,6 +906,33 @@ impl Builder for S3Builder {
844906 loader = Some ( v) ;
845907 }
846908
909+ // If ECS container credentials are configured, use ECSCredentialProvider
910+ if loader. is_none ( ) && self . has_ecs_config ( ) {
911+ let mut ecs_provider = ECSCredentialProvider :: new ( ) ;
912+
913+ if let Some ( ref endpoint) = self . config . container_credentials_endpoint {
914+ ecs_provider = ecs_provider. with_endpoint ( endpoint) ;
915+ }
916+
917+ if let Some ( ref relative_uri) = self . config . container_credentials_relative_uri {
918+ ecs_provider = ecs_provider. with_relative_uri ( relative_uri) ;
919+ }
920+
921+ if let Some ( ref token) = self . config . container_authorization_token {
922+ ecs_provider = ecs_provider. with_auth_token ( token) ;
923+ }
924+
925+ if let Some ( ref token_file) = self . config . container_authorization_token_file {
926+ ecs_provider = ecs_provider. with_auth_token_file ( token_file) ;
927+ }
928+
929+ if let Some ( ref uri_override) = self . config . container_metadata_uri_override {
930+ ecs_provider = ecs_provider. with_metadata_uri_override ( uri_override) ;
931+ }
932+
933+ loader = Some ( Box :: new ( ecs_provider) ) ;
934+ }
935+
847936 // If role_arn is set, we must use AssumeRoleLoad.
848937 if let Some ( role_arn) = self . config . role_arn {
849938 // use current env as source credential loader.
0 commit comments