summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHÃ¥kon Hallingstad <hakon@oath.com>2019-01-12 02:35:34 +0100
committerGitHub <noreply@github.com>2019-01-12 02:35:34 +0100
commit028fd60d61854d074d2d8e5a4fb8b416abc7a62c (patch)
tree9101d9a996ebc8f330ad357f9eb309745bd69fe9
parent9ba701cbecf1d7ac6e28fe102041c5b942b6acf8 (diff)
parentd0d4ecb80ea2bed27cddf3cead54f1d33ab70095 (diff)
Merge pull request #8113 from vespa-engine/hakonhall/authorization-of-flagsv1
Authorization of /flags/v1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/Authorizer.java46
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/AuthorizerTest.java24
2 files changed, 51 insertions, 19 deletions
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/Authorizer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/Authorizer.java
index 95f69dc1c2a..6225a8a4fc4 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/Authorizer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/Authorizer.java
@@ -24,32 +24,52 @@ import java.util.stream.Collectors;
/**
* Authorizer for config server REST APIs. This contains the rules for all API paths where the authorization process
- * requires information from the node-repository to make a decision
+ * may require information from the node-repository to make a decision
*
* @author mpolden
* @author bjorncs
*/
public class Authorizer implements BiPredicate<NodePrincipal, URI> {
-
private final NodeRepository nodeRepository;
private final Set<String> whitelistedHostnames;
+ private final AthenzIdentity controllerIdentity;
+ private final AthenzIdentity configServerIdentity = new AthenzService("vespa.vespa", "configserver");
+ private final AthenzIdentity proxyIdentity = new AthenzService("vespa.vespa", "proxy");
+ private final AthenzIdentity tenantIdentity = new AthenzService("vespa.vespa", "tenant-host");
private final Set<AthenzIdentity> trustedIdentities;
+ private final Set<AthenzIdentity> hostAdminIdentities;
// TODO Remove whitelisted hostnames as these nodes should be included through 'trustedIdentities'
public Authorizer(SystemName system, NodeRepository nodeRepository, Set<String> whitelistedHostnames) {
this.nodeRepository = nodeRepository;
this.whitelistedHostnames = whitelistedHostnames;
- this.trustedIdentities = getTrustedIdentities(system);
+ controllerIdentity = system == SystemName.main
+ ? new AthenzService("vespa.vespa", "hosting")
+ : new AthenzService("vespa.vespa.cd", "hosting");
+ this.trustedIdentities = new HashSet<>(Arrays.asList(controllerIdentity, configServerIdentity));
+ this.hostAdminIdentities = new HashSet<>(Arrays.asList(controllerIdentity, configServerIdentity, proxyIdentity, tenantIdentity));
}
/** Returns whether principal is authorized to access given URI */
@Override
public boolean test(NodePrincipal principal, URI uri) {
- // Trusted services can access everything
- if (principal.getAthenzIdentityName().isPresent()
- && trustedIdentities.contains(principal.getAthenzIdentityName().get())) {
- return true;
+ if (principal.getAthenzIdentityName().isPresent()) {
+ // All host admins can retrieve flags data
+ if (uri.getPath().equals("/flags/v1/data") || uri.getPath().equals("/flags/v1/data/")) {
+ return hostAdminIdentities.contains(principal.getAthenzIdentityName().get());
+ }
+
+ // Only controller can access everything else in flags
+ if (uri.getPath().startsWith("/flags/v1/")) {
+ return principal.getAthenzIdentityName().get().equals(controllerIdentity);
+ }
+
+ // Trusted services can access everything
+ if (trustedIdentities.contains(principal.getAthenzIdentityName().get())) {
+ return true;
+ }
}
+
if (principal.getHostname().isPresent()) {
String hostname = principal.getHostname().get();
if (isAthenzProviderApi(uri)) {
@@ -108,18 +128,6 @@ public class Authorizer implements BiPredicate<NodePrincipal, URI> {
return !resources.isEmpty() && resources.stream().anyMatch(resource -> predicate.test(resource, principal));
}
-
- private static Set<AthenzIdentity> getTrustedIdentities(SystemName system) {
- Set<AthenzIdentity> trustedIdentities = new HashSet<>();
- trustedIdentities.add(new AthenzService("vespa.vespa", "configserver"));
- AthenzService controllerIdentity =
- system == SystemName.main
- ? new AthenzService("vespa.vespa", "hosting")
- : new AthenzService("vespa.vespa.cd", "hosting");
- trustedIdentities.add(controllerIdentity);
- return trustedIdentities;
- }
-
private Optional<Node> getNode(String hostname) {
// Ignore potential path traversal. Node repository happily passes arguments unsanitized all the way down to
// curator...
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/AuthorizerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/AuthorizerTest.java
index 38128e66861..5e643bd09ab 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/AuthorizerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/filter/AuthorizerTest.java
@@ -139,6 +139,30 @@ public class AuthorizerTest {
}
@Test
+ public void flags_authorization() {
+ // Tenant nodes cannot access flags resources
+ assertFalse(authorizedTenantNode("node1", "/flags/v1/data"));
+ assertFalse(authorizedTenantNode("node1", "/flags/v1/data/flagid"));
+ assertFalse(authorizedTenantNode("node1", "/flags/v1/foo"));
+
+ // Host node can access data
+ assertTrue(authorizedTenantHostNode("host1", "/flags/v1/data"));
+ assertFalse(authorizedTenantHostNode("host1", "/flags/v1/data/flagid"));
+ assertFalse(authorizedTenantHostNode("host1", "/flags/v1/foo"));
+ assertTrue(authorizedTenantHostNode("proxy1-host", "/flags/v1/data"));
+ assertFalse(authorizedTenantHostNode("proxy1-host", "/flags/v1/data/flagid"));
+ assertFalse(authorizedTenantHostNode("proxy1-host", "/flags/v1/foo"));
+ assertTrue(authorizedController("vespa.vespa.configserver", "/flags/v1/data"));
+ assertFalse(authorizedController("vespa.vespa.configserver", "/flags/v1/data/flagid"));
+ assertFalse(authorizedController("vespa.vespa.configserver", "/flags/v1/foo"));
+
+ // Controller can access everything
+ assertTrue(authorizedController("vespa.vespa.hosting", "/flags/v1/data"));
+ assertTrue(authorizedController("vespa.vespa.hosting", "/flags/v1/data/flagid"));
+ assertTrue(authorizedController("vespa.vespa.hosting", "/flags/v1/foo"));
+ }
+
+ @Test
public void routing_authorization() {
// Node of proxy or proxyhost type can access routing resource
assertFalse(authorizedTenantNode("node1", "/routing/v1/status"));