diff options
author | Ola Aunrønning <olaa@verizonmedia.com> | 2022-03-07 09:25:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-07 09:25:20 +0100 |
commit | 5ead84bb17aa1ebb39d934d9b74d2d6ef758d566 (patch) | |
tree | a07192f1d6dc8d9ca8102fef5ec79c93f7a560e1 /controller-api | |
parent | 2e05df2de19c2d5b87befa2ee6c4fd182dcb5630 (diff) | |
parent | 810de0a30b9dc658769deb21c5579f88afdbd528 (diff) |
Merge pull request #21480 from vespa-engine/olaa/athenz-synchronization
Synchronize athenz instances on request approval
Diffstat (limited to 'controller-api')
6 files changed, 77 insertions, 17 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..1dd6eb543ef 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 @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.api.integration.athenz; import com.yahoo.config.provision.TenantName; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OAuthCredentials; @@ -16,8 +17,9 @@ import java.util.Collection; */ public interface AccessControlService { boolean approveDataPlaneAccess(AthenzUser user, Instant expiry); - boolean approveSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials); + boolean decideSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials, boolean approve); boolean requestSshAccess(TenantName tenantName); - boolean hasPendingAccessRequests(TenantName tenantName); + AthenzRoleInformation getAccessRoleInformation(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 0568678219e..415a087d990 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 @@ -7,6 +7,7 @@ import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.athenz.api.AthenzGroup; import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzRole; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OAuthCredentials; import com.yahoo.vespa.athenz.client.zms.ZmsClient; @@ -26,11 +27,13 @@ public class AthenzAccessControlService implements AccessControlService { private final AthenzRole dataPlaneAccessRole; private final AthenzGroup vespaTeam; private final ZmsClient vespaZmsClient; //TODO: Merge ZMS clients + private final AthenzInstanceSynchronizer athenzInstanceSynchronizer; - public AthenzAccessControlService(ZmsClient zmsClient, AthenzDomain domain, ZmsClient vespaZmsClient) { + public AthenzAccessControlService(ZmsClient zmsClient, AthenzDomain domain, ZmsClient vespaZmsClient, AthenzInstanceSynchronizer athenzInstanceSynchronizer) { this.zmsClient = zmsClient; this.vespaZmsClient = vespaZmsClient; + this.athenzInstanceSynchronizer = athenzInstanceSynchronizer; this.dataPlaneAccessRole = new AthenzRole(domain, DATAPLANE_ACCESS_ROLENAME); this.vespaTeam = new AthenzGroup(domain, ALLOWED_OPERATOR_GROUPNAME); } @@ -43,7 +46,7 @@ public class AthenzAccessControlService implements AccessControlService { } Map<AthenzIdentity, String> users = zmsClient.listPendingRoleApprovals(dataPlaneAccessRole); if (users.containsKey(user)) { - zmsClient.approvePendingRoleMembership(dataPlaneAccessRole, user, expiry, Optional.empty(), Optional.empty()); + zmsClient.decidePendingRoleMembership(dataPlaneAccessRole, user, expiry, Optional.empty(), Optional.empty(), true); return true; } return false; @@ -62,19 +65,19 @@ public class AthenzAccessControlService implements AccessControlService { * @return Whether the ssh access role has any pending role membership requests */ @Override - public boolean hasPendingAccessRequests(TenantName tenantName) { + public AthenzRoleInformation getAccessRoleInformation(TenantName tenantName) { var role = sshRole(tenantName); if (!vespaZmsClient.listRoles(role.domain()).contains(role)) - return false; - var pendingApprovals = vespaZmsClient.listPendingRoleApprovals(role); - return pendingApprovals.containsKey(vespaTeam); + vespaZmsClient.createRole(role, Map.of()); + + return vespaZmsClient.getFullRoleInformation(role); } /** * @return true if access has been granted - false if already member */ @Override - public boolean approveSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials) { + public boolean decideSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials, boolean approve) { var role = sshRole(tenantName); if (!vespaZmsClient.listRoles(role.domain()).contains(role)) @@ -83,10 +86,13 @@ public class AthenzAccessControlService implements AccessControlService { if (vespaZmsClient.getMembership(role, vespaTeam)) return false; - if (!hasPendingAccessRequests(tenantName)) { - vespaZmsClient.addRoleMember(role, vespaTeam, Optional.empty()); - } - vespaZmsClient.approvePendingRoleMembership(role, vespaTeam, expiry, Optional.empty(), Optional.of(oAuthCredentials)); + 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; } @@ -107,6 +113,16 @@ public class AthenzAccessControlService implements AccessControlService { return true; } + 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/AthenzInstanceSynchronizer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizer.java new file mode 100644 index 00000000000..3b9166d4363 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizer.java @@ -0,0 +1,15 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.athenz; + +import com.yahoo.config.provision.TenantName; + +/** + * @author olaa + * + * Responsible for synchronizing misc roles and their pending memberships between separate Athenz instances + */ +public interface AthenzInstanceSynchronizer { + + void synchronizeInstances(TenantName tenant); + +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizerMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizerMock.java new file mode 100644 index 00000000000..1f0403a0b44 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzInstanceSynchronizerMock.java @@ -0,0 +1,12 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration.athenz; + +import com.yahoo.config.provision.TenantName; + +/** + * @author olaa + */ +public class AthenzInstanceSynchronizerMock implements AthenzInstanceSynchronizer { + @Override + public void synchronizeInstances(TenantName tenant) {} +} 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..c14ca2bdc80 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 @@ -3,12 +3,16 @@ package com.yahoo.vespa.hosted.controller.api.integration.athenz; import com.yahoo.config.provision.TenantName; +import com.yahoo.vespa.athenz.api.AthenzDomain; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzUser; import com.yahoo.vespa.athenz.api.OAuthCredentials; import java.time.Instant; import java.util.Collection; import java.util.HashSet; +import java.util.List; +import java.util.Optional; import java.util.Set; public class MockAccessControlService implements AccessControlService { @@ -31,7 +35,7 @@ public class MockAccessControlService implements AccessControlService { } @Override - public boolean approveSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials) { + public boolean decideSshAccess(TenantName tenantName, Instant expiry, OAuthCredentials oAuthCredentials, boolean approve) { return false; } @@ -41,8 +45,13 @@ public class MockAccessControlService implements AccessControlService { } @Override - public boolean hasPendingAccessRequests(TenantName tenantName) { - return false; + public AthenzRoleInformation getAccessRoleInformation(TenantName tenantName) { + return new AthenzRoleInformation(new AthenzDomain("test-domain"), "tenant-role", false, false, Optional.empty(), List.of()); + } + + @Override + public void setPreapprovedAccess(TenantName tenantName, boolean preapproved) { + } public void addPendingMember(AthenzUser 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..5f567e8b84a 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 @@ -8,6 +8,7 @@ import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.athenz.api.AthenzPolicy; import com.yahoo.vespa.athenz.api.AthenzResourceName; import com.yahoo.vespa.athenz.api.AthenzRole; +import com.yahoo.vespa.athenz.api.AthenzRoleInformation; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.api.OAuthCredentials; import com.yahoo.vespa.athenz.client.zms.RoleAction; @@ -201,7 +202,7 @@ public class ZmsClientMock implements ZmsClient { } @Override - public void approvePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials) { + public void decidePendingRoleMembership(AthenzRole athenzRole, AthenzIdentity athenzIdentity, Instant expiry, Optional<String> reason, Optional<OAuthCredentials> oAuthCredentials, boolean approve) { } @Override @@ -256,6 +257,11 @@ public class ZmsClientMock implements ZmsClient { public void createSubdomain(AthenzDomain parent, String name) {} @Override + public AthenzRoleInformation getFullRoleInformation(AthenzRole role) { + return new AthenzRoleInformation(role.domain(), role.roleName(), true, true, Optional.empty(), List.of()); + } + + @Override public void close() {} private static AthenzDomain getTenantDomain(AthenzResourceName resource) { |