summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmationResource.java3
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceRefreshResource.java44
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceValidator.java11
-rw-r--r--node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java9
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java11
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClientException.java22
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/ErrorResponseEntity.java23
7 files changed, 111 insertions, 12 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmationResource.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmationResource.java
index 4c71cb7855d..7a4e82d134b 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmationResource.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceConfirmationResource.java
@@ -16,7 +16,7 @@ import java.util.logging.Logger;
/**
* @author bjorncs
*/
-@Path("/{path: instance|refresh}")
+@Path("/instance")
public class InstanceConfirmationResource {
private static final Logger log = Logger.getLogger(InstanceConfirmationResource.class.getName());
@@ -32,6 +32,7 @@ public class InstanceConfirmationResource {
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public InstanceConfirmation confirmInstance(InstanceConfirmation instanceConfirmation) {
+ log.log(LogLevel.DEBUG, instanceConfirmation.toString());
if (!instanceValidator.isValidInstance(instanceConfirmation)) {
log.log(LogLevel.ERROR, "Invalid instance: " + instanceConfirmation);
throw new ForbiddenException("Instance is invalid");
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceRefreshResource.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceRefreshResource.java
new file mode 100644
index 00000000000..53972a39c97
--- /dev/null
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/instanceconfirmation/InstanceRefreshResource.java
@@ -0,0 +1,44 @@
+// 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.inject.Inject;
+import com.yahoo.container.jaxrs.annotation.Component;
+import com.yahoo.log.LogLevel;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import java.util.logging.Logger;
+
+/**
+ * ZTS calls this resource when it's requested to refresh an instance certificate
+ *
+ * @author bjorncs
+ */
+@Path("/refresh")
+public class InstanceRefreshResource {
+
+ private static final Logger log = Logger.getLogger(InstanceRefreshResource.class.getName());
+
+ private final InstanceValidator instanceValidator;
+
+ @Inject
+ public InstanceRefreshResource(@Component InstanceValidator instanceValidator) {
+ this.instanceValidator = instanceValidator;
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public InstanceConfirmation confirmInstanceRefresh(InstanceConfirmation instanceConfirmation) {
+ log.log(LogLevel.DEBUG, instanceConfirmation.toString());
+ if (!instanceValidator.isValidRefresh(instanceConfirmation)) {
+ log.log(LogLevel.ERROR, "Invalid instance refresh: " + instanceConfirmation);
+ throw new ForbiddenException("Instance is invalid");
+ }
+ 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 b75f7d05394..dcaf50c1c04 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
@@ -61,6 +61,17 @@ public class InstanceValidator {
return false;
}
+ // TODO Add actual validation. Cannot reuse isValidInstance as identity document is not part of the refresh request.
+ // We'll have to perform some validation on the instance id and other fields of the attribute map.
+ // Separate between tenant and node certificate as well.
+ public boolean isValidRefresh(InstanceConfirmation confirmation) {
+ log.log(LogLevel.INFO, () -> String.format("Accepting refresh for instance with identity '%s', provider '%s', instanceId '%s'.",
+ new AthenzService(confirmation.domain, confirmation.service).getFullName(),
+ confirmation.provider,
+ confirmation.attributes.get("sanDNS").toString()));
+ return true;
+ }
+
// If/when we dont care about logging exactly whats wrong, this can be simplified
// TODO Use identity type to determine if this check should be performed
boolean isSameIdentityAsInServicesXml(ApplicationId applicationId, String domain, String service) {
diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
index ff85c49bb13..a8403b8b10d 100644
--- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
+++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/maintenance/identity/AthenzCredentialsMaintainer.java
@@ -7,6 +7,7 @@ import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.client.zts.DefaultZtsClient;
import com.yahoo.vespa.athenz.client.zts.InstanceIdentity;
import com.yahoo.vespa.athenz.client.zts.ZtsClient;
+import com.yahoo.vespa.athenz.client.zts.ZtsClientException;
import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper;
import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocumentClient;
@@ -142,6 +143,8 @@ public class AthenzCredentialsMaintainer {
log.info(String.format("Deleted private key file (path=%s)", privateKeyFile));
if (Files.deleteIfExists(certificateFile))
log.info(String.format("Deleted certificate file (path=%s)", certificateFile));
+ if (Files.deleteIfExists(identityDocumentFile))
+ log.info(String.format("Deleted identity document file (path=%s)", certificateFile));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -201,6 +204,12 @@ public class AthenzCredentialsMaintainer {
csr);
writePrivateKeyAndCertificate(keyPair.getPrivate(), instanceIdentity.certificate());
log.info("Instance successfully refreshed and credentials written to file");
+ } catch (ZtsClientException e) {
+ // TODO Find out why certificate was revoked and hopefully remove this workaround
+ if (e.getErrorCode() == 403 && e.getDescription().startsWith("Certificate revoked")) {
+ log.error("Certificate cannot be refreshed as it is revoked by ZTS - re-registering the instance now", e);
+ registerIdentity();
+ }
} catch (IOException e) {
throw new UncheckedIOException(e);
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
index 8c67c3386b7..8a94518cee7 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
@@ -10,10 +10,11 @@ import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
import com.yahoo.vespa.athenz.api.NToken;
import com.yahoo.vespa.athenz.api.ZToken;
+import com.yahoo.vespa.athenz.client.zts.bindings.ErrorResponseEntity;
+import com.yahoo.vespa.athenz.client.zts.bindings.IdentityRefreshRequestEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.IdentityResponseEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.InstanceIdentityCredentials;
import com.yahoo.vespa.athenz.client.zts.bindings.InstanceRefreshInformation;
-import com.yahoo.vespa.athenz.client.zts.bindings.IdentityRefreshRequestEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.InstanceRegisterInformation;
import com.yahoo.vespa.athenz.client.zts.bindings.RoleCertificateRequestEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.RoleCertificateResponseEntity;
@@ -33,7 +34,6 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.util.EntityUtils;
import org.eclipse.jetty.http.HttpStatus;
import javax.net.ssl.SSLContext;
@@ -48,7 +48,6 @@ import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.stream.Collectors;
import static com.yahoo.vespa.athenz.tls.SignatureAlgorithm.SHA256_WITH_RSA;
import static com.yahoo.vespa.athenz.tls.SubjectAlternativeName.Type.DNS_NAME;
@@ -237,10 +236,8 @@ public class DefaultZtsClient implements ZtsClient {
if (HttpStatus.isSuccess(response.getStatusLine().getStatusCode())) {
return objectMapper.readValue(response.getEntity().getContent(), entityType);
} else {
- String message = EntityUtils.toString(response.getEntity());
- throw new ZtsClientException(
- String.format("Unable to get identity. http code/message: %d/%s",
- response.getStatusLine().getStatusCode(), message));
+ ErrorResponseEntity errorEntity = objectMapper.readValue(response.getEntity().getContent(), ErrorResponseEntity.class);
+ throw new ZtsClientException(errorEntity.code, errorEntity.description);
}
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClientException.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClientException.java
index 3d3696ad870..0b0d6914fea 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClientException.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClientException.java
@@ -8,11 +8,25 @@ package com.yahoo.vespa.athenz.client.zts;
*/
public class ZtsClientException extends RuntimeException {
- public ZtsClientException(String message) {
- super(message);
+ private final int errorCode;
+ private final String description;
+
+ public ZtsClientException(int errorCode, String description) {
+ super(createMessage(errorCode, description));
+ this.errorCode = errorCode;
+ this.description = description;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
}
- public ZtsClientException(String message, Throwable cause) {
- super(message, cause);
+ public String getDescription() {
+ return description;
}
+
+ private static String createMessage(int code, String description) {
+ return String.format("Received error from ZTS: code=%d, message=\"%s\"", code, description);
+ }
+
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/ErrorResponseEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/ErrorResponseEntity.java
new file mode 100644
index 00000000000..431af084f9f
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/ErrorResponseEntity.java
@@ -0,0 +1,23 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.client.zts.bindings;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author bjorncs
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ErrorResponseEntity {
+
+ public final int code;
+ public final String description;
+
+ @JsonCreator
+ public ErrorResponseEntity(@JsonProperty("code") int code,
+ @JsonProperty("message") String description) {
+ this.code = code;
+ this.description = description;
+ }
+}