Blog
nifisecuritytls

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.

Data DynamicsApril 13, 202612 min read

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

RoleHostnameIP
NiFi Node 1 + ZooKeepernifi1.example.com192.168.0.1
NiFi Node 2 + ZooKeepernifi2.example.com192.168.0.2
NiFi Node 3 + ZooKeepernifi3.example.com192.168.0.3
NiFi Registrynifi1.example.com192.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:

ItemRequirement
Signature AlgorithmSHA-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
KeyStoreMust contain only a single PrivateKeyEntry
Wildcard CertificatesNot supported — each node requires its own unique certificate
Keystore/Key PasswordsMust 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.0

1.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 2048

Option Reference:

OptionDescription
-nComma-separated list of hostnames for certificate generation
-CClient certificate DN (for Initial Admin or API access)
-oOutput directory
-KKey password
-SKeystore password
-PTruststore password
--daysCertificate validity period (825 days max recommended for macOS)
-kKey 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.jks includes 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 changeit

1.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 changeit

Verify the following:

  • SAN includes the node's FQDN as a DNS entry
  • Extended Key Usage includes both serverAuth and clientAuth
  • Key Usage includes DigitalSignature and Key_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=6342

Per-Node Differences

PropertyNode 1Node 2Node 3
nifi.web.https.hostnifi1.example.comnifi2.example.comnifi3.example.com
nifi.cluster.node.addressnifi1.example.comnifi2.example.comnifi3.example.com
nifi.cluster.load.balance.hostnifi1.example.comnifi2.example.comnifi3.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:3888

Create 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/myid

2.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 Identity and Node Identity must 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.

PortPurpose
8443NiFi HTTPS Web UI / API
11443NiFi Cluster Node Protocol
6342NiFi Cluster Load Balancing
2181ZooKeeper Client
2888ZooKeeper Follower
3888ZooKeeper 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 --reload

2.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.log

After 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.pem and nifi-key.key into 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.jks

3.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=true

3.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.log

Access URL: https://nifi1.example.com:18443/nifi-registry


4. Connect NiFi to Registry

Register the Registry Client in the NiFi Web UI:

  1. Controller Settings: Hamburger menu > Controller Settings > Registry Clients
  2. Add Registry Client:
    • Name: NiFi Registry
    • URL: https://nifi1.example.com:18443
  3. 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/status

Python

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/status

Note: The -k flag skips certificate verification for self-signed certificates. In production, use --cacert to 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 changeit

Add the DNs to NiFi's authorizers.xml and assign appropriate permissions.

Note: Initial User Identity entries only take effect on first NiFi startup. If users.xml and authorizations.xml already exist, delete them and restart, or add users via the Web UI.

5.4 Key NiFi REST API Endpoints

EndpointMethodDescription
/nifi-api/flow/statusGETOverall cluster status
/nifi-api/flow/cluster/summaryGETCluster summary
/nifi-api/controller/clusterGETCluster node list
/nifi-api/system-diagnosticsGETSystem diagnostics
/nifi-api/flow/process-groups/rootGETRoot process group info
/nifi-api/access/configGETAccess 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.xml

7. 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.key identical across all nodes
  • nifi.properties TLS and cluster settings configured
  • zookeeper.properties configured for 3 nodes with myid files created
  • state-management.xml ZooKeeper connect string set
  • authorizers.xml Initial Admin Identity and Node Identities configured
  • Firewall ports opened (8443, 11443, 6342, 2181, 2888, 3888)
  • Hostnames registered in /etc/hosts or DNS
  • NiFi Registry TLS configured and started
  • External HTTPS API access verified with client certificate

References