diff options
2 files changed, 83 insertions, 45 deletions
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 415a087d990..11cace3b10e 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 @@ -26,11 +26,11 @@ public class AthenzAccessControlService implements AccessControlService { private final ZmsClient zmsClient; private final AthenzRole dataPlaneAccessRole; private final AthenzGroup vespaTeam; - private final ZmsClient vespaZmsClient; //TODO: Merge ZMS clients + private final Optional<ZmsClient> vespaZmsClient; private final AthenzInstanceSynchronizer athenzInstanceSynchronizer; - public AthenzAccessControlService(ZmsClient zmsClient, AthenzDomain domain, ZmsClient vespaZmsClient, AthenzInstanceSynchronizer athenzInstanceSynchronizer) { + public AthenzAccessControlService(ZmsClient zmsClient, AthenzDomain domain, Optional<ZmsClient> vespaZmsClient, AthenzInstanceSynchronizer athenzInstanceSynchronizer) { this.zmsClient = zmsClient; this.vespaZmsClient = vespaZmsClient; this.athenzInstanceSynchronizer = athenzInstanceSynchronizer; @@ -66,11 +66,16 @@ public class AthenzAccessControlService implements AccessControlService { */ @Override public AthenzRoleInformation getAccessRoleInformation(TenantName tenantName) { - var role = sshRole(tenantName); - if (!vespaZmsClient.listRoles(role.domain()).contains(role)) - vespaZmsClient.createRole(role, Map.of()); + return vespaZmsClient.map( + zms -> { + var role = sshRole(tenantName); + if (!zms.listRoles(role.domain()).contains(role)) + zms.createRole(role, Map.of()); + + return zms.getFullRoleInformation(role); + } + ).orElseThrow(() -> new UnsupportedOperationException("Only allowed in systems running Vespa Athenz instance")); - return vespaZmsClient.getFullRoleInformation(role); } /** @@ -78,22 +83,25 @@ public class AthenzAccessControlService implements AccessControlService { */ @Override public boolean decideSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials, boolean approve) { - var role = sshRole(tenantName); - - if (!vespaZmsClient.listRoles(role.domain()).contains(role)) - vespaZmsClient.createRole(role, Map.of()); - - if (vespaZmsClient.getMembership(role, vespaTeam)) - return false; - - var roleInformation = vespaZmsClient.getFullRoleInformation(role); - if (roleInformation.getPendingRequest().isEmpty()) - return false; - var reason = roleInformation.getPendingRequest().get().getReason(); - - vespaZmsClient.decidePendingRoleMembership(role, vespaTeam, expiry, Optional.of(reason), Optional.of(oAuthCredentials), approve); - athenzInstanceSynchronizer.synchronizeInstances(tenantName); - return true; + return vespaZmsClient.map( + zms -> { + var role = sshRole(tenantName); + if (!zms.listRoles(role.domain()).contains(role)) + zms.createRole(role, Map.of()); + + if (zms.getMembership(role, vespaTeam)) + return false; + + var roleInformation = zms.getFullRoleInformation(role); + if (roleInformation.getPendingRequest().isEmpty()) + return false; + var reason = roleInformation.getPendingRequest().get().getReason(); + + zms.decidePendingRoleMembership(role, vespaTeam, expiry, Optional.of(reason), Optional.of(oAuthCredentials), approve); + athenzInstanceSynchronizer.synchronizeInstances(tenantName); + return true; + } + ).orElseThrow(() -> new UnsupportedOperationException("Only allowed in systems running Vespa Athenz instance")); } /** @@ -101,40 +109,44 @@ public class AthenzAccessControlService implements AccessControlService { */ @Override public boolean requestSshAccess(TenantName tenantName) { - var role = sshRole(tenantName); + return vespaZmsClient.map( + zms -> { + var role = sshRole(tenantName); - if (!vespaZmsClient.listRoles(role.domain()).contains(role)) - vespaZmsClient.createRole(role, Map.of()); + if (!zms.listRoles(role.domain()).contains(role)) + zms.createRole(role, Map.of()); - if (vespaZmsClient.getMembership(role, vespaTeam)) - return false; + if (zms.getMembership(role, vespaTeam)) + return false; - vespaZmsClient.addRoleMember(role, vespaTeam, Optional.empty()); - return true; + zms.addRoleMember(role, vespaTeam, Optional.empty()); + return true; + } + ).orElseThrow(() -> new UnsupportedOperationException("Only allowed in systems running Vespa Athenz instance")); } 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); + vespaZmsClient.ifPresentOrElse( + zms -> { + var role = sshRole(tenantName); + + var policyName = "vespa-access-requester"; + var action = "update_members"; + var approverRole = new AthenzRole(role.domain(), "vespa-access-approver"); + if (preapprovedAccess) { + zms.addPolicyRule(role.domain(), policyName, action, role.toResourceName(), approverRole); + } else { + zms.deletePolicyRule(role.domain(), policyName, action, role.toResourceName(), approverRole); + } + },() -> { throw new UnsupportedOperationException("Only allowed in systems running Vespa Athenz instance"); }); } private AthenzRole sshRole(TenantName tenantName) { - return new AthenzRole(getOrCreateTenantDomain(tenantName), "ssh_access"); + return new AthenzRole(getTenantDomain(tenantName), "ssh_access"); } - private AthenzDomain getOrCreateTenantDomain(TenantName tenantName) { - var domain = new AthenzDomain(TENANT_DOMAIN_PREFIX + "." + tenantName.value()); - - if (vespaZmsClient.getDomainList(domain.getName()).isEmpty()) { - vespaZmsClient.createSubdomain(new AthenzDomain(TENANT_DOMAIN_PREFIX), tenantName.value()); - } - - return domain; + private AthenzDomain getTenantDomain(TenantName tenantName) { + return new AthenzDomain(TENANT_DOMAIN_PREFIX + "." + tenantName.value()); } public boolean isVespaTeamMember(AthenzUser user) { diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java index 44271846d7d..63dfff95c03 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java @@ -135,6 +135,19 @@ public class AthenzDbMock { public boolean matches(AthenzIdentity principal, String action, String resource) { return assertions.stream().anyMatch(a -> a.matches(principal, action, resource)); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Policy policy = (Policy) o; + return Objects.equals(name, policy.name) && Objects.equals(assertions, policy.assertions); + } + + @Override + public int hashCode() { + return Objects.hash(name, assertions); + } } public static class Assertion { @@ -192,5 +205,18 @@ public class AthenzDbMock { public String name() { return name; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Role role = (Role) o; + return Objects.equals(name, role.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } } } |