aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java19
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java10
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java25
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java11
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java2
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java17
8 files changed, 89 insertions, 2 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java
index a08319055ff..b270c27092f 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AccessControlService.java
@@ -19,5 +19,7 @@ public interface AccessControlService {
boolean approveSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials);
boolean requestSshAccess(TenantName tenantName);
boolean hasPendingAccessRequests(TenantName tenantName);
+ boolean hasPreapprovedAccess(TenantName tenantName);
+ void setPreapprovedAccess(TenantName tenantName, boolean preapproved);
Collection<AthenzUser> listMembers();
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java
index a3f789149cf..6b91f49af8e 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzAccessControlService.java
@@ -110,6 +110,25 @@ public class AthenzAccessControlService implements AccessControlService {
return true;
}
+ public boolean hasPreapprovedAccess(TenantName tenantName) {
+ var role = sshRole(tenantName);
+
+ if (!vespaZmsClient.listRoles(role.domain()).contains(role))
+ return true; // true by default
+
+ return !vespaZmsClient.isSelfServeRole(role);
+ }
+
+ public void setPreapprovedAccess(TenantName tenantName, boolean preapprovedAccess) {
+ var role = sshRole(tenantName);
+
+ var attributes = Map.<String, Object>of(
+ "selfServe", !preapprovedAccess,
+ "reviewEnabled", !preapprovedAccess
+ );
+ vespaZmsClient.createRole(role, attributes);
+ }
+
private AthenzRole sshRole(TenantName tenantName) {
return new AthenzRole(getOrCreateTenantDomain(tenantName), "ssh_access");
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java
index b8106450705..505ee97bdf5 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/MockAccessControlService.java
@@ -45,6 +45,16 @@ public class MockAccessControlService implements AccessControlService {
return false;
}
+ @Override
+ public boolean hasPreapprovedAccess(TenantName tenantName) {
+ return false;
+ }
+
+ @Override
+ public void setPreapprovedAccess(TenantName tenantName, boolean preapproved) {
+
+ }
+
public void addPendingMember(AthenzUser user) {
pendingMembers.add(user);
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
index 38b2a36a348..62a999bb7a6 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
@@ -256,6 +256,11 @@ public class ZmsClientMock implements ZmsClient {
public void createSubdomain(AthenzDomain parent, String name) {}
@Override
+ public boolean isSelfServeRole(AthenzRole role) {
+ return false;
+ }
+
+ @Override
public void close() {}
private static AthenzDomain getTenantDomain(AthenzResourceName resource) {
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 673581b3626..3bcf62fde21 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
@@ -294,6 +294,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
if (path.matches("/application/v4/tenant/{tenant}")) return updateTenant(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/access/request/operator")) return requestSshAccess(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/access/approve/operator")) return approveAccessRequest(path.get("tenant"), request);
+ if (path.matches("/application/v4/tenant/{tenant}/access/preapprove/operator")) return addPreapprovedAccess(path.get("tenant"));
if (path.matches("/application/v4/tenant/{tenant}/info")) return updateTenantInfo(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/archive-access")) return allowArchiveAccess(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/secret-store/{name}")) return addSecretStore(path.get("tenant"), path.get("name"), request);
@@ -341,6 +342,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
private HttpResponse handleDELETE(Path path, HttpRequest request) {
if (path.matches("/application/v4/tenant/{tenant}")) return deleteTenant(path.get("tenant"), request);
+ if (path.matches("/application/v4/tenant/{tenant}/access/preapprove/operator")) return removePreapprovedAccess(path.get("tenant"));
if (path.matches("/application/v4/tenant/{tenant}/key")) return removeDeveloperKey(path.get("tenant"), request);
if (path.matches("/application/v4/tenant/{tenant}/archive-access")) return removeArchiveAccess(path.get("tenant"));
if (path.matches("/application/v4/tenant/{tenant}/secret-store/{name}")) return deleteSecretStore(path.get("tenant"), path.get("name"), request);
@@ -414,9 +416,12 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
if (controller.tenants().require(TenantName.from(tenantName)).type() != Tenant.Type.cloud)
return ErrorResponse.badRequest("Can only see access requests for cloud tenants");
- var pendingRequests = controller.serviceRegistry().accessControlService().hasPendingAccessRequests(TenantName.from(tenantName));
+ var accessControlService = controller.serviceRegistry().accessControlService();
+ var pendingRequests = accessControlService.hasPendingAccessRequests(TenantName.from(tenantName));
+ var preapprovedAccess = accessControlService.hasPreapprovedAccess(TenantName.from(tenantName));
var slime = new Slime();
slime.setObject().setBool("hasPendingRequests", pendingRequests);
+ slime.setObject().setBool("preapprovedAccess", preapprovedAccess);
return new SlimeJsonResponse(slime);
}
@@ -448,6 +453,24 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
return new MessageResponse("OK");
}
+ private HttpResponse addPreapprovedAccess(String tenantName) {
+ return setPreapprovedAccess(tenantName, true);
+ }
+
+ private HttpResponse removePreapprovedAccess(String tenantName) {
+ return setPreapprovedAccess(tenantName, false);
+ }
+
+ private HttpResponse setPreapprovedAccess(String tenantName, boolean preapprovedAccess) {
+ var tenant = TenantName.from(tenantName);
+
+ if (controller.tenants().require(tenant).type() != Tenant.Type.cloud)
+ return ErrorResponse.badRequest("Can only set access privel for cloud tenants");
+
+ controller.serviceRegistry().accessControlService().setPreapprovedAccess(tenant, preapprovedAccess);
+ return new MessageResponse("OK");
+ }
+
private HttpResponse tenantInfo(String tenantName, HttpRequest request) {
return controller.tenants().get(TenantName.from(tenantName))
.filter(tenant -> tenant.type() == Tenant.Type.cloud)
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java
index 32f54255262..23c530402b9 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java
@@ -406,6 +406,17 @@ public class DefaultZmsClient extends ClientBase implements ZmsClient {
execute(request, response -> readEntity(response, Void.class));
}
+ public boolean isSelfServeRole(AthenzRole role) {
+ URI uri = zmsUrl.resolve(String.format("domain/%s/role/%s", role.domain().getName(), role.roleName()));
+ var request = RequestBuilder.get(uri).build();
+ var roleEntity = execute(request, response -> readEntity(response, RoleEntity.class));
+
+ if (roleEntity.selfServe() == null || roleEntity.reviewEnabled() == null)
+ return false;
+
+ return roleEntity.selfServe() && roleEntity.reviewEnabled();
+ }
+
private static Header createCookieHeader(OAuthCredentials oAuthCredentials) {
return new BasicHeader("Cookie", oAuthCredentials.asCookie());
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java
index 95b7d9b8976..611fe7aa451 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java
@@ -80,5 +80,7 @@ public interface ZmsClient extends AutoCloseable {
void createSubdomain(AthenzDomain parent, String name);
+ boolean isSelfServeRole(AthenzRole role);
+
void close();
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java
index 28b1f5d3206..f0a498ed644 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/bindings/RoleEntity.java
@@ -15,11 +15,18 @@ import java.util.List;
public class RoleEntity {
private final String roleName;
private final List<Member> roleMembers;
+ private final Boolean selfServe;
+ private final Boolean reviewEnabled;
@JsonCreator
- public RoleEntity(@JsonProperty("roleName") String roleName, @JsonProperty("roleMembers") List<Member> roleMembers) {
+ public RoleEntity(@JsonProperty("roleName") String roleName,
+ @JsonProperty("roleMembers") List<Member> roleMembers,
+ @JsonProperty("selfServe") Boolean selfServe,
+ @JsonProperty("reviewEnabled") Boolean reviewEnabled) {
this.roleName = roleName;
this.roleMembers = roleMembers;
+ this.selfServe = selfServe;
+ this.reviewEnabled = reviewEnabled;
}
public String roleName() {
@@ -30,6 +37,14 @@ public class RoleEntity {
return roleMembers;
}
+ public Boolean selfServe() {
+ return selfServe;
+ }
+
+ public Boolean reviewEnabled() {
+ return reviewEnabled;
+ }
+
@JsonIgnoreProperties(ignoreUnknown = true)
public static final class Member {
private final String memberName;