33
44use async_trait:: async_trait;
55use rusoto_core:: credential:: {
6- AutoRefreshingProvider , AwsCredentials , CredentialsError , EnvironmentProvider ,
7- ProvideAwsCredentials ,
6+ AutoRefreshingProvider , AwsCredentials , ContainerProvider , CredentialsError ,
7+ EnvironmentProvider , ProvideAwsCredentials ,
88} ;
99use rusoto_sts:: WebIdentityProvider ;
1010
1111/// Provides AWS credentials from multiple possible sources using a priority order.
12- /// The following sources are checked in order for credentials when calling credentials. More sources may be supported in future if a need be.
12+ /// The following sources are checked in order for credentials when calling credentials:
1313/// 1) Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
14- /// 2) `WebIdentityProvider`: by default, configured from environment variables `AWS_WEB_IDENTITY_TOKEN_FILE`,
14+ /// 2) `ContainerProvider`: ECS container credentials from the task metadata endpoint.
15+ /// This is used when running in ECS/Fargate with an IAM task role.
16+ /// 3) `WebIdentityProvider`: by default, configured from environment variables `AWS_WEB_IDENTITY_TOKEN_FILE`,
1517/// `AWS_ROLE_ARN` and `AWS_ROLE_SESSION_NAME`. Uses OpenID Connect bearer token to retrieve AWS IAM credentials
1618/// from [AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html).
1719/// The primary use case is running Hyperlane agents in AWS Kubernetes cluster (EKS) configured
1820/// with [IAM Roles for Service Accounts (IRSA)](https://aws.amazon.com/blogs/containers/diving-into-iam-roles-for-service-accounts/).
1921/// The IRSA approach follows security best practices and allows for key rotation.
2022pub ( crate ) struct AwsChainCredentialsProvider {
2123 environment_provider : EnvironmentProvider ,
24+ container_provider : AutoRefreshingProvider < ContainerProvider > ,
2225 web_identity_provider : AutoRefreshingProvider < WebIdentityProvider > ,
2326}
2427
@@ -30,8 +33,11 @@ impl AwsChainCredentialsProvider {
3033 let auto_refreshing_provider =
3134 AutoRefreshingProvider :: new ( WebIdentityProvider :: from_k8s_env ( ) )
3235 . expect ( "Always returns Ok(...)" ) ;
36+ let container_provider =
37+ AutoRefreshingProvider :: new ( ContainerProvider :: new ( ) ) . expect ( "Always returns Ok(...)" ) ;
3338 AwsChainCredentialsProvider {
3439 environment_provider : EnvironmentProvider :: default ( ) ,
40+ container_provider,
3541 web_identity_provider : auto_refreshing_provider,
3642 }
3743 }
@@ -40,11 +46,17 @@ impl AwsChainCredentialsProvider {
4046#[ async_trait]
4147impl ProvideAwsCredentials for AwsChainCredentialsProvider {
4248 async fn credentials ( & self ) -> Result < AwsCredentials , CredentialsError > {
49+ // Try environment variables first
4350 if let Ok ( creds) = self . environment_provider . credentials ( ) . await {
44- Ok ( creds)
45- } else {
46- // Propagate errors from the 'WebIdentityProvider'.
47- self . web_identity_provider . credentials ( ) . await
51+ return Ok ( creds) ;
4852 }
53+
54+ // Try ECS container credentials (for Fargate/ECS with task role)
55+ if let Ok ( creds) = self . container_provider . credentials ( ) . await {
56+ return Ok ( creds) ;
57+ }
58+
59+ // Fall back to web identity (for Kubernetes IRSA)
60+ self . web_identity_provider . credentials ( ) . await
4961 }
5062}
0 commit comments