scala - 如何从证书链、证书和私钥正确配置 HTTPS?阿卡 HTTP

标签 scala ssl https openssl akka-http

介绍

  • 我必须使用 Akka HTTP 编写一个微服务。 [完成]
  • 该服务必须在 docker 容器中运行。 [完成]
  • 与此服务的通信(通过 REST API [完成])已通过 HTTP 小号 . [待办事项]

  • 问题
    尝试从 Web 浏览器发出 HTTPS GET 请求时:
    Browser warning connection not secure
    尝试向服务 发出 cURL 请求时在服务器上 :
    docker ps
    端口
    0.0.0.0:443->443/tcp
    curl -v https://localhost
  • TCP_NODELAY 设置
  • 4 的 200 毫秒后过期(传输 0x5648dd24df90)
  • 连接到 localhost (127.0.0.1) 端口 443 (#0)
  • ALPN,提供 h2
  • ALPN,提供 http/1.1
  • 成功设置证书验证位置:
  • CA文件:无
    CApath:/etc/ssl/certs
  • TLSv1.3 (OUT)、TLS 握手、客户端问候 (1):
  • OpenSSL SSL_connect: SSL_ERROR_SYSCALL 连接到 localhost:443
  • 关闭连接 0
    curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL 连接到 localhost:443

  • 问题
    如何正确配置 Akka HTTP 的服务器以使用 HTTP 小号 , 对于给定的:
  • .pem 文件(包含根证书和中间证书) ,
  • .cert 文件(包含我的域的证书),
  • .key-文件(包含私钥) ???

  • 到目前为止我做了什么?
  • 我将 ca-certs 和 my-cert 连接到单个 cert-chain.pem 文件,并与私钥一起使用 openssl 创建了一个 p12 keystore 。
  • 我写了以下代码:
  • package de.htw_berlin.http
    
    import java.security.SecureRandom
    import akka.http.scaladsl.{ConnectionContext, HttpsConnectionContext}
    import de.htw_berlin.security.{PKCS12KeyStoreFactory, X509KeyManagersFactory}
    
    import java.io.FileInputStream
    import javax.net.ssl.SSLContext
    
    object HttpsConnectionContextFactory {
    
      // TODO refactor
      def apply(keyStoreFilename: String, keyStorePassword: String): HttpsConnectionContext = {
        val p12KeyStore = PKCS12KeyStoreFactory(new FileInputStream(keyStoreFilename), keyStorePassword)
        val sslContext: SSLContext = SSLContext.getInstance("TLS")
        sslContext.init(X509KeyManagersFactory(p12KeyStore, keyStorePassword), null, new SecureRandom)
        ConnectionContext.httpsServer(sslContext)
      }
    
    }
    
    package de.htw_berlin.security
    
    import java.security.KeyStore
    
    import javax.net.ssl.{KeyManager, KeyManagerFactory}
    
    object X509KeyManagersFactory {
    
      def apply(keyStore: KeyStore, keyStorePassword: String): Array[KeyManager] = {
        val keyManagerFactory = KeyManagerFactory.getInstance("SunX509")
        keyManagerFactory.init(keyStore, keyStorePassword.toCharArray)
        keyManagerFactory.getKeyManagers
      }
    
    }
    
    package de.htw_berlin.security
    
    import java.io.InputStream
    import java.security.KeyStore
    
    object PKCS12KeyStoreFactory {
    
      def apply(keyStoreAsInputStream: InputStream, keyStorePassword: String): KeyStore = {
        val p12KeyStore = KeyStore.getInstance("PKCS12")
        p12KeyStore.load(keyStoreAsInputStream, keyStorePassword.toCharArray)
        p12KeyStore
      }
    
    }
    
    package de.htw_berlin.http
    
    import akka.actor.typed.ActorSystem
    import akka.http.scaladsl.Http.ServerBinding
    import akka.http.scaladsl.{Http, HttpsConnectionContext}
    import de.htw_berlin.http.dip.RequestHandler
    
    import scala.concurrent.Future
    
    // TODO test.
    /** Represents a HTTPS server which can be bind to a host and port.
     * The server needs a request handler for processing incoming requests.
     *
     * @param host         the optional host of the server. The default value is Constants.DefaultServerIpv4Address.
     * @param port         the optional port number of the server. The default value is Constants.DefaultHttpsPort.
     * @param httpsContext the https connection context for the https connection.
     * @param actorSystem  an implicit actor system.
     * @see de.htw_berlin.http.dip.RequestHandler
     */
    class Server(val host: String = Constants.DefaultServerIpv4Address,
                 val port: Int = Constants.DefaultHttpsPort,
                 val httpsContext: HttpsConnectionContext)(implicit val actorSystem: ActorSystem[Nothing]) {
    
      /** Binds the current server to the endpoint parameters (host and port) and uses the passed
       * handler for processing incoming connections.
       *
       * @param handler the handler to be used for processing incoming requests.
       * @return a server binding future.
       */
      def bindAndHandleWith(handler: RequestHandler): Future[ServerBinding] =
        Http().newServerAt(host, port).enableHttps(httpsContext).bind(handler.getRoute)
    
    }
    
    package de.htw_berlin.http
    
    /** This object contains constants related with the current module http. */
    object Constants {
    
      /** The server's default IPv4 address. */
      val DefaultServerIpv4Address = "0.0.0.0"
      /** The default port for HTTPS connections. */
      val DefaultHttpsPort = 443
    
    }
    
    不够的话,完整代码在我的公众号repository
    我还做了什么
    除了我阅读了很多关于 x509 标准和 TLS/HTTP 并在另一个线程中搜索答案的事实之外,我还检查了服务器上的端口 443 是否打开(顺便说一句:我在 VPN 连接中做所有事情,所以防火墙应该没关系??)我向管理员寻求帮助,他不熟悉 Akka HTTP 和 docker,但他说 curl 输出可能与证书链有关。

    最佳答案

    尴尬的是,问题与 Docker 和使用 openssl 创建的 keystore 有关:容器内的 root 用户没有读取 keystore 的特权(权限被拒绝异常)。
    但是,代码有效,我将继续将此线程作为社区的引用。

    关于scala - 如何从证书链、证书和私钥正确配置 HTTPS?阿卡 HTTP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65327030/

    相关文章:

    scala - 分配scala空数组

    php - 我可以不购买证书就拥有有效的邮件服务器吗?

    ssl - 无法让 https 在 aws 弹性负载均衡器上使用自签名证书

    ssl - 如果我用 libcurl 写一个 https 程序,我应该下载哪个 CA 证书?

    ruby-on-rails - 如果我使用 Cloudflare 的 "Full SSL",是否需要为 Heroku 购买另一个 SSL 证书?

    reflection - 在scala中通过字符串名称获取对象实例

    scala - 为什么Future的恢复未捕获异常?

    scala - 在 titan + cassandra DB 中使用 gremlin scala 更新边缘属性值

    node.js - 从 Node.js 中的 https.Server#clientError 获取 remoteAddress

    javax.net.ssl.SSLException : hostname in certificate didn't match 异常