Issue setting credentials provider and region with the new high level configuration
Problem:
Latest version 3.2.1 of the encryption client.
With the new high level configuration (see https://github.com/aws/amazon-s3-encryption-client-java/blob/main/src/examples/java/software/amazon/encryption/s3/examples/ClientConfigurationExample.java),
I was expecting to be able to create my client like this:
return S3EncryptionClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.build();
However, when reading a KMS enrcypted file, this does not work software.amazon.encryption.s3.S3EncryptionClientException: Missing Authentication Token (Service: Kms, Status Code: 400, Request ID: ***************)
I tried the following variations:
return S3EncryptionClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.wrappedClient(S3Client.builder().credentialsProvider(credentialsProvider).region(region).build())
.wrappedAsyncClient(S3AsyncClient.builder().credentialsProvider(credentialsProvider).region(region).build())
.build();
This raised the same exception
Finally, the one I got working is the one were I remove the high level provider:
return S3EncryptionClient.builder()
.region(region)
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.wrappedClient(S3Client.builder().credentialsProvider(credentialsProvider).region(region).build())
.wrappedAsyncClient(S3AsyncClient.builder().credentialsProvider(credentialsProvider).region(region).build())
.build();
Also, I was surprised to see the following failing:
return S3EncryptionClient.builder()
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.wrappedClient(S3Client.builder().credentialsProvider(credentialsProvider).region(region).build())
.wrappedAsyncClient(S3AsyncClient.builder().credentialsProvider(credentialsProvider).region(region).build())
.build();
With this time a different error: software.amazon.awssdk.core.exception.SdkClientException: Unable to load region from any of the providers in the chain software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain
Shouldn't all of those work ?
Hey Nathan,
Could you share what credential provider you're using? This is generally unexpected behavior; the KMS client is instantiated using the credentialsProvider that's passed to the S3EC's builder. Based on the code snippets you have provided, the credential provider you're using doesn't work with KMS, but the default one does.
To give more detail:
return S3EncryptionClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.build();
This shares the credentialsProvider and region between KMS and S3 clients.
return S3EncryptionClient.builder()
.credentialsProvider(credentialsProvider)
.region(region)
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.wrappedClient(S3Client.builder().credentialsProvider(credentialsProvider).region(region).build())
.wrappedAsyncClient(S3AsyncClient.builder().credentialsProvider(credentialsProvider).region(region).build())
.build();
This is functionally equivalent to the first snippet; the top-level credentialProvider and region are applied to the KMS client, and the S3 clients are explicitly configured using the same values.
return S3EncryptionClient.builder()
.region(region)
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.wrappedClient(S3Client.builder().credentialsProvider(credentialsProvider).region(region).build())
.wrappedAsyncClient(S3AsyncClient.builder().credentialsProvider(credentialsProvider).region(region).build())
.build();
This configures the region on the KMS client, but the KMS client will use the default credentials provider instead of credentialsProvider since none is given. In other words, the default credential provider works with KMS, and the explicitly provided credentialsProvider instance works with S3.
return S3EncryptionClient.builder()
.kmsKeyId(keyId)
.enableLegacyUnauthenticatedModes(true)
.enableLegacyWrappingAlgorithms(true)
.wrappedClient(S3Client.builder().credentialsProvider(credentialsProvider).region(region).build())
.wrappedAsyncClient(S3AsyncClient.builder().credentialsProvider(credentialsProvider).region(region).build())
.build();
This uses the default region with the KMS client, which in your case is not set, hence the SdkClientException: Unable to load region... error from KMS. This is different from the above configuration because in the above configuration the region is explicitly configured for KMS via the top-level configuration.
We are using the following credentials provider:
public class S3CredentialsProviderChain implements AwsCredentialsProvider {
private static final Log LOG = LogFactory.getLog(S3CredentialsProviderChain.class);
private boolean tryDefaultChain = true;
@Override
public AwsCredentials resolveCredentials() {
if (this.tryDefaultChain) {
try {
return AwsCredentialsProviderChain.builder().build().resolveCredentials();
} catch (final RuntimeException e) {
// No provider found in the default chain, we won't try it again.
this.tryDefaultChain = false;
LOG.debug("No S3 credentials available; falling back to anonymous access for this session");
}
}
return AnonymousCredentialsProvider.create().resolveCredentials();
}
}
I checked in debug mode and an exception is raised when resolving the credentials, thus it returns an AnonymousCredentialsProvider
Hey @NathanEckert,
When you set the credentialProvider() on the S3 Encryption Client and supply a KMS key ID, the S3EC will use that credential provider for the S3 clients AND the KMS client. It seems like the S3CredentialsProviderChain / AnonymousCredentialsProvider you're using don't work with KMS. To resolve this, you can either modify the provider to return credentials that work with KMS as well as S3, or explicitly configure and provide the KMS client separately through the KmsKeyring. This will override the top-level credentialProvider() configuration.
Hi @NathanEckert, this issue has been inactive for over 2 months. So, we are assuming this issue has been resolved. We are therefore closing this issue. Let us know if you have more questions.