Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to connect with ssl=true? #161

Open
borice opened this issue Nov 27, 2018 · 6 comments
Open

How to connect with ssl=true? #161

borice opened this issue Nov 27, 2018 · 6 comments

Comments

@borice
Copy link

borice commented Nov 27, 2018

Can you please provide an example of how to connect to RabbitMQ server with SSL/TLS enabled?

Thank you.

@DStranger
Copy link
Collaborator

Hi @borice,

connection {
    virtual-host = "/"
    hosts = ["127.0.0.1"]
    username = "guest"
    password = "guest"
    port = 5672
    ssl = true
  }

@borice
Copy link
Author

borice commented Dec 4, 2018

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.

@DStranger DStranger reopened this Dec 6, 2018
@DStranger
Copy link
Collaborator

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.

@borice
Copy link
Author

borice commented Dec 12, 2018

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.

@timcharper
Copy link
Member

@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?

@timcharper
Copy link
Member

Also, any reason to not just configure and use the JVM's default keystore?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants