diff options
author | Valerij Fredriksen <valerijf@oath.com> | 2017-11-02 15:57:23 +0100 |
---|---|---|
committer | Valerij Fredriksen <valerijf@oath.com> | 2017-11-02 15:57:23 +0100 |
commit | 1e1b84fbf754e5e90f815a5c2f83ca79865505d5 (patch) | |
tree | 325b6a8c11f98878199e080446774012e52b1b7d /athenz-identity-provider-service/src/main | |
parent | 1721b453c41d030b7892d86f92740b577a7aaf77 (diff) | |
parent | 25a2dc312d6b1b8e8dbefce9e06f9bd4619bd176 (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/src/main')
5 files changed, 98 insertions, 28 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 |