ktor sslConnector serve/read 来自 jar p12 pkcs12 jks 密钥库和 mtls 相互 ssl 连接
ktor sslConnector serve/read from jar p12 pkcs12 jks keystore and mtls mutual ssl connection
我已经弄清楚如何使用 embeddedServer Jetty 启动 ktor 并使用我自己的签名证书(由我自己的自签名 rootCA 证书签名)服务 https/ssl/tls。
现在 ktor sslConnector 需要 keyStorePath
作为 File
,但我更愿意从最终 fat jar 中的 the/a 文件提供密钥库(主要是为了能够运行 它在 kubernetes 集群中)
有没有办法告诉 ktor take/read 一个嵌入到它的 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 take/read 一个嵌入到它的 jar 文件中的资源作为 keyStore?
(还想知道为什么 sslConnector
仍然需要密钥库作为 File
如果它已经将整个密钥库作为第一个参数,但这可能与正在使用的实际 Web 容器无关)
第二个问题:是否可以启用mutual tls,以便ktor服务器在客户端无法呈现时拒绝连接有效证书?如果是,我该如何配置?
对于 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)
}
}
这是我的最终使用代码:
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)
}
我已经弄清楚如何使用 embeddedServer Jetty 启动 ktor 并使用我自己的签名证书(由我自己的自签名 rootCA 证书签名)服务 https/ssl/tls。
现在 ktor sslConnector 需要 keyStorePath
作为 File
,但我更愿意从最终 fat jar 中的 the/a 文件提供密钥库(主要是为了能够运行 它在 kubernetes 集群中)
有没有办法告诉 ktor take/read 一个嵌入到它的 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 take/read 一个嵌入到它的 jar 文件中的资源作为 keyStore?
(还想知道为什么 sslConnector
仍然需要密钥库作为 File
如果它已经将整个密钥库作为第一个参数,但这可能与正在使用的实际 Web 容器无关)
第二个问题:是否可以启用mutual tls,以便ktor服务器在客户端无法呈现时拒绝连接有效证书?如果是,我该如何配置?
对于 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)
}
}
这是我的最终使用代码:
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)
}