Servidor Akka HTTPS (SSL) con ssl-conf

Versión Akka:

Akka 2.4.7

Características de Akka:

Soporte de servidor HTTPS

Ssl-config de Typesafe

Idioma: Scala

Estoy usando la función Http Server de Akka 2.4.7 para proporcionar variosHTTPS conexiones de servicio en diferentes puertos. En esta etapa, el requisito es que este componente del sistema de actor aloje varios de los servicios HTTPS en una JVM: es un back-end que conecta e integra otros servicios.

Pregunta:

Quiero usar elSsl-config de Typesafe biblioteca para configurar cada servidor HTTPS. Cómo hago esto(No tengo éxito en mis intentos)?

Lo que he intentado:

Para cada servicio, he definido bloques de configuración ssl-config en application.conf. Un ejemplo de una configuración nexted es:

my-service {
  ssl-config = {
    debug {
      all = true
    }
    sslParameters {
      clientAuth : "none"
    }
    ssl = {
      keyManager = {
        stores = [
          {path: tmp/certs/autumn/devhost.jks, password: "not-real-password", type: "JKS"}
        ]
      }
    }
  }
}

Agarro esta parte de la configuración usando la ruta HOCON parami servicio definido enapplication.conf y fusionarlo con la configuración predeterminada de referencia para crear un SSLConfigSettings.

  def parseSslConfig(config: Config): SSLConfigSettings = {
    val cfg = config.withFallback(ConfigFactory.defaultReference().getConfig("ssl-config"))
    val parser = new SSLConfigParser(EnrichedConfig(cfg), getClass.getClassLoader)
    parser.parse()
  }

Ahora que tengo un SSLConfigSettings ahora puedo crear unAkkaSSLConfig objeto que a su vez, enAkka 2.4.7, se puede usar para crear unHttpsConnectionContext utilizando el prototipo de la función:

// # https-context-creation // ConnectionContext def https (sslContext: SSLContext, sslConfig: Option [AkkaSSLConfig] = None, enabledCipherSuites: Option [immutable.Seq [String]] = None, enabledProtocols: Option [immutable.Seq [String ]] = Ninguno, clientAuth: Opción [TLSClientAuth] = Ninguno, sslParameters: Opción [SSLParameters] = Ninguno) = new HttpsConnectionContext (sslContext, sslConfig, enabledCipherSuites, enabledProtocols, clientAuth, sslParameters) // # https-context-creation

Entonces, simplemente puedo encender un servidor HTTPS con un código como el siguiente(nota: el gestor de solicitudes se define en otra parte proporcionando elFuture[HttpResponse])

val akkaSSLConfig: AkkaSSLConfig = AkkaSSLConfig().withSettings(sslConfigSettings)
val serverConnectionContext = ConnectionContext.https(SSLContext.getDefault, Some(akkaSSLConfig))

  val httpServer = httpServerSystem.bind(interface = "127.0.0.1",
    port = 8991,
    connectionContext = serverConnectionContext)

  val bindingFuture: Future[Http.ServerBinding] = httpServer.to(Sink.foreach {
    connection =>
      system.log.info(s"Accepted HTTP connection " +
        s"[Local: address=${connection.localAddress.getAddress.getHostAddress}, port=${connection.localAddress.getPort};" +
        s" Remote: address=${connection.remoteAddress.getAddress.getHostAddress} port=${connection.remoteAddress.getPort}]" + connection.remoteAddress)
      connection.handleWithAsyncHandler(httpRequest => requestHandler(httpRequest, connection.localAddress, connection.remoteAddress))
  }).run()

El servidor se inicia sin excepción o error y se une a127.0.0.1 en el puerto definido8991.

