summaryrefslogtreecommitdiffstats
path: root/container-disc
diff options
context:
space:
mode:
authorMorten Tokle <mortent@oath.com>2018-02-20 10:50:56 +0100
committerMorten Tokle <mortent@oath.com>2018-02-21 13:50:22 +0100
commit7175f77035b02a9fc37e6a41d7433d6bff747fff (patch)
tree7d46a166d4fa1ad3a563beb097bcd2108319b780 /container-disc
parent108ab8eb0781fb59b8cbc13281816d5f7425b064 (diff)
Revert "Merge pull request #5072 from vespa-engine/revert-4984-mortent/ckms"
This reverts commit 6d7b65adfcd1e918da8173dab25bf701074f3cdc, reversing changes made to 2ecdfefd5616743f62691f64a517ab787d6f0c10.
Diffstat (limited to 'container-disc')
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/Ckms.java14
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java3
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentials.java51
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentialsService.java93
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImpl.java330
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzService.java124
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtils.java113
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/IdentityDocumentService.java85
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceIdentity.java48
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRefreshInformation.java23
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRegisterInformation.java38
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/SignedIdentityDocument.java33
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/package-info.java8
-rw-r--r--container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImplTest.java252
-rw-r--r--container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtilsTest.java28
15 files changed, 15 insertions, 1228 deletions
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/Ckms.java b/container-disc/src/main/java/com/yahoo/container/jdisc/Ckms.java
new file mode 100644
index 00000000000..26c71686a82
--- /dev/null
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/Ckms.java
@@ -0,0 +1,14 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package com.yahoo.container.jdisc;
+
+/**
+ * @author mortent
+ */
+public interface Ckms {
+ /** Returns the secret for this key */
+ String getSecret(String key);
+
+ /** Returns the secret for this key and version */
+ String getSecret(String key, int version);
+}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java
index c4c57f4bc47..b7190927d11 100644
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/AthenzIdentityProvider.java
@@ -7,8 +7,7 @@ import javax.net.ssl.SSLContext;
* @author mortent
*/
public interface AthenzIdentityProvider {
- String getNToken() throws AthenzIdentityProviderException;
String getDomain();
String getService();
- SSLContext getSslContext();
+ SSLContext getIdentitySslContext();
}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentials.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentials.java
deleted file mode 100644
index 790a7c54333..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentials.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import java.security.KeyPair;
-import java.security.cert.X509Certificate;
-import java.time.Instant;
-
-/**
- * @author bjorncs
- */
-class AthenzCredentials {
-
- private final String nToken;
- private final X509Certificate certificate;
- private final KeyPair keyPair;
- private final SignedIdentityDocument identityDocument;
- private final Instant createdAt;
-
- AthenzCredentials(String nToken,
- X509Certificate certificate,
- KeyPair keyPair,
- SignedIdentityDocument identityDocument,
- Instant createdAt) {
- this.nToken = nToken;
- this.certificate = certificate;
- this.keyPair = keyPair;
- this.identityDocument = identityDocument;
- this.createdAt = createdAt;
- }
-
- String getNToken() {
- return nToken;
- }
-
- X509Certificate getCertificate() {
- return certificate;
- }
-
- KeyPair getKeyPair() {
- return keyPair;
- }
-
- SignedIdentityDocument getIdentityDocument() {
- return identityDocument;
- }
-
- Instant getCreatedAt() {
- return createdAt;
- }
-
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentialsService.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentialsService.java
deleted file mode 100644
index 5786eb9e398..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzCredentialsService.java
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.yahoo.container.core.identity.IdentityConfig;
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.security.KeyPair;
-import java.security.cert.X509Certificate;
-import java.time.Clock;
-
-/**
- * @author bjorncs
- */
-class AthenzCredentialsService {
-
- private static final ObjectMapper mapper = new ObjectMapper();
-
- private final IdentityConfig identityConfig;
- private final IdentityDocumentService identityDocumentService;
- private final AthenzService athenzService;
- private final Clock clock;
-
- AthenzCredentialsService(IdentityConfig identityConfig,
- IdentityDocumentService identityDocumentService,
- AthenzService athenzService,
- Clock clock) {
- this.identityConfig = identityConfig;
- this.identityDocumentService = identityDocumentService;
- this.athenzService = athenzService;
- this.clock = clock;
- }
-
- AthenzCredentials registerInstance() {
- KeyPair keyPair = CryptoUtils.createKeyPair();
- String rawDocument = identityDocumentService.getSignedIdentityDocument();
- SignedIdentityDocument document = parseSignedIdentityDocument(rawDocument);
- PKCS10CertificationRequest csr = CryptoUtils.createCSR(identityConfig.domain(),
- identityConfig.service(),
- document.dnsSuffix,
- document.providerUniqueId,
- keyPair);
- InstanceRegisterInformation instanceRegisterInformation =
- new InstanceRegisterInformation(document.providerService,
- identityConfig.domain(),
- identityConfig.service(),
- rawDocument,
- CryptoUtils.toPem(csr));
- InstanceIdentity instanceIdentity = athenzService.sendInstanceRegisterRequest(instanceRegisterInformation,
- document.ztsEndpoint);
- return toAthenzCredentials(instanceIdentity, keyPair, document);
- }
-
- AthenzCredentials updateCredentials(AthenzCredentials currentCredentials) {
- SignedIdentityDocument document = currentCredentials.getIdentityDocument();
- KeyPair newKeyPair = CryptoUtils.createKeyPair();
- PKCS10CertificationRequest csr = CryptoUtils.createCSR(identityConfig.domain(),
- identityConfig.service(),
- document.dnsSuffix,
- document.providerUniqueId,
- newKeyPair);
- InstanceRefreshInformation refreshInfo = new InstanceRefreshInformation(CryptoUtils.toPem(csr));
- InstanceIdentity instanceIdentity =
- athenzService.sendInstanceRefreshRequest(document.providerService,
- identityConfig.domain(),
- identityConfig.service(),
- document.providerUniqueId,
- refreshInfo,
- document.ztsEndpoint,
- currentCredentials.getCertificate(),
- currentCredentials.getKeyPair().getPrivate());
- return toAthenzCredentials(instanceIdentity, newKeyPair, document);
- }
-
- private AthenzCredentials toAthenzCredentials(InstanceIdentity instanceIdentity,
- KeyPair keyPair,
- SignedIdentityDocument identityDocument) {
- X509Certificate certificate = instanceIdentity.getX509Certificate();
- String serviceToken = instanceIdentity.getServiceToken();
- return new AthenzCredentials(serviceToken, certificate, keyPair, identityDocument, clock.instant());
- }
-
- private static SignedIdentityDocument parseSignedIdentityDocument(String rawDocument) {
- try {
- return mapper.readValue(rawDocument, SignedIdentityDocument.class);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImpl.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImpl.java
deleted file mode 100644
index 3b2b065fa8c..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImpl.java
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.google.inject.Inject;
-import com.yahoo.component.AbstractComponent;
-import com.yahoo.container.core.identity.IdentityConfig;
-import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
-import com.yahoo.container.jdisc.athenz.AthenzIdentityProviderException;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.log.LogLevel;
-import com.yahoo.vespa.defaults.Defaults;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.time.Clock;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.logging.Logger;
-
-/**
- * @author mortent
- * @author bjorncs
- */
-public final class AthenzIdentityProviderImpl extends AbstractComponent implements AthenzIdentityProvider {
-
- private static final Logger log = Logger.getLogger(AthenzIdentityProviderImpl.class.getName());
-
- // TODO Make some of these values configurable through config. Match requested expiration of register/update requests.
- // TODO These should match the requested expiration
- static final Duration EXPIRES_AFTER = Duration.ofDays(1);
- static final Duration EXPIRATION_MARGIN = Duration.ofMinutes(30);
- static final Duration INITIAL_WAIT_NTOKEN = Duration.ofMinutes(5);
- static final Duration UPDATE_PERIOD = EXPIRES_AFTER.dividedBy(3);
- static final Duration REDUCED_UPDATE_PERIOD = Duration.ofMinutes(30);
- static final Duration INITIAL_BACKOFF_DELAY = Duration.ofMinutes(4);
- static final Duration MAX_REGISTER_BACKOFF_DELAY = Duration.ofHours(1);
- static final int BACKOFF_DELAY_MULTIPLIER = 2;
- static final Duration AWAIT_TERMINTATION_TIMEOUT = Duration.ofSeconds(90);
-
- private static final Duration CERTIFICATE_EXPIRY_METRIC_UPDATE_PERIOD = Duration.ofMinutes(5);
- private static final String CERTIFICATE_EXPIRY_METRIC_NAME = "athenz-tenant-cert.expiry.seconds";
-
- static final String REGISTER_INSTANCE_TAG = "register-instance";
- static final String UPDATE_CREDENTIALS_TAG = "update-credentials";
- static final String TIMEOUT_INITIAL_WAIT_TAG = "timeout-initial-wait";
- static final String METRICS_UPDATER_TAG = "metrics-updater";
-
-
- private final AtomicReference<AthenzCredentials> credentials = new AtomicReference<>();
- private final AtomicReference<Throwable> lastThrowable = new AtomicReference<>();
- private final CountDownLatch credentialsRetrievedSignal = new CountDownLatch(1);
- private final AthenzCredentialsService athenzCredentialsService;
- private final Scheduler scheduler;
- private final Clock clock;
- private final String domain;
- private final String service;
-
- private final CertificateExpiryMetricUpdater metricUpdater;
-
- @Inject
- public AthenzIdentityProviderImpl(IdentityConfig config, Metric metric) {
- this(config,
- metric,
- new AthenzCredentialsService(config,
- new IdentityDocumentService(config.loadBalancerAddress()),
- new AthenzService(),
- Clock.systemUTC()),
- new ThreadPoolScheduler(),
- Clock.systemUTC());
- }
-
- // Test only
- AthenzIdentityProviderImpl(IdentityConfig config,
- Metric metric,
- AthenzCredentialsService athenzCredentialsService,
- Scheduler scheduler,
- Clock clock) {
- this.athenzCredentialsService = athenzCredentialsService;
- this.scheduler = scheduler;
- this.clock = clock;
- this.domain = config.domain();
- this.service = config.service();
- scheduler.submit(new RegisterInstanceTask());
- scheduler.schedule(new TimeoutInitialWaitTask(), INITIAL_WAIT_NTOKEN);
-
- metricUpdater = new CertificateExpiryMetricUpdater(metric);
- }
-
- @Override
- public String getNToken() {
- try {
- credentialsRetrievedSignal.await();
- AthenzCredentials credentialsSnapshot = credentials.get();
- if (credentialsSnapshot == null) {
- throw new AthenzIdentityProviderException("Could not retrieve Athenz credentials", lastThrowable.get());
- }
- if (isExpired(credentialsSnapshot)) {
- throw new AthenzIdentityProviderException("Athenz credentials are expired", lastThrowable.get());
- }
- return credentialsSnapshot.getNToken();
- } catch (InterruptedException e) {
- throw new AthenzIdentityProviderException("Failed to register instance credentials", lastThrowable.get());
- }
- }
-
- @Override
- public String getDomain() {
- return domain;
- }
-
- @Override
- public String getService() {
- return service;
- }
-
- @Override
- public SSLContext getSslContext() {
- try {
- SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
- sslContext.init(createKeyManagersWithServiceCertificate(),
- createTrustManagersWithAthenzCa(),
- null);
- return sslContext;
- } catch (NoSuchAlgorithmException | KeyManagementException e) {
- throw new RuntimeException(e);
- }
- }
-
- private KeyManager[] createKeyManagersWithServiceCertificate() {
- try {
- credentialsRetrievedSignal.await();
- KeyStore keyStore = KeyStore.getInstance("JKS");
- keyStore.load(null);
- keyStore.setKeyEntry("instance-key",
- credentials.get().getKeyPair().getPrivate(),
- new char[0],
- new Certificate[]{credentials.get().getCertificate()});
- KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- keyManagerFactory.init(keyStore, new char[0]);
- return keyManagerFactory.getKeyManagers();
- } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException | IOException e) {
- throw new RuntimeException(e);
- } catch (InterruptedException e) {
- throw new AthenzIdentityProviderException("Failed to register instance credentials", lastThrowable.get());
- }
- }
-
- private static TrustManager[] createTrustManagersWithAthenzCa() {
- try {
- KeyStore trustStore = KeyStore.getInstance("JKS");
- try (FileInputStream in = new FileInputStream(Defaults.getDefaults().underVespaHome("share/ssl/certs/yahoo_certificate_bundle.jks"))) {
- trustStore.load(in, null);
- }
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
- trustManagerFactory.init(trustStore);
- return trustManagerFactory.getTrustManagers();
- } catch (CertificateException | IOException | KeyStoreException | NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void deconstruct() {
- scheduler.shutdown(AWAIT_TERMINTATION_TIMEOUT);
- }
-
- private boolean isExpired(AthenzCredentials credentials) {
- return clock.instant().isAfter(getExpirationTime(credentials));
- }
-
- private static Instant getExpirationTime(AthenzCredentials credentials) {
- return credentials.getCreatedAt().plus(EXPIRES_AFTER).minus(EXPIRATION_MARGIN);
- }
-
- private class RegisterInstanceTask implements RunnableWithTag {
-
- private final Duration backoffDelay;
-
- RegisterInstanceTask() {
- this(INITIAL_BACKOFF_DELAY);
- }
-
- RegisterInstanceTask(Duration backoffDelay) {
- this.backoffDelay = backoffDelay;
- }
-
- @Override
- public void run() {
- try {
- credentials.set(athenzCredentialsService.registerInstance());
- credentialsRetrievedSignal.countDown();
- scheduler.schedule(new UpdateCredentialsTask(), UPDATE_PERIOD);
- scheduler.submit(metricUpdater);
- } catch (Throwable t) {
- log.log(LogLevel.ERROR, "Failed to register instance: " + t.getMessage(), t);
- lastThrowable.set(t);
- Duration nextBackoffDelay = backoffDelay.multipliedBy(BACKOFF_DELAY_MULTIPLIER);
- if (nextBackoffDelay.compareTo(MAX_REGISTER_BACKOFF_DELAY) > 0) {
- nextBackoffDelay = MAX_REGISTER_BACKOFF_DELAY;
- }
- scheduler.schedule(new RegisterInstanceTask(nextBackoffDelay), backoffDelay);
- }
- }
-
- @Override
- public String tag() {
- return REGISTER_INSTANCE_TAG;
- }
- }
-
- private class UpdateCredentialsTask implements RunnableWithTag {
- @Override
- public void run() {
- AthenzCredentials currentCredentials = credentials.get();
- try {
- AthenzCredentials newCredentials = isExpired(currentCredentials)
- ? athenzCredentialsService.registerInstance()
- : athenzCredentialsService.updateCredentials(currentCredentials);
- credentials.set(newCredentials);
- scheduler.schedule(new UpdateCredentialsTask(), UPDATE_PERIOD);
- } catch (Throwable t) {
- log.log(LogLevel.WARNING, "Failed to update credentials: " + t.getMessage(), t);
- lastThrowable.set(t);
- Duration timeToExpiration = Duration.between(clock.instant(), getExpirationTime(currentCredentials));
- // NOTE: Update period might be after timeToExpiration, still we do not want to DDoS Athenz.
- Duration updatePeriod =
- timeToExpiration.compareTo(UPDATE_PERIOD) > 0 ? UPDATE_PERIOD : REDUCED_UPDATE_PERIOD;
- scheduler.schedule(new UpdateCredentialsTask(), updatePeriod);
- }
- }
-
- @Override
- public String tag() {
- return UPDATE_CREDENTIALS_TAG;
- }
- }
-
- private class CertificateExpiryMetricUpdater implements RunnableWithTag {
- private final Metric metric;
-
- private CertificateExpiryMetricUpdater(Metric metric) {
- this.metric = metric;
- }
-
- @Override
- public void run() {
- Instant expirationTime = getExpirationTime(credentials.get());
- Duration remainingLifetime = Duration.between(clock.instant(), expirationTime);
- metric.set(CERTIFICATE_EXPIRY_METRIC_NAME, remainingLifetime.getSeconds(), null);
- scheduler.schedule(this, CERTIFICATE_EXPIRY_METRIC_UPDATE_PERIOD);
- }
-
- @Override
- public String tag() {
- return METRICS_UPDATER_TAG;
- }
- }
-
- private class TimeoutInitialWaitTask implements RunnableWithTag {
- @Override
- public void run() {
- credentialsRetrievedSignal.countDown();
- }
-
- @Override
- public String tag() {
- return TIMEOUT_INITIAL_WAIT_TAG;
- }
- }
-
- private static class ThreadPoolScheduler implements Scheduler {
-
- private static final Logger log = Logger.getLogger(ThreadPoolScheduler.class.getName());
-
- private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(0);
-
- @Override
- public void schedule(RunnableWithTag runnable, Duration delay) {
- log.log(LogLevel.FINE, String.format("Scheduling task '%s' in '%s'", runnable.tag(), delay));
- executor.schedule(runnable, delay.getSeconds(), TimeUnit.SECONDS);
- }
-
- @Override
- public void submit(RunnableWithTag runnable) {
- log.log(LogLevel.FINE, String.format("Scheduling task '%s' now", runnable.tag()));
- executor.submit(runnable);
- }
-
- @Override
- public void shutdown(Duration timeout) {
- try {
- executor.shutdownNow();
- executor.awaitTermination(AWAIT_TERMINTATION_TIMEOUT.getSeconds(), TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
-
- }
-
- public interface Scheduler {
- void schedule(RunnableWithTag runnable, Duration delay);
- default void submit(RunnableWithTag runnable) { schedule(runnable, Duration.ZERO); }
- default void shutdown(Duration timeout) {}
- }
-
- public interface RunnableWithTag extends Runnable {
-
- String tag();
- }
-
-}
-
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzService.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzService.java
deleted file mode 100644
index 898f90e3438..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/AthenzService.java
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.apache.http.client.HttpRequestRetryHandler;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.methods.RequestBuilder;
-import org.apache.http.conn.ssl.SSLContextBuilder;
-import org.apache.http.entity.ContentType;
-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;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.net.URI;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-/**
- * @author mortent
- * @author bjorncs
- */
-public class AthenzService {
-
- private static final String INSTANCE_API_PATH = "/zts/v1/instance";
-
- private final ObjectMapper objectMapper = new ObjectMapper();
- private final HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(3, /*requestSentRetryEnabled*/true);
-
- /**
- * Send instance register request to ZTS, get InstanceIdentity
- */
- public InstanceIdentity sendInstanceRegisterRequest(InstanceRegisterInformation instanceRegisterInformation,
- URI uri) {
- try(CloseableHttpClient client = HttpClientBuilder.create().setRetryHandler(retryHandler).build()) {
- HttpUriRequest postRequest = RequestBuilder.post()
- .setUri(uri.resolve(INSTANCE_API_PATH))
- .setEntity(toJsonStringEntity(instanceRegisterInformation))
- .build();
- return getInstanceIdentity(client, postRequest);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public InstanceIdentity sendInstanceRefreshRequest(String providerService,
- String instanceDomain,
- String instanceServiceName,
- String instanceId,
- InstanceRefreshInformation instanceRefreshInformation,
- URI ztsEndpoint,
- X509Certificate certicate,
- PrivateKey privateKey) {
- try (CloseableHttpClient client = createHttpClientWithTlsAuth(certicate, privateKey, retryHandler)) {
- URI uri = ztsEndpoint
- .resolve(INSTANCE_API_PATH + '/')
- .resolve(providerService + '/')
- .resolve(instanceDomain + '/')
- .resolve(instanceServiceName + '/')
- .resolve(instanceId);
- HttpUriRequest postRequest = RequestBuilder.post()
- .setUri(uri)
- .setEntity(toJsonStringEntity(instanceRefreshInformation))
- .build();
- return getInstanceIdentity(client, postRequest);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- private InstanceIdentity getInstanceIdentity(CloseableHttpClient client, HttpUriRequest postRequest)
- throws IOException {
- try (CloseableHttpResponse response = client.execute(postRequest)) {
- if(HttpStatus.isSuccess(response.getStatusLine().getStatusCode())) {
- return objectMapper.readValue(response.getEntity().getContent(), InstanceIdentity.class);
- } else {
- String message = EntityUtils.toString(response.getEntity());
- throw new RuntimeException(String.format("Unable to get identity. http code/message: %d/%s",
- response.getStatusLine().getStatusCode(), message));
- }
- }
- }
-
- private StringEntity toJsonStringEntity(Object value) throws JsonProcessingException {
- return new StringEntity(objectMapper.writeValueAsString(value), ContentType.APPLICATION_JSON);
- }
-
- private static CloseableHttpClient createHttpClientWithTlsAuth(X509Certificate certificate,
- PrivateKey privateKey,
- HttpRequestRetryHandler retryHandler) {
- try {
- String dummyPassword = "athenz";
- KeyStore keyStore = KeyStore.getInstance("JKS");
- keyStore.load(null);
- keyStore.setKeyEntry("athenz", privateKey, dummyPassword.toCharArray(), new Certificate[]{certificate});
- SSLContext sslContext = new SSLContextBuilder()
- .loadKeyMaterial(keyStore, dummyPassword.toCharArray())
- .build();
- return HttpClientBuilder.create()
- .setRetryHandler(retryHandler)
- .setSslcontext(sslContext)
- .build();
- } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException |
- KeyManagementException | CertificateException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtils.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtils.java
deleted file mode 100644
index 388b40a1fe0..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtils.java
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.ExtensionsGenerator;
-import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.GeneralNames;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openssl.PEMParser;
-import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
-import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
-import org.bouncycastle.util.io.pem.PemObject;
-
-import javax.security.auth.x500.X500Principal;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.UncheckedIOException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.NoSuchAlgorithmException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-/**
- * @author bjorncs
- */
-class CryptoUtils {
-
- private static final BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
-
- private CryptoUtils() {}
-
- static KeyPair createKeyPair() {
- try {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
- return kpg.generateKeyPair();
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(e);
- }
- }
-
- static PKCS10CertificationRequest createCSR(String identityDomain,
- String identityService,
- String dnsSuffix,
- String providerUniqueId,
- KeyPair keyPair) {
- try {
- // Add SAN dnsname <service>.<domain-with-dashes>.<provider-dnsname-suffix>
- // and SAN dnsname <provider-unique-instance-id>.instanceid.athenz.<provider-dnsname-suffix>
- GeneralNames subjectAltNames = new GeneralNames(new GeneralName[]{
- new GeneralName(GeneralName.dNSName, String.format("%s.%s.%s",
- identityService,
- identityDomain.replace(".", "-"),
- dnsSuffix)),
- new GeneralName(GeneralName.dNSName, String.format("%s.instanceid.athenz.%s",
- providerUniqueId,
- dnsSuffix))
- });
-
- ExtensionsGenerator extGen = new ExtensionsGenerator();
- extGen.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
-
- X500Principal subject = new X500Principal(
- String.format("CN=%s.%s", identityDomain, identityService));
-
- PKCS10CertificationRequestBuilder requestBuilder =
- new JcaPKCS10CertificationRequestBuilder(subject, keyPair.getPublic());
- requestBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());
- return requestBuilder.build(new JcaContentSignerBuilder("SHA256withRSA").build(keyPair.getPrivate()));
- } catch (OperatorCreationException e) {
- throw new RuntimeException(e);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- static String toPem(PKCS10CertificationRequest csr) {
- try (StringWriter stringWriter = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter)) {
- pemWriter.writeObject(new PemObject("CERTIFICATE REQUEST", csr.getEncoded()));
- pemWriter.flush();
- return stringWriter.toString();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- static X509Certificate parseCertificate(String pemEncodedCertificate) {
- try (PEMParser parser = new PEMParser(new StringReader(pemEncodedCertificate))) {
- Object pemObject = parser.readObject();
- if (pemObject instanceof X509Certificate) {
- return (X509Certificate) pemObject;
- }
- if (pemObject instanceof X509CertificateHolder) {
- return new JcaX509CertificateConverter()
- .setProvider(bouncyCastleProvider)
- .getCertificate((X509CertificateHolder) pemObject);
- }
- throw new IllegalArgumentException("Invalid type of PEM object: " + pemObject);
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- } catch (CertificateException e) {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/IdentityDocumentService.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/IdentityDocumentService.java
deleted file mode 100644
index 7878400964a..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/IdentityDocumentService.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.yahoo.vespa.defaults.Defaults;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLContextBuilder;
-import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.util.EntityUtils;
-import org.eclipse.jetty.http.HttpStatus;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-
-/**
- * @author mortent
- * @author bjorncs
- */
-public class IdentityDocumentService {
-
- private final URI identityDocumentApiUri;
-
- public IdentityDocumentService(String loadBalancerName) {
- this.identityDocumentApiUri = createIdentityDocumentApiUri(loadBalancerName);
- }
-
- /**
- * Get signed identity document from config server
- */
- public String getSignedIdentityDocument() {
- try (CloseableHttpClient httpClient = createHttpClient()) {
- CloseableHttpResponse idDocResponse = httpClient.execute(new HttpGet(identityDocumentApiUri));
- String responseContent = EntityUtils.toString(idDocResponse.getEntity());
- if (HttpStatus.isSuccess(idDocResponse.getStatusLine().getStatusCode())) {
- return responseContent;
- } else {
- // TODO make sure we have retried a few times (AND logged) before giving up
- throw new RuntimeException(
- "Failed to initialize Athenz instance provider: " +
- idDocResponse.getStatusLine() + ": " + responseContent);
- }
- } catch (IOException e) {
- throw new RuntimeException("Failed getting signed identity document", e);
- }
- }
-
- // TODO Use client side auth to establish trusted secure channel
- // TODO Validate TLS certifcate of config server
- private static CloseableHttpClient createHttpClient() {
- try {
- SSLContextBuilder sslContextBuilder = new SSLContextBuilder();
- sslContextBuilder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
- SSLConnectionSocketFactory sslSocketFactory =
- new SSLConnectionSocketFactory(sslContextBuilder.build(),
- SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
- return HttpClientBuilder.create().setSSLSocketFactory(sslSocketFactory).setUserAgent("identity-document-client").build();
- } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
- throw new RuntimeException(e);
- }
- }
-
- private static URI createIdentityDocumentApiUri(String loadBalancerName) {
- try {
- // TODO Figure out a proper way of determining the hostname matching what's registred in node-repository
- return new URIBuilder()
- .setScheme("https")
- .setHost(loadBalancerName)
- .setPort(4443)
- .setPath("/athenz/v1/provider/identity-document")
- .addParameter("hostname", Defaults.getDefaults().vespaHostname())
- .build();
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceIdentity.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceIdentity.java
deleted file mode 100644
index 20bbb2aa67e..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceIdentity.java
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-
-import java.io.IOException;
-import java.security.cert.X509Certificate;
-
-/**
- * Used for deserializing response from ZTS
- *
- * @author mortent
- */
-@JsonIgnoreProperties(ignoreUnknown = true)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class InstanceIdentity {
- @JsonProperty("x509Certificate") private final X509Certificate x509Certificate;
- @JsonProperty("serviceToken") private final String serviceToken;
-
- public InstanceIdentity(@JsonProperty("x509Certificate") @JsonDeserialize(using = X509CertificateDeserializer.class)
- X509Certificate x509Certificate,
- @JsonProperty("serviceToken") String serviceToken) {
- this.x509Certificate = x509Certificate;
- this.serviceToken = serviceToken;
- }
-
- public X509Certificate getX509Certificate() {
- return x509Certificate;
- }
-
- public String getServiceToken() {
- return serviceToken;
- }
-
- public static class X509CertificateDeserializer extends JsonDeserializer<X509Certificate> {
- @Override
- public X509Certificate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
- return CryptoUtils.parseCertificate(parser.getValueAsString());
- }
- }
-
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRefreshInformation.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRefreshInformation.java
deleted file mode 100644
index dd893cb3143..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRefreshInformation.java
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-/**
- * @author bjorncs
- */
-@JsonIgnoreProperties(ignoreUnknown = true)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class InstanceRefreshInformation {
-
- @JsonProperty("csr")
- private final String csr;
- @JsonProperty("token")
- private final boolean requestServiceToken = true;
-
- public InstanceRefreshInformation(String csr) {
- this.csr = csr;
- }
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRegisterInformation.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRegisterInformation.java
deleted file mode 100644
index e2355cb7a2d..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/InstanceRegisterInformation.java
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-/**
- * Used for serializing request to ZTS
- *
- * @author mortent
- */
-@JsonIgnoreProperties(ignoreUnknown = true)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-public class InstanceRegisterInformation {
- @JsonProperty("provider")
- private final String provider;
- @JsonProperty("domain")
- private final String domain;
- @JsonProperty("service")
- private final String service;
- @JsonProperty("attestationData")
- private final String attestationData;
- @JsonProperty("ssh")
- private final String ssh = null; // Not needed
- @JsonProperty("csr")
- private final String csr;
- @JsonProperty("token")
- private final boolean token = true;
-
- public InstanceRegisterInformation(String provider, String domain, String service, String attestationData, String csr) {
- this.provider = provider;
- this.domain = domain;
- this.service = service;
- this.attestationData = attestationData;
- this.csr = csr;
- }
-}
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/SignedIdentityDocument.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/SignedIdentityDocument.java
deleted file mode 100644
index 5d5b5430859..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/SignedIdentityDocument.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.annotation.JsonProperty;
-
-import java.net.URI;
-
-/**
- * @author bjorncs
- */
-// TODO Most of these value should ideally be config provided by config-model
-@JsonIgnoreProperties(ignoreUnknown = true)
-@JsonInclude(JsonInclude.Include.NON_NULL)
-class SignedIdentityDocument {
- public final String providerUniqueId;
- public final String dnsSuffix;
- public final String providerService;
- public final URI ztsEndpoint;
-
- public SignedIdentityDocument(@JsonProperty("provider-unique-id") String providerUniqueId,
- @JsonProperty("dns-suffix") String dnsSuffix,
- @JsonProperty("provider-service") String providerService,
- @JsonProperty("zts-endpoint") URI ztsEndpoint) {
- this.providerUniqueId = providerUniqueId;
- this.dnsSuffix = dnsSuffix;
- this.providerService = providerService;
- this.ztsEndpoint = ztsEndpoint;
- }
-
-}
-
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/package-info.java b/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/package-info.java
deleted file mode 100644
index 2d7cbbb6315..00000000000
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/athenz/impl/package-info.java
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * @author mortent
- */
-@ExportPackage
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.yahoo.osgi.annotation.ExportPackage; \ No newline at end of file
diff --git a/container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImplTest.java b/container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImplTest.java
deleted file mode 100644
index 1ee23334a16..00000000000
--- a/container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/AthenzIdentityProviderImplTest.java
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import com.yahoo.container.core.identity.IdentityConfig;
-import com.yahoo.container.jdisc.athenz.AthenzIdentityProvider;
-import com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.RunnableWithTag;
-import com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.Scheduler;
-import com.yahoo.jdisc.Metric;
-import com.yahoo.test.ManualClock;
-import org.junit.Test;
-
-import java.time.Duration;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.PriorityQueue;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.INITIAL_BACKOFF_DELAY;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.INITIAL_WAIT_NTOKEN;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.MAX_REGISTER_BACKOFF_DELAY;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.METRICS_UPDATER_TAG;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.REDUCED_UPDATE_PERIOD;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.REGISTER_INSTANCE_TAG;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.TIMEOUT_INITIAL_WAIT_TAG;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.UPDATE_CREDENTIALS_TAG;
-import static com.yahoo.container.jdisc.athenz.impl.AthenzIdentityProviderImpl.UPDATE_PERIOD;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * @author mortent
- * @author bjorncs
- */
-public class AthenzIdentityProviderImplTest {
-
- private static final Metric DUMMY_METRIC = new Metric() {
- @Override
- public void set(String s, Number number, Context context) {}
- @Override
- public void add(String s, Number number, Context context) {}
- @Override
- public Context createContext(Map<String, ?> stringMap) { return null; }
- };
-
- private static final IdentityConfig IDENTITY_CONFIG =
- new IdentityConfig(new IdentityConfig.Builder()
- .service("tenantService").domain("tenantDomain").loadBalancerAddress("cfg"));
-
- private final Set<String> IGNORED_TASKS = Stream.of(UPDATE_CREDENTIALS_TAG, METRICS_UPDATER_TAG)
- .collect(Collectors.toSet());
-
- @Test
- public void athenz_credentials_are_retrieved_after_component_contruction_completed() {
- IdentityDocumentService identityDocumentService = mock(IdentityDocumentService.class);
- AthenzService athenzService = mock(AthenzService.class);
- ManualClock clock = new ManualClock(Instant.EPOCH);
- MockScheduler scheduler = new MockScheduler(clock);
-
- when(identityDocumentService.getSignedIdentityDocument()).thenReturn(getIdentityDocument());
- when(athenzService.sendInstanceRegisterRequest(any(), any())).thenReturn(
- new InstanceIdentity(null, "TOKEN"));
- AthenzCredentialsService credentialService =
- new AthenzCredentialsService(IDENTITY_CONFIG, identityDocumentService, athenzService, clock);
-
- AthenzIdentityProvider identityProvider =
- new AthenzIdentityProviderImpl(IDENTITY_CONFIG, DUMMY_METRIC, credentialService, scheduler, clock);
-
- List<MockScheduler.CompletedTask> expectedTasks =
- Arrays.asList(
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, Duration.ZERO),
- new MockScheduler.CompletedTask(TIMEOUT_INITIAL_WAIT_TAG, INITIAL_WAIT_NTOKEN));
- // Don't run update credential tasks, otherwise infinite loop
- List<MockScheduler.CompletedTask> completedTasks =
- scheduler.runAllTasks(task -> !IGNORED_TASKS.contains(task.tag()));
- assertEquals(expectedTasks, completedTasks);
- assertEquals("TOKEN", identityProvider.getNToken());
- }
-
- @Test
- public void register_instance_uses_exponential_backoff() {
- AthenzCredentialsService credentialService = mock(AthenzCredentialsService.class);
- when(credentialService.registerInstance())
- .thenThrow(new RuntimeException("#1"))
- .thenThrow(new RuntimeException("#2"))
- .thenThrow(new RuntimeException("#3"))
- .thenThrow(new RuntimeException("#4"))
- .thenThrow(new RuntimeException("#5"))
- .thenReturn(new AthenzCredentials("TOKEN", null, null, null, Instant.now()));
-
- ManualClock clock = new ManualClock(Instant.EPOCH);
- MockScheduler scheduler = new MockScheduler(clock);
- AthenzIdentityProvider identityProvider =
- new AthenzIdentityProviderImpl(IDENTITY_CONFIG, DUMMY_METRIC, credentialService, scheduler, clock);
-
- List<MockScheduler.CompletedTask> expectedTasks =
- Arrays.asList(
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, Duration.ZERO),
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, INITIAL_BACKOFF_DELAY),
- new MockScheduler.CompletedTask(TIMEOUT_INITIAL_WAIT_TAG, INITIAL_WAIT_NTOKEN),
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, INITIAL_BACKOFF_DELAY.multipliedBy(2)),
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, INITIAL_BACKOFF_DELAY.multipliedBy(4)),
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, INITIAL_BACKOFF_DELAY.multipliedBy(8)),
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, MAX_REGISTER_BACKOFF_DELAY));
- // Don't run update credential tasks, otherwise infinite loop
- List<MockScheduler.CompletedTask> completedTasks =
- scheduler.runAllTasks(task -> !IGNORED_TASKS.contains(task.tag()));
- assertEquals(expectedTasks, completedTasks);
- assertEquals("TOKEN", identityProvider.getNToken());
- }
-
- @Test
- public void failed_credentials_updates_will_schedule_retries() {
- IdentityDocumentService identityDocumentService = mock(IdentityDocumentService.class);
- AthenzService athenzService = mock(AthenzService.class);
- ManualClock clock = new ManualClock(Instant.EPOCH);
- MockScheduler scheduler = new MockScheduler(clock);
-
- when(identityDocumentService.getSignedIdentityDocument()).thenReturn(getIdentityDocument());
- when(athenzService.sendInstanceRegisterRequest(any(), any())).thenReturn(
- new InstanceIdentity(null, "TOKEN"));
- when(athenzService.sendInstanceRefreshRequest(anyString(), anyString(), anyString(),
- anyString(), any(), any(), any(), any()))
- .thenThrow(new RuntimeException("#1"))
- .thenThrow(new RuntimeException("#2"))
- .thenThrow(new RuntimeException("#3"))
- .thenReturn(new InstanceIdentity(null, "TOKEN"));
- AthenzCredentialsService credentialService =
- new AthenzCredentialsService(IDENTITY_CONFIG, identityDocumentService, athenzService, clock);
-
- AthenzIdentityProvider identityProvider =
- new AthenzIdentityProviderImpl(IDENTITY_CONFIG, DUMMY_METRIC, credentialService, scheduler, clock);
-
- List<MockScheduler.CompletedTask> expectedTasks =
- Arrays.asList(
- new MockScheduler.CompletedTask(REGISTER_INSTANCE_TAG, Duration.ZERO),
- new MockScheduler.CompletedTask(TIMEOUT_INITIAL_WAIT_TAG, INITIAL_WAIT_NTOKEN),
- new MockScheduler.CompletedTask(UPDATE_CREDENTIALS_TAG, UPDATE_PERIOD),
- new MockScheduler.CompletedTask(UPDATE_CREDENTIALS_TAG, UPDATE_PERIOD),
- new MockScheduler.CompletedTask(UPDATE_CREDENTIALS_TAG, REDUCED_UPDATE_PERIOD),
- new MockScheduler.CompletedTask(UPDATE_CREDENTIALS_TAG, REDUCED_UPDATE_PERIOD),
- new MockScheduler.CompletedTask(UPDATE_CREDENTIALS_TAG, UPDATE_PERIOD));
- AtomicInteger counter = new AtomicInteger(0);
- List<MockScheduler.CompletedTask> completedTasks =
- scheduler.runAllTasks(task -> !task.tag().equals(METRICS_UPDATER_TAG) &&
- counter.getAndIncrement() < expectedTasks.size());
- assertEquals(expectedTasks, completedTasks);
- assertEquals("TOKEN", identityProvider.getNToken());
- }
-
- private static String getIdentityDocument() {
- return "{\n" +
- " \"identity-document\": \"eyJwcm92aWRlci11bmlxdWUtaWQiOnsidGVuYW50IjoidGVuYW50IiwiYXBwbGljYXRpb24iOiJhcHBsaWNhdGlvbiIsImVudmlyb25tZW50IjoiZGV2IiwicmVnaW9uIjoidXMtbm9ydGgtMSIsImluc3RhbmNlIjoiZGVmYXVsdCIsImNsdXN0ZXItaWQiOiJkZWZhdWx0IiwiY2x1c3Rlci1pbmRleCI6MH0sImNvbmZpZ3NlcnZlci1ob3N0bmFtZSI6ImxvY2FsaG9zdCIsImluc3RhbmNlLWhvc3RuYW1lIjoieC55LmNvbSIsImNyZWF0ZWQtYXQiOjE1MDg3NDgyODUuNzQyMDAwMDAwfQ==\",\n" +
- " \"signature\": \"kkEJB/98cy1FeXxzSjtvGH2a6BFgZu/9/kzCcAqRMZjENxnw5jyO1/bjZVzw2Sz4YHPsWSx2uxb32hiQ0U8rMP0zfA9nERIalSP0jB/hMU8laezGhdpk6VKZPJRC6YKAB9Bsv2qUIfMsSxkMqf66GUvjZAGaYsnNa2yHc1jIYHOGMeJO+HNPYJjGv26xPfAOPIKQzs3RmKrc3FoweTCsIwm5oblqekdJvVWYe0obwlOSB5uwc1zpq3Ie1QBFtJRuCGMVHg1pDPxXKBHLClGIrEvzLmICy6IRdHszSO5qiwujUD7sbrbM0sB/u0cYucxbcsGRUmBvme3UAw2mW9POVQ==\",\n" +
- " \"signing-key-version\": 0,\n" +
- " \"provider-unique-id\": \"tenant.application.dev.us-north-1.default.default.0\",\n" +
- " \"dns-suffix\": \"dnsSuffix\",\n" +
- " \"provider-service\": \"service\",\n" +
- " \"zts-endpoint\": \"localhost/zts\", \n" +
- " \"document-version\": 1\n" +
- "}";
-
- }
-
- private static class MockScheduler implements Scheduler {
-
- private final PriorityQueue<DelayedTask> tasks = new PriorityQueue<>();
- private final ManualClock clock;
-
- MockScheduler(ManualClock clock) {
- this.clock = clock;
- }
-
- @Override
- public void schedule(RunnableWithTag task, Duration delay) {
- tasks.offer(new DelayedTask(task, delay, clock.instant().plus(delay)));
- }
-
- List<CompletedTask> runAllTasks(Predicate<RunnableWithTag> filter) {
- List<CompletedTask> completedTasks = new ArrayList<>();
- while (!tasks.isEmpty()) {
- DelayedTask task = tasks.poll();
- RunnableWithTag runnable = task.runnableWithTag;
- if (filter.test(runnable)) {
- clock.setInstant(task.startTime);
- runnable.run();
- completedTasks.add(new CompletedTask(runnable.tag(), task.delay));
- }
- }
- return completedTasks;
- }
-
- private static class DelayedTask implements Comparable<DelayedTask> {
- final RunnableWithTag runnableWithTag;
- final Duration delay;
- final Instant startTime;
-
- DelayedTask(RunnableWithTag runnableWithTag, Duration delay, Instant startTime) {
- this.runnableWithTag = runnableWithTag;
- this.delay = delay;
- this.startTime = startTime;
- }
-
- @Override
- public int compareTo(DelayedTask other) {
- return this.startTime.compareTo(other.startTime);
- }
- }
-
- private static class CompletedTask {
- final String tag;
- final Duration delay;
-
- CompletedTask(String tag, Duration delay) {
- this.tag = tag;
- this.delay = delay;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- CompletedTask that = (CompletedTask) o;
- return Objects.equals(tag, that.tag) &&
- Objects.equals(delay, that.delay);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(tag, delay);
- }
-
- @Override
- public String toString() {
- return "CompletedTask{" +
- "tag='" + tag + '\'' +
- ", delay=" + delay +
- '}';
- }
- }
- }
-}
diff --git a/container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtilsTest.java b/container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtilsTest.java
deleted file mode 100644
index dc9690355e8..00000000000
--- a/container-disc/src/test/java/com/yahoo/container/jdisc/athenz/impl/CryptoUtilsTest.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.container.jdisc.athenz.impl;
-
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.security.KeyPair;
-
-import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertThat;
-
-/**
- * @author bjorncs
- */
-public class CryptoUtilsTest {
-
- @Test
- public void certificate_signing_request_is_correct_and_can_be_serialized_to_pem() throws IOException {
- KeyPair keyPair = CryptoUtils.createKeyPair();
- PKCS10CertificationRequest csr = CryptoUtils.createCSR(
- "identity-domain", "identity-service", "vespa.cloud.com", "unique.instance.id", keyPair);
- String pem = CryptoUtils.toPem(csr);
- assertThat(pem, containsString("BEGIN CERTIFICATE REQUEST"));
- assertThat(pem, containsString("END CERTIFICATE REQUEST"));
- }
-
-}