@@ -24,9 +24,7 @@ import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider
2424import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider
2525import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
2626import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider
27- import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode
2827import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration
29- import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption
3028import software.amazon.awssdk.core.exception.SdkClientException
3129import software.amazon.awssdk.http.SdkHttpClient
3230import software.amazon.awssdk.regions.Region
@@ -48,7 +46,6 @@ import groovy.transform.Memoized
4846import groovy.util.logging.Slf4j
4947import nextflow.SysEnv
5048import nextflow.cloud.aws.config.AwsConfig
51- import nextflow.cloud.aws.util.S3CredentialsProvider
5249import nextflow.exception.AbortOperationException
5350/**
5451 * Implement a factory class for AWS client objects
@@ -217,7 +214,7 @@ class AwsClientFactory {
217214 final ClientOverrideConfiguration overrideConfiguration = s3ClientConfig. getClientOverrideConfiguration()
218215 final builder = S3Client . builder()
219216 .crossRegionAccessEnabled(global)
220- .credentialsProvider(config . s3Config . anonymous ? AnonymousCredentialsProvider . create() : new S3CredentialsProvider (getCredentialsProvider0() ))
217+ .credentialsProvider(getS3CredentialsProvider( ))
221218 .serviceConfiguration(S3Configuration . builder()
222219 .pathStyleAccessEnabled(config. s3Config. pathStyleAccess)
223220 .multiRegionEnabled(global)
@@ -241,7 +238,7 @@ class AwsClientFactory {
241238 S3AsyncClient getS3AsyncClient (S3AsyncClientConfiguration s3ClientConfig , boolean global = false ) {
242239 def builder = S3AsyncClient . crtBuilder()
243240 .crossRegionAccessEnabled(global)
244- .credentialsProvider(config . s3Config . anonymous ? AnonymousCredentialsProvider . create() : new S3CredentialsProvider (getCredentialsProvider0() ))
241+ .credentialsProvider(getS3CredentialsProvider( ))
245242 .forcePathStyle(config. s3Config. pathStyleAccess)
246243 .region(getRegionObj(region))
247244 if ( config. s3Config. endpoint )
@@ -273,6 +270,35 @@ class AwsClientFactory {
273270
274271 return builder. build()
275272 }
273+ /**
274+ * Returns an AwsCredentialsProvider for S3 clients.
275+ *
276+ * This method wraps the same AWS credentials used for other clients, but ensures proper handling of anonymous S3 access.
277+ * If the 'anonymous' flag is set in Nextflow's AWS S3 configuration, or if no credentials are resolved by other providers,
278+ * an AnonymousCredentialsProvider instance is returned.
279+ *
280+ * Prior to AWS SDK v2, the S3CredentialsProvider automatically managed fallback to anonymous access when no credentials were found.
281+ * However, due to a limitation in the AWS SDK v2 CRT Async S3 client (see https://github.com/aws/aws-sdk-java-v2/issues/5810),
282+ * anonymous credentials only work when explicitly configured via AnonymousCredentialsProvider.
283+ * Custom credential providers or provider chains that resolve to anonymous credentials are not handled correctly by the CRT client.
284+ *
285+ * To work around this, this method explicitly checks whether credentials can be resolved.
286+ * If no credentials are found, it returns an AnonymousCredentialsProvider; otherwise, it returns the resolved provider.
287+ *
288+ * @return an AwsCredentialsProvider instance, falling back to anonymous if needed.
289+ */
290+ private AwsCredentialsProvider getS3CredentialsProvider () {
291+ if ( config. s3Config. anonymous )
292+ return AnonymousCredentialsProvider . create()
293+ def provider = getCredentialsProvider0()
294+ try {
295+ provider. resolveCredentials()
296+ } catch (Exception e) {
297+ log. debug(" No AWS credentials available - falling back to anonymous access" )
298+ return AnonymousCredentialsProvider . create()
299+ }
300+ return provider
301+ }
276302
277303 private void setMultipartConfiguration (MultipartConfiguration multipartConfig , S3CrtAsyncClientBuilder builder ) {
278304 if ( multipartConfig. minimumPartSizeInBytes() != null )
0 commit comments