2016-06-11 14:07:51,403 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpListener - Successfully bound to /127.0.0.1:8991
2016-06-11 14:07:51,404 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpListener - started (akka.io.TcpListener@3d1d819f)
2016-06-11 14:07:51,404 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpListener - now watched by Actor[akka://autumn-backend/system/IO-TCP/selectors/$a#-745039521]
2016-06-11 14:07:51,407 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TcpListener - now watched by Actor[akka://autumn-backend/user/StreamSupervisor-0/$a#-672917867]

Accedo al servidor usando un navegador o curl y el resultado no es bueno. Está pidiendo un certificado de cliente que sé que está mal, ya que configuré explícitamente en ssl-conf que no son necesarios y ssl-conf en JDK8 establece que esto no sea necesario de forma predeterminada.

curl -v https://localhost:8991
* Rebuilt URL to: https://localhost:8991/
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8991 (#0)
* SSL peer handshake failed, the server most likely requires a client certificate to connect
* Closing connection 0
curl: (35) SSL peer handshake failed, the server most likely requires a client certificate to connect

Investigación adicional conopenssl con la opción _s_client_ muestra que no se está produciendo un protocolo de enlace SSL y que no se devuelven certificados, a pesar de saber que el almacén de claves es bueno y funciona en otros lugares.

 openssl s_client -showcerts -connect localhost:8991
CONNECTED(00000003)
140735299473488:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:769:
---
no peer certificate available

No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 317 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
---

El inicio de sesión de Akka en modo de depuración no muestra excepciones y que se ha realizado una conexión TCP, se inicia un actor TLS y luego se detiene inmediatamente.

2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-6] TcpListener - New connection accepted
2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-9] SelectionHandler - now supervising Actor[akka://autumn-backend/system/IO-TCP/selectors/$a/9#1252313265]
2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TcpIncomingConnection - started (akka.io.TcpIncomingConnection@6f12f120)
2016-06-11 14:09:26,378 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TcpIncomingConnection - now watched by Actor[akka://autumn-backend/system/IO-TCP/selectors/$a#-745039521]
2016-06-11 14:09:26,381 INFO  [autumn-backend-akka.actor.default-dispatcher-7] ActorSystemImpl - Accepted HTTP connection [Local: address=127.0.0.1, port=8991; Remote: address=127.0.0.1 port=58726]/127.0.0.1:58726
2016-06-11 14:09:26,384 DEBUG [autumn-backend-akka.actor.default-dispatcher-9] StreamSupervisor - now supervising Actor[akka://autumn-backend/user/StreamSupervisor-0/flow-9-0-unknown-operation#149184815]
2016-06-11 14:09:26,385 DEBUG [autumn-backend-akka.actor.default-dispatcher-7] TcpIncomingConnection - now watched by Actor[akka://autumn-backend/user/StreamSupervisor-0/$j#-1999211380]
2016-06-11 14:09:26,385 DEBUG [autumn-backend-akka.actor.default-dispatcher-9] ActorGraphInterpreter - started (akka.stream.impl.fusing.ActorGraphInterpreter@57451dc8)
2016-06-11 14:09:26,385 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] StreamSupervisor - now supervising Actor[akka://autumn-backend/user/StreamSupervisor-0/flow-9-1-unknown-operation#1511230856]
sslConfig.config.loose.disableSNI = false
2016-06-11 14:09:26,387 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TLSActor - started (akka.stream.impl.io.TLSActor@50f220e8)
2016-06-11 14:09:26,389 DEBUG [autumn-backend-akka.actor.default-dispatcher-5] TLSActor - stopped

La depuración en tiempo de ejecución muestra que se está recogiendo el almacén de claves:

akkaSSLConfig = {com.typesafe.sslconfig.akka.AkkaSSLConfig@7851} 
 system = {akka.actor.ActorSystemImpl@7850} "akka://autumn-backend"
 config = {com.typesafe.sslconfig.ssl.SSLConfigSettings@7849} "SSLConfig(None,SSLDebugConfig(false,false,false,None,false,false,false,false,None,false,false,false,false,false),false,Vector(RSA keySize < 2048, DSA keySize < 2048, EC keySize < 224),Vector(MD2, MD4, MD5),None,Some(Vector(TLSv1.2, TLSv1.1, TLSv1)),class com.typesafe.sslconfig.ssl.DefaultHostnameVerifier,KeyManagerConfig(SunX509,List(KeyStoreConfig(None,Some(config/certs/autumn/devhost.jks),Some(A8C7B78Ymb),JKS))),SSLLooseConfig(false,None,None,false,false,false,false),TLSv1.2,None,None,SSLParametersConfig(Default,Vector()),TrustManagerConfig(PKIX,List()))"
  default = false
  protocol = "TLSv1.2"
  checkRevocation = {scala.None$@7905} "None"
  revocationLists = {scala.None$@7905} "None"
  enabledCipherSuites = {scala.None$@7905} "None"
  enabledProtocols = {scala.Some@7906} "Some(Vector(TLSv1.2, TLSv1.1, TLSv1))"
  disabledSignatureAlgorithms = {scala.collection.immutable.Vector@7907} "Vector" size = 3
  disabledKeyAlgorithms = {scala.collection.immutable.Vector@7911} "Vector" size = 3
  sslParametersConfig = {com.typesafe.sslconfig.ssl.SSLParametersConfig@7917} "SSLParametersConfig(Default,Vector())"
  keyManagerConfig = {com.typesafe.sslconfig.ssl.KeyManagerConfig@7918} "KeyManagerConfig(SunX509,List(KeyStoreConfig(None,Some(config/certs/autumn/devhost.jks),Some(A8C7B78Ymb),JKS)))"
   algorithm = "SunX509"
   keyStoreConfigs = {scala.collection.immutable.$colon$colon@7942} "::" size = 1
    0 = {com.typesafe.sslconfig.ssl.KeyStoreConfig@9390} "KeyStoreConfig(None,Some(config/certs/autumn/devhost.jks),Some(not-real-password),JKS)"

Lo que funciona es si creo un HttpsConnectionContext manualmente y no uso ssl-conf o AkkaSSLConfig, pero ese no es el objetivo. ¿Cómo configuro y creo una conexión de configuración HTTPS usando un objeto AkkaSSLconf y la biblioteca Typesafe ssl-config?

ACTUALIZACIÓN 1:

Si solicito específicamente unTLS instancia del contexto TLS como este:

val sslCtx = SSLContext.getInstance("TLS")

Recibo una excepción de que sslContext no está inicializado. Sinoinit En SSLContext, necesito crear el almacén de claves, el almacén de confianza, que está muy bien, pero parece que estoy ignorando toda la bondad de la biblioteca ssl-conf que ya tiene todo esto definido.

Actualización 2:

Descubrí que puede crear el contexto de conexión HTTPS con el siguiente método:

Http().createServerHttpsContext(akkaSSLConfig)

Puede crear el contexto del servidor HTTPS utilizando AkkaSSLConfig, que es lo bueno que busco. El problema está en probar que el servidor HTTPS no funciona, solo se cuelga durante 1 minuto con la excepción:

2016-06-12 11:14:53,222 DEBUG [autumn-backend-akka.actor.default-dispatcher-12] RepointableActorRef - Aborting tcp connection because of upstream failure: No elements passed in the last 1 minute.
akka.stream.impl.Timers$IdleTimeoutBidi$anon$7.onTimer(Timers.scala:160)
akka.stream.stage.TimerGraphStageLogic.akka$stream$stage$TimerGraphStageLogic$onInternalTimer(GraphStage.scala:1125)
akka.stream.stage.TimerGraphStageLogic$anonfun$akka$stream$stage$TimerGraphStageLogic$getTimerAsyncCallback$1.apply(GraphStage.scala:1114)
akka.stream.stage.TimerGraphStageLogic$anonfun$akka$stream$stage$TimerGraphStageLogic$getTimerAsyncCallback$1.apply(GraphStage.scala:1114)
akka.stream.impl.fusing.GraphInterpreter.runAsyncInput(GraphInterpreter.scala:572)
akka.stream.impl.fusing.GraphInterpreterShell.receive(ActorGraphInterpreter.scala:420)
akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$processEvent(ActorGraphInterpreter.scala:604)
akka.stream.impl.fusing.ActorGraphInterpreter$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:619)
akka.actor.Actor$class.aroundReceive(Actor.scala:484)

Miré la fuente de createServerHttpsContext en el repositorio de Akka en GitHubaquí y encontrado:

  // currently the same configuration as client by default, however we should tune this for server-side apropriately (!)
  def createServerHttpsContext(sslConfig: AkkaSSLConfig): HttpsConnectionContext = {
    log.warning("Automatic server-side configuration is not supported yet, will attempt to use client-side settings. " +
      "Instead it is recommended to construct the Servers HttpsConnectionContext manually (via SSLContext).")
    createClientHttpsContext(sslConfig)
  }

¿Por qué el servidor HTTPS no funciona con elcreateServerHttpsContext(..)? Especialmente dado que, manualmente, básicamente configura un TLS SSLContext, KeyManagerFactory(con tiendas clave), una instancia de SecureRandom y listo.

Respuestas a la pregunta(3)

Su respuesta a la pregunta