summaryrefslogtreecommitdiffstats
path: root/athenz-identity-provider-service
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@oath.com>2017-11-02 15:57:23 +0100
committerValerij Fredriksen <valerijf@oath.com>2017-11-02 15:57:23 +0100
commit1e1b84fbf754e5e90f815a5c2f83ca79865505d5 (patch)
tree325b6a8c11f98878199e080446774012e52b1b7d /athenz-identity-provider-service
parent1721b453c41d030b7892d86f92740b577a7aaf77 (diff)
parent25a2dc312d6b1b8e8dbefce9e06f9bd4619bd176 (diff)
Merge branch 'master' into freva/instance-validator
# Conflicts: # athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java # athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java
Diffstat (limited to 'athenz-identity-provider-service')
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java21
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java14
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGenerator.java11
-rw-r--r--athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/SecretStoreKeyProvider.java56
-rw-r--r--athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def24
-rw-r--r--athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java16
6 files changed, 109 insertions, 33 deletions
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java
index 89ea4301398..06f8d347b78 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderService.java
@@ -6,16 +6,17 @@ import com.yahoo.component.AbstractComponent;
import com.yahoo.config.model.api.SuperModelProvider;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.Zone;
+import com.yahoo.jdisc.http.SecretStore;
import com.yahoo.log.LogLevel;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.config.AthenzProviderServiceConfig;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.AthenzCertificateClient;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.CertificateClient;
-import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.FileBackedKeyProvider;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.IdentityDocumentGenerator;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.IdentityDocumentServlet;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.InstanceConfirmationServlet;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.InstanceValidator;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.KeyProvider;
+import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.SecretStoreKeyProvider;
import com.yahoo.vespa.hosted.athenz.instanceproviderservice.impl.StatusServlet;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import org.eclipse.jetty.server.Server;
@@ -49,9 +50,9 @@ public class AthenzInstanceProviderService extends AbstractComponent {
@Inject
public AthenzInstanceProviderService(AthenzProviderServiceConfig config, SuperModelProvider superModelProvider,
- NodeRepository nodeRepository, Zone zone) {
- this(config, new FileBackedKeyProvider(config.keyPathPrefix()), Executors.newSingleThreadScheduledExecutor(),
- superModelProvider, nodeRepository, zone, new AthenzCertificateClient(config), createSslContextFactory());
+ NodeRepository nodeRepository, Zone zone, SecretStore secretStore) {
+ this(config, new SecretStoreKeyProvider(secretStore, getZoneConfig(config, zone).secretName()), Executors.newSingleThreadScheduledExecutor(),
+ superModelProvider, nodeRepository, zone, new AthenzCertificateClient(config, getZoneConfig(config, zone)), createSslContextFactory());
}
private AthenzInstanceProviderService(AthenzProviderServiceConfig config,
@@ -115,6 +116,11 @@ public class AthenzInstanceProviderService extends AbstractComponent {
}
+ private static AthenzProviderServiceConfig.Zones getZoneConfig(AthenzProviderServiceConfig config, Zone zone) {
+ String key = zone.environment().value() + "." + zone.region().value();
+ return config.zones(key);
+ }
+
static SslContextFactory createSslContextFactory() {
try {
SslContextFactory sslContextFactory = new SslContextFactory();
@@ -137,22 +143,25 @@ public class AthenzInstanceProviderService extends AbstractComponent {
private final SslContextFactory sslContextFactory;
private final KeyProvider keyProvider;
private final AthenzProviderServiceConfig config;
+ private final AthenzProviderServiceConfig.Zones zoneConfig;
AthenzCertificateUpdater(CertificateClient certificateClient,
SslContextFactory sslContextFactory,
KeyProvider keyProvider,
- AthenzProviderServiceConfig config) {
+ AthenzProviderServiceConfig config,
+ AthenzProviderServiceConfig.Zones zoneConfig) {
this.certificateClient = certificateClient;
this.sslContextFactory = sslContextFactory;
this.keyProvider = keyProvider;
this.config = config;
+ this.zoneConfig = zoneConfig;
}
@Override
public void run() {
try {
log.log(LogLevel.INFO, "Updating Athenz certificate through ZTS");
- PrivateKey privateKey = keyProvider.getPrivateKey(config.keyVersion());
+ PrivateKey privateKey = keyProvider.getPrivateKey(zoneConfig.secretVersion());
X509Certificate certificate = certificateClient.updateCertificate(privateKey, EXPIRY_TIME);
String dummyPassword = "athenz";
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java
index 031133ade19..dab1581f580 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/AthenzCertificateClient.java
@@ -21,24 +21,26 @@ public class AthenzCertificateClient implements CertificateClient {
private final AthenzProviderServiceConfig config;
private final AthenzPrincipalAuthority authority;
+ private final AthenzProviderServiceConfig.Zones zoneConfig;
- public AthenzCertificateClient(AthenzProviderServiceConfig config) {
+ public AthenzCertificateClient(AthenzProviderServiceConfig config, AthenzProviderServiceConfig.Zones zoneConfig) {
this.config = config;
this.authority = new AthenzPrincipalAuthority(config.athenzPrincipalHeaderName());
+ this.zoneConfig = zoneConfig;
}
@Override
public X509Certificate updateCertificate(PrivateKey privateKey, TemporalAmount expiryTime) {
SimpleServiceIdentityProvider identityProvider = new SimpleServiceIdentityProvider(
- authority, config.domain(), config.serviceName(),
- privateKey, Integer.toString(config.keyVersion()), TimeUnit.MINUTES.toSeconds(10));
+ authority, zoneConfig.domain(), zoneConfig.serviceName(),
+ privateKey, Integer.toString(zoneConfig.secretVersion()), TimeUnit.MINUTES.toSeconds(10));
ZTSClient ztsClient = new ZTSClient(
- config.ztsUrl(), config.domain(), config.serviceName(), identityProvider);
+ config.ztsUrl(), zoneConfig.domain(), zoneConfig.serviceName(), identityProvider);
InstanceRefreshRequest req =
ZTSClient.generateInstanceRefreshRequest(
- config.domain(), config.serviceName(), privateKey,
+ zoneConfig.domain(), zoneConfig.serviceName(), privateKey,
config.certDnsSuffix(), (int)expiryTime.get(ChronoUnit.SECONDS));
- String pemEncoded = ztsClient.postInstanceRefreshRequest(config.domain(), config.serviceName(), req)
+ String pemEncoded = ztsClient.postInstanceRefreshRequest(zoneConfig.domain(), zoneConfig.serviceName(), req)
.getCertificate();
return Crypto.loadX509Certificate(pemEncoded);
}
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGenerator.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGenerator.java
index 0e8ca0017f4..55acf0b796c 100644
--- a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGenerator.java
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/IdentityDocumentGenerator.java
@@ -27,15 +27,18 @@ public class IdentityDocumentGenerator {
private final String providerService;
private final String ztsUrl;
private final String providerDomain;
+ private final int signingSecretVersion;
- public IdentityDocumentGenerator(AthenzProviderServiceConfig config, NodeRepository nodeRepository, Zone zone, KeyProvider keyProvider) {
+ public IdentityDocumentGenerator(AthenzProviderServiceConfig config, AthenzProviderServiceConfig.Zones zoneConfig,
+ NodeRepository nodeRepository, Zone zone, KeyProvider keyProvider) {
this.nodeRepository = nodeRepository;
this.zone = zone;
this.keyProvider = keyProvider;
this.dnsSuffix = config.certDnsSuffix();
- this.providerService = config.serviceName();
+ this.providerService = zoneConfig.serviceName();
this.ztsUrl = config.ztsUrl();
- this.providerDomain = config.domain();
+ this.providerDomain = zoneConfig.domain();
+ this.signingSecretVersion = zoneConfig.secretVersion();
}
public String generateSignedIdentityDocument(String hostname) {
@@ -49,7 +52,7 @@ public class IdentityDocumentGenerator {
Signature sigGenerator = Signature.getInstance("SHA512withRSA");
// TODO: Get the correct version 0 ok for now
- PrivateKey privateKey = keyProvider.getPrivateKey(0);
+ PrivateKey privateKey = keyProvider.getPrivateKey(signingSecretVersion);
sigGenerator.initSign(privateKey);
sigGenerator.update(encodedIdentityDocument.getBytes());
String signature = Base64.getEncoder().encodeToString(sigGenerator.sign());
diff --git a/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/SecretStoreKeyProvider.java b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/SecretStoreKeyProvider.java
new file mode 100644
index 00000000000..93abda1f9ea
--- /dev/null
+++ b/athenz-identity-provider-service/src/main/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/impl/SecretStoreKeyProvider.java
@@ -0,0 +1,56 @@
+// Copyright 2017 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.impl;
+
+import com.yahoo.athenz.auth.util.Crypto;
+import com.yahoo.jdisc.http.SecretStore;
+
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author mortent
+ */
+public class SecretStoreKeyProvider implements KeyProvider {
+
+ private final SecretStore secretStore;
+ private final String secretName;
+ private final Map<Integer, KeyPair> secrets;
+
+
+ public SecretStoreKeyProvider(SecretStore secretStore, String secretName) {
+ this.secretStore = secretStore;
+ this.secretName = secretName;
+ this.secrets = new HashMap<>();
+ }
+
+ @Override
+ public PrivateKey getPrivateKey(int version) {
+ return getKeyPair(version).getPrivate();
+ }
+
+ @Override
+ public PublicKey getPublicKey(int version) {
+ return getKeyPair(version).getPublic();
+ }
+
+ private KeyPair getKeyPair(int version) {
+ synchronized (secrets) {
+ KeyPair keyPair = secrets.get(version);
+ if (keyPair == null) {
+ keyPair = readKeyPair(version);
+ secrets.put(version, keyPair);
+ }
+ return keyPair;
+ }
+ }
+
+ // TODO: Consider moving to cryptoutils
+ private KeyPair readKeyPair(int version) {
+ PrivateKey privateKey = Crypto.loadPrivateKey(secretStore.getSecret(secretName, version));
+ PublicKey publicKey = Crypto.extractPublicKey(privateKey);
+ return new KeyPair(publicKey, privateKey);
+ }
+}
diff --git a/athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def b/athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def
index 7e9c19cb86a..4aad9a4eae2 100644
--- a/athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def
+++ b/athenz-identity-provider-service/src/main/resources/configdefinitions/athenz-provider-service.def
@@ -2,28 +2,28 @@
namespace=vespa.hosted.athenz.instanceproviderservice.config
# Athenz domain
-domain string
+zones{}.domain string
# Athenz service name
-serviceName string
+zones{}.serviceName string
-# Current key version
-keyVersion int default=0
+# Secret name of private Key
+zones{}.secretName string
-# HTTPS port for Athenz Provider Service endpoint
-port int default=8443
+# Secret version
+zones{}.secretVersion int
-# File name prefix for private and public key. Component assumes suffix .[priv|pub].<version>.
-keyPathPrefix string
+# HTTPS port for Athenz Provider Service endpoint
+port int default=8443
# InstanceConfirmation API path
-apiPath string default="/athenz/v1/provider"
+apiPath string default="/athenz/v1/provider"
# Athenz principal authority header name
-athenzPrincipalHeaderName string default="Athenz-Principal-Auth"
+athenzPrincipalHeaderName string default="Athenz-Principal-Auth"
# Athenz ZTS server url
-ztsUrl string
+ztsUrl string
# Certificate DNS suffix
-certDnsSuffix string
+certDnsSuffix string
diff --git a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java
index a3cc82cd917..6a74d9ce3ad 100644
--- a/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java
+++ b/athenz-identity-provider-service/src/test/java/com/yahoo/vespa/hosted/athenz/instanceproviderservice/AthenzInstanceProviderServiceTest.java
@@ -123,16 +123,19 @@ public class AthenzInstanceProviderServiceTest {
public static AthenzProviderServiceConfig getAthenzProviderConfig(String domain, String service, String dnsSuffix) {
return new AthenzProviderServiceConfig(
new AthenzProviderServiceConfig.Builder()
- .domain(domain)
- .serviceName(service)
+ .zones(ImmutableMap.of(zone.environment().value() + "." + zone.region().value(), zoneConfig))
.port(PORT)
- .keyPathPrefix("dummy-path")
.certDnsSuffix(dnsSuffix)
.ztsUrl("localhost/zts")
.athenzPrincipalHeaderName("Athenz-Principal-Auth")
.apiPath(""));
}
+
+ private AthenzProviderServiceConfig.Zones getZoneConfig(AthenzProviderServiceConfig config, Zone zone) {
+ return config.zones(zone.environment().value() + "." + zone.region().value());
+ }
+
private static boolean getStatus(HttpClient client) {
try {
HttpResponse response = client.execute(new HttpGet("https://localhost:" + PORT + "/status.html"));
@@ -226,17 +229,20 @@ public class AthenzInstanceProviderServiceTest {
private final KeyPair keyPair;
private final AthenzProviderServiceConfig config;
+ private final AthenzProviderServiceConfig.Zones zoneConfig;
- private SelfSignedCertificateClient(KeyPair keyPair, AthenzProviderServiceConfig config) {
+ private SelfSignedCertificateClient(KeyPair keyPair, AthenzProviderServiceConfig config,
+ AthenzProviderServiceConfig.Zones zoneConfig) {
this.keyPair = keyPair;
this.config = config;
+ this.zoneConfig = zoneConfig;
}
@Override
public X509Certificate updateCertificate(PrivateKey privateKey, TemporalAmount expiryTime) {
try {
ContentSigner contentSigner = new JcaContentSignerBuilder("SHA512WithRSA").build(keyPair.getPrivate());
- X500Name dnName = new X500Name("CN=" + config.domain() + "." + config.serviceName());
+ X500Name dnName = new X500Name("CN=" + zoneConfig.domain() + "." + zoneConfig.serviceName());
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.HOUR, 1);
Date endDate = calendar.getTime();