Skip to content

Commit 77bc1d0

Browse files
Make KMS endpoint configurable via kms.endpoint AWS property (#14246)
Co-authored-by: Thomas Powell <[email protected]>
1 parent a473b1c commit 77bc1d0

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

aws/src/integration/java/org/apache/iceberg/aws/TestDefaultAwsClientFactory.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
3131
import software.amazon.awssdk.services.glue.GlueClient;
3232
import software.amazon.awssdk.services.glue.model.GetDatabaseRequest;
33+
import software.amazon.awssdk.services.kms.KmsClient;
3334
import software.amazon.awssdk.services.s3.S3Client;
3435
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
3536
import software.amazon.awssdk.services.s3.model.S3Exception;
@@ -99,4 +100,16 @@ public void testDynamoDbEndpointOverride() {
99100
.isInstanceOf(SdkClientException.class)
100101
.hasMessageContaining("Unable to execute HTTP request: unknown");
101102
}
103+
104+
@Test
105+
public void testKmsEndpointOverride() {
106+
Map<String, String> properties = Maps.newHashMap();
107+
properties.put(AwsProperties.KMS_ENDPOINT, "https://unknown:1234");
108+
AwsClientFactory factory = AwsClientFactories.from(properties);
109+
KmsClient kmsClient = factory.kms();
110+
assertThatThrownBy(kmsClient::listKeys)
111+
.cause()
112+
.isInstanceOf(SdkClientException.class)
113+
.hasMessageContaining("Unable to execute HTTP request: unknown");
114+
}
102115
}

aws/src/main/java/org/apache/iceberg/aws/AwsClientFactories.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import software.amazon.awssdk.services.glue.GlueClient;
4040
import software.amazon.awssdk.services.glue.GlueClientBuilder;
4141
import software.amazon.awssdk.services.kms.KmsClient;
42+
import software.amazon.awssdk.services.kms.KmsClientBuilder;
4243
import software.amazon.awssdk.services.s3.S3AsyncClient;
4344
import software.amazon.awssdk.services.s3.S3BaseClientBuilder;
4445
import software.amazon.awssdk.services.s3.S3Client;
@@ -155,6 +156,7 @@ public KmsClient kms() {
155156
return KmsClient.builder()
156157
.applyMutation(awsClientProperties::applyClientRegionConfiguration)
157158
.applyMutation(httpClientProperties::applyHttpClientConfigurations)
159+
.applyMutation(awsProperties::applyKmsEndpointConfigurations)
158160
.applyMutation(awsClientProperties::applyClientCredentialConfigurations)
159161
.applyMutation(awsClientProperties::applyRetryConfigurations)
160162
.build();
@@ -208,8 +210,9 @@ public static SdkHttpClient.Builder configureHttpClientBuilder(String httpClient
208210
* @deprecated Not for public use. To configure the endpoint for a client, please use {@link
209211
* S3FileIOProperties#applyEndpointConfigurations(S3BaseClientBuilder)}, {@link
210212
* AwsProperties#applyGlueEndpointConfigurations(GlueClientBuilder)}, or {@link
211-
* AwsProperties#applyDynamoDbEndpointConfigurations(DynamoDbClientBuilder)} accordingly. It
212-
* will be removed in 2.0.0
213+
* AwsProperties#applyDynamoDbEndpointConfigurations(DynamoDbClientBuilder)}, or {@link
214+
* AwsProperties#applyKmsEndpointConfigurations(KmsClientBuilder)} accordingly. It will be
215+
* removed in 2.0.0
213216
*/
214217
@Deprecated
215218
public static <T extends SdkClientBuilder> void configureEndpoint(T builder, String endpoint) {

aws/src/main/java/org/apache/iceberg/aws/AwsProperties.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain;
4242
import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder;
4343
import software.amazon.awssdk.services.glue.GlueClientBuilder;
44+
import software.amazon.awssdk.services.kms.KmsClientBuilder;
4445
import software.amazon.awssdk.services.kms.model.DataKeySpec;
4546
import software.amazon.awssdk.services.kms.model.EncryptionAlgorithmSpec;
4647

@@ -208,6 +209,14 @@ public class AwsProperties implements Serializable {
208209
*/
209210
public static final String REST_SESSION_TOKEN = "rest.session-token";
210211

212+
/**
213+
* Configure an alternative endpoint of the KMS service for AwsKeyManagementClient to access.
214+
*
215+
* <p>This could be used to use KMS key management with any KMS-compatible service that has a
216+
* different endpoint
217+
*/
218+
public static final String KMS_ENDPOINT = "kms.endpoint";
219+
211220
/** Encryption algorithm used to encrypt/decrypt master table keys */
212221
public static final String KMS_ENCRYPTION_ALGORITHM_SPEC = "kms.encryption-algorithm-spec";
213222

@@ -243,6 +252,7 @@ public class AwsProperties implements Serializable {
243252
private String restAccessKeyId;
244253
private String restSecretAccessKey;
245254
private String restSessionToken;
255+
private final String kmsEndpoint;
246256
private EncryptionAlgorithmSpec kmsEncryptionAlgorithmSpec;
247257
private DataKeySpec kmsDataKeySpec;
248258

@@ -268,6 +278,7 @@ public AwsProperties() {
268278

269279
this.restSigningName = REST_SIGNING_NAME_DEFAULT;
270280

281+
this.kmsEndpoint = null;
271282
this.kmsEncryptionAlgorithmSpec = KMS_ENCRYPTION_ALGORITHM_SPEC_DEFAULT;
272283
this.kmsDataKeySpec = KMS_DATA_KEY_SPEC_DEFAULT;
273284
}
@@ -312,6 +323,7 @@ public AwsProperties(Map<String, String> properties) {
312323
this.restSecretAccessKey = properties.get(REST_SECRET_ACCESS_KEY);
313324
this.restSessionToken = properties.get(REST_SESSION_TOKEN);
314325

326+
this.kmsEndpoint = properties.get(KMS_ENDPOINT);
315327
this.kmsEncryptionAlgorithmSpec =
316328
EncryptionAlgorithmSpec.fromValue(
317329
properties.getOrDefault(
@@ -411,6 +423,19 @@ public <T extends DynamoDbClientBuilder> void applyDynamoDbEndpointConfiguration
411423
configureEndpoint(builder, dynamoDbEndpoint);
412424
}
413425

426+
/**
427+
* Override the endpoint for a KMS client.
428+
*
429+
* <p>Sample usage:
430+
*
431+
* <pre>
432+
* KmsClient.builder().applyMutation(awsProperties::applyKmsEndpointConfigurations)
433+
* </pre>
434+
*/
435+
public <T extends KmsClientBuilder> void applyKmsEndpointConfigurations(T builder) {
436+
configureEndpoint(builder, kmsEndpoint);
437+
}
438+
414439
public Region restSigningRegion() {
415440
if (restSigningRegion == null) {
416441
this.restSigningRegion = DefaultAwsRegionProviderChain.builder().build().getRegion().id();
@@ -428,6 +453,10 @@ public AwsCredentialsProvider restCredentialsProvider() {
428453
this.restAccessKeyId, this.restSecretAccessKey, this.restSessionToken);
429454
}
430455

456+
public String kmsEndpoint() {
457+
return this.kmsEndpoint;
458+
}
459+
431460
public EncryptionAlgorithmSpec kmsEncryptionAlgorithmSpec() {
432461
return this.kmsEncryptionAlgorithmSpec;
433462
}

0 commit comments

Comments
 (0)