summaryrefslogtreecommitdiffstats
path: root/athenz-identity-provider-service/src
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2019-08-26 15:15:53 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2019-08-26 15:15:53 +0200
commitaca45ba95c5fb0b7d9c1fe89ee3a866ff65c76ac (patch)
tree457edb12eda58d61feab5812fe4ebed72763b6e9 /athenz-identity-provider-service/src
parentf49fbf259ea28bf3025580f875885762f12dc651 (diff)
Include instance hostname in Athenz node certificates
Diffstat (limited to 'athenz-identity-provider-service/src')
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmation.java7
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java29
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java46
3 files changed, 76 insertions, 6 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmation.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmation.java
index e6dd40faaca..24998a49faf 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmation.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmation.java
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
/**
* InstanceConfirmation object as per Athenz InstanceConfirmation API.
@@ -28,6 +29,8 @@ import java.util.Objects;
*/
public class InstanceConfirmation {
+ static final String HOSTNAME_ATTRIBUTE = "hostname";
+
@JsonProperty("provider") public final String provider;
@JsonProperty("domain") public final String domain;
@JsonProperty("service") public final String service;
@@ -53,6 +56,10 @@ public class InstanceConfirmation {
attributes.put(name, value);
}
+ public Optional<String> getInstanceHostname() {
+ return Optional.ofNullable(attributes.get(HOSTNAME_ATTRIBUTE));
+ }
+
@Override
public String toString() {
return "InstanceConfirmation{" +
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java
index f1a93e58526..54611172b57 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java
@@ -10,6 +10,7 @@ import com.yahoo.config.provision.ApplicationId;
import com.yahoo.log.LogLevel;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper;
+import com.yahoo.vespa.athenz.identityprovider.api.IdentityType;
import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument;
import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId;
import com.yahoo.vespa.athenz.identityprovider.client.IdentityDocumentSigner;
@@ -158,6 +159,34 @@ public class InstanceValidator {
log.log(LogLevel.WARNING, "Invalid InstanceConfirmation, wrong ip in : " + vespaUniqueInstanceId);
return false;
}
+
+ // Validate hostname
+ boolean hasValidHostname =
+ confirmation.getInstanceHostname()
+ .map(requestHostname -> validateHostname(vespaUniqueInstanceId, node, requestHostname))
+ .orElse(true);
+ if (!hasValidHostname) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static boolean validateHostname(VespaUniqueInstanceId vespaUniqueInstanceId, Node node, String requestedHostname) {
+ String nodeHostname = node.hostname();
+ if (vespaUniqueInstanceId.type() == IdentityType.TENANT) {
+ log.log(LogLevel.WARNING, "Instance hostname not allowed in tenant certificates");
+ return false;
+ }
+ if (!nodeHostname.equals(requestedHostname)) {
+ log.log(LogLevel.WARNING,
+ String.format(
+ "Invalid instance confirmation: request instance hostname is '%s', but node repository has '%s'",
+ requestedHostname,
+ nodeHostname));
+
+ return false;
+ }
return true;
}
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java
index d5787516254..89ca24f3e93 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidatorTest.java
@@ -1,7 +1,6 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.athenz.instanceproviderservice.instanceconfirmation;
-import com.google.common.collect.ImmutableList;
import com.yahoo.component.Version;
import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.HostInfo;
@@ -123,7 +122,7 @@ public class InstanceValidatorTest {
nodeList = allocateNode(nodeList, node, applicationId);
when(nodeRepository.getNodes()).thenReturn(nodeList);
String nodeIp = node.ipAddresses().stream().findAny().orElseThrow(() -> new RuntimeException("No ipaddress for mocked node"));
- InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, ImmutableList.of(nodeIp));
+ InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, IdentityType.NODE, node.hostname(), List.of(nodeIp));
assertTrue(instanceValidator.isValidRefresh(instanceConfirmation));
}
@@ -140,7 +139,41 @@ public class InstanceValidatorTest {
String nodeIp = node.ipAddresses().stream().findAny().orElseThrow(() -> new RuntimeException("No ipaddress for mocked node"));
// Add invalid ip to list of ip addresses
- InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, ImmutableList.of(nodeIp, "::ff"));
+ InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, IdentityType.NODE, node.hostname(), List.of(nodeIp, "::ff"));
+
+ assertFalse(instanceValidator.isValidRefresh(instanceConfirmation));
+ }
+
+ @Test
+ public void rejects_invalid_hostname() {
+ NodeRepository nodeRepository = mock(NodeRepository.class);
+ InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository);
+
+ List<Node> nodeList = createNodes(10);
+ Node node = nodeList.get(0);
+ nodeList = allocateNode(nodeList, node, applicationId);
+ when(nodeRepository.getNodes()).thenReturn(nodeList);
+ String nodeIp = node.ipAddresses().stream().findAny().orElseThrow(() -> new RuntimeException("No ipaddress for mocked node"));
+
+ // Add invalid ip to list of ip addresses
+ InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, IdentityType.NODE, "invalidhostname", List.of(nodeIp));
+
+ assertFalse(instanceValidator.isValidRefresh(instanceConfirmation));
+ }
+
+ @Test
+ public void rejects_hostname_for_tenant_certificates() {
+ NodeRepository nodeRepository = mock(NodeRepository.class);
+ InstanceValidator instanceValidator = new InstanceValidator(null, null, nodeRepository);
+
+ List<Node> nodeList = createNodes(10);
+ Node node = nodeList.get(0);
+ nodeList = allocateNode(nodeList, node, applicationId);
+ when(nodeRepository.getNodes()).thenReturn(nodeList);
+ String nodeIp = node.ipAddresses().stream().findAny().orElseThrow(() -> new RuntimeException("No ipaddress for mocked node"));
+
+ // Add invalid ip to list of ip addresses
+ InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, IdentityType.TENANT, node.hostname(), List.of(nodeIp));
assertFalse(instanceValidator.isValidRefresh(instanceConfirmation));
}
@@ -152,7 +185,7 @@ public class InstanceValidatorTest {
List<Node> nodeList = createNodes(10);
when(nodeRepository.getNodes()).thenReturn(nodeList);
- InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, ImmutableList.of("::11"));
+ InstanceConfirmation instanceConfirmation = createRefreshInstanceConfirmation(applicationId, domain, service, IdentityType.NODE, nodeList.get(0).hostname(), List.of("::11"));
assertFalse(instanceValidator.isValidRefresh(instanceConfirmation));
@@ -173,10 +206,11 @@ public class InstanceValidatorTest {
return createInstanceConfirmation(vespaUniqueInstanceId, domain, service, signedIdentityDocument);
}
- private InstanceConfirmation createRefreshInstanceConfirmation(ApplicationId applicationId, String domain, String service, List<String> ips) {
- VespaUniqueInstanceId vespaUniqueInstanceId = new VespaUniqueInstanceId(0, "default", applicationId.instance().value(), applicationId.application().value(), applicationId.tenant().value(), "us-north-1", "dev", IdentityType.NODE);
+ private InstanceConfirmation createRefreshInstanceConfirmation(ApplicationId applicationId, String domain, String service, IdentityType identityType, String hostname, List<String> ips) {
+ VespaUniqueInstanceId vespaUniqueInstanceId = new VespaUniqueInstanceId(0, "default", applicationId.instance().value(), applicationId.application().value(), applicationId.tenant().value(), "us-north-1", "dev", identityType);
InstanceConfirmation instanceConfirmation = createInstanceConfirmation(vespaUniqueInstanceId, domain, service, null);
instanceConfirmation.set("sanIP", String.join(",", ips));
+ instanceConfirmation.set(InstanceConfirmation.HOSTNAME_ATTRIBUTE, hostname);
return instanceConfirmation;
}