Skip to content

Commit 6dcb514

Browse files
authored
Update the localstack/localstack docker tag to v4.3.0 adapting to new LocalStack limited key rotation capabilities. (kroxylicious#2024)
* Bump localstack version and fix the test Signed-off-by: ShubhamRwt <[email protected]> * Added suggestions by Keith Signed-off-by: ShubhamRwt <[email protected]> * Added suggestions by Keith Signed-off-by: ShubhamRwt <[email protected]> * Added unit test for AwsKmsTestKmsFacade Signed-off-by: ShubhamRwt <[email protected]> * Added suggestion by Keith and fixed the issues Signed-off-by: ShubhamRwt <[email protected]> --------- Signed-off-by: ShubhamRwt <[email protected]>
1 parent 9b4659a commit 6dcb514

File tree

8 files changed

+336
-43
lines changed

8 files changed

+336
-43
lines changed

kroxylicious-kms-provider-aws-kms-test-support/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,10 @@
8383
<groupId>com.github.spotbugs</groupId>
8484
<artifactId>spotbugs-annotations</artifactId>
8585
</dependency>
86+
<dependency>
87+
<groupId>org.wiremock</groupId>
88+
<artifactId>wiremock</artifactId>
89+
<scope>test</scope>
90+
</dependency>
8691
</dependencies>
8792
</project>

kroxylicious-kms-provider-aws-kms-test-support/src/main/java/io/kroxylicious/kms/provider/aws/kms/AbstractAwsKmsTestKmsFacade.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import io.kroxylicious.kms.provider.aws.kms.model.DescribeKeyRequest;
2929
import io.kroxylicious.kms.provider.aws.kms.model.DescribeKeyResponse;
3030
import io.kroxylicious.kms.provider.aws.kms.model.ErrorResponse;
31+
import io.kroxylicious.kms.provider.aws.kms.model.ListKeyRotationsRequest;
32+
import io.kroxylicious.kms.provider.aws.kms.model.ListKeyRotationsResponse;
3133
import io.kroxylicious.kms.provider.aws.kms.model.RotateKeyRequest;
3234
import io.kroxylicious.kms.provider.aws.kms.model.ScheduleKeyDeletionRequest;
3335
import io.kroxylicious.kms.provider.aws.kms.model.ScheduleKeyDeletionResponse;
@@ -53,13 +55,16 @@ public abstract class AbstractAwsKmsTestKmsFacade implements TestKmsFacade<Confi
5355
private static final String TRENT_SERVICE_ROTATE_KEY = "TrentService.RotateKeyOnDemand";
5456
private static final String TRENT_SERVICE_DELETE_ALIAS = "TrentService.DeleteAlias";
5557
private static final String TRENT_SERVICE_SCHEDULE_KEY_DELETION = "TrentService.ScheduleKeyDeletion";
58+
private static final String TRENT_SERVICE_LIST_KEY_ROTATIONS = "TrentService.ListKeyRotations";
5659

5760
private static final TypeReference<CreateKeyResponse> CREATE_KEY_RESPONSE_TYPE_REF = new TypeReference<>() {
5861
};
5962
private static final TypeReference<DescribeKeyResponse> DESCRIBE_KEY_RESPONSE_TYPE_REF = new TypeReference<>() {
6063
};
6164
private static final TypeReference<ScheduleKeyDeletionResponse> SCHEDULE_KEY_DELETION_RESPONSE_TYPE_REF = new TypeReference<>() {
6265
};
66+
private static final TypeReference<ListKeyRotationsResponse> LIST_KEY_ROTATIONS_RESPONSE_TYPE_REF = new TypeReference<>() {
67+
};
6368
private static final TypeReference<ErrorResponse> ERROR_RESPONSE_TYPE_REF = new TypeReference<>() {
6469
};
6570
private final HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL).build();
@@ -142,9 +147,21 @@ public void deleteKek(String alias) {
142147
@Override
143148
public void rotateKek(String alias) {
144149
var key = read(alias);
150+
// The LocalStack (4.3.0) implementation of RotateOnDemand doesn't preserve key history
151+
// https://docs.localstack.cloud/references/coverage/coverage_kms/#:~:text=Show%20Tests-,RotateKeyOnDemand,-ScheduleKeyDeletion
152+
// https://github.com/localstack/localstack/pull/12342
153+
154+
// We are using ListKeyRotationsRequest as a probe to discover AWS's capabilities.
155+
// If we get 501 status code we will know that we are on LocalStack as it does not implement it
156+
// (see https://docs.localstack.cloud/references/coverage/coverage_kms/#:~:text=Show%20Tests-,ListKeyRotations,-ListKeys)
157+
final ListKeyRotationsRequest listKeyRotationKey = new ListKeyRotationsRequest(key.keyMetadata().keyId());
158+
var listKeyRotationRequest = createRequest(listKeyRotationKey, TRENT_SERVICE_LIST_KEY_ROTATIONS);
159+
145160
final RotateKeyRequest rotateKey = new RotateKeyRequest(key.keyMetadata().keyId());
146161
var rotateKeyRequest = createRequest(rotateKey, TRENT_SERVICE_ROTATE_KEY);
162+
147163
try {
164+
sendRequest(alias, listKeyRotationRequest, LIST_KEY_ROTATIONS_RESPONSE_TYPE_REF);
148165
sendRequestExpectingNoResponse(rotateKeyRequest);
149166
}
150167
catch (AwsNotImplementException e) {
@@ -153,9 +170,6 @@ public void rotateKek(String alias) {
153170
}
154171

155172
private void pseudoRotate(String alias) {
156-
// RotateKeyOnDemand is not implemented in localstack.
157-
// https://docs.localstack.cloud/references/coverage/coverage_kms/#:~:text=Show%20Tests-,RotateKeyOnDemand,-ScheduleKeyDeletion
158-
// https://github.com/localstack/localstack/issues/10723
159173

160174
// mimic rotate by creating a new key and repoint the alias at it, leaving the original key in place.
161175
final CreateKeyRequest request = new CreateKeyRequest("[rotated] key for alias: " + alias);

kroxylicious-kms-provider-aws-kms-test-support/src/main/java/io/kroxylicious/kms/provider/aws/kms/AwsKmsTestKmsFacade.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
public class AwsKmsTestKmsFacade extends AbstractAwsKmsTestKmsFacade {
2020
private static final Logger LOG = LoggerFactory.getLogger(AwsKmsTestKmsFacade.class);
21-
private static final DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:4.2.0");
21+
private static final DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:4.3.0");
2222
private LocalStackContainer localStackContainer;
2323

2424
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright Kroxylicious Authors.
3+
*
4+
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
package io.kroxylicious.kms.provider.aws.kms.model;
8+
9+
import java.util.Objects;
10+
11+
import com.fasterxml.jackson.annotation.JsonProperty;
12+
13+
import edu.umd.cs.findbugs.annotations.NonNull;
14+
15+
public record ListKeyRotationsRequest(@JsonProperty("KeyId") @NonNull String keyId) {
16+
public ListKeyRotationsRequest {
17+
Objects.requireNonNull(keyId);
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Kroxylicious Authors.
3+
*
4+
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
package io.kroxylicious.kms.provider.aws.kms.model;
8+
9+
import java.util.Objects;
10+
11+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
12+
import com.fasterxml.jackson.annotation.JsonProperty;
13+
14+
import edu.umd.cs.findbugs.annotations.NonNull;
15+
16+
@JsonIgnoreProperties(ignoreUnknown = true)
17+
public record ListKeyRotationsResponse(@JsonProperty("Truncated") @NonNull Boolean truncated) {
18+
public ListKeyRotationsResponse {
19+
Objects.requireNonNull(truncated);
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright Kroxylicious Authors.
3+
*
4+
* Licensed under the Apache Software License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
5+
*/
6+
7+
package io.kroxylicious.kms.provider.aws.kms;
8+
9+
import org.junit.jupiter.api.BeforeEach;
10+
import org.junit.jupiter.api.Test;
11+
import org.testcontainers.DockerClientFactory;
12+
13+
import io.kroxylicious.kms.provider.aws.kms.config.Config;
14+
import io.kroxylicious.kms.service.AbstractTestKmsFacadeTest;
15+
import io.kroxylicious.kms.service.UnknownAliasException;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
19+
import static org.assertj.core.api.Assumptions.assumeThat;
20+
21+
class AwsKmsTestKmsFacadeIT extends AbstractTestKmsFacadeTest<Config, String, AwsKmsEdek> {
22+
23+
AwsKmsTestKmsFacadeIT() {
24+
super(new AwsKmsTestKmsFacadeFactory());
25+
}
26+
27+
@BeforeEach
28+
void beforeEach() {
29+
assumeThat(DockerClientFactory.instance().isDockerAvailable()).withFailMessage("docker unavailable").isTrue();
30+
}
31+
32+
@Test
33+
void classAndConfig() {
34+
try (var facade = factory.build()) {
35+
facade.start();
36+
assertThat(facade.getKmsServiceClass()).isEqualTo(AwsKmsService.class);
37+
assertThat(facade.getKmsServiceConfig()).isInstanceOf(Config.class);
38+
}
39+
}
40+
41+
@Test
42+
void generateKekFailsIfAliasExists() {
43+
try (var facade = factory.build()) {
44+
facade.start();
45+
var manager = facade.getTestKekManager();
46+
manager.generateKek(ALIAS);
47+
48+
assertThatThrownBy(() -> manager.generateKek(ALIAS))
49+
.isInstanceOf(IllegalStateException.class)
50+
.hasMessageContaining("400");
51+
}
52+
}
53+
54+
@Test
55+
void rotateKekFailsIfAliasDoesNotExist() {
56+
try (var facade = factory.build()) {
57+
facade.start();
58+
var manager = facade.getTestKekManager();
59+
60+
assertThatThrownBy(() -> manager.rotateKek(ALIAS))
61+
.isInstanceOf(UnknownAliasException.class);
62+
}
63+
}
64+
65+
@Test
66+
void deleteKekFailsIfAliasDoesNotExist() {
67+
try (var facade = factory.build()) {
68+
facade.start();
69+
var manager = facade.getTestKekManager();
70+
71+
assertThatThrownBy(() -> manager.deleteKek(ALIAS))
72+
.isInstanceOf(UnknownAliasException.class);
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)