Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/user-guide/latest/datasources.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ AWS credential providers can be configured using the `fs.s3a.aws.credentials.pro
| `com.amazonaws.auth.InstanceProfileCredentialsProvider`<br/>`software.amazon.awssdk.auth.credentials.InstanceProfileCredentialsProvider` | Access S3 using EC2 instance metadata service (IMDS) | None |
| `com.amazonaws.auth.ContainerCredentialsProvider`<br/>`software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider`<br/>`com.amazonaws.auth.EC2ContainerCredentialsProviderWrapper` | Access S3 using ECS task credentials | None |
| `com.amazonaws.auth.WebIdentityTokenCredentialsProvider`<br/>`software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider` | Authenticate using web identity token file | None |
| `com.amazonaws.auth.profile.ProfileCredentialsProvider`<br/>`software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider` | Authenticate using a named profile from the local AWS credentials file | None |

Multiple credential providers can be specified in a comma-separated list using the `fs.s3a.aws.credentials.provider` configuration, just as Hadoop AWS supports. If `fs.s3a.aws.credentials.provider` is not configured, Hadoop S3A's default credential provider chain will be used. All configuration options also support bucket-specific overrides using the pattern `fs.s3a.bucket.{bucket-name}.{option}`.

Expand Down
36 changes: 34 additions & 2 deletions native/core/src/parquet/objectstore/s3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ use async_trait::async_trait;
use aws_config::{
ecs::EcsCredentialsProvider, environment::EnvironmentVariableCredentialsProvider,
imds::credentials::ImdsCredentialsProvider, meta::credentials::CredentialsProviderChain,
provider_config::ProviderConfig, sts::AssumeRoleProvider,
web_identity_token::WebIdentityTokenCredentialsProvider, BehaviorVersion,
profile::ProfileFileCredentialsProvider, provider_config::ProviderConfig,
sts::AssumeRoleProvider, web_identity_token::WebIdentityTokenCredentialsProvider,
BehaviorVersion,
};
use aws_credential_types::{
provider::{error::CredentialsError, ProvideCredentials},
Expand Down Expand Up @@ -316,6 +317,8 @@ const AWS_ENVIRONMENT_V1: &str = "com.amazonaws.auth.EnvironmentVariableCredenti
const AWS_WEB_IDENTITY: &str =
"software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider";
const AWS_WEB_IDENTITY_V1: &str = "com.amazonaws.auth.WebIdentityTokenCredentialsProvider";
const AWS_PROFILE: &str = "software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider";
const AWS_PROFILE_V1: &str = "com.amazonaws.auth.profile.ProfileCredentialsProvider";
const AWS_ANONYMOUS: &str = "software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider";
const AWS_ANONYMOUS_V1: &str = "com.amazonaws.auth.AnonymousAWSCredentials";

Expand Down Expand Up @@ -439,6 +442,7 @@ fn build_aws_credential_provider_metadata(
}
HADOOP_ASSUMED_ROLE => build_assume_role_credential_provider_metadata(configs, bucket),
AWS_WEB_IDENTITY_V1 | AWS_WEB_IDENTITY => Ok(CredentialProviderMetadata::WebIdentity),
AWS_PROFILE_V1 | AWS_PROFILE => Ok(CredentialProviderMetadata::Profile),
_ => Err(object_store::Error::Generic {
store: "S3",
source: format!("Unsupported credential provider: {credential_provider_name}").into(),
Expand Down Expand Up @@ -669,6 +673,7 @@ enum CredentialProviderMetadata {
Imds,
Environment,
WebIdentity,
Profile,
Static {
is_valid: bool,
access_key: String,
Expand All @@ -691,6 +696,7 @@ impl CredentialProviderMetadata {
CredentialProviderMetadata::Imds => "Imds",
CredentialProviderMetadata::Environment => "Environment",
CredentialProviderMetadata::WebIdentity => "WebIdentity",
CredentialProviderMetadata::Profile => "Profile",
CredentialProviderMetadata::Static { .. } => "Static",
CredentialProviderMetadata::AssumeRole { .. } => "AssumeRole",
CredentialProviderMetadata::Chain(..) => "Chain",
Expand All @@ -706,6 +712,7 @@ impl CredentialProviderMetadata {
CredentialProviderMetadata::Imds => "Imds".to_string(),
CredentialProviderMetadata::Environment => "Environment".to_string(),
CredentialProviderMetadata::WebIdentity => "WebIdentity".to_string(),
CredentialProviderMetadata::Profile => "Profile".to_string(),
CredentialProviderMetadata::Static { is_valid, .. } => {
format!("Static(valid: {is_valid})")
}
Expand Down Expand Up @@ -768,6 +775,12 @@ impl CredentialProviderMetadata {
.build();
Ok(Arc::new(credential_provider))
}
CredentialProviderMetadata::Profile => {
let credential_provider = ProfileFileCredentialsProvider::builder()
.configure(&ProviderConfig::with_default_region().await)
.build();
Ok(Arc::new(credential_provider))
}
CredentialProviderMetadata::Static {
is_valid,
access_key,
Expand Down Expand Up @@ -1447,6 +1460,25 @@ mod tests {
}
}

#[tokio::test]
#[cfg_attr(miri, ignore)] // AWS credential providers call foreign functions
async fn test_profile_credential_provider() {
for provider_name in [AWS_PROFILE, AWS_PROFILE_V1] {
let configs = TestConfigBuilder::new()
.with_credential_provider(provider_name)
.build();

let result =
build_credential_provider(&configs, "test-bucket", Duration::from_secs(300))
.await
.unwrap();
assert!(result.is_some(), "Should return a credential provider");

let test_provider = result.unwrap().metadata();
assert_eq!(test_provider, CredentialProviderMetadata::Profile);
}
}

#[tokio::test]
#[cfg_attr(miri, ignore)] // AWS credential providers call foreign functions
async fn test_hadoop_iam_instance_credential_provider() {
Expand Down
Loading