Apache NiFi 2.x 3-Node Cluster Setup Guide — TLS Certificates, NiFi Registry, and External API Access
A practical guide to building a secure NiFi cluster: Root CA and per-node certificate generation with NiFi Toolkit, 3-node cluster configuration, NiFi Registry TLS, and external HTTPS API access.
Overview
Apache NiFi 2.x requires HTTPS and authentication by default. To deploy a NiFi cluster in production, you need unique TLS certificates for each node to encrypt both inter-node communication and client access.
This guide covers:
- 3-node NiFi cluster with Embedded ZooKeeper
- NiFi Toolkit for Root CA and per-node certificate generation
- NiFi Registry TLS configuration
- External HTTPS API access with client certificates
Environment
| Role | Hostname | IP |
|---|---|---|
| NiFi Node 1 + ZooKeeper | nifi1.example.com | 192.168.0.1 |
| NiFi Node 2 + ZooKeeper | nifi2.example.com | 192.168.0.2 |
| NiFi Node 3 + ZooKeeper | nifi3.example.com | 192.168.0.3 |
| NiFi Registry | nifi1.example.com | 192.168.0.1 (co-located with Node 1) |
Prerequisites: Java 21 JDK must be installed on all nodes (NiFi 2.x requirement).
1. TLS Certificate Generation with NiFi Toolkit
1.1 TLS Certificate Requirements (Cloudera CFM Reference)
Certificates used in NiFi must meet the following requirements:
| Item | Requirement |
|---|---|
| Signature Algorithm | SHA-256 (sha256WithRSAEncryption) |
| Key Usage (X509v3) | Digital Signature, Key Encipherment |
| Extended Key Usage (X509v3) | TLS Web Server Authentication (serverAuth), TLS Web Client Authentication (clientAuth) |
| Subject Alternative Names (SAN) | Must include the node's FQDN as a DNS entry |
| KeyStore | Must contain only a single PrivateKeyEntry |
| Wildcard Certificates | Not supported — each node requires its own unique certificate |
| Keystore/Key Passwords | Must be identical or both unset |
1.2 Download NiFi Toolkit
The NiFi Toolkit is distributed alongside Apache NiFi. Use the same version as your NiFi 2.x installation.
# Download NiFi Toolkit (match your NiFi version)
wget https://archive.apache.org/dist/nifi/2.4.0/nifi-toolkit-2.4.0-bin.zip
unzip nifi-toolkit-2.4.0-bin.zip
cd nifi-toolkit-2.4.01.3 Batch Certificate Generation in Standalone Mode
The NiFi Toolkit's tls-toolkit in Standalone mode handles everything in one command — from Root CA creation to per-node Keystore/Truststore generation and nifi.properties updates.
./bin/tls-toolkit.sh standalone \
-n 'nifi1.example.com,nifi2.example.com,nifi3.example.com' \
-C 'CN=admin, OU=NIFI' \
-o ./certs \
-K changeit \
-S changeit \
-P changeit \
--days 825 \
-k 2048Option Reference:
| Option | Description |
|---|---|
-n | Comma-separated list of hostnames for certificate generation |
-C | Client certificate DN (for Initial Admin or API access) |
-o | Output directory |
-K | Key password |
-S | Keystore password |
-P | Truststore password |
--days | Certificate validity period (825 days max recommended for macOS) |
-k | Key size (2048 bit) |
1.4 Verify Generated Output
tree ./certs/./certs/
├── nifi-cert.pem # Root CA public certificate
├── nifi-key.key # Root CA private key
├── nifi1.example.com/
│ ├── keystore.jks # Node 1 Keystore
│ ├── truststore.jks # Node 1 Truststore (includes Root CA)
│ └── nifi.properties # Auto-generated TLS configuration
├── nifi2.example.com/
│ ├── keystore.jks
│ ├── truststore.jks
│ └── nifi.properties
├── nifi3.example.com/
│ ├── keystore.jks
│ ├── truststore.jks
│ └── nifi.properties
├── CN=admin_OU=NIFI.p12 # Client certificate (PKCS12)
├── CN=admin_OU=NIFI.password # Client certificate password
└── CN=admin_OU=NIFI_config.json # Client certificate metadata
Key Point: The Toolkit-generated
truststore.jksincludes the Root CA certificate, enabling mutual trust between all nodes signed by the same CA.
1.5 Using an Existing Root CA
If your organization already has a Root CA or Intermediate CA, use the --additionalCACertificate option.
./bin/tls-toolkit.sh standalone \
-n 'nifi1.example.com,nifi2.example.com,nifi3.example.com' \
-C 'CN=admin, OU=NIFI' \
--additionalCACertificate /path/to/existing-ca.pem \
-o ./certs \
-K changeit \
-S changeit \
-P changeit1.6 Certificate Validation
Verify that generated certificates meet all requirements.
# Inspect Keystore contents
keytool -list -v -keystore ./certs/nifi1.example.com/keystore.jks \
-storepass changeit
# Check SAN, Key Usage, Extended Key Usage
keytool -list -v -keystore ./certs/nifi1.example.com/keystore.jks \
-storepass changeit | grep -A 5 "SubjectAlternativeName\|ExtendedKeyUsages\|KeyUsage"
# Verify Root CA is in Truststore
keytool -list -keystore ./certs/nifi1.example.com/truststore.jks \
-storepass changeitVerify the following:
- SAN includes the node's FQDN as a DNS entry
- Extended Key Usage includes both
serverAuthandclientAuth - Key Usage includes
DigitalSignatureandKey_Encipherment
2. NiFi Cluster Configuration
2.1 Distribute Certificates
Copy the appropriate Keystore and Truststore to each node.
# Node 1 (192.168.0.1)
scp ./certs/nifi1.example.com/keystore.jks root@192.168.0.1:/opt/nifi/conf/
scp ./certs/nifi1.example.com/truststore.jks root@192.168.0.1:/opt/nifi/conf/
# Node 2 (192.168.0.2)
scp ./certs/nifi2.example.com/keystore.jks root@192.168.0.2:/opt/nifi/conf/
scp ./certs/nifi2.example.com/truststore.jks root@192.168.0.2:/opt/nifi/conf/
# Node 3 (192.168.0.3)
scp ./certs/nifi3.example.com/keystore.jks root@192.168.0.3:/opt/nifi/conf/
scp ./certs/nifi3.example.com/truststore.jks root@192.168.0.3:/opt/nifi/conf/2.2 Generate Sensitive Properties Key
All cluster nodes must use the same nifi.sensitive.props.key value.
# Generate a random key
openssl rand -base64 32
# Example output: k8Jh3F7gT2mN9pQr4sVw6xYz1aBcDeF0hIjKlMnOpRs=Important: Store this key securely. If lost, NiFi will be unable to decrypt encrypted properties.
2.3 nifi.properties Configuration
Edit /opt/nifi/conf/nifi.properties on each node. Replace {NODE_HOSTNAME} with the appropriate hostname.
Common Settings (identical across all nodes)
# ==================== Web Properties ====================
nifi.web.http.host=
nifi.web.http.port=
nifi.web.https.host={NODE_HOSTNAME}
nifi.web.https.port=8443
# ==================== Security Properties ====================
nifi.security.keystore=./conf/keystore.jks
nifi.security.keystoreType=jks
nifi.security.keystorePasswd=changeit
nifi.security.keyPasswd=changeit
nifi.security.truststore=./conf/truststore.jks
nifi.security.truststoreType=jks
nifi.security.truststorePasswd=changeit
# ==================== Sensitive Properties ====================
nifi.sensitive.props.key=k8Jh3F7gT2mN9pQr4sVw6xYz1aBcDeF0hIjKlMnOpRs=
# ==================== Cluster Properties ====================
nifi.cluster.is.node=true
nifi.cluster.node.address={NODE_HOSTNAME}
nifi.cluster.node.protocol.port=11443
nifi.cluster.protocol.is.secure=true
# ==================== ZooKeeper Properties ====================
nifi.state.management.embedded.zookeeper.start=true
nifi.zookeeper.connect.string=nifi1.example.com:2181,nifi2.example.com:2181,nifi3.example.com:2181
nifi.zookeeper.connect.timeout=10 secs
nifi.zookeeper.session.timeout=10 secs
# ==================== Cluster Load Balancing ====================
nifi.cluster.load.balance.host={NODE_HOSTNAME}
nifi.cluster.load.balance.port=6342Per-Node Differences
| Property | Node 1 | Node 2 | Node 3 |
|---|---|---|---|
nifi.web.https.host | nifi1.example.com | nifi2.example.com | nifi3.example.com |
nifi.cluster.node.address | nifi1.example.com | nifi2.example.com | nifi3.example.com |
nifi.cluster.load.balance.host | nifi1.example.com | nifi2.example.com | nifi3.example.com |
2.4 Embedded ZooKeeper Configuration
zookeeper.properties
Edit /opt/nifi/conf/zookeeper.properties on each node.
dataDir=./state/zookeeper
clientPort=2181
initLimit=10
syncLimit=5
tickTime=2000
autopurge.snapRetainCount=30
autopurge.purgeInterval=1
server.1=nifi1.example.com:2888:3888
server.2=nifi2.example.com:2888:3888
server.3=nifi3.example.com:2888:3888Create myid Files
Create a myid file in each node's ZooKeeper data directory.
# Node 1 (192.168.0.1)
mkdir -p /opt/nifi/state/zookeeper
echo 1 > /opt/nifi/state/zookeeper/myid
# Node 2 (192.168.0.2)
mkdir -p /opt/nifi/state/zookeeper
echo 2 > /opt/nifi/state/zookeeper/myid
# Node 3 (192.168.0.3)
mkdir -p /opt/nifi/state/zookeeper
echo 3 > /opt/nifi/state/zookeeper/myid2.5 state-management.xml Configuration
Update the ZooKeeper connect string in /opt/nifi/conf/state-management.xml on each node.
<cluster-provider>
<id>zk-provider</id>
<class>org.apache.nifi.controller.state.providers.zookeeper.ZooKeeperStateProvider</class>
<property name="Connect String">nifi1.example.com:2181,nifi2.example.com:2181,nifi3.example.com:2181</property>
<property name="Root Node">/nifi</property>
<property name="Session Timeout">10 seconds</property>
<property name="Access Control">CreatorOnly</property>
</cluster-provider>2.6 authorizers.xml Configuration
Set the Initial Admin Identity. This DN must match the client certificate DN generated by the Toolkit.
<authorizers>
<userGroupProvider>
<identifier>file-user-group-provider</identifier>
<class>org.apache.nifi.authorization.FileUserGroupProvider</class>
<property name="Users File">./conf/users.xml</property>
<property name="Initial User Identity 1">CN=admin, OU=NIFI</property>
<property name="Initial User Identity 2">CN=nifi1.example.com, OU=NIFI</property>
<property name="Initial User Identity 3">CN=nifi2.example.com, OU=NIFI</property>
<property name="Initial User Identity 4">CN=nifi3.example.com, OU=NIFI</property>
</userGroupProvider>
<accessPolicyProvider>
<identifier>file-access-policy-provider</identifier>
<class>org.apache.nifi.authorization.FileAccessPolicyProvider</class>
<property name="User Group Provider">file-user-group-provider</property>
<property name="Authorizations File">./conf/authorizations.xml</property>
<property name="Initial Admin Identity">CN=admin, OU=NIFI</property>
<property name="Node Identity 1">CN=nifi1.example.com, OU=NIFI</property>
<property name="Node Identity 2">CN=nifi2.example.com, OU=NIFI</property>
<property name="Node Identity 3">CN=nifi3.example.com, OU=NIFI</property>
</accessPolicyProvider>
<authorizer>
<identifier>managed-authorizer</identifier>
<class>org.apache.nifi.authorization.StandardManagedAuthorizer</class>
<property name="Access Policy Provider">file-access-policy-provider</property>
</authorizer>
</authorizers>Note: The DN format in
Initial Admin IdentityandNode Identitymust exactly match the certificate DN — including spaces, case, and ordering.
2.7 Firewall Port Configuration
Open the required ports on all nodes for cluster communication.
| Port | Purpose |
|---|---|
| 8443 | NiFi HTTPS Web UI / API |
| 11443 | NiFi Cluster Node Protocol |
| 6342 | NiFi Cluster Load Balancing |
| 2181 | ZooKeeper Client |
| 2888 | ZooKeeper Follower |
| 3888 | ZooKeeper Leader Election |
# Using firewalld (run on each node)
firewall-cmd --permanent --add-port=8443/tcp
firewall-cmd --permanent --add-port=11443/tcp
firewall-cmd --permanent --add-port=6342/tcp
firewall-cmd --permanent --add-port=2181/tcp
firewall-cmd --permanent --add-port=2888/tcp
firewall-cmd --permanent --add-port=3888/tcp
firewall-cmd --reload2.8 /etc/hosts Configuration
Ensure hostnames resolve correctly on all nodes (if DNS is not used).
192.168.0.1 nifi1.example.com nifi1
192.168.0.2 nifi2.example.com nifi2
192.168.0.3 nifi3.example.com nifi3
2.9 Start the Cluster
Start NiFi on all nodes. Starting them roughly simultaneously is recommended.
# Run on each node
/opt/nifi/bin/nifi.sh start
# Monitor logs
tail -f /opt/nifi/logs/nifi-app.logAfter successful startup, access the UI at https://nifi1.example.com:8443/nifi.
3. NiFi Registry TLS Configuration
NiFi Registry also requires TLS to communicate securely with the NiFi cluster. We'll install it on Node 1 (192.168.0.1).
3.1 Generate Registry Certificates
NiFi Registry needs a certificate signed by the same Root CA. Reuse the existing CA to generate it.
# Reuse the existing CA for Registry certificates
mkdir -p ./certs-registry
cp ./certs/nifi-cert.pem ./certs-registry/
cp ./certs/nifi-key.key ./certs-registry/
./bin/tls-toolkit.sh standalone \
-n 'nifi1.example.com' \
-o ./certs-registry \
-K changeit \
-S changeit \
-P changeit \
--nifiDnPrefix 'CN=' \
--nifiDnSuffix ', OU=NIFI-REGISTRY'Tip: By copying
nifi-cert.pemandnifi-key.keyinto the output directory beforehand, the Toolkit reuses that CA for signing instead of creating a new one.
3.2 Deploy Certificates
cp ./certs-registry/nifi1.example.com/keystore.jks /opt/nifi-registry/conf/keystore.jks
cp ./certs-registry/nifi1.example.com/truststore.jks /opt/nifi-registry/conf/truststore.jks3.3 nifi-registry.properties Configuration
Edit /opt/nifi-registry/conf/nifi-registry.properties.
# ==================== Web Properties ====================
nifi.registry.web.http.host=
nifi.registry.web.http.port=
nifi.registry.web.https.host=nifi1.example.com
nifi.registry.web.https.port=18443
# ==================== Security Properties ====================
nifi.registry.security.keystore=./conf/keystore.jks
nifi.registry.security.keystoreType=jks
nifi.registry.security.keystorePasswd=changeit
nifi.registry.security.keyPasswd=changeit
nifi.registry.security.truststore=./conf/truststore.jks
nifi.registry.security.truststoreType=jks
nifi.registry.security.truststorePasswd=changeit
nifi.registry.security.needClientAuth=true3.4 NiFi Registry authorizers.xml
Register NiFi node identities in /opt/nifi-registry/conf/authorizers.xml.
<authorizers>
<userGroupProvider>
<identifier>file-user-group-provider</identifier>
<class>org.apache.nifi.registry.security.authorization.file.FileUserGroupProvider</class>
<property name="Users File">./conf/users.xml</property>
<property name="Initial User Identity 1">CN=admin, OU=NIFI</property>
<property name="Initial User Identity 2">CN=nifi1.example.com, OU=NIFI</property>
<property name="Initial User Identity 3">CN=nifi2.example.com, OU=NIFI</property>
<property name="Initial User Identity 4">CN=nifi3.example.com, OU=NIFI</property>
</userGroupProvider>
<accessPolicyProvider>
<identifier>file-access-policy-provider</identifier>
<class>org.apache.nifi.registry.security.authorization.file.FileAccessPolicyProvider</class>
<property name="User Group Provider">file-user-group-provider</property>
<property name="Authorizations File">./conf/authorizations.xml</property>
<property name="Initial Admin Identity">CN=admin, OU=NIFI</property>
<property name="NiFi Identity 1">CN=nifi1.example.com, OU=NIFI</property>
<property name="NiFi Identity 2">CN=nifi2.example.com, OU=NIFI</property>
<property name="NiFi Identity 3">CN=nifi3.example.com, OU=NIFI</property>
</accessPolicyProvider>
<authorizer>
<identifier>managed-authorizer</identifier>
<class>org.apache.nifi.registry.security.authorization.StandardManagedAuthorizer</class>
<property name="Access Policy Provider">file-access-policy-provider</property>
</authorizer>
</authorizers>3.5 Start NiFi Registry
/opt/nifi-registry/bin/nifi-registry.sh start
tail -f /opt/nifi-registry/logs/nifi-registry-app.logAccess URL: https://nifi1.example.com:18443/nifi-registry
4. Connect NiFi to Registry
Register the Registry Client in the NiFi Web UI:
- Controller Settings: Hamburger menu > Controller Settings > Registry Clients
- Add Registry Client:
- Name:
NiFi Registry - URL:
https://nifi1.example.com:18443
- Name:
- Since NiFi uses its own node certificate (signed by the same Root CA) when connecting to Registry, no additional TLS configuration is needed.
5. External HTTPS API Access
To call NiFi REST APIs from external systems, you must authenticate with a certificate trusted by NiFi. NiFi 2.x does not allow unauthenticated HTTP access.
5.1 Option 1: Client Certificate (mTLS)
Use the Toolkit-generated client certificate (CN=admin_OU=NIFI.p12).
curl
# Check client certificate password
cat ./certs/CN=admin_OU=NIFI.password
# API call with PKCS12 client certificate
curl -k --cert-type P12 \
--cert ./certs/CN=admin_OU=NIFI.p12:<CLIENT_PASSWORD> \
https://nifi1.example.com:8443/nifi-api/flow/statusPython
Convert PKCS12 to PEM format first.
# Convert PKCS12 to PEM (separate cert and key)
openssl pkcs12 -in ./certs/CN=admin_OU=NIFI.p12 \
-clcerts -nokeys -out client-cert.pem \
-passin pass:<CLIENT_PASSWORD>
openssl pkcs12 -in ./certs/CN=admin_OU=NIFI.p12 \
-nocerts -nodes -out client-key.pem \
-passin pass:<CLIENT_PASSWORD>import requests
response = requests.get(
'https://nifi1.example.com:8443/nifi-api/flow/status',
cert=('client-cert.pem', 'client-key.pem'),
verify='./certs/nifi-cert.pem' # Verify server with Root CA
)
print(response.json())Java
import javax.net.ssl.*;
import java.io.FileInputStream;
import java.net.http.*;
import java.net.URI;
import java.security.KeyStore;
// Load Keystore (client certificate)
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(new FileInputStream("CN=admin_OU=NIFI.p12"),
"<CLIENT_PASSWORD>".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keyStore, "<CLIENT_PASSWORD>".toCharArray());
// Load Truststore (Root CA)
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("truststore.jks"),
"changeit".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustStore);
// Configure SSL Context
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// Make API call
HttpClient client = HttpClient.newBuilder()
.sslContext(sslContext)
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://nifi1.example.com:8443/nifi-api/flow/status"))
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());5.2 Option 2: Bearer Token (JWT)
Login with username/password to get a token, then use it for subsequent requests. Available when Single User or LDAP authentication is configured.
# Get token
TOKEN=$(curl -k -X POST \
https://nifi1.example.com:8443/nifi-api/access/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'username=admin&password=your_password')
# API call with token
curl -k -H "Authorization: Bearer $TOKEN" \
https://nifi1.example.com:8443/nifi-api/flow/statusNote: The
-kflag skips certificate verification for self-signed certificates. In production, use--cacertto specify the Root CA.
5.3 Option 3: Additional Client Certificates
Generate separate client certificates for external systems (monitoring tools, CI/CD pipelines) to control access granularly.
./bin/tls-toolkit.sh standalone \
-n 'nifi1.example.com' \
-C 'CN=monitoring-system, OU=OPERATIONS' \
-C 'CN=cicd-pipeline, OU=DEVOPS' \
-o ./certs-clients \
-K changeit \
-S changeit \
-P changeitAdd the DNs to NiFi's authorizers.xml and assign appropriate permissions.
Note:
Initial User Identityentries only take effect on first NiFi startup. Ifusers.xmlandauthorizations.xmlalready exist, delete them and restart, or add users via the Web UI.
5.4 Key NiFi REST API Endpoints
| Endpoint | Method | Description |
|---|---|---|
/nifi-api/flow/status | GET | Overall cluster status |
/nifi-api/flow/cluster/summary | GET | Cluster summary |
/nifi-api/controller/cluster | GET | Cluster node list |
/nifi-api/system-diagnostics | GET | System diagnostics |
/nifi-api/flow/process-groups/root | GET | Root process group info |
/nifi-api/access/config | GET | Access configuration (no auth required) |
6. Troubleshooting
Certificate Errors
# "PKIX path building failed"
# -> Root CA missing from Truststore or incomplete certificate chain
keytool -list -keystore truststore.jks -storepass changeit
# "No subject alternative names present"
# -> SAN doesn't include the hostname
keytool -list -v -keystore keystore.jks -storepass changeit | grep -A 3 "SubjectAlternativeName"
# "Certificate does not conform to algorithm constraints"
# -> Key size too small (1024 bit or less)
Cluster Connection Errors
# "Unable to communicate with node"
# -> Check firewall ports
nc -zv nifi2.example.com 11443
# ZooKeeper connection failure
# -> Check myid file
cat /opt/nifi/state/zookeeper/myid
# -> Check ZooKeeper port
nc -zv nifi1.example.com 2181
authorizers.xml DN Mismatch
# Check the exact DN from the certificate
keytool -list -v -keystore keystore.jks -storepass changeit | grep "Owner:"
# Example output: Owner: CN=nifi1.example.com, OU=NIFI
# -> Must exactly match the Node Identity in authorizers.xml7. Checklist
Verify the following after completing all configuration:
- Java 21 JDK installed on all nodes
- Root CA and per-node certificates generated with TLS Toolkit
- Certificates meet SAN, Key Usage, and Extended Key Usage requirements
- Keystore/Truststore deployed to each node
nifi.sensitive.props.keyidentical across all nodesnifi.propertiesTLS and cluster settings configuredzookeeper.propertiesconfigured for 3 nodes withmyidfiles createdstate-management.xmlZooKeeper connect string setauthorizers.xmlInitial Admin Identity and Node Identities configured- Firewall ports opened (8443, 11443, 6342, 2181, 2888, 3888)
- Hostnames registered in
/etc/hostsor DNS - NiFi Registry TLS configured and started
- External HTTPS API access verified with client certificate