ktor sslConnector 从 jar p12 pkcs12 jks 密钥库和 mtls 相互 ssl 连接中服务/读取
Posted
技术标签:
【中文标题】ktor sslConnector 从 jar p12 pkcs12 jks 密钥库和 mtls 相互 ssl 连接中服务/读取【英文标题】:ktor sslConnector serve/read from jar p12 pkcs12 jks keystore and mtls mutual ssl connection 【发布时间】: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
——这仅适用于相反的“解析”模式。
【参考方案1】:
对于Netty
和Jetty
引擎,实际上使用了作为sslConnector
的第一个参数传递的keystore
。 keyStorePath
属性仅用于 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)
【讨论】:
感谢这个例子,你能分享一下你是如何实现 createTrustStoreAndKeyStore() 的吗? gist.github.com/HoffiMuc/bb183db2e9d54cf1d94a71a3705117f4以上是关于ktor sslConnector 从 jar p12 pkcs12 jks 密钥库和 mtls 相互 ssl 连接中服务/读取的主要内容,如果未能解决你的问题,请参考以下文章
运行 fat jar 的 ktor 抛出 java.lang.UnsupportedOperationException::Kotlin 反射中尚不支持包和文件外观
Ktor App 部署到 AppEngine 时未调用 Main 方法