mirror of https://github.com/apache/nifi.git
NIFI-3580 Add configurable TLS Cipher Suite properties
This closes #5018 Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
parent
aedacdf86f
commit
17fa0cf3c1
|
@ -207,6 +207,8 @@ public abstract class NiFiProperties {
|
|||
public static final String WEB_HTTPS_PORT = "nifi.web.https.port";
|
||||
public static final String WEB_HTTPS_PORT_FORWARDING = "nifi.web.https.port.forwarding";
|
||||
public static final String WEB_HTTPS_HOST = "nifi.web.https.host";
|
||||
public static final String WEB_HTTPS_CIPHERSUITES_INCLUDE = "nifi.web.https.ciphersuites.include";
|
||||
public static final String WEB_HTTPS_CIPHERSUITES_EXCLUDE = "nifi.web.https.ciphersuites.exclude";
|
||||
public static final String WEB_HTTPS_NETWORK_INTERFACE_PREFIX = "nifi.web.https.network.interface.";
|
||||
public static final String WEB_WORKING_DIR = "nifi.web.jetty.working.directory";
|
||||
public static final String WEB_THREADS = "nifi.web.jetty.threads";
|
||||
|
|
|
@ -209,6 +209,28 @@ In order to facilitate the secure setup of NiFi, you can use the `tls-toolkit` c
|
|||
* <<toolkit-guide.adoc#tls_intermediate_ca,Using An Existing Intermediate Certificate Authority>>
|
||||
* <<toolkit-guide.adoc#additional_certificate_commands,Additional Certificate Commands>>
|
||||
|
||||
[[tls_cipher_suites]]
|
||||
=== TLS Cipher Suites
|
||||
|
||||
The Java Runtime Environment provides the ability to specify custom TLS cipher suites to be used by servers when accepting client connections. See
|
||||
link:https://java.com/en/configure_crypto.html[here^] for more information. To use this feature for the NiFi web service, the following NiFi properties
|
||||
may be set:
|
||||
|
||||
[options="header,footer"]
|
||||
|==================================================================================================================================================
|
||||
| Property Name | Description
|
||||
|`nifi.web.https.ciphersuites.include` | Set of ciphers that are available to be used by incoming client connections. Replaces system defaults if set.
|
||||
|`nifi.web.https.ciphersuites.exclude` | Set of ciphers that must not be used by incoming client connections. Filters available ciphers if set.
|
||||
|==================================================================================================================================================
|
||||
|
||||
Each property should take the form of a comma-separated list of common cipher names as specified
|
||||
link:https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#ciphersuites[here^]. Regular expressions
|
||||
(for example `^.*GCM_SHA256$`) may also be specified.
|
||||
|
||||
The semantics match the use of the following Jetty APIs:
|
||||
|
||||
* link:https://www.eclipse.org/jetty/javadoc/jetty-9/org/eclipse/jetty/util/ssl/SslContextFactory.html#setIncludeCipherSuites(java.lang.String\...)[SslContextFactory.setIncludeCipherSuites()]
|
||||
* link:https://www.eclipse.org/jetty/javadoc/jetty-9/org/eclipse/jetty/util/ssl/SslContextFactory.html#setExcludeCipherSuites(java.lang.String\...)[SslContextFactory.setExcludeCipherSuites()]
|
||||
|
||||
[[user_authentication]]
|
||||
== User Authentication
|
||||
|
@ -3494,6 +3516,14 @@ Providing three total network interfaces, including `nifi.web.http.network.inte
|
|||
|`nifi.web.https.host`|The HTTPS host. It is blank by default.
|
||||
|`nifi.web.https.port`|The HTTPS port. It is blank by default. When configuring NiFi to run securely, this port should be configured.
|
||||
|`nifi.web.https.port.forwarding`|Same as `nifi.web.http.port.forwarding`, but with HTTPS for secure communication. It is blank by default.
|
||||
|`nifi.web.https.ciphersuites.include`|Cipher suites used to initialize the SSLContext of the Jetty HTTPS port. If unspecified, the runtime SSLContext defaults are used.
|
||||
|`nifi.web.https.ciphersuites.exclude`|Cipher suites that may not be used by an SSL client to establish a connection to Jetty. If unspecified, the runtime SSLContext defaults are used.
|
||||
|
||||
|
||||
In Chrome, the SSL cipher negotiated with Jetty may be examined in the 'Developer Tools' plugin, in the 'Security' tab.
|
||||
In Firefox, the SSL cipher negotiated with Jetty may be examined in the 'Secure Connection' widget found to the left of the URL in the browser address bar.
|
||||
|
||||
|
||||
|`nifi.web.https.network.interface`*|The name of the network interface to which NiFi should bind for HTTPS requests. It is blank by default. +
|
||||
+
|
||||
*NOTE*: Multiple network interfaces can be specified by using the `nifi.web.https.network.interface.` prefix with unique suffixes and separate network interface names as values. +
|
||||
|
|
|
@ -167,6 +167,10 @@ nifi.web.request.timeout=${nifi.web.request.timeout}
|
|||
nifi.web.request.ip.whitelist=${nifi.web.request.ip.whitelist}
|
||||
nifi.web.should.send.server.version=${nifi.web.should.send.server.version}
|
||||
|
||||
# Include or Exclude TLS Cipher Suites for HTTPS
|
||||
nifi.web.https.ciphersuites.include=
|
||||
nifi.web.https.ciphersuites.exclude=
|
||||
|
||||
# security properties #
|
||||
nifi.sensitive.props.key=
|
||||
nifi.sensitive.props.key.protected=${nifi.sensitive.props.key.protected}
|
||||
|
|
|
@ -138,6 +138,10 @@ public class JettyServer implements NiFiServer, ExtensionUiLoader {
|
|||
return nameToTest.endsWith(".war") && pathname.isFile();
|
||||
};
|
||||
|
||||
// property parsing util
|
||||
private static final String REGEX_SPLIT_PROPERTY = ",\\s*";
|
||||
protected static final String JOIN_ARRAY = ", ";
|
||||
|
||||
private Server server;
|
||||
private NiFiProperties props;
|
||||
|
||||
|
@ -1012,6 +1016,22 @@ public class JettyServer implements NiFiServer, ExtensionUiLoader {
|
|||
contextFactory.setIncludeProtocols(TlsConfiguration.getCurrentSupportedTlsProtocolVersions());
|
||||
contextFactory.setExcludeProtocols("TLS", "TLSv1", "TLSv1.1", "SSL", "SSLv2", "SSLv2Hello", "SSLv3");
|
||||
|
||||
// on configuration, replace default application cipher suites with those configured
|
||||
final String includeCipherSuitesProps = props.getProperty(NiFiProperties.WEB_HTTPS_CIPHERSUITES_INCLUDE);
|
||||
if (StringUtils.isNotEmpty(includeCipherSuitesProps)) {
|
||||
final String[] includeCipherSuites = includeCipherSuitesProps.split(REGEX_SPLIT_PROPERTY);
|
||||
logger.info("Setting include cipher suites from configuration; parsed property = [{}].",
|
||||
StringUtils.join(includeCipherSuites, JOIN_ARRAY));
|
||||
contextFactory.setIncludeCipherSuites(includeCipherSuites);
|
||||
}
|
||||
final String excludeCipherSuitesProps = props.getProperty(NiFiProperties.WEB_HTTPS_CIPHERSUITES_EXCLUDE);
|
||||
if (StringUtils.isNotEmpty(excludeCipherSuitesProps)) {
|
||||
final String[] excludeCipherSuites = excludeCipherSuitesProps.split(REGEX_SPLIT_PROPERTY);
|
||||
logger.info("Setting exclude cipher suites from configuration; parsed property = [{}].",
|
||||
StringUtils.join(excludeCipherSuites, JOIN_ARRAY));
|
||||
contextFactory.setExcludeCipherSuites(excludeCipherSuites);
|
||||
}
|
||||
|
||||
// require client auth when not supporting login, Kerberos service, or anonymous access
|
||||
if (props.isClientAuthRequiredForRestApi()) {
|
||||
contextFactory.setNeedClientAuth(true);
|
||||
|
|
|
@ -19,13 +19,17 @@ package org.apache.nifi.web.server;
|
|||
|
||||
import static org.apache.nifi.security.util.KeyStoreUtils.SUN_PROVIDER_NAME;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.security.util.KeystoreType;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
@ -142,4 +146,36 @@ public class JettyServerTest {
|
|||
verify(mockSCF).setTrustStoreType(trustStoreType);
|
||||
verify(mockSCF).setTrustStoreProvider(BouncyCastleProvider.PROVIDER_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify correct processing of cipher suites with multiple elements. Verify call to override runtime ciphers.
|
||||
*/
|
||||
@Test
|
||||
public void testConfigureSslIncludeExcludeCiphers() {
|
||||
final String[] includeCipherSuites = {"TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256"};
|
||||
final String includeCipherSuitesProp = StringUtils.join(includeCipherSuites, JettyServer.JOIN_ARRAY);
|
||||
final String[] excludeCipherSuites = {".*DHE.*", ".*ECDH.*"};
|
||||
final String excludeCipherSuitesProp = StringUtils.join(excludeCipherSuites, JettyServer.JOIN_ARRAY);
|
||||
final Map<String, String> addProps = new HashMap<>();
|
||||
addProps.put(NiFiProperties.WEB_HTTPS_CIPHERSUITES_INCLUDE, includeCipherSuitesProp);
|
||||
addProps.put(NiFiProperties.WEB_HTTPS_CIPHERSUITES_EXCLUDE, excludeCipherSuitesProp);
|
||||
final NiFiProperties nifiProperties = NiFiProperties.createBasicNiFiProperties(null, addProps);
|
||||
|
||||
final SslContextFactory.Server mockSCF = mock(SslContextFactory.Server.class);
|
||||
JettyServer.configureSslContextFactory(mockSCF, nifiProperties);
|
||||
verify(mockSCF, times(1)).setIncludeCipherSuites(includeCipherSuites);
|
||||
verify(mockSCF, times(1)).setExcludeCipherSuites(excludeCipherSuites);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify skip cipher configuration when NiFiProperties are not specified.
|
||||
*/
|
||||
@Test
|
||||
public void testDoNotConfigureSslIncludeExcludeCiphers() {
|
||||
final NiFiProperties nifiProperties = NiFiProperties.createBasicNiFiProperties(null);
|
||||
final SslContextFactory.Server mockSCF = mock(SslContextFactory.Server.class);
|
||||
JettyServer.configureSslContextFactory(mockSCF, nifiProperties);
|
||||
verify(mockSCF, times(0)).setIncludeCipherSuites(any());
|
||||
verify(mockSCF, times(0)).setExcludeCipherSuites(any());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue