ENT-2689: Change SSL config structure (#1551)

* ENT-2689: Intent of the changes to be made (doesn't compile)

* ENT-2689: Propagate renaming of `customSSLConfiguration`

* ENT-2689: Documentation update

* ENT-2689: More renaming

* ENT-2689: Add a test for SSL keystores location override

* ENT-2689: Add V3 configuration compatibility unit tests (failing for now)

* ENT-2689: Add ability to read V3 configs.

* ENT-2689: Reflect changes on Integration tests.

* ENT-2689: For BridgeControlListener use Artemis SSL configuration if specified, otherwise fall back onto main SSL configuration.

* Revert: ENT-2689: For BridgeControlListener use Artemis SSL configuration if specified, otherwise fall back onto main SSL configuration.

And rename `p2pSslOptions` to `publicSSLConfiguration`.

* ENT-2689: Move V3 config structures into a separate file.
This commit is contained in:
Viktor Kolomeyko 2018-11-13 16:34:41 +00:00 committed by GitHub
parent b456ed4ddd
commit 482277bad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 281 additions and 151 deletions

View File

@ -135,14 +135,14 @@ class BridgeIntegrationTest {
val bridgeFolder = tempFolder.root.toPath()
val bridgeConfigResource = "/net/corda/bridge/withfloatdiffpasswords/bridge/firewall.conf"
val bridgeConfig = createAndLoadConfigFromResource(bridgeFolder, bridgeConfigResource)
listOf(bridgeConfig.p2pSslOptions, bridgeConfig.bridgeInnerConfig?.customSSLConfiguration).forEach { it?.createBridgeKeyStores(DUMMY_BANK_A_NAME) }
listOf(bridgeConfig.publicSSLConfiguration, bridgeConfig.bridgeInnerConfig?.tunnelSSLConfiguration).forEach { it?.createBridgeKeyStores(DUMMY_BANK_A_NAME) }
createNetworkParams(bridgeFolder)
assertEquals(FirewallMode.BridgeInner, bridgeConfig.firewallMode)
assertEquals(NetworkHostAndPort("localhost", 11005), bridgeConfig.outboundConfig!!.artemisBrokerAddress)
val floatFolder = tempFolder.root.toPath() / "float"
val floatConfigResource = "/net/corda/bridge/withfloatdiffpasswords/float/firewall.conf"
val floatConfig = createAndLoadConfigFromResource(floatFolder, floatConfigResource)
listOf(floatConfig.p2pSslOptions, floatConfig.inboundConfig?.customSSLConfiguration, floatConfig.floatOuterConfig?.customSSLConfiguration).forEach { it?.createBridgeKeyStores(DUMMY_BANK_A_NAME) }
listOf(floatConfig.publicSSLConfiguration, floatConfig.inboundConfig?.customSSLConfiguration, floatConfig.floatOuterConfig?.tunnelSSLConfiguration).forEach { it?.createBridgeKeyStores(DUMMY_BANK_A_NAME) }
createNetworkParams(floatFolder)
assertEquals(FirewallMode.FloatOuter, floatConfig.firewallMode)
assertEquals(NetworkHostAndPort("0.0.0.0", 10005), floatConfig.inboundConfig!!.listeningAddress)

View File

@ -58,14 +58,14 @@ class AMQPListenerTest {
assertEquals(true, stateFollower.next())
assertEquals(true, amqpListenerService.active)
assertEquals(false, serverListening("localhost", 10005))
val keyStoreBytes = bridgeConfig.p2pSslOptions.keyStore.path.readAll()
val trustStoreBytes = bridgeConfig.p2pSslOptions.trustStore.path.readAll()
val keyStoreBytes = bridgeConfig.publicSSLConfiguration.keyStore.path.readAll()
val trustStoreBytes = bridgeConfig.publicSSLConfiguration.trustStore.path.readAll()
// start listening
amqpListenerService.provisionKeysAndActivate(keyStoreBytes,
bridgeConfig.p2pSslOptions.keyStore.storePassword.toCharArray(),
bridgeConfig.p2pSslOptions.keyStore.entryPassword.toCharArray(),
bridgeConfig.publicSSLConfiguration.keyStore.storePassword.toCharArray(),
bridgeConfig.publicSSLConfiguration.keyStore.entryPassword.toCharArray(),
trustStoreBytes,
bridgeConfig.p2pSslOptions.trustStore.storePassword.toCharArray())
bridgeConfig.publicSSLConfiguration.trustStore.storePassword.toCharArray())
// Fire lots of activity to prove we are good
assertEquals(TestAuditService.AuditEvent.STATUS_CHANGE, auditFollower.next())
assertEquals(true, amqpListenerService.active)
@ -76,8 +76,8 @@ class AMQPListenerTest {
assertEquals(TestAuditService.AuditEvent.FAILED_CONNECTION, auditFollower.next())
val clientConfig = createAndLoadConfigFromResource(tempFolder.root.toPath() / "client", configResource)
clientConfig.createBridgeKeyStores(DUMMY_BANK_B_NAME)
val clientKeyStore = clientConfig.p2pSslOptions.keyStore.get()
val clientTrustStore = clientConfig.p2pSslOptions.trustStore.get()
val clientKeyStore = clientConfig.publicSSLConfiguration.keyStore.get()
val clientTrustStore = clientConfig.publicSSLConfiguration.trustStore.get()
val amqpConfig = object : AMQPConfiguration {
override val keyStore = clientKeyStore
override val trustStore = clientTrustStore
@ -134,14 +134,14 @@ class AMQPListenerTest {
val amqpListenerService = BridgeAMQPListenerServiceImpl(bridgeConfig, maxMessageSize, auditService)
amqpListenerService.start()
auditService.start()
val keyStoreBytes = bridgeConfig.p2pSslOptions.keyStore.path.readAll()
val trustStoreBytes = bridgeConfig.p2pSslOptions.trustStore.path.readAll()
val keyStoreBytes = bridgeConfig.publicSSLConfiguration.keyStore.path.readAll()
val trustStoreBytes = bridgeConfig.publicSSLConfiguration.trustStore.path.readAll()
// start listening
amqpListenerService.provisionKeysAndActivate(keyStoreBytes,
bridgeConfig.p2pSslOptions.keyStore.storePassword.toCharArray(),
bridgeConfig.p2pSslOptions.keyStore.entryPassword.toCharArray(),
bridgeConfig.publicSSLConfiguration.keyStore.storePassword.toCharArray(),
bridgeConfig.publicSSLConfiguration.keyStore.entryPassword.toCharArray(),
trustStoreBytes,
bridgeConfig.p2pSslOptions.trustStore.storePassword.toCharArray())
bridgeConfig.publicSSLConfiguration.trustStore.storePassword.toCharArray())
val connectionFollower = amqpListenerService.onConnection.toBlocking().iterator
val auditFollower = auditService.onAuditEvent.toBlocking().iterator
val clientKeys = Crypto.generateKeyPair(ECDSA_SECP256R1_SHA256)

View File

@ -38,7 +38,7 @@ interface BridgeOutboundConfiguration {
val artemisBrokerAddress: NetworkHostAndPort
val alternateArtemisBrokerAddresses: List<NetworkHostAndPort>
// Allows override of [KeyStore] details for the artemis connection, otherwise the general top level details are used.
val customSSLConfiguration: BridgeSSLConfiguration?
val artemisSSLConfiguration: BridgeSSLConfiguration?
// Allows use of a SOCKS 4/5 proxy
val proxyConfig: ProxyConfig?
}
@ -63,9 +63,7 @@ interface BridgeInnerConfiguration {
val expectedCertificateSubject: CordaX500Name
// Allows override of [KeyStore] details for the control port, otherwise the general top level details are used.
// Used for connection to Float in DMZ
val customSSLConfiguration: BridgeSSLConfiguration?
// The SSL keystores to provision into the Float in DMZ
val customFloatOuterSSLConfiguration: BridgeSSLConfiguration?
val tunnelSSLConfiguration: BridgeSSLConfiguration?
val enableSNI: Boolean
}
@ -83,7 +81,7 @@ interface FloatOuterConfiguration {
val floatAddress: NetworkHostAndPort
val expectedCertificateSubject: CordaX500Name
// Allows override of [KeyStore] details for the control port, otherwise the general top level details are used.
val customSSLConfiguration: BridgeSSLConfiguration?
val tunnelSSLConfiguration: BridgeSSLConfiguration?
}
interface AuditServiceConfiguration {
@ -92,6 +90,9 @@ interface AuditServiceConfiguration {
interface FirewallConfiguration {
val baseDirectory: Path
val certificatesDirectory: Path
val sslKeystore: Path
val trustStoreFile: Path
val firewallMode: FirewallMode
val outboundConfig: BridgeOutboundConfiguration?
val inboundConfig: BridgeInboundConfiguration?
@ -116,7 +117,7 @@ interface FirewallConfiguration {
val p2pConfirmationWindowSize: Int
val whitelistedHeaders: List<String>
val crlCheckSoftFail: Boolean
val p2pSslOptions: MutualSslConfiguration
val publicSSLConfiguration: MutualSslConfiguration
val auditServiceConfiguration: AuditServiceConfiguration
// An optional Health Check Phrase which if passed through the channel will cause AMQP Server to echo it back instead of doing normal pipeline processing
val healthCheckPhrase: String?

View File

@ -40,7 +40,7 @@ class BridgeArtemisConnectionServiceImpl(val conf: FirewallConfiguration,
init {
statusFollower = ServiceStateCombiner(listOf(auditService))
sslConfiguration = conf.outboundConfig?.customSSLConfiguration ?: conf.p2pSslOptions
sslConfiguration = conf.outboundConfig?.artemisSSLConfiguration ?: conf.publicSSLConfiguration
}
override fun start() {

View File

@ -5,6 +5,7 @@ import com.typesafe.config.ConfigException
import com.typesafe.config.ConfigRenderOptions
import net.corda.bridge.FirewallCmdLineOptions
import net.corda.bridge.services.api.*
import net.corda.bridge.services.config.internal.Version3BridgeConfigurationImpl
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
@ -20,70 +21,6 @@ fun Config.parseAsFirewallConfiguration(): FirewallConfiguration {
FirewallCmdLineOptions.logger.info("Attempting to parse using old format")
// Previously `proxyConfig` was known as `socksProxyConfig`
data class Version3BridgeOutboundConfigurationImpl(val artemisBrokerAddress: NetworkHostAndPort,
val alternateArtemisBrokerAddresses: List<NetworkHostAndPort>,
val customSSLConfiguration: BridgeSSLConfigurationImpl?,
val socksProxyConfig: ProxyConfig? = null) {
fun toConfig(): BridgeOutboundConfigurationImpl {
return BridgeOutboundConfigurationImpl(artemisBrokerAddress, alternateArtemisBrokerAddresses,
customSSLConfiguration, socksProxyConfig)
}
}
data class Version3BridgeConfigurationImpl(
val baseDirectory: Path,
val certificatesDirectory: Path = baseDirectory / "certificates",
val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
val crlCheckSoftFail: Boolean,
val keyStorePassword: String,
val trustStorePassword: String,
val bridgeMode: FirewallMode,
val networkParametersPath: Path,
val outboundConfig: Version3BridgeOutboundConfigurationImpl?,
val inboundConfig: BridgeInboundConfigurationImpl?,
val bridgeInnerConfig: BridgeInnerConfigurationImpl?,
val floatOuterConfig: FloatOuterConfigurationImpl?,
val haConfig: BridgeHAConfigImpl?,
val enableAMQPPacketTrace: Boolean,
val artemisReconnectionIntervalMin: Int = 5000,
val artemisReconnectionIntervalMax: Int = 60000,
val politeShutdownPeriod: Int = 1000,
val p2pConfirmationWindowSize: Int = 1048576,
val whitelistedHeaders: List<String> = ArtemisMessagingComponent.Companion.P2PMessagingHeaders.whitelistedHeaders.toList(),
val healthCheckPhrase: String? = null
) {
fun toConfig(): FirewallConfiguration {
return FirewallConfigurationImpl(
baseDirectory,
certificatesDirectory,
sslKeystore,
trustStoreFile,
crlCheckSoftFail,
keyStorePassword,
trustStorePassword,
bridgeMode,
networkParametersPath,
outboundConfig?.toConfig(),
inboundConfig,
bridgeInnerConfig,
floatOuterConfig,
haConfig,
enableAMQPPacketTrace,
artemisReconnectionIntervalMin,
artemisReconnectionIntervalMax,
politeShutdownPeriod,
p2pConfirmationWindowSize,
whitelistedHeaders,
AuditServiceConfigurationImpl(60), // Same as `firewalldefault.conf`, new in v4
healthCheckPhrase
)
}
}
try {
// Note: "Ignore" is needed to disregard any default properties from "firewalldefault.conf" that are not applicable to V3 configuration
val oldStyleConfig = parseAs<Version3BridgeConfigurationImpl>(UnknownConfigKeysPolicy.IGNORE::handle)
@ -115,7 +52,7 @@ data class BridgeSSLConfigurationImpl(private val sslKeystore: Path,
data class BridgeOutboundConfigurationImpl(override val artemisBrokerAddress: NetworkHostAndPort,
override val alternateArtemisBrokerAddresses: List<NetworkHostAndPort>,
override val customSSLConfiguration: BridgeSSLConfigurationImpl?,
override val artemisSSLConfiguration: BridgeSSLConfigurationImpl?,
override val proxyConfig: ProxyConfig? = null) : BridgeOutboundConfiguration
data class BridgeInboundConfigurationImpl(override val listeningAddress: NetworkHostAndPort,
@ -123,13 +60,12 @@ data class BridgeInboundConfigurationImpl(override val listeningAddress: Network
data class BridgeInnerConfigurationImpl(override val floatAddresses: List<NetworkHostAndPort>,
override val expectedCertificateSubject: CordaX500Name,
override val customSSLConfiguration: BridgeSSLConfigurationImpl?,
override val customFloatOuterSSLConfiguration: BridgeSSLConfigurationImpl?,
override val tunnelSSLConfiguration: BridgeSSLConfigurationImpl?,
override val enableSNI: Boolean = true) : BridgeInnerConfiguration
data class FloatOuterConfigurationImpl(override val floatAddress: NetworkHostAndPort,
override val expectedCertificateSubject: CordaX500Name,
override val customSSLConfiguration: BridgeSSLConfigurationImpl?) : FloatOuterConfiguration
override val tunnelSSLConfiguration: BridgeSSLConfigurationImpl?) : FloatOuterConfiguration
data class BridgeHAConfigImpl(override val haConnectionString: String, override val haPriority: Int = 10, override val haTopic: String = "/bridge/ha") : BridgeHAConfig
@ -137,9 +73,9 @@ data class AuditServiceConfigurationImpl(override val loggingIntervalSec: Long)
data class FirewallConfigurationImpl(
override val baseDirectory: Path,
private val certificatesDirectory: Path = baseDirectory / "certificates",
private val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
private val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
override val certificatesDirectory: Path = baseDirectory / "certificates",
override val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
override val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
override val crlCheckSoftFail: Boolean,
private val keyStorePassword: String,
private val trustStorePassword: String,
@ -172,7 +108,7 @@ data class FirewallConfigurationImpl(
private val p2pTrustStoreFilePath = trustStoreFile
// Due to Artemis limitations setting private key password same as key store password.
private val p2pTrustStore = FileBasedCertificateStoreSupplier(p2pTrustStoreFilePath, trustStorePassword, entryPassword = trustStorePassword)
override val p2pSslOptions: MutualSslConfiguration = SslConfiguration.mutual(p2pKeyStore, p2pTrustStore)
override val publicSSLConfiguration: MutualSslConfiguration = SslConfiguration.mutual(p2pKeyStore, p2pTrustStore)
}

View File

@ -0,0 +1,92 @@
package net.corda.bridge.services.config.internal
import net.corda.bridge.services.api.FirewallConfiguration
import net.corda.bridge.services.api.FirewallMode
import net.corda.bridge.services.config.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.ArtemisMessagingComponent
import net.corda.nodeapi.internal.protonwrapper.netty.ProxyConfig
import java.nio.file.Path
// Previously `proxyConfig` was known as `socksProxyConfig` and `artemisSSLConfiguration` as `customSSLConfiguration`
internal data class Version3BridgeOutboundConfigurationImpl(val artemisBrokerAddress: NetworkHostAndPort,
val alternateArtemisBrokerAddresses: List<NetworkHostAndPort>,
val customSSLConfiguration: BridgeSSLConfigurationImpl?,
val socksProxyConfig: ProxyConfig? = null) {
fun toConfig(): BridgeOutboundConfigurationImpl {
return BridgeOutboundConfigurationImpl(artemisBrokerAddress, alternateArtemisBrokerAddresses,
customSSLConfiguration, socksProxyConfig)
}
}
// Previously `tunnelSSLConfiguration` was known as `customSSLConfiguration`
internal data class Version3BridgeInnerConfigurationImpl(val floatAddresses: List<NetworkHostAndPort>,
val expectedCertificateSubject: CordaX500Name,
val customSSLConfiguration: BridgeSSLConfigurationImpl?,
val enableSNI: Boolean = true) {
fun toConfig(): BridgeInnerConfigurationImpl {
return BridgeInnerConfigurationImpl(floatAddresses, expectedCertificateSubject, customSSLConfiguration, enableSNI)
}
}
// Previously `tunnelSSLConfiguration` was known as `customSSLConfiguration`
internal data class Version3FloatOuterConfigurationImpl(val floatAddress: NetworkHostAndPort,
val expectedCertificateSubject: CordaX500Name,
val customSSLConfiguration: BridgeSSLConfigurationImpl?) {
fun toConfig(): FloatOuterConfigurationImpl {
return FloatOuterConfigurationImpl(floatAddress, expectedCertificateSubject, customSSLConfiguration)
}
}
internal data class Version3BridgeConfigurationImpl(
val baseDirectory: Path,
val certificatesDirectory: Path = baseDirectory / "certificates",
val sslKeystore: Path = certificatesDirectory / "sslkeystore.jks",
val trustStoreFile: Path = certificatesDirectory / "truststore.jks",
val crlCheckSoftFail: Boolean,
val keyStorePassword: String,
val trustStorePassword: String,
val bridgeMode: FirewallMode,
val networkParametersPath: Path,
val outboundConfig: Version3BridgeOutboundConfigurationImpl?,
val inboundConfig: BridgeInboundConfigurationImpl?,
val bridgeInnerConfig: Version3BridgeInnerConfigurationImpl?,
val floatOuterConfig: Version3FloatOuterConfigurationImpl?,
val haConfig: BridgeHAConfigImpl?,
val enableAMQPPacketTrace: Boolean,
val artemisReconnectionIntervalMin: Int = 5000,
val artemisReconnectionIntervalMax: Int = 60000,
val politeShutdownPeriod: Int = 1000,
val p2pConfirmationWindowSize: Int = 1048576,
val whitelistedHeaders: List<String> = ArtemisMessagingComponent.Companion.P2PMessagingHeaders.whitelistedHeaders.toList(),
val healthCheckPhrase: String? = null
) {
fun toConfig(): FirewallConfiguration {
return FirewallConfigurationImpl(
baseDirectory,
certificatesDirectory,
sslKeystore,
trustStoreFile,
crlCheckSoftFail,
keyStorePassword,
trustStorePassword,
bridgeMode,
networkParametersPath,
outboundConfig?.toConfig(),
inboundConfig,
bridgeInnerConfig?.toConfig(),
floatOuterConfig?.toConfig(),
haConfig,
enableAMQPPacketTrace,
artemisReconnectionIntervalMin,
artemisReconnectionIntervalMax,
politeShutdownPeriod,
p2pConfirmationWindowSize,
whitelistedHeaders,
AuditServiceConfigurationImpl(60), // Same as `firewalldefault.conf`, new in v4
healthCheckPhrase
)
}
}

View File

@ -38,8 +38,8 @@ class FloatControlListenerService(val conf: FirewallConfiguration,
private var connectSubscriber: Subscription? = null
private var receiveSubscriber: Subscription? = null
private var amqpControlServer: AMQPServer? = null
private val sslConfiguration: MutualSslConfiguration = conf.floatOuterConfig?.customSSLConfiguration
?: conf.p2pSslOptions
private val sslConfiguration: MutualSslConfiguration = conf.floatOuterConfig?.tunnelSSLConfiguration
?: conf.publicSSLConfiguration
private val floatControlAddress = conf.floatOuterConfig!!.floatAddress
private val floatClientName = conf.floatOuterConfig!!.expectedCertificateSubject
private var activeConnectionInfo: ConnectionChange? = null

View File

@ -26,7 +26,7 @@ class InProcessBridgeReceiverService(val conf: FirewallConfiguration,
init {
statusFollower = ServiceStateCombiner(listOf(auditService, haService, amqpListenerService, filterService))
sslConfiguration = conf.inboundConfig?.customSSLConfiguration ?: conf.p2pSslOptions
sslConfiguration = conf.inboundConfig?.customSSLConfiguration ?: conf.publicSSLConfiguration
}
override fun start() {

View File

@ -40,8 +40,8 @@ class TunnelingBridgeReceiverService(val conf: FirewallConfiguration,
private var connectSubscriber: Subscription? = null
private var receiveSubscriber: Subscription? = null
private var amqpControlClient: AMQPClient? = null
private val controlLinkSSLConfiguration: MutualSslConfiguration = conf.bridgeInnerConfig?.customSSLConfiguration ?: conf.p2pSslOptions
private val floatListenerSSLConfiguration: MutualSslConfiguration = conf.bridgeInnerConfig?.customFloatOuterSSLConfiguration ?: conf.p2pSslOptions
private val controlLinkSSLConfiguration: MutualSslConfiguration = conf.bridgeInnerConfig?.tunnelSSLConfiguration ?: conf.publicSSLConfiguration
private val floatListenerSSLConfiguration: MutualSslConfiguration = conf.publicSSLConfiguration
private val expectedCertificateSubject: CordaX500Name = conf.bridgeInnerConfig!!.expectedCertificateSubject
private val secureRandom: SecureRandom = newSecureRandom()

View File

@ -27,7 +27,7 @@ class DirectBridgeSenderService(val conf: FirewallConfiguration,
private val statusFollower: ServiceStateCombiner = ServiceStateCombiner(listOf(auditService, artemisConnectionService, haService))
private var statusSubscriber: Subscription? = null
private var listenerActiveSubscriber: Subscription? = null
private var bridgeControlListener = BridgeControlListener(conf.p2pSslOptions,
private var bridgeControlListener = BridgeControlListener(conf.publicSSLConfiguration,
conf.outboundConfig!!.proxyConfig,
maxMessageSize,
conf.bridgeInnerConfig?.enableSNI ?: true,

View File

@ -56,7 +56,7 @@ fun createAndLoadConfigFromResource(baseDirectory: Path, configResource: String)
fun FirewallConfiguration.createBridgeKeyStores(legalName: CordaX500Name,
rootCert: X509Certificate = DEV_ROOT_CA.certificate,
intermediateCa: CertificateAndKeyPair = DEV_INTERMEDIATE_CA) = p2pSslOptions.createBridgeKeyStores(legalName, rootCert, intermediateCa)
intermediateCa: CertificateAndKeyPair = DEV_INTERMEDIATE_CA) = publicSSLConfiguration.createBridgeKeyStores(legalName, rootCert, intermediateCa)
fun MutualSslConfiguration.createBridgeKeyStores(legalName: CordaX500Name,
rootCert: X509Certificate = DEV_ROOT_CA.certificate,

View File

@ -65,23 +65,43 @@ class ConfigTest {
fun `Load overridden cert config`() {
val configResource = "/net/corda/bridge/custombasecerts/firewall.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
assertEquals(Paths.get("customcerts/mysslkeystore.jks"), config.p2pSslOptions.keyStore.path)
assertEquals(Paths.get("customcerts/mytruststore.jks"), config.p2pSslOptions.trustStore.path)
assertEquals(Paths.get("customcerts/mysslkeystore.jks"), config.publicSSLConfiguration.keyStore.path)
assertEquals(Paths.get("customcerts/mytruststore.jks"), config.publicSSLConfiguration.trustStore.path)
}
@Test
fun `Load custom inner certificate config`() {
val configResource = "/net/corda/bridge/separatedwithcustomcerts/bridge/firewall.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
assertEquals(Paths.get("outboundcerts/outboundkeys.jks"), config.outboundConfig!!.customSSLConfiguration!!.keyStore.path)
assertEquals(Paths.get("outboundcerts/outboundtrust.jks"), config.outboundConfig!!.customSSLConfiguration!!.trustStore.path)
assertEquals("outboundkeypassword", config.outboundConfig!!.customSSLConfiguration!!.keyStore.storePassword)
assertEquals("outboundtrustpassword", config.outboundConfig!!.customSSLConfiguration!!.trustStore.storePassword)
val artemisSSLConfiguration = config.outboundConfig!!.artemisSSLConfiguration!!
assertEquals(Paths.get("outboundcerts/outboundkeys.jks"), artemisSSLConfiguration.keyStore.path)
assertEquals(Paths.get("outboundcerts/outboundtrust.jks"), artemisSSLConfiguration.trustStore.path)
assertEquals("outboundkeypassword", artemisSSLConfiguration.keyStore.storePassword)
assertEquals("outboundtrustpassword", artemisSSLConfiguration.trustStore.storePassword)
assertNull(config.inboundConfig)
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), config.bridgeInnerConfig!!.customSSLConfiguration!!.keyStore.path)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), config.bridgeInnerConfig!!.customSSLConfiguration!!.trustStore.path)
assertEquals("tunnelkeypassword", config.bridgeInnerConfig!!.customSSLConfiguration!!.keyStore.storePassword)
assertEquals("tunneltrustpassword", config.bridgeInnerConfig!!.customSSLConfiguration!!.trustStore.storePassword)
val tunnelSSLConfiguration = config.bridgeInnerConfig!!.tunnelSSLConfiguration!!
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), tunnelSSLConfiguration.keyStore.path)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), tunnelSSLConfiguration.trustStore.path)
assertEquals("tunnelkeypassword", tunnelSSLConfiguration.keyStore.storePassword)
assertEquals("tunneltrustpassword", tunnelSSLConfiguration.trustStore.storePassword)
assertNull(config.floatOuterConfig)
}
@Test
fun `Load custom inner certificate config V3`() {
val configResource = "/net/corda/bridge/separatedwithcustomcerts/bridge/firewall_v3.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
val artemisSSLConfiguration = config.outboundConfig!!.artemisSSLConfiguration!!
assertEquals(Paths.get("outboundcerts/outboundkeys.jks"), artemisSSLConfiguration.keyStore.path)
assertEquals(Paths.get("outboundcerts/outboundtrust.jks"), artemisSSLConfiguration.trustStore.path)
assertEquals("outboundkeypassword", artemisSSLConfiguration.keyStore.storePassword)
assertEquals("outboundtrustpassword", artemisSSLConfiguration.trustStore.storePassword)
assertNull(config.inboundConfig)
val tunnelSSLConfiguration = config.bridgeInnerConfig!!.tunnelSSLConfiguration!!
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), tunnelSSLConfiguration.keyStore.path)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), tunnelSSLConfiguration.trustStore.path)
assertEquals("tunnelkeypassword", tunnelSSLConfiguration.keyStore.storePassword)
assertEquals("tunneltrustpassword", tunnelSSLConfiguration.trustStore.storePassword)
assertNull(config.floatOuterConfig)
}
@ -89,12 +109,12 @@ class ConfigTest {
fun `Load custom inner certificate config diff passwords`() {
val configResource = "/net/corda/bridge/separatedwithcustomcerts/bridge/firewall_diffPasswords.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
val outboundSSLConfiguration = config.outboundConfig!!.customSSLConfiguration!!
val outboundSSLConfiguration = config.outboundConfig!!.artemisSSLConfiguration!!
assertEquals("outboundkeypassword", outboundSSLConfiguration.keyStore.storePassword)
assertEquals("outboundprivatekeypassword", outboundSSLConfiguration.keyStore.entryPassword)
assertEquals("outboundtrustpassword", outboundSSLConfiguration.trustStore.storePassword)
assertNull(config.inboundConfig)
val innerSLConfiguration = config.bridgeInnerConfig!!.customSSLConfiguration!!
val innerSLConfiguration = config.bridgeInnerConfig!!.tunnelSSLConfiguration!!
assertEquals("tunnelkeypassword", innerSLConfiguration.keyStore.storePassword)
assertEquals("tunneltrustpassword", innerSLConfiguration.trustStore.storePassword)
assertNull(config.floatOuterConfig)
@ -104,15 +124,35 @@ class ConfigTest {
fun `Load custom outer certificate config`() {
val configResource = "/net/corda/bridge/separatedwithcustomcerts/float/firewall.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
assertEquals(Paths.get("inboundcerts/inboundkeys.jks"), config.inboundConfig!!.customSSLConfiguration!!.keyStore.path)
assertEquals(Paths.get("inboundcerts/inboundtrust.jks"), config.inboundConfig!!.customSSLConfiguration!!.trustStore.path)
assertEquals("inboundkeypassword", config.inboundConfig!!.customSSLConfiguration!!.keyStore.storePassword)
assertEquals("inboundtrustpassword", config.inboundConfig!!.customSSLConfiguration!!.trustStore.storePassword)
val customSSLConfiguration = config.inboundConfig!!.customSSLConfiguration!!
assertEquals(Paths.get("inboundcerts/inboundkeys.jks"), customSSLConfiguration.keyStore.path)
assertEquals(Paths.get("inboundcerts/inboundtrust.jks"), customSSLConfiguration.trustStore.path)
assertEquals("inboundkeypassword", customSSLConfiguration.keyStore.storePassword)
assertEquals("inboundtrustpassword", customSSLConfiguration.trustStore.storePassword)
assertNull(config.outboundConfig)
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), config.floatOuterConfig!!.customSSLConfiguration!!.keyStore.path)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), config.floatOuterConfig!!.customSSLConfiguration!!.trustStore.path)
assertEquals("tunnelkeypassword", config.floatOuterConfig!!.customSSLConfiguration!!.keyStore.storePassword)
assertEquals("tunneltrustpassword", config.floatOuterConfig!!.customSSLConfiguration!!.trustStore.storePassword)
val tunnelSSLConfiguration = config.floatOuterConfig!!.tunnelSSLConfiguration!!
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), tunnelSSLConfiguration.keyStore.path)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), tunnelSSLConfiguration.trustStore.path)
assertEquals("tunnelkeypassword", tunnelSSLConfiguration.keyStore.storePassword)
assertEquals("tunneltrustpassword", tunnelSSLConfiguration.trustStore.storePassword)
assertNull(config.bridgeInnerConfig)
}
@Test
fun `Load custom outer certificate config V3`() {
val configResource = "/net/corda/bridge/separatedwithcustomcerts/float/firewall_v3.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
val customSSLConfiguration = config.inboundConfig!!.customSSLConfiguration!!
assertEquals(Paths.get("inboundcerts/inboundkeys.jks"), customSSLConfiguration.keyStore.path)
assertEquals(Paths.get("inboundcerts/inboundtrust.jks"), customSSLConfiguration.trustStore.path)
assertEquals("inboundkeypassword", customSSLConfiguration.keyStore.storePassword)
assertEquals("inboundtrustpassword", customSSLConfiguration.trustStore.storePassword)
assertNull(config.outboundConfig)
val tunnelSSLConfiguration = config.floatOuterConfig!!.tunnelSSLConfiguration!!
assertEquals(Paths.get("tunnelcerts/tunnelkeys.jks"), tunnelSSLConfiguration.keyStore.path)
assertEquals(Paths.get("tunnelcerts/tunneltrust.jks"), tunnelSSLConfiguration.trustStore.path)
assertEquals("tunnelkeypassword", tunnelSSLConfiguration.keyStore.storePassword)
assertEquals("tunneltrustpassword", tunnelSSLConfiguration.trustStore.storePassword)
assertNull(config.bridgeInnerConfig)
}
@ -185,4 +225,13 @@ class ConfigTest {
.isInstanceOf(UnknownConfigurationKeysException::class.java)
.hasMessageContaining("invalidOption")
}
@Test
fun `Load with sslKeystore path overridden`() {
val configResource = "/net/corda/bridge/keystoreoverride/firewall.conf"
val config = createAndLoadConfigFromResource(tempFolder.root.toPath(), configResource)
assertEquals("opt" / "myCertificates", config.certificatesDirectory)
assertEquals("opt" / "myCertificates" / "ssl" / "mySslKeystore.jks", config.sslKeystore)
assertEquals("opt" / "myCertificates" /"truststore.jks", config.trustStoreFile)
}
}

View File

@ -0,0 +1,17 @@
certificatesDirectory = opt/myCertificates
sslKeystore = opt/myCertificates/ssl/mySslKeystore.jks
firewallMode = SenderReceiver
outboundConfig : {
artemisBrokerAddress = "localhost:11005"
proxyConfig : {
version = HTTP
proxyAddress = "proxyHost:12345"
userName = "proxyUser"
password = "pwd"
}
}
inboundConfig : {
listeningAddress = "0.0.0.0:10005"
}
networkParametersPath = network-parameters

View File

@ -1,7 +1,7 @@
firewallMode = BridgeInner
outboundConfig : {
artemisBrokerAddress = "localhost:11005"
customSSLConfiguration : {
artemisSSLConfiguration : {
keyStorePassword = "outboundkeypassword"
trustStorePassword = "outboundtrustpassword"
sslKeystore = "outboundcerts/outboundkeys.jks"
@ -12,7 +12,7 @@ outboundConfig : {
bridgeInnerConfig : {
floatAddresses = [ "localhost:12005" ]
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
tunnelSSLConfiguration : {
keyStorePassword = "tunnelkeypassword"
trustStorePassword = "tunneltrustpassword"
sslKeystore = "tunnelcerts/tunnelkeys.jks"

View File

@ -1,7 +1,7 @@
firewallMode = BridgeInner
outboundConfig : {
artemisBrokerAddress = "localhost:11005"
customSSLConfiguration : {
artemisSSLConfiguration : {
keyStorePassword = "outboundkeypassword"
keyStorePrivateKeyPassword = "outboundprivatekeypassword"
trustStorePassword = "outboundtrustpassword"
@ -13,7 +13,7 @@ outboundConfig : {
bridgeInnerConfig : {
floatAddresses = [ "localhost:12005" ]
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
tunnelSSLConfiguration : {
keyStorePassword = "tunnelkeypassword"
trustStorePassword = "tunneltrustpassword"
sslKeystore = "tunnelcerts/tunnelkeys.jks"

View File

@ -0,0 +1,23 @@
bridgeMode = BridgeInner
outboundConfig : {
artemisBrokerAddress = "localhost:11005"
customSSLConfiguration : {
keyStorePassword = "outboundkeypassword"
trustStorePassword = "outboundtrustpassword"
sslKeystore = "outboundcerts/outboundkeys.jks"
trustStoreFile = "outboundcerts/outboundtrust.jks"
crlCheckSoftFail = true
}
}
bridgeInnerConfig : {
floatAddresses = [ "localhost:12005" ]
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
keyStorePassword = "tunnelkeypassword"
trustStorePassword = "tunneltrustpassword"
sslKeystore = "tunnelcerts/tunnelkeys.jks"
trustStoreFile = "tunnelcerts/tunneltrust.jks"
crlCheckSoftFail = true
}
}
networkParametersPath = network-parameters

View File

@ -12,7 +12,7 @@ inboundConfig : {
floatOuterConfig : {
floatAddress = "localhost:12005"
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
tunnelSSLConfiguration : {
keyStorePassword = "tunnelkeypassword"
trustStorePassword = "tunneltrustpassword"
sslKeystore = "tunnelcerts/tunnelkeys.jks"

View File

@ -0,0 +1,23 @@
bridgeMode = FloatOuter
inboundConfig : {
listeningAddress = "0.0.0.0:10005"
customSSLConfiguration : {
keyStorePassword = "inboundkeypassword"
trustStorePassword = "inboundtrustpassword"
sslKeystore = "inboundcerts/inboundkeys.jks"
trustStoreFile = "inboundcerts/inboundtrust.jks"
crlCheckSoftFail = true
}
}
floatOuterConfig : {
floatAddress = "localhost:12005"
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
keyStorePassword = "tunnelkeypassword"
trustStorePassword = "tunneltrustpassword"
sslKeystore = "tunnelcerts/tunnelkeys.jks"
trustStoreFile = "tunnelcerts/tunneltrust.jks"
crlCheckSoftFail = true
}
}
networkParametersPath = network-parameters

View File

@ -5,7 +5,7 @@ outboundConfig : {
bridgeInnerConfig : {
floatAddresses = [ "localhost:12005" ]
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
tunnelSSLConfiguration : {
keyStorePassword = "bridgetunnelkeypassword"
keyStorePrivateKeyPassword = "bridgetunnelprivatekeypassword"
trustStorePassword = "bridgetunneltrustpassword"

View File

@ -13,7 +13,7 @@ inboundConfig : {
floatOuterConfig : {
floatAddress = "localhost:12005"
expectedCertificateSubject = "O=Bank A, L=London, C=GB"
customSSLConfiguration : {
tunnelSSLConfiguration : {
keyStorePassword = "bridgetunnelkeypassword"
keyStorePrivateKeyPassword = "bridgetunnelprivatekeypassword"
trustStorePassword = "bridgetunneltrustpassword"

View File

@ -74,6 +74,12 @@ Fields
The available config fields are listed below. ``baseDirectory`` is available as a substitution value and contains the
absolute path to the firewall's base directory.
:certificatesDirectory: An optional parameter which specifies directory from which SSL keys and Trust store keys will be loaded from. If missing the value is defaulted to ``baseDirectory/certificates``.
:sslKeystore: An optional parameter which specifies the file from which SSL keys stores will be loaded from. If missing the value is defaulted to ``certificatesDirectory/sslkeystore.jks``.
:trustStoreFile: An optional parameter which specifies the file from which Trust store keys will be loaded from. If missing the value is defaulted to ``certificatesDirectory/truststore.jks``.
:firewallMode: Determines operating mode of the firewall. See above.
:keyStorePassword: The password to unlock the TLS KeyStore file (``<workspace>/certificates/sslkeystore.jks``) containing the
@ -101,7 +107,7 @@ absolute path to the firewall's base directory.
:alternateArtemisBrokerAddresses: Optionally if there are multiple Artemis broker address e.g. for hot-cold node deployment, then additional hosts and ports may be included in a list.
:customSSLConfiguration: The default behaviour is that the outgoing ``TLS 1.2/AMQP 1.0`` connections present certificate details from (``<workspace>/certificates/sslkeystore.jks``)
:artemisSSLConfiguration: The default behaviour is that the outgoing ``TLS 1.2/AMQP 1.0`` connections present certificate details from (``<workspace>/certificates/sslkeystore.jks``)
and validate against (``<workspace>/certificates/truststore.jks``), using the passwords defined in the root config. However, distinct KeyStores may be configured in this section:
:keyStorePassword: The password for the TLS KeyStore.
@ -155,7 +161,7 @@ absolute path to the firewall's base directory.
:expectedCertificateSubject: The X500 Subject name that will be presented in client certificates from the remote ``FloatOuter`` instances.
:customSSLConfiguration: .. note:: For ease of use the TLS default control tunnel connections present certificate details from (``<workspace>/certificates/sslkeystore.jks``)
:tunnelSSLConfiguration: .. note:: For ease of use the TLS default control tunnel connections present certificate details from (``<workspace>/certificates/sslkeystore.jks``)
and validate against (``<workspace>/certificates/truststore.jks``), using the passwords defined in the root config.
However, it is strongly recommended that distinct KeyStores should be configured in this section to use locally valid certificates only, so that compromise of the DMZ machines does not give access to the node's primary TLS keys.
@ -171,23 +177,6 @@ absolute path to the firewall's base directory.
:trustStoreFile: The path to the TrustStore file to use in control tunnel connections.
:crlCheckSoftFail: If true (recommended setting) allows certificate checks to pass if the CRL(certificate revocation list) provider is unavailable.
:customFloatOuterSSLConfiguration: The keys and certificates for the ``FloatOuter`` are provisioned dynamically from the ``BridgeInner`` over the control tunnel and are not loaded from disk in the DMZ.
By default, they are taken from (``<workspace>/certificates/sslkeystore.jks``)
and validate against (``<workspace>/certificates/truststore.jks``), using the passwords defined in the root config. However, alternate sources may be defined in this section.
:keyStorePassword: The password for the TLS KeyStore.
:keyStorePrivateKeyPassword: Optional parameter to lock the private keys within the KeyStore. If it is missing, it will be assumed that the private keys password is the same as
``keyStorePassword`` above.
:trustStorePassword: The password for TLS TrustStore.
:sslKeystore: The path to the KeyStore file to use in the ``FloatOuter`` when it activates the peer listening socket.
:trustStoreFile: The path to the TrustStore file to use in the ``FloatOuter`` when it activates the peer listening socket.
:crlCheckSoftFail: If true (recommended setting) allows certificate checks to pass if the CRL(certificate revocation list) provider is unavailable.
:floatOuterConfig: This section is required for ``FloatOuter`` mode and configures the control tunnel listening socket. It should be absent for ``SenderReceiver`` and ``BridgeInner`` modes:
@ -195,7 +184,7 @@ absolute path to the firewall's base directory.
:expectedCertificateSubject: The X500 Subject name that will be presented in client certificates from the ``BridgeInner`` when it connects to this ``FloatOuter`` instance.
:customSSLConfiguration: .. note:: For ease of use the TLS default control tunnel connection presents certificate details from (``<workspace>/certificates/sslkeystore.jks``)
:tunnelSSLConfiguration: .. note:: For ease of use the TLS default control tunnel connection presents certificate details from (``<workspace>/certificates/sslkeystore.jks``)
and validate against (``<workspace>/certificates/truststore.jks``), using the passwords defined in the root config.
However, it is strongly recommended that distinct KeyStores should be configured in this section to use locally valid certificates only, so that compromise of the DMZ machines does not give access to the node's primary TLS keys.
@ -412,7 +401,7 @@ Configuration in ``firewall.conf`` for ``bridgeserver1``:
bridgeInnerConfig { // Required section
floatAddresses = ["dmzinternal1:12005", "dmzinternal2:12005"] // The BridgeInner initiates a connection to one of this pool of FloatOuter and round-robins
expectedCertificateSubject = "CN=Float Local,O=Tunnel,L=London,C=GB" // This must align with the certificate subject used by the FloatOuter control.
customSSLConfiguration { // Use a tunnel specific set of certificates distinct from the node's sslkeystore.jks and truststore.jks.
tunnelSSLConfiguration { // Use a tunnel specific set of certificates distinct from the node's sslkeystore.jks and truststore.jks.
keyStorePassword = "bridgepass"
trustStorePassword = "trustpass"
sslKeystore = "./bridgecerts/bridge.jks"
@ -443,7 +432,7 @@ Configuration in ``firewall.conf`` for ``bridgeserver2``:
bridgeInnerConfig { // Required section
floatAddresses = ["dmzinternal2:12005", "dmzinternal1:12005"] // The BridgeInner initiates a connection to one of this pool of FloatOuter and round-robins
expectedCertificateSubject = "CN=Float Local,O=Tunnel,L=London,C=GB" // This must align with the certificate subject used by the FloatOuter control.
customSSLConfiguration { // Use a tunnel specific set of certificates distinct from the node's sslkeystore.jks and truststore.jks.
tunnelSSLConfiguration { // Use a tunnel specific set of certificates distinct from the node's sslkeystore.jks and truststore.jks.
keyStorePassword = "bridgepass"
trustStorePassword = "trustpass"
sslKeystore = "./bridgecerts/bridge.jks"
@ -468,7 +457,7 @@ Configuration in ``firewall.conf`` for ``floatserver1``:
floatOuterConfig { // Required section
floatAddress = "dmzinternal1:12005" // await control instructions on inner NIC
expectedCertificateSubject = "CN=Bridge Local,O=Tunnel,L=London,C=GB" // Must line up with X500 Subject of certificates on BridgeInner
customSSLConfiguration {
tunnelSSLConfiguration {
keyStorePassword = "floatpass"
trustStorePassword = "trustpass"
sslKeystore = "./floatcerts/float.jks"
@ -489,7 +478,7 @@ Configuration in ``firewall.conf`` for ``floatserver2``:
floatOuterConfig { // Required section
floatAddress = "dmzinternal2:12005" // await control instructions on inner NIC
expectedCertificateSubject = "CN=Bridge Local,O=Tunnel,L=London,C=GB" // Must line up with X500 Subject of certificates on BridgeInner
customSSLConfiguration {
tunnelSSLConfiguration {
keyStorePassword = "floatpass"
trustStorePassword = "trustpass"
sslKeystore = "./floatcerts/float.jks"