mirror of https://github.com/apache/nifi.git
NIFI-3355 Allows NiFi to bind to specific network interfaces, with separate interface lists for HTTP and HTTPS.
This closes #1508. Signed-off-by: Bryan Rosander <brosander@apache.org>
This commit is contained in:
parent
4a68dacc43
commit
8b90343715
|
@ -152,9 +152,11 @@ public abstract class NiFiProperties {
|
|||
public static final String WEB_HTTP_PORT = "nifi.web.http.port";
|
||||
public static final String WEB_HTTP_PORT_FORWARDING = "nifi.web.http.port.forwarding";
|
||||
public static final String WEB_HTTP_HOST = "nifi.web.http.host";
|
||||
public static final String WEB_HTTP_NETWORK_INTERFACE_PREFIX = "nifi.web.http.network.interface.";
|
||||
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_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";
|
||||
|
||||
|
@ -1016,6 +1018,50 @@ public abstract class NiFiProperties {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the network interface list to use for HTTP. This method returns a mapping of
|
||||
* network interface property names to network interface names.
|
||||
*
|
||||
* @return the property name and network interface name of all HTTP network interfaces
|
||||
*/
|
||||
public Map<String, String> getHttpNetworkInterfaces() {
|
||||
final Map<String, String> networkInterfaces = new HashMap<>();
|
||||
|
||||
// go through each property
|
||||
for (String propertyName : getPropertyKeys()) {
|
||||
// determine if the property is a network interface name
|
||||
if (StringUtils.startsWith(propertyName, WEB_HTTP_NETWORK_INTERFACE_PREFIX)) {
|
||||
// get the network interface property key
|
||||
final String key = StringUtils.substringAfter(propertyName,
|
||||
WEB_HTTP_NETWORK_INTERFACE_PREFIX);
|
||||
networkInterfaces.put(key, getProperty(propertyName));
|
||||
}
|
||||
}
|
||||
return networkInterfaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the network interface list to use for HTTPS. This method returns a mapping of
|
||||
* network interface property names to network interface names.
|
||||
*
|
||||
* @return the property name and network interface name of all HTTPS network interfaces
|
||||
*/
|
||||
public Map<String, String> getHttpsNetworkInterfaces() {
|
||||
final Map<String, String> networkInterfaces = new HashMap<>();
|
||||
|
||||
// go through each property
|
||||
for (String propertyName : getPropertyKeys()) {
|
||||
// determine if the property is a network interface name
|
||||
if (StringUtils.startsWith(propertyName, WEB_HTTPS_NETWORK_INTERFACE_PREFIX)) {
|
||||
// get the network interface property key
|
||||
final String key = StringUtils.substringAfter(propertyName,
|
||||
WEB_HTTPS_NETWORK_INTERFACE_PREFIX);
|
||||
networkInterfaces.put(key, getProperty(propertyName));
|
||||
}
|
||||
}
|
||||
return networkInterfaces;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return getPropertyKeys().size();
|
||||
}
|
||||
|
|
|
@ -152,8 +152,9 @@ NiFi provides several different configuration options for security purposes. The
|
|||
|
||||
Once the above properties have been configured, we can enable the User Interface to be accessed over HTTPS instead of HTTP. This is accomplished
|
||||
by setting the `nifi.web.https.host` and `nifi.web.https.port` properties. The `nifi.web.https.host` property indicates which hostname the server
|
||||
should run on. This allows admins to configure the application to run only on specific network interfaces. If it is desired that the HTTPS interface
|
||||
be accessible from all network interfaces, a value of `0.0.0.0` should be used.
|
||||
should run on. If it is desired that the HTTPS interface be accessible from all network interfaces, a value of `0.0.0.0` should be used. To allow
|
||||
admins to configure the application to run only on specific network interfaces, `nifi.web.http.network.interface*` or `nifi.web.http.network.interface*`
|
||||
properties can be specified.
|
||||
|
||||
NOTE: It is important when enabling HTTPS that the `nifi.web.http.port` property be unset.
|
||||
|
||||
|
@ -2162,9 +2163,29 @@ These properties pertain to the web-based User Interface.
|
|||
|nifi.web.http.host|The HTTP host. It is blank by default.
|
||||
|nifi.web.http.port|The HTTP port. The default value is 8080.
|
||||
|nifi.web.http.port.forwarding|The port which forwards incoming HTTP requests to nifi.web.http.host. This property is designed to be used with 'port forwarding', when NiFi has to be started by a non-root user for better security, yet it needs to be accessed via low port to go through a firewall. For example, to expose NiFi via HTTP protocol on port 80, but actually listening on port 8080, you need to configure OS level port forwarding such as `iptables` (Linux/Unix) or `pfctl` (OS X) that redirects requests from 80 to 8080. Then set `nifi.web.http.port` as 8080, and `nifi.web.http.port.forwarding` as 80. It is blank by default.
|
||||
|nifi.web.http.network.interface*|The name of the network interface to which NiFi should bind for HTTP requests. It is blank by default. +
|
||||
+
|
||||
*NOTE*: Multiple network interfaces can be specified by using the *_nifi.web.http.network.interface._* prefix with unique suffixes and separate network interface names as values. +
|
||||
+
|
||||
For example, to provide two additional network interfaces, a user could also specify additional properties with keys of: +
|
||||
+
|
||||
nifi.web.http.network.interface.eth0=eth0 +
|
||||
nifi.web.http.network.interface.eth1=eth1 +
|
||||
+
|
||||
Providing three total network interfaces, including _nifi.web.http.network.interface.default_.
|
||||
|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.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. +
|
||||
+
|
||||
For example, to provide two additional network interfaces, a user could also specify additional properties with keys of: +
|
||||
+
|
||||
nifi.web.https.network.interface.eth0=eth0 +
|
||||
nifi.web.https.network.interface.eth1=eth1 +
|
||||
+
|
||||
Providing three total network interfaces, including _nifi.web.https.network.interface.default_.
|
||||
|nif.web.jetty.working.directory|The location of the Jetty working directory. The default value is ./work/jetty.
|
||||
|nifi.web.jetty.threads|The number of Jetty threads. The default value is 200.
|
||||
|====
|
||||
|
|
|
@ -119,8 +119,10 @@
|
|||
<nifi.web.war.directory>./lib</nifi.web.war.directory>
|
||||
<nifi.web.http.host />
|
||||
<nifi.web.http.port>8080</nifi.web.http.port>
|
||||
<nifi.web.http.network.interface.default />
|
||||
<nifi.web.https.host />
|
||||
<nifi.web.https.port />
|
||||
<nifi.web.https.network.interface.default />
|
||||
<nifi.jetty.work.dir>./work/jetty</nifi.jetty.work.dir>
|
||||
<nifi.web.jetty.threads>200</nifi.web.jetty.threads>
|
||||
|
||||
|
|
|
@ -124,8 +124,10 @@ nifi.remote.input.http.transaction.ttl=30 sec
|
|||
nifi.web.war.directory=${nifi.web.war.directory}
|
||||
nifi.web.http.host=${nifi.web.http.host}
|
||||
nifi.web.http.port=${nifi.web.http.port}
|
||||
nifi.web.http.network.interface.default=${nifi.web.http.network.interface.default}
|
||||
nifi.web.https.host=${nifi.web.https.host}
|
||||
nifi.web.https.port=${nifi.web.https.port}
|
||||
nifi.web.https.network.interface.default=${nifi.web.https.network.interface.default}
|
||||
nifi.web.jetty.working.directory=${nifi.jetty.work.dir}
|
||||
nifi.web.jetty.threads=${nifi.web.jetty.threads}
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
*/
|
||||
package org.apache.nifi.web.server;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -85,9 +87,11 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Encapsulates the Jetty instance.
|
||||
|
@ -569,17 +573,43 @@ public class JettyServer implements NiFiServer {
|
|||
|
||||
logger.info("Configuring Jetty for HTTP on port: " + port);
|
||||
|
||||
// create the connector
|
||||
final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
|
||||
final List<Connector> serverConnectors = Lists.newArrayList();
|
||||
|
||||
// set host and port
|
||||
if (StringUtils.isNotBlank(props.getProperty(NiFiProperties.WEB_HTTP_HOST))) {
|
||||
http.setHost(props.getProperty(NiFiProperties.WEB_HTTP_HOST));
|
||||
final Map<String, String> httpNetworkInterfaces = props.getHttpNetworkInterfaces();
|
||||
if (httpNetworkInterfaces.isEmpty() || httpNetworkInterfaces.values().stream().filter(value -> !Strings.isNullOrEmpty(value)).collect(Collectors.toList()).isEmpty()) {
|
||||
// create the connector
|
||||
final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
|
||||
// set host and port
|
||||
if (StringUtils.isNotBlank(props.getProperty(NiFiProperties.WEB_HTTP_HOST))) {
|
||||
http.setHost(props.getProperty(NiFiProperties.WEB_HTTP_HOST));
|
||||
}
|
||||
http.setPort(port);
|
||||
serverConnectors.add(http);
|
||||
} else {
|
||||
// add connectors for all IPs from http network interfaces
|
||||
serverConnectors.addAll(Lists.newArrayList(httpNetworkInterfaces.values().stream().map(ifaceName -> {
|
||||
NetworkInterface iface = null;
|
||||
try {
|
||||
iface = NetworkInterface.getByName(ifaceName);
|
||||
} catch (SocketException e) {
|
||||
logger.error("Unable to get network interface by name {}", ifaceName, e);
|
||||
}
|
||||
if (iface == null) {
|
||||
logger.warn("Unable to find network interface named {}", ifaceName);
|
||||
}
|
||||
return iface;
|
||||
}).filter(Objects::nonNull).flatMap(iface -> Collections.list(iface.getInetAddresses()).stream())
|
||||
.map(inetAddress -> {
|
||||
// create the connector
|
||||
final ServerConnector http = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
|
||||
// set host and port
|
||||
http.setHost(inetAddress.getHostAddress());
|
||||
http.setPort(port);
|
||||
return http;
|
||||
}).collect(Collectors.toList())));
|
||||
}
|
||||
http.setPort(port);
|
||||
|
||||
// add this connector
|
||||
server.addConnector(http);
|
||||
// add all connectors
|
||||
serverConnectors.forEach(server::addConnector);
|
||||
}
|
||||
|
||||
if (props.getSslPort() != null) {
|
||||
|
@ -590,28 +620,59 @@ public class JettyServer implements NiFiServer {
|
|||
|
||||
logger.info("Configuring Jetty for HTTPs on port: " + port);
|
||||
|
||||
// add some secure config
|
||||
final HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration);
|
||||
httpsConfiguration.setSecureScheme("https");
|
||||
httpsConfiguration.setSecurePort(props.getSslPort());
|
||||
httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
|
||||
final List<Connector> serverConnectors = Lists.newArrayList();
|
||||
|
||||
// build the connector
|
||||
final ServerConnector https = new ServerConnector(server,
|
||||
new SslConnectionFactory(createSslContextFactory(), "http/1.1"),
|
||||
new HttpConnectionFactory(httpsConfiguration));
|
||||
final Map<String, String> httpsNetworkInterfaces = props.getHttpsNetworkInterfaces();
|
||||
if (httpsNetworkInterfaces.isEmpty() || httpsNetworkInterfaces.values().stream().filter(value -> !Strings.isNullOrEmpty(value)).collect(Collectors.toList()).isEmpty()) {
|
||||
final ServerConnector https = createUnconfiguredSslServerConnector(server, httpConfiguration);
|
||||
|
||||
// set host and port
|
||||
if (StringUtils.isNotBlank(props.getProperty(NiFiProperties.WEB_HTTPS_HOST))) {
|
||||
https.setHost(props.getProperty(NiFiProperties.WEB_HTTPS_HOST));
|
||||
// set host and port
|
||||
if (StringUtils.isNotBlank(props.getProperty(NiFiProperties.WEB_HTTPS_HOST))) {
|
||||
https.setHost(props.getProperty(NiFiProperties.WEB_HTTPS_HOST));
|
||||
}
|
||||
https.setPort(port);
|
||||
serverConnectors.add(https);
|
||||
} else {
|
||||
// add connectors for all IPs from https network interfaces
|
||||
serverConnectors.addAll(Lists.newArrayList(httpsNetworkInterfaces.values().stream().map(ifaceName -> {
|
||||
NetworkInterface iface = null;
|
||||
try {
|
||||
iface = NetworkInterface.getByName(ifaceName);
|
||||
} catch (SocketException e) {
|
||||
logger.error("Unable to get network interface by name {}", ifaceName, e);
|
||||
}
|
||||
if (iface == null) {
|
||||
logger.warn("Unable to find network interface named {}", ifaceName);
|
||||
}
|
||||
return iface;
|
||||
}).filter(Objects::nonNull).flatMap(iface -> Collections.list(iface.getInetAddresses()).stream())
|
||||
.map(inetAddress -> {
|
||||
final ServerConnector https = createUnconfiguredSslServerConnector(server, httpConfiguration);
|
||||
|
||||
// set host and port
|
||||
https.setHost(inetAddress.getHostAddress());
|
||||
https.setPort(port);
|
||||
return https;
|
||||
}).collect(Collectors.toList())));
|
||||
}
|
||||
https.setPort(port);
|
||||
|
||||
// add this connector
|
||||
server.addConnector(https);
|
||||
// add all connectors
|
||||
serverConnectors.forEach(server::addConnector);
|
||||
}
|
||||
}
|
||||
|
||||
private ServerConnector createUnconfiguredSslServerConnector(Server server, HttpConfiguration httpConfiguration) {
|
||||
// add some secure config
|
||||
final HttpConfiguration httpsConfiguration = new HttpConfiguration(httpConfiguration);
|
||||
httpsConfiguration.setSecureScheme("https");
|
||||
httpsConfiguration.setSecurePort(props.getSslPort());
|
||||
httpsConfiguration.addCustomizer(new SecureRequestCustomizer());
|
||||
|
||||
// build the connector
|
||||
return new ServerConnector(server,
|
||||
new SslConnectionFactory(createSslContextFactory(), "http/1.1"),
|
||||
new HttpConnectionFactory(httpsConfiguration));
|
||||
}
|
||||
|
||||
private SslContextFactory createSslContextFactory() {
|
||||
final SslContextFactory contextFactory = new SslContextFactory();
|
||||
configureSslContextFactory(contextFactory, props);
|
||||
|
|
Loading…
Reference in New Issue