【问题标题】:ktor sslConnector serve/read from jar p12 pkcs12 jks keystore and mtls mutual ssl connectionktor sslConnector 从 jar p12 pkcs12 jks 密钥库和 mtls 相互 ssl 连接中服务/读取
【发布时间】:2021-10-21 06:29:51
【问题描述】:

我已经弄清楚如何使用 EmbeddedServer Jetty 启动 ktor 并使用我自己的签名证书(由我自己的自签名 rootCA 证书签名)提供 https/ssl/tls。

现在 ktor sslConnector 需要将 keyStorePath 设置为 File,但我更愿意从最终 fat jar 中的 /a 文件中提供密钥库(主要是为了能够在 kubernetes 集群中运行它)

有没有办法告诉 ktor 获取/读取嵌入在其 jar 文件中的资源作为 keyStore?

    // openssl pkcs12 -export -nodes -passout pass:${keystorePW} -in "domain.cert" -inkey "domain.key" -certfile "intermediateAndRootCAchain.ca" -name "aliasName" -out "webserverKeystore.p12"
    val keystore: KeyStore = KeyStore.getInstance(keystoreFile, keystorePW.toCharArray())

    @Suppress("UNUSED_PARAMETER")
    fun doIt(args: Array<String>) {
        val server = embeddedServer(Jetty, applicationEngineEnvironment {
            module {
                configureRouting()
                configureHTTP(sslPort)
                configureSerialization()
            }

            connector {
                this.host = host // redirected to https
                this.port = port // redirected to sslPort
            }

            sslConnector(keystore,
                keyAlias = certAlias, // alias name inside keystore: keytool -v -list -keystore certs/keystore.jks
                keyStorePassword = { keystorePW.toCharArray() },
                privateKeyPassword = { keystorePW.toCharArray() } // somehow this is the same as keystorePW if using openssl pkcs12 -export from above
            ) {
                this.port = sslPort
                keyStorePath = keystoreFile
            }
        })

        server.start(wait = true)
    }

有没有办法告诉 ktor 获取/读取嵌入在其 jar 文件中的资源作为 keyStore?

(也想知道为什么sslConnector 仍然需要作为File 的密钥库,如果它已经将整个密钥库作为第一个参数,但这可能与正在使用的实际 Web 容器无关)

第二个问题:是否可以启用 mutual tls,以便在客户端无法提供有效证书时 ktor 服务器拒绝连接?如果是,我将如何配置?

【问题讨论】:

  • 我不知道 ktor,但在 Java 中,您可以(仍然)使用 pre-9 方式从 jar 资源加载 KeyStore:x = KeyStore.getInstance("PKCS12"); x.load( whatever.getResourceAsStream("/blah"), pw_chararray)(并关闭逻辑要整洁)。同样在 Java 中,SSLSocket/SSLEngine.setNeedClientAuth(true).setSSLParameters(containing_same) 中止,如果没有或错误的客户端证书,但我不知道 ktor。 PS:openssl pkcs12 -export 忽略了-nodes——这仅适用于相反的“解析”模式。

标签: kotlin ssl embedded-resource ktor mtls


【解决方案1】:

对于NettyJetty 引擎,实际上使用了作为sslConnector 的第一个参数传递的keystorekeyStorePath 属性仅用于 Tomcat 引擎。

不幸的是,无法在 Ktor 中配置双向 TLS 身份验证,但作为一种解决方法,您可以通过将连接器添加到底层 Jetty 服务器来手动完成。 This article 可能对您有用。这是一个不完整的例子:

embeddedServer(
    Jetty, 
    applicationEngineEnvironment {
        module {
            // ...
        }
    }
) {
    configureServer = {
        val factory = SslConnectionFactory(
            SslContextFactory.Server().apply {
                // keyStore = ...
                // setKeyManagerPassword(...)
                // setKeyStorePassword(...)
                needClientAuth = true
            },
            HttpVersion.HTTP_1_1.asString()
        )

        val connector = ServerConnector(this, factory).apply {
            // host = ...
            // port = ...
        }

        addConnector(connector)
    }
}

【讨论】:

    【解决方案2】:

    这是我最终的使用代码:

            val (theTrustStore, theKeyStore) = createTrustStoreAndKeyStore()
    
            val server = embeddedServer(Jetty, applicationEngineEnvironment {
                module {
                    configureRouting()
                    configureHTTP(theSslPort)
                    configureSerialization()
                }
    
                connector {
                    this.host = theBindHost // redirected to https
                    this.port = thePort // redirected to sslPort
                }
    
                // // without mTLS (m = mutual)
                // sslConnector(theKeyStore,
                //     keyAlias = theHost, // alias name inside keystore: keytool -v -list -keystore certs/keystore.jks
                //     keyStorePassword = { keystorePW.toCharArray() },
                //     privateKeyPassword = { privateKeyPW.toCharArray() } // somehow this is the same as keystorePW if using openssl pkcs12 -export from above
                // ) {
                //     this.host = theBindHost
                //     this.port = theSslPort
                //     keyStorePath = null // only used by tomcat engine
                // }
            }) {
                configureServer = {
                    val factory = SslConnectionFactory(
                        SslContextFactory.Server().apply {
                            keyStore = theKeyStore
                            trustStore = theTrustStore
                            // setKeyManagerPassword(...)
                            // setKeyStorePassword(...)
                            needClientAuth = true
                        },
                        HttpVersion.HTTP_1_1.asString()
                    )
    
                    val httpConfig = HttpConfiguration()
                    httpConfig.secureScheme = "https"
                    httpConfig.securePort = theSslPort
                    // SSL HTTP Configuration
                    val httpsConfig = HttpConfiguration(httpConfig)
                    httpsConfig.addCustomizer(SecureRequestCustomizer()) // so that servlets can see the encryption details
    
    
                    val connector = ServerConnector(
                        this,
                        factory,
                        HttpConnectionFactory(httpsConfig)
                    ).apply {
                        host = theBindHost
                        port = theSslPort
                    }
    
                    addConnector(connector)
                }
            }
    
            server.start(wait = true)
        }
    

    【讨论】:

    猜你喜欢
    • 2018-03-29
    • 1970-01-01
    • 2014-10-13
    • 2017-07-23
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 2019-10-21
    • 2013-04-25
    相关资源
    最近更新 更多