This is an automated email from the ASF dual-hosted git repository.
feiwang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-kyuubi.git
The following commit(s) were added to refs/heads/master by this push:
new 7bcb522d6 [KYUUBI #3658] Support SSL for Kyuubi thrift binary
connection
7bcb522d6 is described below
commit 7bcb522d6e26bf1fb8403620da02d79e6af05d91
Author: Fei Wang <[email protected]>
AuthorDate: Mon Oct 24 21:39:31 2022 +0800
[KYUUBI #3658] Support SSL for Kyuubi thrift binary connection
### _Why are the changes needed?_
Support SSL for kyuubi thrift binary conenction.
### _How was this patch tested?_
- [ ] Add some test cases that check the changes thoroughly including
negative and positive cases if possible
- [ ] Add screenshots for manual tests if appropriate
Will add screenshot for IT.
- [ ] [Run
test](https://kyuubi.apache.org/docs/latest/develop_tools/testing.html#running-tests)
locally before make a pull request
Closes #3658 from turboFei/ssl_binary.
Closes #3658
ffd603ec [Fei Wang] comment
ce652b7e [Fei Wang] revert UT
52e24abb [Fei Wang] ut
f6cae357 [Fei Wang] save
c6b664f1 [Fei Wang] exclude passwords
d34a4ca2 [Fei Wang] comments
11bfa9ad [Fei Wang] refactor
e2ca77ea [Fei Wang] align
86aaf87c [Fei Wang] with alternative
d17e0d11 [Fei Wang] style
eb4ba52a [Fei Wang] Support SSL for Kyuubi thrift binary connection
Authored-by: Fei Wang <[email protected]>
Signed-off-by: Fei Wang <[email protected]>
---
docs/deployment/settings.md | 10 ++-
.../org/apache/kyuubi/config/KyuubiConf.scala | 70 +++++++++++++++++++-
.../kyuubi/service/TBinaryFrontendService.scala | 76 +++++++++++++++++++++-
.../kyuubi/server/KyuubiTHttpFrontendService.scala | 12 +++-
4 files changed, 161 insertions(+), 7 deletions(-)
diff --git a/docs/deployment/settings.md b/docs/deployment/settings.md
index caaae3d9d..a9976bb93 100644
--- a/docs/deployment/settings.md
+++ b/docs/deployment/settings.md
@@ -297,9 +297,16 @@ kyuubi.frontend.protocols|THRIFT_BINARY|A comma separated
list for all frontend
kyuubi.frontend.proxy.http.client.ip.header|X-Real-IP|The http header to
record the real client ip address. If your server is behind a load balancer or
other proxy, the server will see this load balancer or proxy IP address as the
client IP address, to get around this common issue, most load balancers or
proxies offer the ability to record the real remote IP address in an HTTP
header that will be added to the request for other devices to use. Note that,
because the header value can be sp [...]
kyuubi.frontend.rest.bind.host|<undefined>|Hostname or IP of the machine
on which to run the REST frontend service.|string|1.4.0
kyuubi.frontend.rest.bind.port|10099|Port of the machine on which to run the
REST frontend service.|int|1.4.0
+kyuubi.frontend.ssl.keystore.algorithm|<undefined>|SSL certificate
keystore algorithm.|string|1.7.0
+kyuubi.frontend.ssl.keystore.password|<undefined>|SSL certificate
keystore password.|string|1.7.0
+kyuubi.frontend.ssl.keystore.path|<undefined>|SSL certificate keystore
location.|string|1.7.0
+kyuubi.frontend.ssl.keystore.type|<undefined>|SSL certificate keystore
type.|string|1.7.0
kyuubi.frontend.thrift.backoff.slot.length|PT0.1S|Time to back off during
login to the thrift frontend service.|duration|1.4.0
kyuubi.frontend.thrift.binary.bind.host|<undefined>|Hostname or IP of
the machine on which to run the thrift frontend service via binary
protocol.|string|1.4.0
kyuubi.frontend.thrift.binary.bind.port|10009|Port of the machine on which to
run the thrift frontend service via binary protocol.|int|1.4.0
+kyuubi.frontend.thrift.binary.ssl.disallowed.protocols|SSLv2,SSLv3|SSL
versions to disallow for Kyuubi thrift binary frontend.|seq|1.7.0
+kyuubi.frontend.thrift.binary.ssl.enabled|false|Set this to true for using SSL
encryption in thrift binary frontend server.|boolean|1.7.0
+kyuubi.frontend.thrift.binary.ssl.include.ciphersuites||A comma separated list
of include SSL cipher suite names for thrift binary frontend.|seq|1.7.0
kyuubi.frontend.thrift.http.allow.user.substitution|true|Allow alternate user
to be specified as part of open connection request when using HTTP transport
mode.|boolean|1.6.0
kyuubi.frontend.thrift.http.bind.host|<undefined>|Hostname or IP of the
machine on which to run the thrift frontend service via http
protocol.|string|1.6.0
kyuubi.frontend.thrift.http.bind.port|10010|Port of the machine on which to
run the thrift frontend service via http protocol.|int|1.6.0
@@ -313,9 +320,10 @@ kyuubi.frontend.thrift.http.max.idle.time|PT30M|Maximum
idle time for a connecti
kyuubi.frontend.thrift.http.path|cliservice|Path component of URL endpoint
when in HTTP mode.|string|1.6.0
kyuubi.frontend.thrift.http.request.header.size|6144|Request header size in
bytes, when using HTTP transport mode. Jetty defaults used.|int|1.6.0
kyuubi.frontend.thrift.http.response.header.size|6144|Response header size in
bytes, when using HTTP transport mode. Jetty defaults used.|int|1.6.0
+kyuubi.frontend.thrift.http.ssl.exclude.ciphersuites||A comma separated list
of exclude SSL cipher suite names for thrift http frontend.|seq|1.7.0
kyuubi.frontend.thrift.http.ssl.keystore.password|<undefined>|SSL
certificate keystore password.|string|1.6.0
kyuubi.frontend.thrift.http.ssl.keystore.path|<undefined>|SSL
certificate keystore location.|string|1.6.0
-kyuubi.frontend.thrift.http.ssl.protocol.blacklist|SSLv2,SSLv3|SSL Versions to
disable when using HTTP transport mode.|string|1.6.0
+kyuubi.frontend.thrift.http.ssl.protocol.blacklist|SSLv2,SSLv3|SSL Versions to
disable when using HTTP transport mode.|seq|1.6.0
kyuubi.frontend.thrift.http.use.SSL|false|Set this to true for using SSL
encryption in http mode.|boolean|1.6.0
kyuubi.frontend.thrift.http.xsrf.filter.enabled|false|If enabled, Kyuubi will
block any requests made to it over http if an X-XSRF-HEADER header is not
present|boolean|1.6.0
kyuubi.frontend.thrift.login.timeout|PT20S|Timeout for Thrift clients during
login to the thrift frontend service.|duration|1.4.0
diff --git
a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala
b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala
index ddefa455c..762b8b1ee 100644
--- a/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala
+++ b/kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala
@@ -379,6 +379,57 @@ object KyuubiConf {
.version("1.4.0")
.fallbackConf(FRONTEND_BIND_HOST)
+ val FRONTEND_THRIFT_BINARY_SSL_ENABLED: ConfigEntry[Boolean] =
+ buildConf("kyuubi.frontend.thrift.binary.ssl.enabled")
+ .doc("Set this to true for using SSL encryption in thrift binary
frontend server.")
+ .version("1.7.0")
+ .booleanConf
+ .createWithDefault(false)
+
+ val FRONTEND_SSL_KEYSTORE_PATH: OptionalConfigEntry[String] =
+ buildConf("kyuubi.frontend.ssl.keystore.path")
+ .doc("SSL certificate keystore location.")
+ .version("1.7.0")
+ .stringConf
+ .createOptional
+
+ val FRONTEND_SSL_KEYSTORE_PASSWORD: OptionalConfigEntry[String] =
+ buildConf("kyuubi.frontend.ssl.keystore.password")
+ .doc("SSL certificate keystore password.")
+ .version("1.7.0")
+ .stringConf
+ .createOptional
+
+ val FRONTEND_SSL_KEYSTORE_TYPE: OptionalConfigEntry[String] =
+ buildConf("kyuubi.frontend.ssl.keystore.type")
+ .doc("SSL certificate keystore type.")
+ .version("1.7.0")
+ .stringConf
+ .createOptional
+
+ val FRONTEND_SSL_KEYSTORE_ALGORITHM: OptionalConfigEntry[String] =
+ buildConf("kyuubi.frontend.ssl.keystore.algorithm")
+ .doc("SSL certificate keystore algorithm.")
+ .version("1.7.0")
+ .stringConf
+ .createOptional
+
+ val FRONTEND_THRIFT_BINARY_SSL_DISALLOWED_PROTOCOLS:
ConfigEntry[Seq[String]] =
+ buildConf("kyuubi.frontend.thrift.binary.ssl.disallowed.protocols")
+ .doc("SSL versions to disallow for Kyuubi thrift binary frontend.")
+ .version("1.7.0")
+ .stringConf
+ .toSequence()
+ .createWithDefault(Seq("SSLv2", "SSLv3"))
+
+ val FRONTEND_THRIFT_BINARY_SSL_INCLUDE_CIPHER_SUITES:
ConfigEntry[Seq[String]] =
+ buildConf("kyuubi.frontend.thrift.binary.ssl.include.ciphersuites")
+ .doc("A comma separated list of include SSL cipher suite names for
thrift binary frontend.")
+ .version("1.7.0")
+ .stringConf
+ .toSequence()
+ .createWithDefault(Nil)
+
@deprecated("using kyuubi.frontend.thrift.binary.bind.port instead", "1.4.0")
val FRONTEND_BIND_PORT: ConfigEntry[Int] =
buildConf("kyuubi.frontend.bind.port")
.doc("(deprecated) Port of the machine on which to run the thrift frontend
service " +
@@ -584,6 +635,7 @@ object KyuubiConf {
buildConf("kyuubi.frontend.thrift.http.ssl.keystore.path")
.doc("SSL certificate keystore location.")
.version("1.6.0")
+ .withAlternative("kyuubi.frontend.ssl.keystore.path")
.stringConf
.createOptional
@@ -591,15 +643,25 @@ object KyuubiConf {
buildConf("kyuubi.frontend.thrift.http.ssl.keystore.password")
.doc("SSL certificate keystore password.")
.version("1.6.0")
+ .withAlternative("kyuubi.frontend.ssl.keystore.password")
.stringConf
.createOptional
- val FRONTEND_THRIFT_HTTP_SSL_PROTOCOL_BLACKLIST: ConfigEntry[String] =
+ val FRONTEND_THRIFT_HTTP_SSL_PROTOCOL_BLACKLIST: ConfigEntry[Seq[String]] =
buildConf("kyuubi.frontend.thrift.http.ssl.protocol.blacklist")
.doc("SSL Versions to disable when using HTTP transport mode.")
.version("1.6.0")
.stringConf
- .createWithDefault("SSLv2,SSLv3")
+ .toSequence()
+ .createWithDefault(Seq("SSLv2", "SSLv3"))
+
+ val FRONTEND_THRIFT_HTTP_SSL_EXCLUDE_CIPHER_SUITES: ConfigEntry[Seq[String]]
=
+ buildConf("kyuubi.frontend.thrift.http.ssl.exclude.ciphersuites")
+ .doc("A comma separated list of exclude SSL cipher suite names for
thrift http frontend.")
+ .version("1.7.0")
+ .stringConf
+ .toSequence()
+ .createWithDefault(Nil)
val FRONTEND_THRIFT_HTTP_ALLOW_USER_SUBSTITUTION: ConfigEntry[Boolean] =
buildConf("kyuubi.frontend.thrift.http.allow.user.substitution")
@@ -2007,7 +2069,9 @@ object KyuubiConf {
SERVER_LIMIT_CONNECTIONS_PER_IPADDRESS,
SERVER_LIMIT_CONNECTIONS_PER_USER_IPADDRESS,
SERVER_LIMIT_CONNECTIONS_PER_USER,
- SESSION_LOCAL_DIR_ALLOW_LIST)
+ SESSION_LOCAL_DIR_ALLOW_LIST,
+ FRONTEND_SSL_KEYSTORE_PASSWORD,
+ FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PASSWORD)
/**
* Holds information about keys that have been deprecated.
diff --git
a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TBinaryFrontendService.scala
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TBinaryFrontendService.scala
index c6e218754..561d8067a 100644
---
a/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TBinaryFrontendService.scala
+++
b/kyuubi-common/src/main/scala/org/apache/kyuubi/service/TBinaryFrontendService.scala
@@ -17,12 +17,15 @@
package org.apache.kyuubi.service
+import java.security.KeyStore
+import java.util.Locale
import java.util.concurrent.{SynchronousQueue, ThreadPoolExecutor, TimeUnit}
+import javax.net.ssl.{KeyManagerFactory, SSLServerSocket}
import org.apache.hive.service.rpc.thrift._
import org.apache.thrift.protocol.TBinaryProtocol
import org.apache.thrift.server.{TServer, TThreadPoolServer}
-import org.apache.thrift.transport.TServerSocket
+import org.apache.thrift.transport.{TServerSocket, TSSLTransportFactory}
import org.apache.kyuubi.{KyuubiException, Logging}
import org.apache.kyuubi.config.KyuubiConf
@@ -65,7 +68,35 @@ abstract class TBinaryFrontendService(name: String)
new NamedThreadFactory(name + "Handler-Pool", false))
val transFactory = authFactory.getTTransportFactory
val tProcFactory = authFactory.getTProcessorFactory(this)
- val tServerSocket = new TServerSocket(serverSocket)
+ val tServerSocket =
+ // only enable ssl for server side
+ if (isServer() && conf.get(FRONTEND_THRIFT_BINARY_SSL_ENABLED)) {
+ val keyStorePath = conf.get(FRONTEND_SSL_KEYSTORE_PATH)
+ val keyStorePassword = conf.get(FRONTEND_SSL_KEYSTORE_PASSWORD)
+ val keyStoreType = conf.get(FRONTEND_SSL_KEYSTORE_TYPE)
+ val keyStoreAlgorithm = conf.get(FRONTEND_SSL_KEYSTORE_ALGORITHM)
+ val disallowedSslProtocols =
conf.get(FRONTEND_THRIFT_BINARY_SSL_DISALLOWED_PROTOCOLS)
+ val includeCipherSuites =
conf.get(FRONTEND_THRIFT_BINARY_SSL_INCLUDE_CIPHER_SUITES)
+
+ if (keyStorePath.isEmpty) {
+ throw new IllegalArgumentException(
+ s"${FRONTEND_SSL_KEYSTORE_PATH.key} not configured for SSL
connection")
+ }
+ if (keyStorePassword.isEmpty) {
+ throw new IllegalArgumentException(
+ s"${FRONTEND_SSL_KEYSTORE_PASSWORD.key} not configured for SSL
connection")
+ }
+
+ getServerSSLSocket(
+ keyStorePath.get,
+ keyStorePassword.get,
+ keyStoreType,
+ keyStoreAlgorithm,
+ disallowedSslProtocols,
+ includeCipherSuites)
+ } else {
+ new TServerSocket(serverSocket)
+ }
val maxMessageSize = conf.get(FRONTEND_THRIFT_MAX_MESSAGE_SIZE)
val requestTimeout = conf.get(FRONTEND_THRIFT_LOGIN_TIMEOUT).toInt
val beBackoffSlotLength =
conf.get(FRONTEND_THRIFT_LOGIN_BACKOFF_SLOT_LENGTH).toInt
@@ -94,6 +125,47 @@ abstract class TBinaryFrontendService(name: String)
super.initialize(conf)
}
+ private def getServerSSLSocket(
+ keyStorePath: String,
+ keyStorePassword: String,
+ keyStoreType: Option[String],
+ keyStoreAlgorithm: Option[String],
+ disallowedSslProtocols: Seq[String],
+ includeCipherSuites: Seq[String]): TServerSocket = {
+ val params =
+ if (includeCipherSuites.nonEmpty) {
+ new TSSLTransportFactory.TSSLTransportParameters("TLS",
includeCipherSuites.toArray)
+ } else {
+ new TSSLTransportFactory.TSSLTransportParameters()
+ }
+ params.setKeyStore(
+ keyStorePath,
+ keyStorePassword,
+ keyStoreAlgorithm.getOrElse(KeyManagerFactory.getDefaultAlgorithm),
+ keyStoreType.getOrElse(KeyStore.getDefaultType))
+
+ val tServerSocket =
+ TSSLTransportFactory.getServerSocket(portNum, 0,
serverSocket.getInetAddress, params)
+
+ tServerSocket.getServerSocket match {
+ case sslServerSocket: SSLServerSocket =>
+ val lowerDisallowedSslProtocols =
disallowedSslProtocols.map(_.toLowerCase(Locale.ROOT))
+ val enabledProtocols = sslServerSocket.getEnabledProtocols.flatMap {
protocol =>
+ if
(lowerDisallowedSslProtocols.contains(protocol.toLowerCase(Locale.ROOT))) {
+ debug(s"Disabling SSL Protocol: $protocol")
+ None
+ } else {
+ Some(protocol)
+ }
+ }
+ sslServerSocket.setEnabledProtocols(enabledProtocols)
+ info(s"SSL Server Socket enabled protocols: $enabledProtocols")
+
+ case _ =>
+ }
+ tServerSocket
+ }
+
override def run(): Unit =
try {
if (isServer()) {
diff --git
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala
index de2fc7814..4c0e2b875 100644
---
a/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala
+++
b/kyuubi-server/src/main/scala/org/apache/kyuubi/server/KyuubiTHttpFrontendService.scala
@@ -132,14 +132,24 @@ final class KyuubiTHttpFrontendService(
}
val sslContextFactory = new SslContextFactory.Server
- val excludedProtocols =
conf.get(FRONTEND_THRIFT_HTTP_SSL_PROTOCOL_BLACKLIST).split(",")
+ val excludedProtocols =
conf.get(FRONTEND_THRIFT_HTTP_SSL_PROTOCOL_BLACKLIST)
+ val excludeCipherSuites =
conf.get(FRONTEND_THRIFT_HTTP_SSL_EXCLUDE_CIPHER_SUITES)
+ val keyStoreType = conf.get(FRONTEND_SSL_KEYSTORE_TYPE)
+ val keyStoreAlgorithm = conf.get(FRONTEND_SSL_KEYSTORE_ALGORITHM)
info("Thrift HTTP Server SSL: adding excluded protocols: " +
String.join(",", excludedProtocols: _*))
sslContextFactory.addExcludeProtocols(excludedProtocols: _*)
info("Thrift HTTP Server SSL: SslContextFactory.getExcludeProtocols
= " +
String.join(",", sslContextFactory.getExcludeProtocols: _*))
+ info("Thrift HTTP Server SSL: setting excluded cipher Suites: " +
+ String.join(",", excludeCipherSuites: _*))
+ sslContextFactory.setExcludeCipherSuites(excludeCipherSuites: _*)
+ info("Thrift HTTP Server SSL:
SslContextFactory.getExcludeCipherSuites = " +
+ String.join(",", sslContextFactory.getExcludeCipherSuites: _*))
sslContextFactory.setKeyStorePath(keyStorePath.get)
sslContextFactory.setKeyStorePassword(keyStorePassword.get)
+ keyStoreType.foreach(sslContextFactory.setKeyStoreType)
+
keyStoreAlgorithm.foreach(sslContextFactory.setKeyManagerFactoryAlgorithm)
new ServerConnector(
server.get,
sslContextFactory,