Skip to content

Commit f1cf95f

Browse files
committed
[KYUUBI #2719] [SUB-TASK][KPIP-4] Support internal rest request authentication to enable http request redirection across kyuubi instances
### _Why are the changes needed?_ Support internal rest request authentication to enable redirect http request across kyuubi instances ### _How was this patch tested?_ - [x] Add some test cases that check the changes thoroughly including negative and positive cases if possible - [ ] Add screenshots for manual tests if appropriate - [x] [Run test](https://kyuubi.apache.org/docs/latest/develop_tools/testing.html#running-tests) locally before make a pull request Closes #2719 from turboFei/internal_access. Closes #2719 b9e150e [Fei Wang] revert config key change aa37872 [Fei Wang] make it internal ce96d92 [Fei Wang] comments 6fe8523 [Fei Wang] Support internal rest request authentication to enable redirect http request across kyuubi instances Authored-by: Fei Wang <fwang12@ebay.com> Signed-off-by: Fei Wang <fwang12@ebay.com>
1 parent 9578475 commit f1cf95f

File tree

14 files changed

+152
-37
lines changed

14 files changed

+152
-37
lines changed

docs/deployment/settings.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,6 @@ Key | Default | Meaning | Type | Since
220220
<code>kyuubi.engine.pool.name</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>engine-pool</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The name of engine pool.</div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.5.0</div>
221221
<code>kyuubi.engine.pool.size</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>-1</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The size of engine pool. Note that, if the size is less than 1, the engine pool will not be enabled; otherwise, the size of the engine pool will be min(this, kyuubi.engine.pool.size.threshold).</div>|<div style='width: 30pt'>int</div>|<div style='width: 20pt'>1.4.0</div>
222222
<code>kyuubi.engine.pool.size.threshold</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>9</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>This parameter is introduced as a server-side parameter, and controls the upper limit of the engine pool.</div>|<div style='width: 30pt'>int</div>|<div style='width: 20pt'>1.4.0</div>
223-
<code>kyuubi.engine.security.crypto.cipher</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>AES/CBC/PKCS5PADDING</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The cipher transformation to use for encrypting engine access token.</div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.5.0</div>
224-
<code>kyuubi.engine.security.crypto.ivLength</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>16</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>Initial vector length, in bytes.</div>|<div style='width: 30pt'>int</div>|<div style='width: 20pt'>1.5.0</div>
225-
<code>kyuubi.engine.security.crypto.keyAlgorithm</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>AES</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The algorithm for generated secret keys.</div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.5.0</div>
226-
<code>kyuubi.engine.security.crypto.keyLength</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>128</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The length in bits of the encryption key to generate. Valid values are 128, 192 and 256</div>|<div style='width: 30pt'>int</div>|<div style='width: 20pt'>1.5.0</div>
227-
<code>kyuubi.engine.security.enabled</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>false</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>Whether to enable the internal secure access between Kyuubi server and engine.</div>|<div style='width: 30pt'>boolean</div>|<div style='width: 20pt'>1.5.0</div>
228-
<code>kyuubi.engine.security.secret.provider</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>org.apache.kyuubi.service.authentication.ZooKeeperEngineSecuritySecretProviderImpl</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The class used to manage the engine security secret. This class must be a subclass of EngineSecuritySecretProvider.</div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.5.0</div>
229-
<code>kyuubi.engine.security.token.max.lifetime</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>PT10M</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The max lifetime of the token used for secure access between Kyuubi server and engine.</div>|<div style='width: 30pt'>duration</div>|<div style='width: 20pt'>1.5.0</div>
230223
<code>kyuubi.engine.session.initialize.sql</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'></div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>SemiColon-separated list of SQL statements to be initialized in the newly created engine session before queries. This configuration can not be used in JDBC url due to the limitation of Beeline/JDBC driver.</div>|<div style='width: 30pt'>seq</div>|<div style='width: 20pt'>1.3.0</div>
231224
<code>kyuubi.engine.share.level</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>USER</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>Engines will be shared in different levels, available configs are: <ul> <li>CONNECTION: engine will not be shared but only used by the current client connection</li> <li>USER: engine will be shared by all sessions created by a unique username, see also kyuubi.engine.share.level.subdomain</li> <li>GROUP: engine will be shared by all sessions created by all users belong to the same primary group name. The engine will be launched by the group name as the effective username, so here the group name is kind of special user who is able to visit the compute resources/data of a team. It follows the [Hadoop GroupsMapping](https://reurl.cc/xE61Y5) to map user to a primary group. If the primary group is not found, it fallback to the USER level. <li>SERVER: the App will be shared by Kyuubi servers</li></ul></div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.2.0</div>
232225
<code>kyuubi.engine.share.level.sub.domain</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>&lt;undefined&gt;</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>(deprecated) - Using kyuubi.engine.share.level.subdomain instead</div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.2.0</div>
@@ -292,7 +285,6 @@ Key | Default | Meaning | Type | Since
292285
<code>kyuubi.ha.zookeeper.connection.retry.policy</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>EXPONENTIAL_BACKOFF</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The retry policy for connecting to the zookeeper ensemble, all candidates are: <ul><li>ONE_TIME</li><li> N_TIME</li><li> EXPONENTIAL_BACKOFF</li><li> BOUNDED_EXPONENTIAL_BACKOFF</li><li> UNTIL_ELAPSED</li></ul></div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.0.0</div>
293286
<code>kyuubi.ha.zookeeper.connection.timeout</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>15000</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The timeout(ms) of creating the connection to the zookeeper ensemble</div>|<div style='width: 30pt'>int</div>|<div style='width: 20pt'>1.0.0</div>
294287
<code>kyuubi.ha.zookeeper.engine.auth.type</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>NONE</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The type of zookeeper authentication for engine, all candidates are <ul><li>NONE</li><li> KERBEROS</li><li> DIGEST</li></ul></div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.3.2</div>
295-
<code>kyuubi.ha.zookeeper.engine.secure.secret.node</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>&lt;undefined&gt;</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The zk node contains the secret that used for internal secure between Kyuubi server and Kyuubi engine, please make sure that it is only visible for Kyuubi.</div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.5.0</div>
296288
<code>kyuubi.ha.zookeeper.namespace</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>kyuubi</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>The root directory for the service to deploy its instance uri</div>|<div style='width: 30pt'>string</div>|<div style='width: 20pt'>1.0.0</div>
297289
<code>kyuubi.ha.zookeeper.node.creation.timeout</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>PT2M</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>Timeout for creating zookeeper node</div>|<div style='width: 30pt'>duration</div>|<div style='width: 20pt'>1.2.0</div>
298290
<code>kyuubi.ha.zookeeper.publish.configs</code>|<div style='width: 65pt;word-wrap: break-word;white-space: normal'>false</div>|<div style='width: 170pt;word-wrap: break-word;white-space: normal'>When set to true, publish Kerberos configs to Zookeeper.Note that the Hive driver needs to be greater than 1.3 or 2.0 or apply HIVE-11581 patch.</div>|<div style='width: 30pt'>boolean</div>|<div style='width: 20pt'>1.4.0</div>

kyuubi-common/src/main/scala/org/apache/kyuubi/config/KyuubiConf.scala

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,21 +1250,26 @@ object KyuubiConf {
12501250

12511251
val ENGINE_SECURITY_ENABLED: ConfigEntry[Boolean] =
12521252
buildConf("kyuubi.engine.security.enabled")
1253-
.doc("Whether to enable the internal secure access between Kyuubi server and engine.")
1253+
.internal
1254+
.doc("Whether to enable the internal secure access. Before 1.6.0, it is used for the secure" +
1255+
" access between kyuubi server and kyuubi engine. Since 1.6.0, kyuubi supports internal" +
1256+
" secure across kyuubi server instances.")
12541257
.version("1.5.0")
12551258
.booleanConf
12561259
.createWithDefault(false)
12571260

12581261
val ENGINE_SECURITY_TOKEN_MAX_LIFETIME: ConfigEntry[Long] =
12591262
buildConf("kyuubi.engine.security.token.max.lifetime")
1260-
.doc("The max lifetime of the token used for secure access between Kyuubi server and engine.")
1263+
.internal
1264+
.doc("The max lifetime of the token used for internal secure access.")
12611265
.version("1.5.0")
12621266
.timeConf
12631267
.createWithDefault(Duration.ofMinutes(10).toMillis)
12641268

12651269
val ENGINE_SECURITY_SECRET_PROVIDER: ConfigEntry[String] =
12661270
buildConf("kyuubi.engine.security.secret.provider")
1267-
.doc("The class used to manage the engine security secret. This class must be a " +
1271+
.internal
1272+
.doc("The class used to manage the internal security secret. This class must be a " +
12681273
"subclass of EngineSecuritySecretProvider.")
12691274
.version("1.5.0")
12701275
.stringConf
@@ -1273,6 +1278,7 @@ object KyuubiConf {
12731278

12741279
val ENGINE_SECURITY_CRYPTO_KEY_LENGTH: ConfigEntry[Int] =
12751280
buildConf("kyuubi.engine.security.crypto.keyLength")
1281+
.internal
12761282
.doc("The length in bits of the encryption key to generate. " +
12771283
"Valid values are 128, 192 and 256")
12781284
.version("1.5.0")
@@ -1282,21 +1288,24 @@ object KyuubiConf {
12821288

12831289
val ENGINE_SECURITY_CRYPTO_IV_LENGTH: ConfigEntry[Int] =
12841290
buildConf("kyuubi.engine.security.crypto.ivLength")
1291+
.internal
12851292
.doc("Initial vector length, in bytes.")
12861293
.version("1.5.0")
12871294
.intConf
12881295
.createWithDefault(16)
12891296

12901297
val ENGINE_SECURITY_CRYPTO_KEY_ALGORITHM: ConfigEntry[String] =
12911298
buildConf("kyuubi.engine.security.crypto.keyAlgorithm")
1299+
.internal
12921300
.doc("The algorithm for generated secret keys.")
12931301
.version("1.5.0")
12941302
.stringConf
12951303
.createWithDefault("AES")
12961304

12971305
val ENGINE_SECURITY_CRYPTO_CIPHER_TRANSFORMATION: ConfigEntry[String] =
12981306
buildConf("kyuubi.engine.security.crypto.cipher")
1299-
.doc("The cipher transformation to use for encrypting engine access token.")
1307+
.internal
1308+
.doc("The cipher transformation to use for encrypting internal access token.")
13001309
.version("1.5.0")
13011310
.stringConf
13021311
.createWithDefault("AES/CBC/PKCS5PADDING")

kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/EngineSecureAuthenticationProviderImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ package org.apache.kyuubi.service.authentication
1919

2020
class EngineSecureAuthenticationProviderImpl extends PasswdAuthenticationProvider {
2121
override def authenticate(user: String, password: String): Unit = {
22-
EngineSecurityAccessor.get().authToken(password)
22+
InternalSecurityAccessor.get().authToken(password)
2323
}
2424
}

kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/EngineSecurityAccessor.scala renamed to kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/InternalSecurityAccessor.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import org.apache.kyuubi.{KyuubiSQLException, Logging}
2424
import org.apache.kyuubi.config.KyuubiConf
2525
import org.apache.kyuubi.config.KyuubiConf._
2626

27-
class EngineSecurityAccessor(conf: KyuubiConf, val isServer: Boolean) {
27+
class InternalSecurityAccessor(conf: KyuubiConf, val isServer: Boolean) {
2828
val cryptoKeyLengthBytes = conf.get(ENGINE_SECURITY_CRYPTO_KEY_LENGTH) / java.lang.Byte.SIZE
2929
val cryptoIvLength = conf.get(ENGINE_SECURITY_CRYPTO_IV_LENGTH)
3030
val cryptoKeyAlgorithm = conf.get(ENGINE_SECURITY_CRYPTO_KEY_ALGORITHM)
@@ -109,16 +109,16 @@ class EngineSecurityAccessor(conf: KyuubiConf, val isServer: Boolean) {
109109
}
110110
}
111111

112-
object EngineSecurityAccessor extends Logging {
113-
@volatile private var _engineSecurityAccessor: EngineSecurityAccessor = _
112+
object InternalSecurityAccessor extends Logging {
113+
@volatile private var _engineSecurityAccessor: InternalSecurityAccessor = _
114114

115115
def initialize(conf: KyuubiConf, isServer: Boolean): Unit = {
116116
if (_engineSecurityAccessor == null) {
117-
_engineSecurityAccessor = new EngineSecurityAccessor(conf, isServer)
117+
_engineSecurityAccessor = new InternalSecurityAccessor(conf, isServer)
118118
}
119119
}
120120

121-
def get(): EngineSecurityAccessor = {
121+
def get(): InternalSecurityAccessor = {
122122
_engineSecurityAccessor
123123
}
124124
}

kyuubi-common/src/main/scala/org/apache/kyuubi/service/authentication/KyuubiAuthenticationFactory.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class KyuubiAuthenticationFactory(conf: KyuubiConf, isServer: Boolean = true) ex
5757
}
5858

5959
if (conf.get(ENGINE_SECURITY_ENABLED)) {
60-
EngineSecurityAccessor.initialize(conf, isServer)
60+
InternalSecurityAccessor.initialize(conf, isServer)
6161
}
6262

6363
private def getSaslProperties: java.util.Map[String, String] = {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ package org.apache.kyuubi.service.authentication
2020
import org.apache.kyuubi.{KyuubiFunSuite, KyuubiSQLException}
2121
import org.apache.kyuubi.config.KyuubiConf
2222

23-
class EngineSecurityAccessorSuite extends KyuubiFunSuite {
23+
class InternalSecurityAccessorSuite extends KyuubiFunSuite {
2424
private val conf = KyuubiConf()
2525
conf.set(
2626
KyuubiConf.ENGINE_SECURITY_SECRET_PROVIDER,
@@ -31,7 +31,7 @@ class EngineSecurityAccessorSuite extends KyuubiFunSuite {
3131
val newConf = conf.clone
3232
newConf.set(KyuubiConf.ENGINE_SECURITY_CRYPTO_CIPHER_TRANSFORMATION, cipher)
3333

34-
val secureAccessor = new EngineSecurityAccessor(newConf, true)
34+
val secureAccessor = new InternalSecurityAccessor(newConf, true)
3535
val value = "tokenToEncrypt"
3636
val encryptedValue = secureAccessor.encrypt(value)
3737
assert(secureAccessor.decrypt(encryptedValue) === value)
@@ -40,7 +40,7 @@ class EngineSecurityAccessorSuite extends KyuubiFunSuite {
4040
secureAccessor.authToken(token)
4141
intercept[KyuubiSQLException](secureAccessor.authToken("invalidToken"))
4242

43-
val engineSecureAccessor = new EngineSecurityAccessor(newConf, false)
43+
val engineSecureAccessor = new InternalSecurityAccessor(newConf, false)
4444
engineSecureAccessor.authToken(token)
4545
}
4646
}

kyuubi-ha/src/main/scala/org/apache/kyuubi/ha/HighAvailabilityConf.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,9 @@ object HighAvailabilityConf {
153153

154154
val HA_ZK_ENGINE_SECURE_SECRET_NODE: OptionalConfigEntry[String] =
155155
buildConf("kyuubi.ha.zookeeper.engine.secure.secret.node")
156-
.doc("The zk node contains the secret that used for internal secure between Kyuubi server " +
157-
"and Kyuubi engine, please make sure that it is only visible for Kyuubi.")
156+
.internal
157+
.doc("The zk node contains the secret that used for internal secure, please make sure " +
158+
"that it is only visible for Kyuubi.")
158159
.version("1.5.0")
159160
.stringConf
160161
.createOptional

kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthSchemes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ package org.apache.kyuubi.server.http.authentication
2020
object AuthSchemes extends Enumeration {
2121
type AuthScheme = Value
2222

23-
val BASIC, NEGOTIATE = Value
23+
val BASIC, NEGOTIATE, KYUUBI_INTERNAL = Value
2424
}

kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/AuthenticationFilter.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import org.apache.hadoop.security.authentication.client.AuthenticationException
2828
import org.apache.kyuubi.Logging
2929
import org.apache.kyuubi.config.KyuubiConf
3030
import org.apache.kyuubi.config.KyuubiConf.AUTHENTICATION_METHOD
31-
import org.apache.kyuubi.service.authentication.AuthTypes
31+
import org.apache.kyuubi.service.authentication.{AuthTypes, InternalSecurityAccessor}
3232
import org.apache.kyuubi.service.authentication.AuthTypes.{KERBEROS, NOSASL}
3333

3434
class AuthenticationFilter(conf: KyuubiConf) extends Filter with Logging {
@@ -72,6 +72,10 @@ class AuthenticationFilter(conf: KyuubiConf) extends Filter with Logging {
7272
val basicHandler = new BasicAuthenticationHandler(basicAuthType)
7373
addAuthHandler(basicHandler)
7474
}
75+
if (InternalSecurityAccessor.get() != null) {
76+
val internalHandler = new KyuubiInternalAuthenticationHandler
77+
addAuthHandler(internalHandler)
78+
}
7579
super.init(filterConfig)
7680
}
7781

kyuubi-server/src/main/scala/org/apache/kyuubi/server/http/authentication/KyuubiHttpAuthenticationFactory.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper
2626

2727
import org.apache.kyuubi.config.KyuubiConf
2828
import org.apache.kyuubi.config.KyuubiConf.{AUTHENTICATION_METHOD, ENGINE_SECURITY_ENABLED}
29-
import org.apache.kyuubi.service.authentication.{AuthTypes, EngineSecurityAccessor}
29+
import org.apache.kyuubi.service.authentication.{AuthTypes, InternalSecurityAccessor}
3030
import org.apache.kyuubi.service.authentication.AuthTypes.KERBEROS
3131

3232
class KyuubiHttpAuthenticationFactory(conf: KyuubiConf) {
@@ -35,7 +35,7 @@ class KyuubiHttpAuthenticationFactory(conf: KyuubiConf) {
3535
private val ugi = UserGroupInformation.getCurrentUser
3636

3737
if (conf.get(ENGINE_SECURITY_ENABLED)) {
38-
EngineSecurityAccessor.initialize(conf, true)
38+
InternalSecurityAccessor.initialize(conf, true)
3939
}
4040

4141
private[kyuubi] val httpHandlerWrapperFactory =

0 commit comments

Comments
 (0)