Skip to content

S3 file storage: support ambient AWS credentials (ECS task roles, EKS IRSA) instead of static keys only #6851

Description

@boris-ohme

Current Behavior

The s3 file storage provider only supports static credentials. In S3FileStorageProvider.create() the MinIO client is built like this:

final var accessKey = config.getOptionalValue("dt.file-storage.s3.access-key", String.class).orElse(null);
final var secretKey = config.getOptionalValue("dt.file-storage.s3.secret-key", String.class).orElse(null);
if (accessKey != null && secretKey != null) {
    clientBuilder.credentials(accessKey, secretKey);
}

When access-key / secret-key are not configured, no credentials provider is installed at all, so the client sends unsigned (anonymous) requests (BaseS3Client.executeAsync: Credentials credentials = (provider == null) ? null : provider.fetch();). There is no fallback to ambient AWS credential resolution — environment variables, ~/.aws config, ECS task roles (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI), EKS IRSA (web identity), EKS Pod Identity, and EC2 instance profiles are all ignored.

On AWS this makes the s3 provider effectively unusable in well-configured environments: on ECS and Kubernetes/EKS the standard (and often org-mandated) way to grant S3 access is the task role / IRSA, not long-lived IAM user keys. Minting a static key pair just for file storage is an anti-pattern (no rotation, secret sprawl) and is frequently prohibited outright.

This matters more than it first appears, because the default local provider silently breaks horizontally scaled deployments: with more than one apiserver replica, a BOM accepted by one replica may have its import-bom workflow picked up by another (the workflow engine coordinates through PostgreSQL), where FileStorage#get throws NoSuchFileException, the workflow fails terminally, and the project is left empty — while /api/v1/event/token/{uuid} reports processing complete. We hit exactly this running 2 replicas on ECS (verified on 5.0.3). Shared storage is the fix, and S3 is the natural choice — but only static keys are supported today. (We worked around it with an EFS volume mounted over the data directory.)

Observed on 5.0.3; the code on main is unchanged.

Proposed Behavior

When dt.file-storage.s3.access-key / secret-key are not configured, fall back to ambient credential resolution instead of anonymous access. The MinIO client already bundled with Dependency-Track ships everything needed in io.minio.credentials — no new dependencies:

if (accessKey != null && secretKey != null) {
    clientBuilder.credentials(accessKey, secretKey);
} else {
    clientBuilder.credentialsProvider(new ChainedProvider(
            new AwsEnvironmentProvider(),
            new AwsConfigProvider(),
            new IamAwsProvider(null, httpClient)));
}

IamAwsProvider already handles the ECS container credentials endpoint (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI / _FULL_URI), EKS IRSA (AWS_WEB_IDENTITY_TOKEN_FILE), and EC2 IMDS, so this single change makes the provider work with ECS task roles and Kubernetes service-account-based auth out of the box, while keeping current static-key behavior fully backward compatible. If truly anonymous access should remain reachable, it could be kept behind an explicit opt-in flag rather than being the silent default.

Happy to submit a PR for this.

Checklist

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestp2Non-critical bugs, and features that help organizations to identify and reduce risksize/MMedium effort

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions