Skip to content

Commit

Permalink
Merge pull request #565 from QuorumEngineering/feature/hashicorp-vaul…
Browse files Browse the repository at this point in the history
…t-support

Add support for Hashicorp Vault to store Tessera keys
  • Loading branch information
Krish1979 authored Dec 17, 2018
2 parents caa956e + 7145583 commit 08fa1bb
Show file tree
Hide file tree
Showing 94 changed files with 3,636 additions and 342 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,42 @@ private Options buildBaseOptions() {
.build()
);

options.addOption(
Option.builder("keygenvaultapprole")
.desc("AppRole path for Hashicorp Vault authentication (defaults to 'approle')")
.hasArg()
.optionalArg(false)
.argName("STRING")
.build()
);

options.addOption(
Option.builder("keygenvaultkeystore")
.desc("Path to JKS keystore for TLS Hashicorp Vault communication")
.hasArg()
.optionalArg(false)
.argName("PATH")
.build()
);

options.addOption(
Option.builder("keygenvaulttruststore")
.desc("Path to JKS truststore for TLS Hashicorp Vault communication")
.hasArg()
.optionalArg(false)
.argName("PATH")
.build()
);

options.addOption(
Option.builder("keygenvaultsecretengine")
.desc("Name of already enabled Hashicorp v2 kv secret engine")
.hasArg()
.optionalArg(false)
.argName("STRING")
.build()
);

