summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOla Aunrønning <olaa@verizonmedia.com>2021-03-05 13:05:17 +0100
committerOla Aunrønning <olaa@verizonmedia.com>2021-03-05 13:08:08 +0100
commita274f9d5b8f24676a576e12ef35423549eea0d56 (patch)
treee24a785b362d2c87cf1f98285c5545b36726f988
parent1acaa2e62aecdda2b4c321ae133654cc1a0316f3 (diff)
Include region and parameter name when validating secret store. Don't inject AwsParameterStore to AwsParameterStoreValidationHandler
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/SecretStoreValidator.java26
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java26
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/tenant/SecretStoreExternalIdRetriever.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/MockSecretStoreValidator.java7
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/SecretStoreValidatorTest.java29
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java10
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java6
-rw-r--r--jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStore.java86
-rw-r--r--jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStoreValidationHandler.java43
13 files changed, 147 insertions, 103 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
index 54ff693dbf5..c044a545b6f 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java
@@ -29,6 +29,7 @@ import com.yahoo.docproc.jdisc.metric.NullMetric;
import com.yahoo.io.IOUtils;
import com.yahoo.jdisc.Metric;
import com.yahoo.path.Path;
+import com.yahoo.slime.Slime;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.transaction.Transaction;
import com.yahoo.vespa.config.server.application.Application;
@@ -702,9 +703,9 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye
: applicationSet.get().getAllVersions(applicationId);
}
- public HttpResponse validateSecretStore(ApplicationId applicationId, TenantSecretStore tenantSecretStore, String tenantSecretName) {
+ public HttpResponse validateSecretStore(ApplicationId applicationId, SystemName systemName, Slime slime) {
Application application = getApplication(applicationId);
- return secretStoreValidator.validateSecretStore(application, tenantSecretStore, tenantSecretName);
+ return secretStoreValidator.validateSecretStore(application, systemName, slime);
}
// ---------------- Convergence ----------------------------------------------------------------
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/SecretStoreValidator.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/SecretStoreValidator.java
index 72f5747e15c..71eed450955 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/SecretStoreValidator.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/SecretStoreValidator.java
@@ -3,12 +3,16 @@ package com.yahoo.vespa.config.server.http;
import ai.vespa.util.http.VespaHttpClientBuilder;
import com.yahoo.config.model.api.HostInfo;
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.jdisc.secretstore.SecretStore;
import com.yahoo.slime.Slime;
import com.yahoo.slime.SlimeUtils;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.config.model.api.TenantSecretStore;
+import com.yahoo.vespa.config.server.tenant.SecretStoreExternalIdRetriever;
import com.yahoo.yolean.Exceptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
@@ -22,6 +26,7 @@ import static com.yahoo.yolean.Exceptions.uncheck;
/**
* @author olaa
+ * Takes the payload received from the controller, adds external ID and acts as a proxy for the AwsParameterStoreValidationHandler result
*/
public class SecretStoreValidator {
@@ -35,22 +40,12 @@ public class SecretStoreValidator {
this.secretStore = secretStore;
}
- public HttpResponse validateSecretStore(Application application, TenantSecretStore tenantSecretStore, String tenantSecretName) {
- var slime = toSlime(tenantSecretStore, tenantSecretName);
+ public HttpResponse validateSecretStore(Application application, SystemName system, Slime slime) {
+ addExternalId(application.getId().tenant(), system, slime);
var uri = getUri(application);
return postRequest(uri, slime);
}
- private Slime toSlime(TenantSecretStore tenantSecretStore, String tenantSecretName) {
- var slime = new Slime();
- var cursor = slime.setObject();
- cursor.setString("externalId", secretStore.getSecret(tenantSecretName));
- cursor.setString("awsId", tenantSecretStore.getAwsId());
- cursor.setString("name", tenantSecretStore.getName());
- cursor.setString("role", tenantSecretStore.getRole());
- return slime;
- }
-
private URI getUri(Application application) {
var hostname = application.getModel().getHosts()
.stream()
@@ -78,4 +73,11 @@ public class SecretStoreValidator {
}
}
+ private void addExternalId(TenantName tenantName, SystemName system, Slime slime) {
+ var data = slime.get();
+ var name = data.field("name").asString();
+ var secretName = SecretStoreExternalIdRetriever.secretName(tenantName, system, name);
+ data.setString("externalId", secretStore.getSecret(secretName));
+ }
+
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
index ba2989164ee..3634a6825a3 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandler.java
@@ -29,7 +29,6 @@ import com.yahoo.vespa.config.server.http.HttpHandler;
import com.yahoo.vespa.config.server.http.JSONResponse;
import com.yahoo.vespa.config.server.http.NotFoundException;
import com.yahoo.vespa.config.server.tenant.Tenant;
-import com.yahoo.config.model.api.TenantSecretStore;
import java.io.IOException;
import java.net.URLDecoder;
@@ -47,7 +46,6 @@ import java.util.stream.Stream;
import static com.yahoo.yolean.Exceptions.uncheck;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Map.Entry.comparingByKey;
import static java.util.stream.Collectors.toList;
/**
@@ -70,7 +68,7 @@ public class ApplicationHandler extends HttpHandler {
"http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/metrics/*",
"http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/metrics/*",
"http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/logs",
- "http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/validate-secret-store/*",
+ "http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/validate-secret-store",
"http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/tester/*/*",
"http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/tester/*",
"http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*/quota",
@@ -231,9 +229,8 @@ public class ApplicationHandler extends HttpHandler {
}
if (isValidateSecretStoreRequest(request)) {
- var tenantSecretStore = tenantSecretStoreFromRequest(request);
- var tenantSecretName = tenantSecretNameFromRequest(request);
- return applicationRepository.validateSecretStore(applicationId, tenantSecretStore, tenantSecretName);
+ var slime = uncheck(() -> SlimeUtils.jsonToSlime(request.getData().readAllBytes()));
+ return applicationRepository.validateSecretStore(applicationId, zone.system(), slime);
}
throw new NotFoundException("Illegal POST request '" + request.getUri() + "'");
@@ -360,8 +357,8 @@ public class ApplicationHandler extends HttpHandler {
}
private static boolean isValidateSecretStoreRequest(HttpRequest request) {
- return getBindingMatch(request).groupCount() == 8 &&
- request.getUri().getPath().contains("/validate-secret-store/");
+ return getBindingMatch(request).groupCount() == 7 &&
+ request.getUri().getPath().endsWith("/validate-secret-store");
}
private static boolean isServiceConvergeListRequest(HttpRequest request) {
@@ -424,11 +421,6 @@ public class ApplicationHandler extends HttpHandler {
return bm.group(8);
}
- private static String tenantSecretNameFromRequest(HttpRequest req) {
- BindingMatch<?> bm = getBindingMatch(req);
- return bm.group(7);
- }
-
private static ApplicationId getApplicationIdFromRequest(HttpRequest req) {
// Two bindings for this: with full app id or only application name
BindingMatch<?> bm = getBindingMatch(req);
@@ -533,14 +525,6 @@ public class ApplicationHandler extends HttpHandler {
}
- private TenantSecretStore tenantSecretStoreFromRequest(HttpRequest httpRequest) {
- var data = uncheck(() -> SlimeUtils.jsonToSlime(httpRequest.getData().readAllBytes()).get());
- var awsId = data.field("awsId").asString();
- var name = data.field("name").asString();
- var role = data.field("role").asString();
- return new TenantSecretStore(name, awsId, role);
- }
-
private static JSONResponse createMessageResponse(String message) {
return new JSONResponse(Response.Status.OK) { { object.setString("message", message); } };
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/SecretStoreExternalIdRetriever.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/SecretStoreExternalIdRetriever.java
index cd2ae9d9d0c..0c254606169 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/SecretStoreExternalIdRetriever.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/SecretStoreExternalIdRetriever.java
@@ -25,7 +25,7 @@ public class SecretStoreExternalIdRetriever {
.collect(Collectors.toList());
}
- private static String secretName(TenantName tenant, SystemName system, String storeName) {
+ public static String secretName(TenantName tenant, SystemName system, String storeName) {
return String.format(SECRET_NAME_FORMAT, tenantSecretGroup(system), tenant.value(), storeName);
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/MockSecretStoreValidator.java b/configserver/src/test/java/com/yahoo/vespa/config/server/MockSecretStoreValidator.java
index c464af404d9..a02e8a3f3a6 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/MockSecretStoreValidator.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/MockSecretStoreValidator.java
@@ -1,9 +1,12 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server;
+import com.yahoo.config.provision.SystemName;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.container.jdisc.SecretStoreProvider;
+import com.yahoo.restapi.SlimeJsonResponse;
import com.yahoo.restapi.StringResponse;
+import com.yahoo.slime.Slime;
import com.yahoo.vespa.config.server.application.Application;
import com.yahoo.config.model.api.TenantSecretStore;
import com.yahoo.vespa.config.server.http.SecretStoreValidator;
@@ -17,7 +20,7 @@ public class MockSecretStoreValidator extends SecretStoreValidator {
super(new SecretStoreProvider().get());
}
- public HttpResponse validateSecretStore(Application application, TenantSecretStore tenantSecretStore, String tenantSecretName) {
- return new StringResponse(tenantSecretStore.toString() + " - " + tenantSecretName);
+ public HttpResponse validateSecretStore(Application application, SystemName system, Slime slime) {
+ return new SlimeJsonResponse(slime);
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/SecretStoreValidatorTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/SecretStoreValidatorTest.java
index d308cd72b55..8e5dd16bc05 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/SecretStoreValidatorTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/SecretStoreValidatorTest.java
@@ -4,9 +4,13 @@ import com.github.tomakehurst.wiremock.junit.WireMockRule;
import com.yahoo.config.model.api.HostInfo;
import com.yahoo.config.model.api.Model;
import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.container.jdisc.secretstore.SecretStore;
+import com.yahoo.slime.SlimeUtils;
import com.yahoo.vespa.config.server.application.Application;
-import com.yahoo.config.model.api.TenantSecretStore;
+import com.yahoo.vespa.config.server.tenant.SecretStoreExternalIdRetriever;
import org.junit.Rule;
import org.junit.Test;
@@ -35,20 +39,26 @@ public class SecretStoreValidatorTest {
@Test
public void createsCorrectRequestData() throws IOException {
var app = mockApplication();
- var tenantSecretStore = new TenantSecretStore("store", "123", "role");
- var tenantSecretName = "some-secret";
- when(secretStore.getSecret(tenantSecretName)).thenReturn("some-secret-value");
-
+ var requestBody = SlimeUtils.jsonToSlime("{\"awsId\":\"123\"," +
+ "\"name\":\"store\"," +
+ "\"role\":\"role\"," +
+ "\"region\":\"some-region\"," +
+ "\"parameterName\":\"some-parameter\"" +
+ "}");
+ var expectedSecretName = SecretStoreExternalIdRetriever.secretName(TenantName.defaultName(), SystemName.PublicCd, "store");
+ when(secretStore.getSecret(expectedSecretName)).thenReturn("some-secret-value");
stubFor(post(urlEqualTo("/validate-secret-store"))
- .withRequestBody(equalToJson("{\"externalId\":\"some-secret-value\"," +
- "\"awsId\":\"123\"," +
+ .withRequestBody(equalToJson("{\"awsId\":\"123\"," +
"\"name\":\"store\"," +
- "\"role\":\"role\"" +
+ "\"role\":\"role\"," +
+ "\"region\":\"some-region\"," +
+ "\"parameterName\":\"some-parameter\"," +
+ "\"externalId\":\"some-secret-value\"" +
"}"))
.willReturn(aResponse()
.withStatus(200)
.withBody("is ok")));
- var response = secretStoreValidator.validateSecretStore(app, tenantSecretStore, tenantSecretName);
+ var response = secretStoreValidator.validateSecretStore(app, SystemName.PublicCd, requestBody);
var body = new ByteArrayOutputStream();
response.render(body);
assertEquals("is ok", body.toString());
@@ -60,6 +70,7 @@ public class SecretStoreValidatorTest {
var hostList = createHostList();
when(app.getModel()).thenReturn(model);
when(model.getHosts()).thenReturn(hostList);
+ when(app.getId()).thenReturn(ApplicationId.defaultId());
return app;
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
index ab9457c5d2a..d364785f415 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/ApplicationHandlerTest.java
@@ -401,17 +401,17 @@ public class ApplicationHandlerTest {
@Test
public void testValidateSecretStore() throws IOException {
applicationRepository.deploy(new File("src/test/apps/app-logserver-with-container"), prepareParams(applicationId));
- var url = toUrlPath(applicationId, Zone.defaultZone(), true) + "/validate-secret-store/some-secret-name";
+ var url = toUrlPath(applicationId, Zone.defaultZone(), true) + "/validate-secret-store";
var mockHandler = createApplicationHandler();
- var requestData = new ByteArrayInputStream("{\"name\": \"store\", \"awsId\":\"aws-id\", \"role\":\"role\"}".getBytes(StandardCharsets.UTF_8));
+ var requestString = "{\"name\":\"store\",\"awsId\":\"aws-id\",\"role\":\"role\",\"region\":\"us-west-1\",\"parameterName\":\"some-parameter\"}";
+ var requestData = new ByteArrayInputStream(requestString.getBytes(StandardCharsets.UTF_8));
var response = mockHandler.handle(createTestRequest(url, POST, requestData));
assertEquals(200, response.getStatus());
- // MockSecretStoreValidator returns response on format tenantSecretStore.toString() - tenantSecretName
- var expectedResponse = "TenantSecretStore{name='store', awsId='aws-id', role='role'} - some-secret-name";
- assertEquals(expectedResponse, getRenderedString(response));
+ // MockSecretStoreValidator simply returns the request body
+ assertEquals(requestString, getRenderedString(response));
}
@Test
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
index 315665dbffc..ed545dc35d1 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java
@@ -151,6 +151,6 @@ public interface ConfigServer {
void setSuspension(DeploymentId deploymentId, boolean suspend);
/** Validates secret store configuration. */
- String validateSecretStore(DeploymentId deploymentId, TenantSecretStore tenantSecretStore);
+ String validateSecretStore(DeploymentId deploymentId, TenantSecretStore tenantSecretStore, String region, String parameterName);
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 4ecd972fc24..228a7bab439 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -223,7 +223,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
if (path.matches("/application/v4/tenant")) return tenants(request);
if (path.matches("/application/v4/tenant/{tenant}")) return tenant(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/info")) return tenantInfo(path.get("tenant"), request);
- if (path.matches("/application/v4/tenant/{tenant}/secret-store/{name}/validate")) return validateSecretStore(path.get("tenant"), path.get("name"));
+ if (path.matches("/application/v4/tenant/{tenant}/secret-store/{name}/region/{region}/parameter-name/{parameter-name}/validate")) return validateSecretStore(path.get("tenant"), path.get("name"), path.get("region"), path.get("parameter-name"));
if (path.matches("/application/v4/tenant/{tenant}/application")) return applications(path.get("tenant"), Optional.empty(), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return application(path.get("tenant"), path.get("application"), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/compile-version")) return compileVersion(path.get("tenant"), path.get("application"));
@@ -584,7 +584,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
}
- private HttpResponse validateSecretStore(String tenantName, String name) {
+ private HttpResponse validateSecretStore(String tenantName, String name, String region, String parameterName) {
var tenant = TenantName.from(tenantName);
if (controller.tenants().require(tenant).type() != Tenant.Type.cloud)
return ErrorResponse.badRequest("Tenant '" + tenant + "' is not a cloud tenant");
@@ -601,7 +601,7 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
if (tenantSecretStore.isEmpty())
return ErrorResponse.notFoundError("No secret store '" + name + "' configured for tenant '" + tenantName + "'");
- var response = controller.serviceRegistry().configServer().validateSecretStore(deployment.get(), tenantSecretStore.get());
+ var response = controller.serviceRegistry().configServer().validateSecretStore(deployment.get(), tenantSecretStore.get(), region, parameterName);
return new MessageResponse(response);
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
index b669e942494..a5c2176b321 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
@@ -576,7 +576,7 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer
}
@Override
- public String validateSecretStore(DeploymentId deployment, TenantSecretStore tenantSecretStore) {
+ public String validateSecretStore(DeploymentId deployment, TenantSecretStore tenantSecretStore, String region, String parameterName) {
return deployment.toString() + " - " + tenantSecretStore.toString();
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
index 4d18388dda6..84ef800b2f2 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -152,7 +152,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
@Test
public void validate_secret_store() {
var secretStoreRequest =
- request("/application/v4/tenant/scoober/secret-store/secret-foo/validate", GET)
+ request("/application/v4/tenant/scoober/secret-store/secret-foo/region/us-west-1/parameter-name/foo/validate", GET)
.roles(Set.of(Role.administrator(tenantName)));
tester.assertResponse(secretStoreRequest, "{" +
"\"error-code\":\"BAD_REQUEST\"," +
@@ -161,7 +161,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
deployApplication();
secretStoreRequest =
- request("/application/v4/tenant/scoober/secret-store/secret-foo/validate", GET)
+ request("/application/v4/tenant/scoober/secret-store/secret-foo/region/us-west-1/parameter-name/foo/validate", GET)
.roles(Set.of(Role.administrator(tenantName)));
tester.assertResponse(secretStoreRequest, "{" +
"\"error-code\":\"NOT_FOUND\"," +
@@ -175,7 +175,7 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
// ConfigServerMock returns message on format deployment.toString() + " - " + tenantSecretStore.toString()
secretStoreRequest =
- request("/application/v4/tenant/scoober/secret-store/secret-foo/validate", GET)
+ request("/application/v4/tenant/scoober/secret-store/secret-foo/region/us-west-1/parameter-name/foo/validate", GET)
.roles(Set.of(Role.administrator(tenantName)));
tester.assertResponse(secretStoreRequest, "{" +
"\"message\":\"scoober.albums in prod.us-central-1 - TenantSecretStore{name='secret-foo', awsId='123', role='some-role'}\"" +
diff --git a/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStore.java b/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStore.java
index 3e90e4ca204..48436a086ee 100644
--- a/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStore.java
+++ b/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStore.java
@@ -14,6 +14,11 @@ import com.yahoo.component.AbstractComponent;
import com.yahoo.container.jdisc.secretstore.SecretNotFoundException;
import com.yahoo.container.jdisc.secretstore.SecretStore;
import com.yahoo.container.jdisc.secretstore.SecretStoreConfig;
+import com.yahoo.slime.Cursor;
+import com.yahoo.slime.Slime;
+
+import java.util.List;
+import java.util.stream.Collectors;
/**
* @author mortent
@@ -21,32 +26,36 @@ import com.yahoo.container.jdisc.secretstore.SecretStoreConfig;
public class AwsParameterStore extends AbstractComponent implements SecretStore {
private final VespaAwsCredentialsProvider credentialsProvider;
- private final SecretStoreConfig secretStoreConfig;
+ private final List<AwsSettings> configuredStores;
@Inject
public AwsParameterStore(SecretStoreConfig secretStoreConfig) {
- this.secretStoreConfig = secretStoreConfig;
+ this(translateConfig(secretStoreConfig));
+ }
+
+ public AwsParameterStore(List<AwsSettings> configuredStores) {
+ this.configuredStores = configuredStores;
this.credentialsProvider = new VespaAwsCredentialsProvider();
}
@Override
public String getSecret(String key) {
- for (var group : secretStoreConfig.groups()) {
+ for (var store : configuredStores) {
AWSSecurityTokenService tokenService = AWSSecurityTokenServiceClientBuilder
.standard()
- .withRegion(group.region())
+ .withRegion(store.getRegion())
.withCredentials(credentialsProvider)
.build();
STSAssumeRoleSessionCredentialsProvider assumeExtAccountRole = new STSAssumeRoleSessionCredentialsProvider
- .Builder(toRoleArn(group.awsId(), group.role()), "vespa")
- .withExternalId(group.externalId())
+ .Builder(toRoleArn(store.getAwsId(), store.getRole()), "vespa")
+ .withExternalId(store.getExternalId())
.withStsClient(tokenService)
.build();
AWSSimpleSystemsManagement client = AWSSimpleSystemsManagementClient.builder()
.withCredentials(assumeExtAccountRole)
- .withRegion(group.region())
+ .withRegion(store.getRegion())
.build();
GetParametersRequest parametersRequest = new GetParametersRequest().withNames(key).withWithDecryption(true);
@@ -70,4 +79,67 @@ public class AwsParameterStore extends AbstractComponent implements SecretStore
private String toRoleArn(String awsId, String role) {
return "arn:aws:iam::" + awsId + ":role/" + role;
}
+
+ private static List<AwsSettings> translateConfig(SecretStoreConfig secretStoreConfig) {
+ return secretStoreConfig.groups()
+ .stream()
+ .map(config -> new AwsSettings(config.name(), config.role(), config.awsId(), config.externalId(), config.region()))
+ .collect(Collectors.toList());
+ }
+
+ public static class AwsSettings {
+ String name;
+ String role;
+ String awsId;
+ String externalId;
+ String region;
+
+ AwsSettings(String name, String role, String awsId, String externalId, String region) {
+ this.name = name;
+ this.role = role;
+ this.awsId = awsId;
+ this.externalId = externalId;
+ this.region = region;
+ }
+
+
+ public String getName() {
+ return name;
+ }
+
+ public String getRole() {
+ return role;
+ }
+
+ public String getAwsId() {
+ return awsId;
+ }
+
+ public String getExternalId() {
+ return externalId;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ static AwsSettings fromSlime(Slime slime) {
+ var json = slime.get();
+ return new AwsSettings(
+ json.field("name").asString(),
+ json.field("role").asString(),
+ json.field("awsId").asString(),
+ json.field("externalId").asString(),
+ json.field("region").asString()
+ );
+ }
+
+ void toSlime(Cursor slime) {
+ slime.setString("name", name);
+ slime.setString("role", role);
+ slime.setString("awsId", awsId);
+ slime.setString("externalId", "*****");
+ slime.setString("region", region);
+ }
+ }
}
diff --git a/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStoreValidationHandler.java b/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStoreValidationHandler.java
index d45ead37480..d813f04512a 100644
--- a/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStoreValidationHandler.java
+++ b/jdisc-cloud-aws/src/main/java/com/yahoo/jdisc/cloud/aws/AwsParameterStoreValidationHandler.java
@@ -8,13 +8,14 @@ import com.yahoo.container.jdisc.LoggingRequestHandler;
import com.yahoo.io.IOUtils;
import com.yahoo.restapi.ErrorResponse;
import com.yahoo.restapi.SlimeJsonResponse;
-import com.yahoo.slime.Cursor;
import com.yahoo.slime.Slime;
import com.yahoo.slime.SlimeUtils;
import com.yahoo.yolean.Exceptions;
+import com.yahoo.jdisc.cloud.aws.AwsParameterStore.AwsSettings;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -27,12 +28,10 @@ import java.util.logging.Logger;
public class AwsParameterStoreValidationHandler extends LoggingRequestHandler {
private static final Logger log = Logger.getLogger(AwsParameterStoreValidationHandler.class.getName());
- private final AwsParameterStore awsParameterStore;
@Inject
- public AwsParameterStoreValidationHandler(Context ctx, AwsParameterStore awsParameterStore) {
+ public AwsParameterStoreValidationHandler(Context ctx) {
super(ctx);
- this.awsParameterStore = awsParameterStore;
}
@Override
@@ -57,7 +56,9 @@ public class AwsParameterStoreValidationHandler extends LoggingRequestHandler {
settings.toSlime(root.setObject("settings"));
try {
- awsParameterStore.getSecret("vespa-secret");
+ var parameterName = json.get().field("parameterName").asString();
+ var store = new AwsParameterStore(List.of(settings));
+ store.getSecret(parameterName);
root.setString("status", "ok");
} catch (RuntimeException e) {
root.setString("status", "error");
@@ -78,34 +79,4 @@ public class AwsParameterStoreValidationHandler extends LoggingRequestHandler {
}
}
- private static class AwsSettings {
- String name;
- String role;
- String awsId;
- String externalId;
-
- AwsSettings(String name, String role, String awsId, String externalId) {
- this.name = name;
- this.role = role;
- this.awsId = awsId;
- this.externalId = externalId;
- }
-
- static AwsSettings fromSlime(Slime slime) {
- var json = slime.get();
- return new AwsSettings(
- json.field("name").asString(),
- json.field("role").asString(),
- json.field("awsId").asString(),
- json.field("externalId").asString()
- );
- }
-
- void toSlime(Cursor slime) {
- slime.setString("name", name);
- slime.setString("role", role);
- slime.setString("awsId", awsId);
- slime.setString("externalId", "*****");
- }
- }
-}
+} \ No newline at end of file