Open borice opened 5 years ago
Hi @borice,
connection {
virtual-host = "/"
hosts = ["127.0.0.1"]
username = "guest"
password = "guest"
port = 5672
ssl = true
}
Thank you @DStranger, however I was looking for a different answer. How do I specify the TLS certificates to be used for the connection? I would like to set up an encrypted connection for the messaging subsystem whereby all the messages between client and server are encrypted, and the client's certificate is verified. Also, I believe the port should be 5671 for TLS connections, no? Thank you.
EDIT: for example, I want to be able to use
ssl_options.verify=verify_peer
and ssl_options.fail_if_no_peer_cert=true
in the server configuration, and be able to connect to it via op_rabbit.
Hi @borice! Sorry, I didn't really give your question too much thought.
This is how TLS configuration is done with the java client, but I think this is not currently possible in op-rabbit
.
Hi again.
I managed to get SSL working the way I want. Here's how I did it (can be refactored better, but here it goes as PoC):
I added a new ssl-config
section to the oprabbit.connection configuration:
connection {
virtual-host = "/"
hosts = ["REDACTED"]
username = "REDACTED"
password = "REDACTED"
port = 5671
connection-timeout = 3s
ssl = true
ssl-config {
ssl: "TLSv1.2"
keyManager.store {
type: "PKCS12"
path: "client_key.p12"
password: "REDACTED"
}
trustManager.store {
type: "JKS"
path: "rabbitstore.jks"
password: "REDACTED"
}
}
}
and then, in code:
implicit val actorSystem: ActorSystem = ActorSystem("rabbitmq")
val connectionConfig = RabbitConfig.connectionConfig
val connectionParams = ConnectionParams.fromConfig(connectionConfig)
val sslContext =
if (connectionParams.ssl) Some(getSslContext(connectionConfig.getConfig("ssl-config")))
else None
val factory = new ConnectionFactory()
val firstHost = connectionParams.hosts.head
factory.setHost(firstHost.getHost)
factory.setPort(firstHost.getPort)
factory.setUsername(connectionParams.username)
factory.setPassword(connectionParams.password)
factory.setVirtualHost(connectionParams.virtualHost)
factory.setClientProperties(connectionParams.clientProperties.asJava)
factory.setConnectionTimeout(connectionParams.connectionTimeout)
factory.setExceptionHandler(connectionParams.exceptionHandler)
factory.setRequestedChannelMax(connectionParams.requestedChannelMax)
factory.setRequestedFrameMax(connectionParams.requestedFrameMax)
factory.setRequestedHeartbeat(connectionParams.requestedHeartbeat)
factory.setSaslConfig(connectionParams.saslConfig)
connectionParams.sharedExecutor foreach factory.setSharedExecutor
factory.setShutdownTimeout(connectionParams.shutdownTimeout)
factory.setSocketFactory(connectionParams.socketFactory)
sslContext foreach factory.useSslProtocol
val connectionActorProps = ConnectionActor.props(factory)
val connectionActor = actorSystem.actorOf(connectionActorProps, RabbitControl.CONNECTION_ACTOR_NAME)
val rabbitControlProps = Props(classOf[RabbitControl], connectionActor)
val rabbitControl = actorSystem.actorOf(rabbitControlProps)
// now you can use rabbitControl as normal
with supporting methods:
def getSslContext(config: Config): SSLContext = {
val keyStoreConfig = config.getConfig("keyManager.store")
val keyManagerFactory = getKeyManagerFactory(keyStoreConfig)
val trustStoreConfig = config.getConfig("trustManager.store")
val trustManagerFactory = getTrustManagerFactory(trustStoreConfig)
val ssl = if (config.hasPath("ssl")) config.getString("ssl") else "TLSv1.2"
val sslContext = SSLContext.getInstance(ssl)
sslContext.init(keyManagerFactory.getKeyManagers, trustManagerFactory.getTrustManagers, null)
sslContext
}
def getKeyManagerFactory(config: Config): KeyManagerFactory = {
val ksType = if (config.hasPath("type")) config.getString("type") else "PKCS12"
val ksPath = config.getString("path")
val ksPassword = if (config.hasPath("password")) Some(config.getString("password").toCharArray) else None
val ks = KeyStore.getInstance(ksType)
using(new FileInputStream(ksPath))(ks.load(_, ksPassword.orNull))
val kmf = KeyManagerFactory.getInstance("SunX509")
kmf.init(ks, ksPassword.orNull)
kmf
}
def getTrustManagerFactory(config: Config): TrustManagerFactory = {
val ksType = if (config.hasPath("type")) config.getString("type") else "PKCS12"
val ksPath = config.getString("path")
val ksPassword = if (config.hasPath("password")) Some(config.getString("password").toCharArray) else None
val ks = KeyStore.getInstance(ksType)
using(new FileInputStream(ksPath))(ks.load(_, ksPassword.orNull))
val tmf = TrustManagerFactory.getInstance("SunX509")
tmf.init(ks)
tmf
}
def using[A, B <: {def close() : Unit}](closeable: B)(f: B => A): A =
try {
f(closeable)
}
finally {
closeable.close()
}
Hope this helps someone else.
@borice this is great! Any chance you'd be willing to put this in to a PR with some additions to the README for how to use?
Also, any reason to not just configure and use the JVM's default keystore?
Can you please provide an example of how to connect to RabbitMQ server with SSL/TLS enabled?
Thank you.