options.addOption(
Option.builder("pidfile")
.desc("Path to pid file")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package com.quorum.tessera.config.cli.parsers;

import com.quorum.tessera.config.ArgonOptions;
import com.quorum.tessera.config.AzureKeyVaultConfig;
import com.quorum.tessera.config.KeyVaultConfig;
import com.quorum.tessera.config.KeyVaultType;
import com.quorum.tessera.config.*;
import com.quorum.tessera.config.cli.CliException;
import com.quorum.tessera.config.keypairs.ConfigKeyPair;
import com.quorum.tessera.config.util.JaxbUtil;
import com.quorum.tessera.key.generation.KeyGenerator;
import com.quorum.tessera.key.generation.KeyGeneratorFactory;
import com.quorum.tessera.key.generation.KeyVaultOptions;
import org.apache.commons.cli.CommandLine;

import javax.validation.ConstraintViolation;
Expand All @@ -18,6 +16,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -41,14 +40,15 @@ public class KeyGenerationParser implements Parser<List<ConfigKeyPair>> {
public List<ConfigKeyPair> parse(final CommandLine commandLine) throws IOException {

final ArgonOptions argonOptions = this.argonOptions(commandLine).orElse(null);
final KeyVaultOptions keyVaultOptions = this.keyVaultOptions(commandLine).orElse(null);
final KeyVaultConfig keyVaultConfig = this.keyVaultConfig(commandLine).orElse(null);

final KeyGenerator generator = factory.create(keyVaultConfig);

if (commandLine.hasOption("keygen")) {
return this.filenames(commandLine)
.stream()
.map(name -> generator.generate(name, argonOptions))
.map(name -> generator.generate(name, argonOptions, keyVaultOptions))
.collect(Collectors.toList());
}

Expand All @@ -68,6 +68,12 @@ private Optional<ArgonOptions> argonOptions(final CommandLine commandLine) throw
return Optional.empty();
}

private Optional<KeyVaultOptions> keyVaultOptions(final CommandLine commandLine) {
Optional<String> secretEngineName = Optional.ofNullable(commandLine.getOptionValue("keygenvaultsecretengine"));

return secretEngineName.map(KeyVaultOptions::new);
}

private List<String> filenames(final CommandLine commandLine) {

if (commandLine.hasOption("filename")) {
Expand All @@ -88,23 +94,55 @@ private Optional<KeyVaultConfig> keyVaultConfig(CommandLine commandLine) {
return Optional.empty();
}

String t = commandLine.getOptionValue("keygenvaulttype");
final String t = commandLine.getOptionValue("keygenvaulttype");

KeyVaultType keyVaultType;
try {
KeyVaultType.valueOf(t);
keyVaultType = KeyVaultType.valueOf(
t.trim()
.toUpperCase()
);
} catch(IllegalArgumentException | NullPointerException e) {
throw new CliException("Key vault type either not provided or not recognised. Ensure provided value is UPPERCASE and has no leading or trailing whitespace characters");
throw new CliException("Key vault type either not provided or not recognised");
}

String keyVaultUrl = commandLine.getOptionValue("keygenvaulturl");

//Only Azure supported atm so no need to check keyvaulttype
KeyVaultConfig keyVaultConfig = new AzureKeyVaultConfig(keyVaultUrl);
KeyVaultConfig keyVaultConfig;

if(keyVaultType.equals(KeyVaultType.AZURE)) {
keyVaultConfig = new AzureKeyVaultConfig(keyVaultUrl);

Set<ConstraintViolation<AzureKeyVaultConfig>> violations = validator.validate((AzureKeyVaultConfig)keyVaultConfig);
Set<ConstraintViolation<AzureKeyVaultConfig>> violations = validator.validate((AzureKeyVaultConfig)keyVaultConfig);

if(!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
} else {
if(!commandLine.hasOption("filename")) {
throw new CliException("At least one -filename must be provided when saving generated keys in a Hashicorp Vault");
}

if(!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
String approlePath = commandLine.getOptionValue("keygenvaultapprole");

Optional<Path> tlsKeyStorePath = Optional.ofNullable(commandLine.getOptionValue("keygenvaultkeystore"))
.map(Paths::get);

Optional<Path> tlsTrustStorePath = Optional.ofNullable(commandLine.getOptionValue("keygenvaulttruststore"))
.map(Paths::get);

keyVaultConfig = new HashicorpKeyVaultConfig(
keyVaultUrl,
approlePath,
tlsKeyStorePath.orElse(null),
tlsTrustStorePath.orElse(null)
);

Set<ConstraintViolation<HashicorpKeyVaultConfig>> violations = validator.validate((HashicorpKeyVaultConfig)keyVaultConfig);

if(!violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
}

return Optional.of(keyVaultConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public void keygenWithConfig() throws Exception {
Files.write(publicKeyPath, Arrays.asList("SOMEDATA"));

FilesystemKeyPair keypair = new FilesystemKeyPair(publicKeyPath, privateKeyPath);
when(keyGenerator.generate(anyString(), eq(null))).thenReturn(keypair);
when(keyGenerator.generate(anyString(), eq(null), eq(null))).thenReturn(keypair);

Path unixSocketPath = Files.createTempFile(UUID.randomUUID().toString(), ".ipc");

Expand All @@ -143,7 +143,7 @@ public void keygenWithConfig() throws Exception {
assertThat(result.getConfig()).isNotNull();
assertThat(result.isSuppressStartup()).isFalse();

verify(keyGenerator).generate(anyString(), eq(null));
verify(keyGenerator).generate(anyString(), eq(null), eq(null));
verifyNoMoreInteractions(keyGenerator);

}
Expand Down Expand Up @@ -191,7 +191,7 @@ public void output() throws Exception {
Files.write(publicKeyPath, Arrays.asList("SOMEDATA"));

FilesystemKeyPair keypair = new FilesystemKeyPair(publicKeyPath, privateKeyPath);
when(keyGenerator.generate(anyString(), eq(null))).thenReturn(keypair);
when(keyGenerator.generate(anyString(), eq(null), eq(null))).thenReturn(keypair);

Path generatedKey = Paths.get("/tmp/" + UUID.randomUUID().toString());

Expand Down Expand Up @@ -376,7 +376,7 @@ public void allowStartupForKeygenAndConfigfileOptions() throws Exception {
Files.write(publicKeyPath, Arrays.asList("SOMEDATA"));

FilesystemKeyPair keypair = new FilesystemKeyPair(publicKeyPath, privateKeyPath);
when(keyGenerator.generate(anyString(), eq(null))).thenReturn(keypair);
when(keyGenerator.generate(anyString(), eq(null), eq(null))).thenReturn(keypair);

final Path configFile = createAndPopulatePaths(getClass().getResource("/sample-config.json"));

Expand All @@ -389,7 +389,7 @@ public void allowStartupForKeygenAndConfigfileOptions() throws Exception {
public void suppressStartupForKeygenAndVaultUrlAndConfigfileOptions() throws Exception {
final KeyGenerator keyGenerator = MockKeyGeneratorFactory.getMockKeyGenerator();
final FilesystemKeyPair keypair = new FilesystemKeyPair(Paths.get(""), Paths.get(""));
when(keyGenerator.generate(anyString(), eq(null))).thenReturn(keypair);
when(keyGenerator.generate(anyString(), eq(null), eq(null))).thenReturn(keypair);

final Path configFile = createAndPopulatePaths(getClass().getResource("/sample-config.json"));
final String vaultUrl = "https://test.vault.azure.net";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.quorum.tessera.config.cli;

import com.quorum.tessera.config.*;
import com.quorum.tessera.config.Config;
import com.quorum.tessera.config.KeyConfiguration;
import com.quorum.tessera.config.Peer;
import com.quorum.tessera.config.SslAuthenticationMode;
import com.quorum.tessera.config.util.JaxbUtil;
import org.junit.Ignore;
import org.junit.Test;
Expand Down Expand Up @@ -29,80 +32,84 @@ public class OverrideUtilTest {
public void buildOptions() {

final List<String> expected = Arrays.asList(
"jdbc.username",
"jdbc.password",
"jdbc.url",
"jdbc.autoCreateTables",
"peer.url",
"keys.passwordFile",
"keys.passwords",
"keys.keyData.config.data.aopts.algorithm",
"keys.keyData.config.data.aopts.iterations",
"keys.keyData.config.data.aopts.memory",
"keys.keyData.config.data.aopts.parallelism",
"keys.keyData.privateKeyPath",
"keys.azureKeyVaultConfig.url",
"alwaysSendTo",
"unixSocketFile",
"useWhiteList",
"disablePeerDiscovery",
"serverConfigs.sslConfig.serverTrustStore",
"serverConfigs.influxConfig.dbName",
"serverConfigs.sslConfig.knownClientsFile",
"serverConfigs.influxConfig.hostName",
"serverConfigs.sslConfig.serverTrustCertificates",
"serverConfigs.sslConfig.clientTrustCertificates",
"serverConfigs.sslConfig.clientTrustStorePassword",
"serverConfigs.sslConfig.generateKeyStoreIfNotExisted",
"serverConfigs.influxConfig.pushIntervalInSecs",
"serverConfigs.bindingAddress",
"serverConfigs.sslConfig.serverKeyStore",
"serverConfigs.sslConfig.serverTrustStorePassword",
"serverConfigs.sslConfig.serverKeyStorePassword",
"serverConfigs.sslConfig.clientTrustMode",
"serverConfigs.sslConfig.clientKeyStorePassword",
"serverConfigs.communicationType",
"serverConfigs.sslConfig.clientTlsCertificatePath",
"serverConfigs.sslConfig.serverTlsKeyPath",
"serverConfigs.sslConfig.clientKeyStore",
"serverConfigs.sslConfig.serverTrustMode",
"serverConfigs.influxConfig.port",
"serverConfigs.sslConfig.clientTlsKeyPath",
"serverConfigs.app",
"serverConfigs.sslConfig.clientTrustStore",
"serverConfigs.enabled",
"serverConfigs.sslConfig.serverTlsCertificatePath",
"serverConfigs.sslConfig.tls",
"serverConfigs.sslConfig.knownServersFile",
"server.hostName",
"server.sslConfig.knownServersFile",
"server.sslConfig.clientTrustStorePassword",
"server.sslConfig.clientKeyStorePassword",
"server.sslConfig.clientTlsKeyPath",
"server.sslConfig.clientTrustCertificates",
"server.sslConfig.knownClientsFile",
"server.communicationType",
"server.sslConfig.serverTrustStorePassword",
"server.sslConfig.serverTrustCertificates",
"server.sslConfig.clientTrustStore",
"server.sslConfig.tls",
"server.sslConfig.serverTlsCertificatePath",
"server.grpcPort",
"server.sslConfig.serverKeyStore",
"server.influxConfig.port",
"server.port",
"server.sslConfig.generateKeyStoreIfNotExisted",
"server.sslConfig.clientTlsCertificatePath",
"server.sslConfig.serverTlsKeyPath",
"server.influxConfig.hostName",
"server.sslConfig.serverTrustStore",
"server.bindingAddress",
"server.sslConfig.serverTrustMode",
"server.sslConfig.clientKeyStore",
"server.influxConfig.dbName",
"server.sslConfig.clientTrustMode",
"server.influxConfig.pushIntervalInSecs",
"server.sslConfig.serverKeyStorePassword"
"jdbc.username",
"jdbc.password",
"jdbc.url",
"jdbc.autoCreateTables",
"peer.url",
"keys.passwordFile",
"keys.passwords",
"keys.keyData.config.data.aopts.algorithm",
"keys.keyData.config.data.aopts.iterations",
"keys.keyData.config.data.aopts.memory",
"keys.keyData.config.data.aopts.parallelism",
"keys.keyData.privateKeyPath",
"keys.azureKeyVaultConfig.url",
"keys.hashicorpKeyVaultConfig.approlePath",
"keys.hashicorpKeyVaultConfig.tlsKeyStorePath",
"keys.hashicorpKeyVaultConfig.tlsTrustStorePath",
"keys.hashicorpKeyVaultConfig.url",
"alwaysSendTo",
"unixSocketFile",
"useWhiteList",
"disablePeerDiscovery",
"serverConfigs.sslConfig.serverTrustStore",
"serverConfigs.influxConfig.dbName",
"serverConfigs.sslConfig.knownClientsFile",
"serverConfigs.influxConfig.hostName",
"serverConfigs.sslConfig.serverTrustCertificates",
"serverConfigs.sslConfig.clientTrustCertificates",
"serverConfigs.sslConfig.clientTrustStorePassword",
"serverConfigs.sslConfig.generateKeyStoreIfNotExisted",
"serverConfigs.influxConfig.pushIntervalInSecs",
"serverConfigs.bindingAddress",
"serverConfigs.sslConfig.serverKeyStore",
"serverConfigs.sslConfig.serverTrustStorePassword",
"serverConfigs.sslConfig.serverKeyStorePassword",
"serverConfigs.sslConfig.clientTrustMode",
"serverConfigs.sslConfig.clientKeyStorePassword",
"serverConfigs.communicationType",
"serverConfigs.sslConfig.clientTlsCertificatePath",
"serverConfigs.sslConfig.serverTlsKeyPath",
"serverConfigs.sslConfig.clientKeyStore",
"serverConfigs.sslConfig.serverTrustMode",
"serverConfigs.influxConfig.port",
"serverConfigs.sslConfig.clientTlsKeyPath",
"serverConfigs.app",
"serverConfigs.sslConfig.clientTrustStore",
"serverConfigs.enabled",
"serverConfigs.sslConfig.serverTlsCertificatePath",
"serverConfigs.sslConfig.tls",
"serverConfigs.sslConfig.knownServersFile",
"server.hostName",
"server.sslConfig.knownServersFile",
"server.sslConfig.clientTrustStorePassword",
"server.sslConfig.clientKeyStorePassword",
"server.sslConfig.clientTlsKeyPath",
"server.sslConfig.clientTrustCertificates",
"server.sslConfig.knownClientsFile",
"server.communicationType",
"server.sslConfig.serverTrustStorePassword",
"server.sslConfig.serverTrustCertificates",
"server.sslConfig.clientTrustStore",
"server.sslConfig.tls",
"server.sslConfig.serverTlsCertificatePath",
"server.grpcPort",
"server.sslConfig.serverKeyStore",
"server.influxConfig.port",
"server.port",
"server.sslConfig.generateKeyStoreIfNotExisted",
"server.sslConfig.clientTlsCertificatePath",
"server.sslConfig.serverTlsKeyPath",
"server.influxConfig.hostName",
"server.sslConfig.serverTrustStore",
"server.bindingAddress",
"server.sslConfig.serverTrustMode",
"server.sslConfig.clientKeyStore",
"server.influxConfig.dbName",
"server.sslConfig.clientTrustMode",
"server.influxConfig.pushIntervalInSecs",
"server.sslConfig.serverKeyStorePassword"
);

final Map<String, Class> results = OverrideUtil.buildConfigOptions();
Expand Down
Loading

0 comments on commit 08fa1bb

Please sign in to comment.