Skip to content

Commit d8e6099

Browse files
committed
HIVE-29606: Support SSL include protocols and cipher suites for Hive Metastore
1 parent ba43ea3 commit d8e6099

6 files changed

Lines changed: 115 additions & 29 deletions

File tree

standalone-metastore/metastore-client/src/main/java/org/apache/hadoop/hive/metastore/client/ThriftHiveMetaStoreClient.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
import com.google.common.annotations.VisibleForTesting;
2222
import com.google.common.base.Preconditions;
23+
import com.google.common.base.Splitter;
24+
import com.google.common.collect.Iterables;
2325
import com.google.common.collect.Lists;
2426
import org.apache.hadoop.classification.InterfaceAudience;
2527
import org.apache.hadoop.conf.Configuration;
@@ -535,6 +537,9 @@ private Map<String, String> getAdditionalHeaders() {
535537
Map<String, String> headers = new HashMap<>();
536538
String keyValuePairs = MetastoreConf.getVar(conf,
537539
MetastoreConf.ConfVars.METASTORE_CLIENT_ADDITIONAL_HEADERS);
540+
if (keyValuePairs.isEmpty()) {
541+
return headers;
542+
}
538543
try {
539544
String[] headerKeyValues = keyValuePairs.split(",");
540545
for (String header : headerKeyValues) {
@@ -575,9 +580,13 @@ private THttpClient createHttpClient(URI store, boolean useSSL) throws MetaExcep
575580
String trustStorePassword = MetastoreConf.getPassword(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_PASSWORD);
576581
String trustStoreType = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_TYPE).trim();
577582
String trustStoreAlgorithm = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTMANAGERFACTORY_ALGORITHM).trim();
583+
String[] includeProtocols = Iterables.toArray(Splitter.on(",").trimResults().omitEmptyStrings()
584+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS)), String.class);
585+
String[] includeCipherSuites = Iterables.toArray(Splitter.on(":").trimResults().omitEmptyStrings()
586+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES)), String.class);
578587
tHttpClient =
579588
SecurityUtils.getThriftHttpsClient(httpUrl, trustStorePath, trustStorePassword, trustStoreAlgorithm,
580-
trustStoreType, httpClientBuilder);
589+
trustStoreType, includeProtocols, includeCipherSuites, httpClientBuilder);
581590
} else {
582591
tHttpClient = new THttpClient(httpUrl, httpClientBuilder.build());
583592
}
@@ -659,8 +668,13 @@ private TTransport createBinaryClient(URI store, boolean useSSL) throws TTranspo
659668
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_TYPE).trim();
660669
String trustStoreAlgorithm =
661670
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTMANAGERFACTORY_ALGORITHM).trim();
671+
String[] includeProtocols = Iterables.toArray(Splitter.on(",").trimResults().omitEmptyStrings()
672+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS)), String.class);
673+
String[] includeCipherSuites = Iterables.toArray(Splitter.on(":").trimResults().omitEmptyStrings()
674+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES)), String.class);
662675
binaryTransport = SecurityUtils.getSSLSocket(store.getHost(), store.getPort(), clientSocketTimeout,
663-
connectionTimeout, trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm);
676+
connectionTimeout, trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm,
677+
includeProtocols, includeCipherSuites);
664678
} else {
665679
binaryTransport = new TSocket(new TConfiguration(), store.getHost(), store.getPort(),
666680
clientSocketTimeout, connectionTimeout);

standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/conf/MetastoreConf.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,10 @@ public enum ConfVars {
14771477
"Metastore SSL certificate truststore type."),
14781478
SSL_TRUSTMANAGERFACTORY_ALGORITHM("metastore.trustmanagerfactory.algorithm", "hive.metastore.trustmanagerfactory.algorithm", "",
14791479
"Metastore SSL certificate truststore algorithm."),
1480+
SSL_INCLUDE_PROTOCOLS("metastore.include.protocols", "hive.metastore.include.protocols", "",
1481+
"List of include SSL protocols separated by comma for Metastore"),
1482+
SSL_INCLUDE_CIPHERSUITES("metastore.include.ciphersuites", "hive.metastore.include.ciphersuites", "",
1483+
"List of include cipher suite names separated by colon for Metastore"),
14801484
STATS_AUTO_GATHER("metastore.stats.autogather", "hive.stats.autogather", true,
14811485
"A flag to gather statistics (only basic) automatically during the INSERT OVERWRITE command."),
14821486
STATS_FETCH_BITVECTOR("metastore.stats.fetch.bitvector", "hive.stats.fetch.bitvector", false,

standalone-metastore/metastore-common/src/main/java/org/apache/hadoop/hive/metastore/utils/SecurityUtils.java

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@
6262
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
6363
import java.io.IOException;
6464
import java.net.InetSocketAddress;
65-
import java.net.UnknownHostException;
6665
import java.security.KeyStore;
6766

6867
import java.util.ArrayList;
6968
import java.util.Arrays;
7069
import java.util.HashMap;
7170
import java.util.List;
7271
import java.util.Map;
72+
import java.util.Set;
73+
import java.util.stream.Collectors;
7374

7475
public class SecurityUtils {
7576
private static final Logger LOG = LoggerFactory.getLogger(SecurityUtils.class);
@@ -278,17 +279,32 @@ public static TServerSocket getServerSocket(String hiveHost, int portNum) throws
278279
return new TServerSocket(serverAddress);
279280
}
280281

282+
private static TSSLTransportFactory.TSSLTransportParameters getSSLTransportParameters(boolean isKeyStore,
283+
String storePath, String storePassword, String storeAlgorithm, String storeType, String[] cipherSuites) {
284+
TSSLTransportFactory.TSSLTransportParameters params;
285+
if (cipherSuites.length > 0) {
286+
params = new TSSLTransportFactory.TSSLTransportParameters("TLS", cipherSuites);
287+
} else {
288+
params = new TSSLTransportFactory.TSSLTransportParameters();
289+
}
290+
if (isKeyStore) {
291+
params.setKeyStore(storePath, storePassword, storeAlgorithm, storeType);
292+
} else {
293+
params.setTrustStore(storePath, storePassword, storeAlgorithm, storeType);
294+
params.requireClientAuth(true);
295+
}
296+
return params;
297+
}
298+
281299
public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, String keyStorePath,
282-
String keyStorePassWord, String keyStoreType, String keyStoreAlgorithm, List<String> sslVersionBlacklist)
283-
throws TTransportException, UnknownHostException {
284-
TSSLTransportFactory.TSSLTransportParameters params =
285-
new TSSLTransportFactory.TSSLTransportParameters();
286-
String kStoreType = keyStoreType.isEmpty()? KeyStore.getDefaultType() : keyStoreType;
287-
String kStoreAlgorithm = keyStoreAlgorithm.isEmpty()?
288-
KeyManagerFactory.getDefaultAlgorithm() : keyStoreAlgorithm;
289-
params.setKeyStore(keyStorePath, keyStorePassWord, kStoreAlgorithm, kStoreType);
300+
String keyStorePassWord, String keyStoreType, String keyStoreAlgorithm, List<String> sslVersionBlacklist,
301+
String[] includeProtocols, String[] cipherSuites) throws TTransportException {
302+
TSSLTransportFactory.TSSLTransportParameters params = getSSLTransportParameters(true,
303+
keyStorePath, keyStorePassWord,
304+
keyStoreAlgorithm.isEmpty() ? KeyManagerFactory.getDefaultAlgorithm() : keyStoreAlgorithm,
305+
keyStoreType.isEmpty() ? KeyStore.getDefaultType() : keyStoreType, cipherSuites);
290306
InetSocketAddress serverAddress;
291-
if (hiveHost == null || hiveHost.isEmpty()) {
307+
if (StringUtils.isEmpty(hiveHost)) {
292308
// Wildcard bind
293309
serverAddress = new InetSocketAddress(portNum);
294310
} else {
@@ -303,14 +319,20 @@ public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, Str
303319
}
304320
SSLServerSocket sslServerSocket = (SSLServerSocket) thriftServerSocket.getServerSocket();
305321
List<String> enabledProtocols = new ArrayList<>();
306-
for (String protocol : sslServerSocket.getEnabledProtocols()) {
322+
for (String protocol : sslServerSocket.getSupportedProtocols()) {
307323
if (sslVersionBlacklistLocal.contains(protocol.toLowerCase())) {
308324
LOG.debug("Disabling SSL Protocol: " + protocol);
309325
} else {
310326
enabledProtocols.add(protocol);
311327
}
312328
}
313-
sslServerSocket.setEnabledProtocols(enabledProtocols.toArray(new String[0]));
329+
if (includeProtocols.length > 0) {
330+
Set<String> includeProtocolsLowerCase = Arrays.stream(includeProtocols).map(String::toLowerCase)
331+
.collect(Collectors.toSet());
332+
enabledProtocols = enabledProtocols.stream()
333+
.filter(protocol -> includeProtocolsLowerCase.contains(protocol.toLowerCase())).toList();
334+
}
335+
sslServerSocket.setEnabledProtocols(enabledProtocols.toArray(String[]::new));
314336
LOG.info("SSL Server Socket Enabled Protocols: "
315337
+ Arrays.toString(sslServerSocket.getEnabledProtocols()));
316338
}
@@ -319,18 +341,23 @@ public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, Str
319341

320342
public static TTransport getSSLSocket(String host, int port, int socketTimeout, int connectionTimeout,
321343
String trustStorePath, String trustStorePassWord, String trustStoreType,
322-
String trustStoreAlgorithm) throws TTransportException {
323-
TSSLTransportFactory.TSSLTransportParameters params =
324-
new TSSLTransportFactory.TSSLTransportParameters();
325-
String tStoreType = trustStoreType.isEmpty()? KeyStore.getDefaultType() : trustStoreType;
326-
String tStoreAlgorithm = trustStoreAlgorithm.isEmpty()?
327-
TrustManagerFactory.getDefaultAlgorithm() : trustStoreAlgorithm;
328-
params.setTrustStore(trustStorePath, trustStorePassWord,
329-
tStoreAlgorithm, tStoreType);
330-
params.requireClientAuth(true);
344+
String trustStoreAlgorithm, String[] includeProtocols, String[] cipherSuites) throws TTransportException {
345+
TSSLTransportFactory.TSSLTransportParameters params = getSSLTransportParameters(false,
346+
trustStorePath, trustStorePassWord,
347+
trustStoreAlgorithm.isEmpty() ? TrustManagerFactory.getDefaultAlgorithm() : trustStoreAlgorithm,
348+
trustStoreType.isEmpty() ? KeyStore.getDefaultType() : trustStoreType,
349+
cipherSuites);
331350
// The underlying SSLSocket object is bound to host:port with the given SO_TIMEOUT and
332351
// connection timeout and SSLContext created with the given params
333352
TSocket tSSLSocket = TSSLTransportFactory.getClientSocket(host, port, socketTimeout, params);
353+
if (includeProtocols.length > 0) {
354+
SSLSocket sslSocket = (SSLSocket) (tSSLSocket.getSocket());
355+
Set<String> includeProtocolsLowerCase = Arrays.stream(includeProtocols).map(String::toLowerCase)
356+
.collect(Collectors.toSet());
357+
String[] enabledProtocols = Arrays.stream(sslSocket.getSupportedProtocols())
358+
.filter(protocol -> includeProtocolsLowerCase.contains(protocol.toLowerCase())).toArray(String[]::new);
359+
sslSocket.setEnabledProtocols(enabledProtocols);
360+
}
334361
tSSLSocket.setConnectTimeout(connectionTimeout);
335362
return getSSLSocketWithHttps(tSSLSocket);
336363
}
@@ -341,13 +368,17 @@ public static TTransport getSSLSocket(String host, int port, int socketTimeout,
341368
*/
342369
public static THttpClient getThriftHttpsClient(String httpsUrl, String trustStorePath,
343370
String trustStorePasswd, String trustStoreAlgorithm, String trustStoreType,
371+
String[] includeProtocols, String[] cipherSuites,
344372
HttpClientBuilder underlyingHttpClientBuilder) throws TTransportException, IOException,
345373
KeyStoreException, NoSuchAlgorithmException, CertificateException,
346374
KeyManagementException {
347375
Preconditions.checkNotNull(underlyingHttpClientBuilder, "httpClientBuilder should not be null");
348376
if (trustStoreType == null || trustStoreType.isEmpty()) {
349377
trustStoreType = KeyStore.getDefaultType();
350378
}
379+
if (trustStoreAlgorithm.isEmpty()) {
380+
trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
381+
}
351382
KeyStore sslTrustStore = KeyStore.getInstance(trustStoreType);
352383
try (FileInputStream fis = new FileInputStream(trustStorePath)) {
353384
sslTrustStore.load(fis, trustStorePasswd.toCharArray());
@@ -356,8 +387,16 @@ public static THttpClient getThriftHttpsClient(String httpsUrl, String trustStor
356387
SSLContext sslContext =
357388
SSLContexts.custom().setTrustManagerFactoryAlgorithm(trustStoreAlgorithm).
358389
loadTrustMaterial(sslTrustStore, null).build();
390+
String[] protocols = null;
391+
String[] ciphers = null;
392+
if (includeProtocols.length > 0) {
393+
protocols = includeProtocols;
394+
}
395+
if (cipherSuites.length > 0) {
396+
ciphers = cipherSuites;
397+
}
359398
SSLConnectionSocketFactory socketFactory =
360-
new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier(null));
399+
new SSLConnectionSocketFactory(sslContext, protocols, ciphers, new DefaultHostnameVerifier(null));
361400
final Registry<ConnectionSocketFactory> registry =
362401
RegistryBuilder.<ConnectionSocketFactory> create().register("https", socketFactory)
363402
.build();

standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/HiveMetaStore.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import java.lang.reflect.Method;
2222
import java.util.concurrent.ExecutorService;
2323
import java.util.concurrent.SynchronousQueue;
24+
import com.google.common.base.Splitter;
25+
import com.google.common.collect.Iterables;
2426
import org.apache.hadoop.conf.Configuration;
2527
import org.apache.hadoop.fs.FileSystem;
2628
import org.apache.hadoop.hive.common.ZKDeRegisterWatcher;
@@ -556,9 +558,14 @@ private static ThriftServer startBinaryMetastore(int port, HadoopThriftAuthBridg
556558
for (String sslVersion : MetastoreConf.getVar(conf, ConfVars.SSL_PROTOCOL_BLACKLIST).split(",")) {
557559
sslVersionBlacklist.add(sslVersion);
558560
}
561+
String[] includeProtocols = Iterables.toArray(Splitter.on(",").trimResults().omitEmptyStrings()
562+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS)), String.class);
563+
String[] includeCipherSuites = Iterables.toArray(Splitter.on(":").trimResults().omitEmptyStrings()
564+
.split(MetastoreConf.getVar(conf, ConfVars.SSL_INCLUDE_CIPHERSUITES)), String.class);
559565

560566
serverSocket = SecurityUtils.getServerSSLSocket(msHost, port, keyStorePath,
561-
keyStorePassword, keyStoreType, keyStoreAlgorithm, sslVersionBlacklist);
567+
keyStorePassword, keyStoreType, keyStoreAlgorithm, sslVersionBlacklist,
568+
includeProtocols, includeCipherSuites);
562569
}
563570

564571
ExecutorService executorService = new ThreadPoolExecutor(minWorkerThreads, maxWorkerThreads,

standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/ServletSecurity.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
import static javax.ws.rs.core.HttpHeaders.WWW_AUTHENTICATE;
2222

2323
import com.google.common.base.Preconditions;
24+
import com.google.common.base.Splitter;
25+
import com.google.common.collect.Iterables;
26+
27+
import java.security.KeyStore;
2428
import java.util.List;
2529
import java.util.function.Function;
2630
import org.apache.hadoop.conf.Configuration;
@@ -39,6 +43,7 @@
3943
import org.slf4j.Logger;
4044
import org.slf4j.LoggerFactory;
4145

46+
import javax.net.ssl.KeyManagerFactory;
4247
import javax.servlet.ServletException;
4348
import javax.servlet.http.HttpServlet;
4449
import javax.servlet.http.HttpServletRequest;
@@ -359,16 +364,27 @@ static SslContextFactory createSslContextFactory(Configuration conf) throws IOEx
359364
if (LOG.isInfoEnabled()) {
360365
LOG.info("HTTP Server SSL: adding excluded protocols: {}", Arrays.toString(excludedProtocols));
361366
}
367+
String[] includeProtocols = Iterables.toArray(Splitter.on(",").trimResults().omitEmptyStrings()
368+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS)), String.class);
369+
String[] includeCipherSuites = Iterables.toArray(Splitter.on(":").trimResults().omitEmptyStrings()
370+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES)), String.class);
362371
SslContextFactory factory = new SslContextFactory.Server();
372+
if (includeProtocols.length > 0) {
373+
factory.setIncludeProtocols(includeProtocols);
374+
}
363375
factory.addExcludeProtocols(excludedProtocols);
364376
if (LOG.isInfoEnabled()) {
365377
LOG.info("HTTP Server SSL: SslContextFactory.getExcludeProtocols = {}",
366378
Arrays.toString(factory.getExcludeProtocols()));
367379
}
368380
factory.setKeyStorePath(keyStorePath);
369381
factory.setKeyStorePassword(keyStorePassword);
370-
factory.setKeyStoreType(keyStoreType);
371-
factory.setKeyManagerFactoryAlgorithm(keyStoreAlgorithm);
382+
factory.setKeyStoreType(keyStoreType.isEmpty() ? KeyStore.getDefaultType() : keyStoreType);
383+
factory.setKeyManagerFactoryAlgorithm(keyStoreAlgorithm.isEmpty() ?
384+
KeyManagerFactory.getDefaultAlgorithm() : keyStoreAlgorithm);
385+
if (includeCipherSuites.length > 0) {
386+
factory.setIncludeCipherSuites(includeCipherSuites);
387+
}
372388
return factory;
373389
}
374390
}

