diff --git a/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java b/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java index 1dcb0b7028..83795fc65b 100644 --- a/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java +++ b/embeddedwebserver/src/main/java/org/apache/ranger/server/tomcat/EmbeddedServer.java @@ -51,6 +51,7 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.Date; +import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; @@ -164,7 +165,10 @@ public void start() { ssl.setScheme("https"); ssl.setAttribute("SSLEnabled", "true"); ssl.setAttribute("sslProtocol", EmbeddedServerUtil.getConfig("ranger.service.https.attrib.ssl.protocol", DEFAULT_SSL_PROTOCOL)); - ssl.setAttribute("keystoreType", EmbeddedServerUtil.getConfig("ranger.keystore.file.type", RANGER_KEYSTORE_FILE_TYPE_DEFAULT)); + + String keystoreType = EmbeddedServerUtil.getConfig("ranger.keystore.file.type", RANGER_KEYSTORE_FILE_TYPE_DEFAULT); + ssl.setAttribute("keystoreType", keystoreType); + ssl.setAttribute("truststoreType", EmbeddedServerUtil.getConfig("ranger.truststore.file.type", RANGER_TRUSTSTORE_FILE_TYPE_DEFAULT)); String clientAuth = EmbeddedServerUtil.getConfig("ranger.service.https.attrib.clientAuth", "false"); @@ -176,6 +180,8 @@ public void start() { ssl.setAttribute("clientAuth", clientAuth); String providerPath = EmbeddedServerUtil.getConfig("ranger.credential.provider.path"); + + // Resolve KeyStore & related properties String credentialAlias = EmbeddedServerUtil.getConfig("ranger.service.https.attrib.keystore.credential.alias", "keyStoreCredentialAlias"); String keystorePass = null; @@ -189,7 +195,6 @@ public void start() { String keystoreFile = getKeystoreFile(); String keyAlias = EmbeddedServerUtil.getConfig("ranger.service.https.attrib.keystore.keyalias", "rangeradmin"); - String keystoreType = EmbeddedServerUtil.getConfig("ranger.keystore.file.type", RANGER_KEYSTORE_FILE_TYPE_DEFAULT); String validationError = validateHttpsKeystore(keystoreFile, keystorePass, keyAlias, keystoreType); if (validationError != null) { @@ -200,6 +205,32 @@ public void start() { ssl.setAttribute("keystorePass", keystorePass); ssl.setAttribute("keystoreFile", keystoreFile); + // Resolve TrustStore & related properties + String truststoreCredsAlias = EmbeddedServerUtil.getConfig("ranger.service.https.attrib.truststore.credential.alias"); + String truststorePass = null; + + if (providerPath != null && truststoreCredsAlias != null) { + truststorePass = CredentialReader.getDecryptedString(providerPath.trim(), truststoreCredsAlias.trim(), EmbeddedServerUtil.getConfig("ranger.truststore.file.type", RANGER_TRUSTSTORE_FILE_TYPE_DEFAULT)); + } + + if (StringUtils.isBlank(truststorePass) || "none".equalsIgnoreCase(truststorePass.trim())) { + truststorePass = EmbeddedServerUtil.getConfig("ranger.service.https.attrib.truststore.pass"); + } + + String trustStoreFile = EmbeddedServerUtil.getConfig("ranger.service.https.attrib.truststore.file"); + + if (StringUtils.isNotBlank(trustStoreFile) && StringUtils.isNotBlank(truststorePass)) { + validationError = validateHttpsTruststore(trustStoreFile, truststorePass, keystoreType); + + if (validationError != null) { + LOG.warning("HTTPS configuration validation for trustStore failed: " + validationError + " TLS handshaking may fail if mTLS is enabled."); + } + ssl.setAttribute("truststorePass", truststorePass); + ssl.setAttribute("truststoreFile", trustStoreFile); + } else { + LOG.info("Truststore not configured for HTTPS connector. File=" + trustStoreFile + ", and is trustStorePassword empty " + StringUtils.isBlank(truststorePass)); + } + String enabledProtocols = EmbeddedServerUtil.getConfig("ranger.service.https.attrib.ssl.enabled.protocols", DEFAULT_ENABLED_PROTOCOLS); ssl.setAttribute("sslEnabledProtocols", enabledProtocols); @@ -548,6 +579,55 @@ static String validateHttpsKeystore(String keystoreFile, String keystorePass, St return null; } + static String validateHttpsTruststore(String trustStoreFile, String trustStorePass, String trustStoreType) { + if (StringUtils.isBlank(trustStoreFile)) { + return "TrustStore file is not configured. Check 'ranger.service.https.attrib.truststore.file'."; + } + + if (StringUtils.isBlank(trustStorePass)) { + return "TrustStore password could not be resolved. Check 'ranger.service.https.attrib.truststore.credential.alias' or 'ranger.service.https.attrib.truststore.pass'."; + } + + if (StringUtils.isBlank(trustStoreType)) { + return "Truststore type is not configured. Check 'ranger.truststore.file.type'."; + } + + try (InputStream in = getFileInputStream(trustStoreFile)) { + if (in == null) { + return "Truststore file [" + trustStoreFile + "] was not found or is not readable. Check 'ranger.service.https.attrib.truststore.file'."; + } + + KeyStore trustStore = KeyStore.getInstance(trustStoreType); + + trustStore.load(in, trustStorePass.toCharArray()); + + if (trustStore.size() == 0) { + return "Truststore [" + trustStoreFile + "] contains no entries."; + } + + int trustedCertCount = 0; + + for (Enumeration aliases = trustStore.aliases(); aliases.hasMoreElements(); ) { + String alias = aliases.nextElement(); + if (trustStore.entryInstanceOf(alias, KeyStore.TrustedCertificateEntry.class)) { + trustedCertCount++; + } + } + + if (trustedCertCount == 0) { + return "Truststore [" + trustStoreFile + "] contains no trusted certificate entries."; + } + } catch (KeyStoreException e) { + return "Truststore [" + trustStoreFile + "] could not be inspected using type [" + trustStoreType + "]. Check 'ranger.truststore.file.type'."; + } catch (NoSuchAlgorithmException | CertificateException e) { + return "Truststore [" + trustStoreFile + "] could not be loaded because its algorithm or certificate data is invalid."; + } catch (IOException e) { + return "Truststore [" + trustStoreFile + "] could not be loaded. The file may be unreadable, its format may be invalid, or its password may be incorrect."; + } + + return null; + } + private SSLContext getSSLContext() { KeyManager[] kmList = getKeyManagers(); TrustManager[] tmList = getTrustManagers(); diff --git a/kms/scripts/install.properties b/kms/scripts/install.properties index c8b8d5f0e7..d4dde09a6c 100755 --- a/kms/scripts/install.properties +++ b/kms/scripts/install.properties @@ -86,6 +86,8 @@ ranger_kms_http_enabled=true ranger_kms_https_keystore_file= ranger_kms_https_keystore_keyalias=rangerkms ranger_kms_https_keystore_password= +ranger_kms_https_truststore_file= +ranger_kms_https_truststore_password= #------------------------- RANGER KMS Install Dir ------------------ COMPONENT_INSTALL_DIR_NAME= diff --git a/kms/scripts/setup.sh b/kms/scripts/setup.sh index 5be51f2d76..aaf2c69def 100755 --- a/kms/scripts/setup.sh +++ b/kms/scripts/setup.sh @@ -164,6 +164,8 @@ ranger_kms_http_enabled=$(get_prop 'ranger_kms_http_enabled' $PROPFILE) ranger_kms_https_keystore_file=$(get_prop 'ranger_kms_https_keystore_file' $PROPFILE) ranger_kms_https_keystore_keyalias=$(get_prop 'ranger_kms_https_keystore_keyalias' $PROPFILE) ranger_kms_https_keystore_password=$(get_prop 'ranger_kms_https_keystore_password' $PROPFILE) +ranger_kms_https_truststore_file=$(get_prop 'ranger_kms_https_truststore_file' $PROPFILE) +ranger_kms_https_truststore_password=$(get_prop 'ranger_kms_https_truststore_password' $PROPFILE) javax_net_ssl_keyStore=$(get_prop 'javax_net_ssl_keyStore' $PROPFILE) javax_net_ssl_keyStorePassword=$(get_prop 'javax_net_ssl_keyStorePassword' $PROPFILE) @@ -1112,6 +1114,37 @@ update_properties() { updatePropertyToFilePy $propertyName $newPropertyValue $to_file_kms_site fi fi + if [ "${ranger_kms_https_truststore_file}" != "" ] && [ "${ranger_kms_https_truststore_password}" != "" ] + then + propertyName=ranger.service.https.attrib.truststore.file + newPropertyValue="${ranger_kms_https_truststore_file}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_kms_site + + policymgr_https_truststore_credential_alias=truststoreCredentialAlias + propertyName=ranger.service.https.attrib.truststore.credential.alias + newPropertyValue="${policymgr_https_truststore_credential_alias}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_kms_site + + if [ "${keystore}" != "" ] + then + propertyName=ranger.service.https.attrib.truststore.pass + newPropertyValue="_" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_kms_site + $PYTHON_COMMAND_INVOKER ranger_credential_helper.py -l "cred/lib/*" -f "$keystore" -k "$policymgr_https_truststore_credential_alias" -v "$ranger_kms_https_truststore_password" -c 1 + else + propertyName=ranger.service.https.attrib.truststore.pass + newPropertyValue="${ranger_kms_https_truststore_password}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_kms_site + fi + if test -f $keystore; then + chown -R ${unix_user}:${unix_group} ${keystore} + chmod 640 ${keystore} + else + propertyName=ranger.service.https.attrib.truststore.pass + newPropertyValue="${ranger_kms_https_truststore_password}" + updatePropertyToFilePy $propertyName $newPropertyValue $to_file_kms_site + fi + fi fi } diff --git a/security-admin/scripts/install.properties b/security-admin/scripts/install.properties index 6a6ababc0f..46c1c311b7 100644 --- a/security-admin/scripts/install.properties +++ b/security-admin/scripts/install.properties @@ -147,6 +147,8 @@ policymgr_http_enabled=true policymgr_https_keystore_file= policymgr_https_keystore_keyalias=rangeradmin policymgr_https_keystore_password= +policymgr_https_truststore_file= +policymgr_https_truststore_password= #Add Supported Components list below separated by semi-colon, default value is empty string to support all components #Example : policymgr_supportedcomponents=hive,hbase,hdfs diff --git a/security-admin/scripts/setup.sh b/security-admin/scripts/setup.sh index b0bc262148..ca7f6eb127 100755 --- a/security-admin/scripts/setup.sh +++ b/security-admin/scripts/setup.sh @@ -124,6 +124,8 @@ policymgr_http_enabled=$(get_prop 'policymgr_http_enabled' $PROPFILE) policymgr_https_keystore_file=$(get_prop 'policymgr_https_keystore_file' $PROPFILE) policymgr_https_keystore_keyalias=$(get_prop 'policymgr_https_keystore_keyalias' $PROPFILE) policymgr_https_keystore_password=$(get_prop 'policymgr_https_keystore_password' $PROPFILE) +policymgr_https_truststore_file=$(get_prop 'policymgr_https_truststore_file' $PROPFILE) +policymgr_https_truststore_password=$(get_prop 'policymgr_https_truststore_password' $PROPFILE) policymgr_supportedcomponents=$(get_prop_or_default 'policymgr_supportedcomponents' $PROPFILE '') unix_user=$(get_prop 'unix_user' $PROPFILE) unix_user_pwd=$(get_prop 'unix_user_pwd' $PROPFILE) @@ -1217,6 +1219,37 @@ update_properties() { updatePropertyToFilePy $propertyName "${newPropertyValue}" $to_file_ranger fi fi + if [ "${policymgr_https_truststore_file}" != "" ] && [ "${policymgr_https_truststore_password}" != "" ] + then + propertyName=ranger.service.https.attrib.truststore.file + newPropertyValue="${policymgr_https_truststore_file}" + updatePropertyToFilePy $propertyName "${newPropertyValue}" $to_file_ranger + + policymgr_https_truststore_credential_alias=trustStoreCredentialAlias + propertyName=ranger.service.https.attrib.truststore.credential.alias + newPropertyValue="${policymgr_https_truststore_credential_alias}" + updatePropertyToFilePy $propertyName "${newPropertyValue}" $to_file_ranger + + if [ "${keystore}" != "" ] + then + propertyName=ranger.service.https.attrib.truststore.pass + newPropertyValue="_" + updatePropertyToFilePy $propertyName "${newPropertyValue}" $to_file_ranger + $PYTHON_COMMAND_INVOKER ranger_credential_helper.py -l "cred/lib/*" -f "$keystore" -k "$policymgr_https_truststore_credential_alias" -v "$policymgr_https_truststore_password" -c 1 + + if test -f "${keystore}"; then + chown -R ${unix_user}:${unix_group} ${keystore} + else + propertyName=ranger.service.https.attrib.truststore.pass + newPropertyValue="${policymgr_https_truststore_password}" + updatePropertyToFilePy $propertyName "${newPropertyValue}" $to_file_ranger + fi + else + propertyName=ranger.service.https.attrib.truststore.pass + newPropertyValue="${policymgr_https_truststore_password}" + updatePropertyToFilePy $propertyName "${newPropertyValue}" $to_file_ranger + fi + fi fi if [ "${ranger_unixauth_keystore}" != "" ] && [ "${ranger_unixauth_keystore_password}" != "" ]