Skip to content

Commit bbd7c44

Browse files
HIVE-29606: Support SSL include protocols and cipher suites for Hive Metastore (apache#6476)
1 parent 6d11793 commit bbd7c44

6 files changed

Lines changed: 125 additions & 28 deletions

File tree

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ private Map<String, String> getAdditionalHeaders() {
535535
Map<String, String> headers = new HashMap<>();
536536
String keyValuePairs = MetastoreConf.getVar(conf,
537537
MetastoreConf.ConfVars.METASTORE_CLIENT_ADDITIONAL_HEADERS);
538+
if (keyValuePairs.isEmpty()) {
539+
return headers;
540+
}
538541
try {
539542
String[] headerKeyValues = keyValuePairs.split(",");
540543
for (String header : headerKeyValues) {
@@ -575,9 +578,11 @@ private THttpClient createHttpClient(URI store, boolean useSSL) throws MetaExcep
575578
String trustStorePassword = MetastoreConf.getPassword(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_PASSWORD);
576579
String trustStoreType = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_TYPE).trim();
577580
String trustStoreAlgorithm = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTMANAGERFACTORY_ALGORITHM).trim();
581+
String includeProtocols = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS);
582+
String includeCipherSuites = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES);
578583
tHttpClient =
579584
SecurityUtils.getThriftHttpsClient(httpUrl, trustStorePath, trustStorePassword, trustStoreAlgorithm,
580-
trustStoreType, httpClientBuilder);
585+
trustStoreType, includeProtocols, includeCipherSuites, httpClientBuilder);
581586
} else {
582587
tHttpClient = new THttpClient(httpUrl, httpClientBuilder.build());
583588
}
@@ -659,8 +664,11 @@ private TTransport createBinaryClient(URI store, boolean useSSL) throws TTranspo
659664
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_TYPE).trim();
660665
String trustStoreAlgorithm =
661666
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTMANAGERFACTORY_ALGORITHM).trim();
667+
String includeProtocols = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS);
668+
String includeCipherSuites = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES);
662669
binaryTransport = SecurityUtils.getSSLSocket(store.getHost(), store.getPort(), clientSocketTimeout,
663-
connectionTimeout, trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm);
670+
connectionTimeout, trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm,
671+
includeProtocols, includeCipherSuites);
664672
} else {
665673
binaryTransport = new TSocket(new TConfiguration(), store.getHost(), store.getPort(),
666674
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
@@ -1491,6 +1491,10 @@ public enum ConfVars {
14911491
"Metastore SSL certificate truststore type."),
14921492
SSL_TRUSTMANAGERFACTORY_ALGORITHM("metastore.trustmanagerfactory.algorithm", "hive.metastore.trustmanagerfactory.algorithm", "",
14931493
"Metastore SSL certificate truststore algorithm."),
1494+
SSL_INCLUDE_PROTOCOLS("metastore.include.protocols", "hive.metastore.include.protocols", "",
1495+
"Comma-separated list of SSL protocols to include for the Metastore."),
1496+
SSL_INCLUDE_CIPHERSUITES("metastore.include.ciphersuites", "hive.metastore.include.ciphersuites", "",
1497+
"Colon-separated list of cipher suite names to include for the Metastore."),
14941498
STATS_AUTO_GATHER("metastore.stats.autogather", "hive.stats.autogather", true,
14951499
"A flag to gather statistics (only basic) automatically during the INSERT OVERWRITE command."),
14961500
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: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
import java.security.NoSuchAlgorithmException;
2626
import java.security.cert.CertificateException;
2727
import javax.net.ssl.SSLContext;
28+
29+
import com.google.common.base.Splitter;
30+
import com.google.common.collect.Iterables;
2831
import org.apache.hadoop.hive.metastore.api.MetaException;
2932
import org.apache.hadoop.hive.metastore.security.DelegationTokenIdentifier;
3033
import org.apache.hadoop.hive.metastore.security.DelegationTokenSelector;
@@ -62,14 +65,15 @@
6265
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
6366
import java.io.IOException;
6467
import java.net.InetSocketAddress;
65-
import java.net.UnknownHostException;
6668
import java.security.KeyStore;
6769

6870
import java.util.ArrayList;
6971
import java.util.Arrays;
7072
import java.util.HashMap;
7173
import java.util.List;
7274
import java.util.Map;
75+
import java.util.Set;
76+
import java.util.stream.Collectors;
7377

7478
public class SecurityUtils {
7579
private static final Logger LOG = LoggerFactory.getLogger(SecurityUtils.class);
@@ -278,17 +282,61 @@ public static TServerSocket getServerSocket(String hiveHost, int portNum) throws
278282
return new TServerSocket(serverAddress);
279283
}
280284

285+
public static String[] parseIncludeProtocols(String protocols) {
286+
return Iterables.toArray(Splitter.on(",").trimResults().omitEmptyStrings()
287+
.split(protocols), String.class);
288+
}
289+
290+
public static String[] parseIncludeCipherSuites(String cipherSuites) {
291+
return Iterables.toArray(Splitter.on(":").trimResults().omitEmptyStrings()
292+
.split(cipherSuites), String.class);
293+
}
294+
295+
private static String[] filterEnabledProtocols(String[] enabledProtocols,
296+
String includeProtocols) throws TTransportException {
297+
String[] filteredProtocols = enabledProtocols;
298+
String[] parsedIncludeProtocols = parseIncludeProtocols(includeProtocols);
299+
if (parsedIncludeProtocols.length > 0) {
300+
Set<String> protocolsLowerCase = Arrays.stream(parsedIncludeProtocols).map(String::toLowerCase)
301+
.collect(Collectors.toSet());
302+
filteredProtocols = Arrays.stream(enabledProtocols).filter(protocol ->
303+
protocolsLowerCase.contains(protocol.toLowerCase())).toArray(String[]::new);
304+
}
305+
if (filteredProtocols.length == 0) {
306+
throw new TTransportException("No TLS protocols to enable. "
307+
+ "Protocols configured to include: " + Arrays.toString(parsedIncludeProtocols)
308+
+ ", Protocols allowed to enable: " + Arrays.toString(enabledProtocols));
309+
}
310+
return filteredProtocols;
311+
}
312+
313+
private static TSSLTransportFactory.TSSLTransportParameters getSSLTransportParameters(boolean isKeyStore,
314+
String storePath, String storePassword, String storeAlgorithm, String storeType, String includeCipherSuites) {
315+
TSSLTransportFactory.TSSLTransportParameters params;
316+
String[] parsedCipherSuites = parseIncludeCipherSuites(includeCipherSuites);
317+
if (parsedCipherSuites.length > 0) {
318+
params = new TSSLTransportFactory.TSSLTransportParameters("TLS", parsedCipherSuites);
319+
} else {
320+
params = new TSSLTransportFactory.TSSLTransportParameters();
321+
}
322+
if (isKeyStore) {
323+
params.setKeyStore(storePath, storePassword, storeAlgorithm, storeType);
324+
} else {
325+
params.setTrustStore(storePath, storePassword, storeAlgorithm, storeType);
326+
params.requireClientAuth(true);
327+
}
328+
return params;
329+
}
330+
281331
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);
332+
String keyStorePassWord, String keyStoreType, String keyStoreAlgorithm, List<String> sslVersionBlacklist,
333+
String includeProtocols, String includeCipherSuites) throws TTransportException {
334+
TSSLTransportFactory.TSSLTransportParameters params = getSSLTransportParameters(true,
335+
keyStorePath, keyStorePassWord,
336+
keyStoreAlgorithm.isEmpty() ? KeyManagerFactory.getDefaultAlgorithm() : keyStoreAlgorithm,
337+
keyStoreType.isEmpty() ? KeyStore.getDefaultType() : keyStoreType, includeCipherSuites);
290338
InetSocketAddress serverAddress;
291-
if (hiveHost == null || hiveHost.isEmpty()) {
339+
if (StringUtils.isEmpty(hiveHost)) {
292340
// Wildcard bind
293341
serverAddress = new InetSocketAddress(portNum);
294342
} else {
@@ -310,7 +358,12 @@ public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, Str
310358
enabledProtocols.add(protocol);
311359
}
312360
}
313-
sslServerSocket.setEnabledProtocols(enabledProtocols.toArray(new String[0]));
361+
if (enabledProtocols.isEmpty()) {
362+
throw new TTransportException("No TLS protocols to enable after discarding configured blacklist protocols. "
363+
+ "Protocols allowed to enable: " + Arrays.toString(sslServerSocket.getEnabledProtocols()));
364+
}
365+
sslServerSocket.setEnabledProtocols(filterEnabledProtocols(enabledProtocols.toArray(String[]::new),
366+
includeProtocols));
314367
LOG.info("SSL Server Socket Enabled Protocols: "
315368
+ Arrays.toString(sslServerSocket.getEnabledProtocols()));
316369
}
@@ -319,18 +372,16 @@ public static TServerSocket getServerSSLSocket(String hiveHost, int portNum, Str
319372

320373
public static TTransport getSSLSocket(String host, int port, int socketTimeout, int connectionTimeout,
321374
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);
375+
String trustStoreAlgorithm, String includeProtocols, String includeCipherSuites) throws TTransportException {
376+
TSSLTransportFactory.TSSLTransportParameters params = getSSLTransportParameters(false,
377+
trustStorePath, trustStorePassWord,
378+
trustStoreAlgorithm.isEmpty() ? TrustManagerFactory.getDefaultAlgorithm() : trustStoreAlgorithm,
379+
trustStoreType.isEmpty() ? KeyStore.getDefaultType() : trustStoreType, includeCipherSuites);
331380
// The underlying SSLSocket object is bound to host:port with the given SO_TIMEOUT and
332381
// connection timeout and SSLContext created with the given params
333382
TSocket tSSLSocket = TSSLTransportFactory.getClientSocket(host, port, socketTimeout, params);
383+
SSLSocket sslSocket = (SSLSocket) (tSSLSocket.getSocket());
384+
sslSocket.setEnabledProtocols(filterEnabledProtocols(sslSocket.getEnabledProtocols(), includeProtocols));
334385
tSSLSocket.setConnectTimeout(connectionTimeout);
335386
return getSSLSocketWithHttps(tSSLSocket);
336387
}
@@ -341,13 +392,17 @@ public static TTransport getSSLSocket(String host, int port, int socketTimeout,
341392
*/
342393
public static THttpClient getThriftHttpsClient(String httpsUrl, String trustStorePath,
343394
String trustStorePasswd, String trustStoreAlgorithm, String trustStoreType,
395+
String includeProtocols, String includeCipherSuites,
344396
HttpClientBuilder underlyingHttpClientBuilder) throws TTransportException, IOException,
345397
KeyStoreException, NoSuchAlgorithmException, CertificateException,
346398
KeyManagementException {
347399
Preconditions.checkNotNull(underlyingHttpClientBuilder, "httpClientBuilder should not be null");
348400
if (trustStoreType == null || trustStoreType.isEmpty()) {
349401
trustStoreType = KeyStore.getDefaultType();
350402
}
403+
if (trustStoreAlgorithm.isEmpty()) {
404+
trustStoreAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
405+
}
351406
KeyStore sslTrustStore = KeyStore.getInstance(trustStoreType);
352407
try (FileInputStream fis = new FileInputStream(trustStorePath)) {
353408
sslTrustStore.load(fis, trustStorePasswd.toCharArray());
@@ -356,8 +411,18 @@ public static THttpClient getThriftHttpsClient(String httpsUrl, String trustStor
356411
SSLContext sslContext =
357412
SSLContexts.custom().setTrustManagerFactoryAlgorithm(trustStoreAlgorithm).
358413
loadTrustMaterial(sslTrustStore, null).build();
414+
String[] protocols = null;
415+
String[] parsedProtocols = parseIncludeProtocols(includeProtocols);
416+
if (parsedProtocols.length > 0) {
417+
protocols = parsedProtocols;
418+
}
419+
String[] ciphers = null;
420+
String[] parsedCipherSuites = parseIncludeCipherSuites(includeCipherSuites);
421+
if (parsedCipherSuites.length > 0) {
422+
ciphers = parsedCipherSuites;
423+
}
359424
SSLConnectionSocketFactory socketFactory =
360-
new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier(null));
425+
new SSLConnectionSocketFactory(sslContext, protocols, ciphers, new DefaultHostnameVerifier(null));
361426
final Registry<ConnectionSocketFactory> registry =
362427
RegistryBuilder.<ConnectionSocketFactory> create().register("https", socketFactory)
363428
.build();

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,9 +556,12 @@ private static ThriftServer startBinaryMetastore(int port, HadoopThriftAuthBridg
556556
for (String sslVersion : MetastoreConf.getVar(conf, ConfVars.SSL_PROTOCOL_BLACKLIST).split(",")) {
557557
sslVersionBlacklist.add(sslVersion);
558558
}
559+
String includeProtocols = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS);
560+
String includeCipherSuites = MetastoreConf.getVar(conf, ConfVars.SSL_INCLUDE_CIPHERSUITES);
559561

560562
serverSocket = SecurityUtils.getServerSSLSocket(msHost, port, keyStorePath,
561-
keyStorePassword, keyStoreType, keyStoreAlgorithm, sslVersionBlacklist);
563+
keyStorePassword, keyStoreType, keyStoreAlgorithm, sslVersionBlacklist,
564+
includeProtocols, includeCipherSuites);
562565
}
563566

564567
ExecutorService executorService = new ThreadPoolExecutor(minWorkerThreads, maxWorkerThreads,

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

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

2323
import com.google.common.base.Preconditions;
24+
25+
import java.security.KeyStore;
2426
import java.util.List;
2527
import java.util.function.Function;
2628
import org.apache.hadoop.conf.Configuration;
@@ -30,6 +32,7 @@
3032
import org.apache.hadoop.hive.metastore.auth.oauth2.OAuth2AuthenticatorFactory;
3133
import org.apache.hadoop.hive.metastore.conf.MetastoreConf;
3234
import org.apache.hadoop.hive.metastore.utils.MetaStoreUtils;
35+
import org.apache.hadoop.hive.metastore.utils.SecurityUtils;
3336
import org.apache.hadoop.security.SecurityUtil;
3437
import org.apache.hadoop.security.UserGroupInformation;
3538
import org.eclipse.jetty.util.ssl.SslContextFactory;
@@ -39,6 +42,7 @@
3942
import org.slf4j.Logger;
4043
import org.slf4j.LoggerFactory;
4144

45+
import javax.net.ssl.KeyManagerFactory;
4246
import javax.servlet.ServletException;
4347
import javax.servlet.http.HttpServlet;
4448
import javax.servlet.http.HttpServletRequest;
@@ -359,16 +363,27 @@ static SslContextFactory createSslContextFactory(Configuration conf) throws IOEx
359363
if (LOG.isInfoEnabled()) {
360364
LOG.info("HTTP Server SSL: adding excluded protocols: {}", Arrays.toString(excludedProtocols));
361365
}
366+
String[] includeProtocols = SecurityUtils.parseIncludeProtocols(
367+
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS));
368+
String[] includeCipherSuites = SecurityUtils.parseIncludeCipherSuites(
369+
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES));
362370
SslContextFactory factory = new SslContextFactory.Server();
371+
if (includeProtocols.length > 0) {
372+
factory.setIncludeProtocols(includeProtocols);
373+
}
363374
factory.addExcludeProtocols(excludedProtocols);
364375
if (LOG.isInfoEnabled()) {
365376
LOG.info("HTTP Server SSL: SslContextFactory.getExcludeProtocols = {}",
366377
Arrays.toString(factory.getExcludeProtocols()));
367378
}
368379
factory.setKeyStorePath(keyStorePath);
369380
factory.setKeyStorePassword(keyStorePassword);
370-
factory.setKeyStoreType(keyStoreType);
371-
factory.setKeyManagerFactoryAlgorithm(keyStoreAlgorithm);
381+
factory.setKeyStoreType(keyStoreType.isEmpty() ? KeyStore.getDefaultType() : keyStoreType);
382+
factory.setKeyManagerFactoryAlgorithm(keyStoreAlgorithm.isEmpty() ?
383+
KeyManagerFactory.getDefaultAlgorithm() : keyStoreAlgorithm);
384+
if (includeCipherSuites.length > 0) {
385+
factory.setIncludeCipherSuites(includeCipherSuites);
386+
}
372387
return factory;
373388
}
374389
}

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,12 @@ private TTransport open(Configuration conf, @NotNull URI uri) throws
456456
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTSTORE_TYPE).trim();
457457
String trustStoreAlgorithm =
458458
MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_TRUSTMANAGERFACTORY_ALGORITHM).trim();
459-
459+
String includeProtocols = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_PROTOCOLS);
460+
String includeCipherSuites = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.SSL_INCLUDE_CIPHERSUITES);
460461
// Create an SSL socket and connect
461462
transport = SecurityUtils.getSSLSocket(host, port, clientSocketTimeout, connectionTimeout,
462-
trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm);
463+
trustStorePath, trustStorePassword, trustStoreType, trustStoreAlgorithm,
464+
includeProtocols, includeCipherSuites);
463465
LOG.info("Opened an SSL connection to metastore, current connections");
464466
}
465467

0 commit comments

Comments
 (0)