standalone-metastore/metastore-tools/tools-common/src/main/java/org/apache/hadoop/hive/metastore/tools/HMSClient.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
package org.apache.hadoop.hive.metastore.tools;
2020

21+
import com.google.common.base.Splitter;
22+
import com.google.common.collect.Iterables;
2123
import org.apache.hadoop.conf.Configuration;
2224
import org.apache.hadoop.hive.metastore.Warehouse;
2325
import org.apache.hadoop.hive.metastore.api.AbortTxnsRequest;
@@ -456,10 +458,14 @@ private TTransport open(Configuration conf, @NotNull URI uri) throws
456458
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_TYPE).trim();
457459
String trustStoreAlgorithm =
458460
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTMANAGERFACTORY_ALGORITHM).trim();
459-
461+
String[] includeProtocols = Iterables.toArray(Splitter.on(",").trimResults().omitEmptyStrings()
462+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS)), String.class);
463+
String[] includeCipherSuites = Iterables.toArray(Splitter.on(":").trimResults().omitEmptyStrings()
464+
.split(MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES)), String.class);
460465
// Create an SSL socket and connect
461466
transport = SecurityUtils.getSSLSocket(host, port, clientSocketTimeout, connectionTimeout,
462-
trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm);
467+
trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm,
468+
includeProtocols, includeCipherSuites);
463469
LOG.info("Opened an SSL connection to metastore, current connections");
464470
}
465471

0 commit comments

Comments
 (0)