1

我已经想出了如何使用 EmbeddedServer Jetty 启动 ktor 并使用我自己的签名证书(由我自己的自签名 rootCA 证书签名)提供 https/ssl/tls 服务。

现在 ktor sslConnector 需要keyStorePathas 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 容器无关)

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

4

2 回答 2

1

对于NettyJetty引擎,实际使用keystore作为第一个参数传递的 a 。sslConnectorkeyStorePath属性仅用于Tomcat引擎。

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

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)
    }
}
于 2021-08-20T13:53:49.093 回答
0

这是我的最终使用代码:

        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)
    }
于 2021-08-30T11:00:24.537 回答