Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ abstract class TBinaryFrontendService(name: String)
private var _actualPort: Int = _
override protected lazy val actualPort: Int = _actualPort

protected var keyStorePath: Option[String] = None
protected var keyStorePassword: Option[String] = None
protected var keyStoreType: Option[String] = None

// Removed OOM hook since Kyuubi #1800 to respect the hive server2 #2383

override def initialize(conf: KyuubiConf): Unit = synchronized {
Expand All @@ -73,9 +77,9 @@ abstract class TBinaryFrontendService(name: String)
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)
keyStorePath = conf.get(FRONTEND_SSL_KEYSTORE_PATH)
keyStorePassword = conf.get(FRONTEND_SSL_KEYSTORE_PASSWORD)
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ object MetricsConstants {
final private val THRIFT_BINARY_CONN = KYUUBI + "thrift.binary.connection."
final private val REST_CONN = KYUUBI + "rest.connection."

final val THRIFT_SSL_CERT_EXPIRATION = KYUUBI + "thrift.ssl.cert.expiration"

final val CONN_OPEN: String = CONN + "opened"
final val CONN_FAIL: String = CONN + "failed"
final val CONN_TOTAL: String = CONN + "total"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import org.apache.kyuubi.session.KyuubiSessionImpl
import org.apache.kyuubi.shaded.hive.service.rpc.thrift._
import org.apache.kyuubi.shaded.thrift.protocol.TProtocol
import org.apache.kyuubi.shaded.thrift.server.ServerContext
import org.apache.kyuubi.util.SSLUtils

final class KyuubiTBinaryFrontendService(
override val serverable: Serverable)
Expand Down Expand Up @@ -122,4 +123,9 @@ final class KyuubiTBinaryFrontendService(
resp.setStatus(notSupportTokenErrorStatus)
resp
}

override def start(): Unit = {
super.start()
SSLUtils.tracingThriftSSLCertExpiration(keyStorePath, keyStorePassword, keyStoreType)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import org.apache.kyuubi.service.TFrontendService.{CURRENT_SERVER_CONTEXT, OK_ST
import org.apache.kyuubi.session.KyuubiSessionImpl
import org.apache.kyuubi.shaded.hive.service.rpc.thrift.{TCLIService, TOpenSessionReq, TOpenSessionResp}
import org.apache.kyuubi.shaded.thrift.protocol.TBinaryProtocol
import org.apache.kyuubi.util.NamedThreadFactory
import org.apache.kyuubi.util.{NamedThreadFactory, SSLUtils}

/**
* Apache Thrift based hive service rpc
Expand All @@ -67,6 +67,10 @@ final class KyuubiTHttpFrontendService(
override protected lazy val actualPort: Int = portNum
override protected lazy val serverSocket: ServerSocket = null

private var keyStorePath: Option[String] = None
private var keyStorePassword: Option[String] = None
private var keyStoreType: Option[String] = None

private var server: Option[Server] = None
private val APPLICATION_THRIFT = "application/x-thrift"

Expand Down Expand Up @@ -122,15 +126,15 @@ final class KyuubiTHttpFrontendService(
// Change connector if SSL is used
val connector =
if (useSsl) {
val keyStorePath = conf.get(FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PATH)
keyStorePath = conf.get(FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PATH)

if (keyStorePath.isEmpty) {
throw new IllegalArgumentException(FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PATH.key +
" Not configured for SSL connection, please set the key with: " +
FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PATH.doc)
}

val keyStorePassword = conf.get(FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PASSWORD)
keyStorePassword = conf.get(FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PASSWORD)
if (keyStorePassword.isEmpty) {
throw new IllegalArgumentException(FRONTEND_THRIFT_HTTP_SSL_KEYSTORE_PASSWORD.key +
" Not configured for SSL connection. please set the key with: " +
Expand All @@ -140,7 +144,7 @@ final class KyuubiTHttpFrontendService(
val sslContextFactory = new SslContextFactory.Server
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)
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: _*))
Expand Down Expand Up @@ -359,4 +363,9 @@ final class KyuubiTHttpFrontendService(

ret
}

override def start(): Unit = {
super.start()
SSLUtils.tracingThriftSSLCertExpiration(keyStorePath, keyStorePassword, keyStoreType)
}
}
70 changes: 70 additions & 0 deletions kyuubi-server/src/main/scala/org/apache/kyuubi/util/SSLUtils.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.kyuubi.util
import java.io.FileInputStream
import java.security.KeyStore
import java.security.cert.X509Certificate

import scala.collection.JavaConverters._

import org.apache.kyuubi.{Logging, Utils}
import org.apache.kyuubi.metrics.{MetricsConstants, MetricsSystem}

object SSLUtils extends Logging {

/**
* Get the keystore certificate latest expiration time.
*/
private def getKeyStoreExpirationTime(
keyStorePath: String,
keyStorePassword: String,
keyStoreType: Option[String]): Option[Long] = {
try {
val keyStore = KeyStore.getInstance(keyStoreType.getOrElse(KeyStore.getDefaultType))
keyStore.load(new FileInputStream(keyStorePath), keyStorePassword.toCharArray)
keyStore.aliases().asScala.toSeq.map { alias =>
keyStore.getCertificate(alias).asInstanceOf[X509Certificate].getNotAfter.getTime
}.sorted.headOption
} catch {
case e: Throwable =>
error("Error getting keystore expiration time.", e)
None
}
}

def tracingThriftSSLCertExpiration(
keyStorePath: Option[String],
keyStorePassword: Option[String],
keyStoreType: Option[String]): Unit = {
if (keyStorePath.isDefined && keyStorePassword.isDefined) {
SSLUtils.getKeyStoreExpirationTime(
keyStorePath.get,
keyStorePassword.get,
keyStoreType).foreach { expiration =>
info(s"Thrift SSL Serve KeyStore ${keyStorePath.get} will expire at:" +
s" ${Utils.getDateFromTimestamp(expiration)}")
MetricsSystem.tracing { ms =>
ms.registerGauge(
MetricsConstants.THRIFT_SSL_CERT_EXPIRATION,
expiration - System.currentTimeMillis(),
0L)
}
}
}
}
}
Loading