Apache NiFi: как решить ошибки, которые не гуглятся

Настройка и запуск Apache NiFi и Zookeeper, настройка авторизации по LDAP и работа NiFi по HTTPS, настройка и запуск Apache NiFi Registry, пример запуска NiFi c Kerberos — вот темы, которые будут в этой статье.

stdsnhrxoqf9vanduxvwre5ablg.jpeg

Не вижу смысла полностью рассказывать, как настраивать NiFi и NiFi Registry — есть официальная документация и мануалы в сети. Я сосредоточился на ошибках, информации по которым нет, в том числе и на английском. При самостоятельном поиске решения, это реально масса времени. Я провел месяцы в режиме DEBUG и TRACE, чтобы понять, как всё сделать правильно. Готов поделится.
На всякий случай, NiFi (Niagara Files) — система для обработки потоковых данных. У нас она читает сообщения из Кафки и кладет в базу данных без написания кода.

В ходе работы мне пришлось настраивать и разворачивать кластер NiFi несколько раз, на разные виртуальные машины. Для этого у нас в компании уже было создано множество автоматизаций на Ansible, которые помогают в данный момент разворачивать и настраивать кластеры NiFi намного быстрее.

Настройка и запуск Apache NiFi


В Группе НЛМК настройка и запуск NiFi происходит с помощью Ansible Playbooks, которые на «голые» ВМ ставят софт, размечают диски, настраивают экспортеры, генерируют сертификаты, устанавливают zookepeer, а далее и сам NiFi.

Я расскажу, как аутентификация пользователей будет происходить с помощью LDAP, поэтому по умолчанию у вас должен быть сервер каталогов AD (не буду объяснять, как АD настраивать, у многих это уже есть).

Так же для запуска NiFi по HTTPS необходимо создать сертификаты. Для этого простого шага можете воспользоваться документацией здесь Securing NiFi with Provided Certificates. В нашей компании сертификатами занимаются отдельные люди, поэтому на этапе установки сертификаты у меня уже были. Тут не буду объяснять, как их сгенерить, лишь расскажу, как настроить identity mapping и установить связь между NiFi и NiFi Registry.

Разворачивать все сервисы мы будем с помощью docker. Для работы NiFi в режиме кластера необходимо подготовить и запустить zookeeper.

Настройка и запуск Zookeeper


NiFi в режиме кластера не запустится без zookeeper. Вот пример, как настроить и запустить zookeeper быстро.

docker-compose.yaml 
---
version: '3.5'

services:
  zookeeper:
    image: 'bitnami/zookeeper:3.7.0'
    hostname: nifi-test-node-1.mycompany
    restart: unless-stopped
    ports:
      - '2181:2181'
      - '2888:2888'
      - '3888:3888'
    env_file:
      - zookeeper.env
    volumes:
      - zookeeper_data:/bitnami

volumes:
  zookeeper_data:
    driver: local
...


Для образа bitnami/ zookeeper необходимо настроить параметры, список которых можно взять тут.

Для безопасности включим авторизацию, настроив список параметров. Ниже в комментариях я подписал значение каждой переменной.

zookeeper.env
# ID сервера зоокипера
ZOO_SERVER_ID=1

# Запрещаем присоединяться анонимно
ALLOW_ANONYMOUS_LOGIN=NO
# Включаем авторизацию
ZOO_ENABLE_AUTH=yes
# Указываем пользователей сервера
ZOO_SERVER_USERS=user1,user1
# Указываем пароли для пользователей сервера
ZOO_SERVER_PASSWORDS=password1,password2
# Пользователь который будет использоваться при авторизации других нод Zookeeper
ZOO_CLIENT_USER=user1
# Пароль от клиентского пользователя
ZOO_CLIENT_PASSWORD=password1
# Необходимо правильно указать другие ноды Zookeeper и ZOO_SERVER_ID для корректного коннекта между нодами
ZOO_SERVERS=nifi-test-node-1.mycompany:2888:3888::1,nifi-test-node-2.mycompany:2888:3888::2,nifi-test-node-3.mycompany:2888:3888::3
ZOO_ENABLE_PROMETHEUS_METRICS=YES


После того, как zookeeper запустится и все ноды войдут в режим кластера, в логах появятся сообщения об успешном коннекте каждой ноды. Если этого не произойдет, то NiFi будет выдавать ошибку о том, что он не может подключиться к Zookeeper.

Разберем ошибки, которые могут быть при запуске Zookeeper:

  • Ошибка Zookeeper »Cannot open channel to 2 at election address nifi-test-node-2.mycompany/ip:3888 java.net.ConnectException: Connection refused (Connection refused)» ошибка говорит о том, что либо нода zookeeper nifi-test-node-2.mycompany еще не поднята. Либо вторая нода считает себя другой 1 или 3, поэтому zookeeper не может войти в режим кластера. Для решения этой проблемы необходимо обратить внимание на параметры ZOO_SERVER_ID и ZOO_SERVERS, в ZOO_SERVERS необходимо чтобы был указан ID у ноды.
  • Если же вы используете другой zookeeper то необходимо обратить внимание на zoo.cfg, а именно на server.1=nifi-test-node-1.mycompany:2888:3888 server.2=nifi-test-node-2.mycompany:2888:3888 и так далее. А также на значение файла /data/myid значение в файле должно соответствовать номеру ноды zookeeper.
  • Ошибка NiFi (возникает, если неправильно настроить Zookeeper) »WARN [main] o.a.nifi.controller.StandardFlowService There is currently no Cluster Coordinator. This often happens upon restart of NiFi when running an embedded ZooKeeper. Will register this node to become the active Cluster Coordinator and will attempt to connect to cluster again.» Данная ошибка возникает в NiFi, когда он не может подключиться к указанному zookeeper, и пытается подключится к внутреннему, но у nifi отключен внутренний zookeeper (описание ошибки в системе на английском немного некорректное). Можно проверить внутри этого файла conf/nifi.properties nifi.state.management.embedded.zookeeper.start=false.

    Т. е. эта ошибка говорит о двух ситуациях: 1) когда nifi не может подключится к внутреннему zookeeper — это то, что и написано в описании ошибки на английском 2), но может быть и второй случай, о котором описание умалчивает: когда nifi не может подключится к внешнему zookeeper.

    Для решения второго случая необходимо проверить параметры в NiFi conf/nifi.properties: nifi.zookeeper.connect.string=nifi-test-node-1.mycompany:2181,nifi-test-node-1.mycompany:2181,nifi-test-node-1.mycompany:2181


Настройка и запуск Apache NiFi


После успешного запуска Zookeeper, перейдем к настройкам параметров самого кластера NiFi. В данном разделе я разберу ошибки, которые получим, если неправильно настроим кластер.
Разберем файлы конфигурации NiFi для работы по LDAP:

1) conf/nifi.properties

Вот блоки, которые необходимо настроить, чтобы NiFi запустился без ошибок.

nifi.properties
# ... - Можно оставлять стандартные настройки без изменений

# Site to Site properties
# ...
# Значение данного параметра ставим на True
nifi.remote.input.secure=True

# web properties #
# При запуске по https необходимо пропустить параметры nifi.web.http.host и nifi.web.http.port и оставить их пустыми
nifi.web.http.host=
nifi.web.http.port=
nifi.web.http.network.interface.default=
# При запуске по https необходимо заполнить параметры nifi.web.https.host и nifi.web.https.port
nifi.web.https.host=nifi-test-node-1.mycompany
nifi.web.https.port=9091
nifi.web.https.network.interface.default=

#...
# Если у вас есть балансировщик на ноды NiFi необходимо здесь указать web proxy host
nifi.web.proxy.host=my-test-nifi-proxy.com
#...

# security properties #
# До NiFi 1.14 значение этого параметра можно было оставлять пустым и ваш flow файл конфигурации бы не шифровался, и NiFi работал бы в нормальном режиме
# C версией NiFi выше 1.14 необходимо указать данный ключ иначе NiFi выдаст ошибку.
nifi.sensitive.props.key=<ваше_значение_ключа>
#...

# Так же необходимо настроить пути до сертификатов и их пароли для запуска NiFi в secure режиме
nifi.security.keystore=/etc/ssl/keystore.jks
nifi.security.keystoreType=JKS
nifi.security.keystorePasswd=<пароль>
nifi.security.keyPasswd=<пароль>
nifi.security.truststore=/etc/ssl/truststore.jks
nifi.security.truststoreType=JKS
nifi.security.truststorePasswd=<пароль>
nifi.security.user.authorizer=managed-authorizer
nifi.security.allow.anonymous.authentication=false
# Обратите значение на этот параметр
nifi.security.user.login.identity.provider=ldap-provider

#...
# Identity Mapping Properties #
# Данные параметры необходимы для более быстрой нормализации идентификаторов пользователей
# Данная настройка зависит только от вашей организации. Подробная докуемнтация тут https://docs.cloudera.com/HDPDocuments/HDF3/HDF-3.2.0/nifi-system-properties/content/identity-mapping-properties.html
nifi.security.identity.mapping.pattern.dn=^L=(.*?), ST=(.*?), C=(.*?), OU=(.*?), O=(.*?),.*?$
nifi.security.identity.mapping.value.dn=$4@$5
nifi.security.identity.mapping.transform.dn=LOWER

# cluster node properties (only configure for cluster nodes) #
# Для запуска NiFi в режиме кластера необходимо указать значение True в nifi.cluster.is.node и настроить дополнительные параметры по вашим приоритетам
# иначе нода NiFi не будет прицепляться к кластеру
nifi.cluster.is.node=True
nifi.cluster.node.address=nifi-test-node-1.mycompany
nifi.cluster.node.protocol.port=9088
nifi.cluster.node.protocol.threads=10
nifi.cluster.node.protocol.max.threads=50
nifi.cluster.node.event.history.size=25
nifi.cluster.node.connection.timeout=5 sec
nifi.cluster.node.read.timeout=5 sec
nifi.cluster.node.max.concurrent.requests=100
nifi.cluster.firewall.file=
nifi.cluster.flow.election.max.wait.time=5 mins
nifi.cluster.flow.election.max.candidates=

# zookeeper properties, used for cluster management #
# При запуске на внешнем zookeeper,настройку которого мы обсуждали ранее необходимо заполнить параметры nifi.zookeeper.*
nifi.zookeeper.connect.string=nifi-test-node-1.mycompany:2181,nifi-test-node-2.mycompany:2181,nifi-test-node-3.mycompany:2181
nifi.zookeeper.connect.timeout=10 secs
nifi.zookeeper.session.timeout=10 secs
nifi.zookeeper.root.node=/nifi


  1. При запуске по https необходимо пропустить параметры nifi.web.http.host и nifi.web.http.port и оставить их пустыми.
  2. При запуске по https необходимо заполнить параметры nifi.web.https.host и nifi.web.https.port.
  3. Если параметры, указанные выше, останутся заполненными, то NiFi выдаст ошибку »IllegalStateException: Only one of the HTTP and HTTPS connectors can be configured at one time».
  4. До NiFi 1.14 значение этого nifi.sensitive.props.key=<ваше_значение_ключа> параметра можно было оставлять пустым и ваш flow файл конфигурации бы не шифровался, и NiFi работал бы в нормальном режиме.

    C версией NiFi выше 1.14 необходимо указать данный ключ иначе NiFi выдаст ошибку »IllegalArgumentException: There was an issue decrypting protected properties»

  5. Параметры nifi.security.identity.mapping.* зависят от вашей компании, но их необходимо заполнить для корректной аутентификации пользователей и самих нод найфая друг с другом. Документация.
  6. Для запуска NiFi в режиме кластера необходимо указать значение True в nifi.cluster.is.node и настроить дополнительные параметры nifi.cluster.node.* по вашим приоритетам иначе нода NiFi не будет прицепляться к кластеру.
  7. При запуске на внешнем zookeeper, настройку которого мы обсуждали ранее, необходимо заполнить параметры nifi.zookeeper.*


2) conf/authorizers.xml

В файле authorizers.xml определяются значения параметров, влияющих на способ представления пользователей и групп в NiFi, и определяется базовый администратор с которого можно начать настройку кластера.

Документация

authorizers.xml


    
        file-user-group-provider
        org.apache.nifi.authorization.FileUserGroupProvider
        ./conf/users.xml
        
        nifi_habr@test
        nifiadmin
    

    
        ldap-user-group-provider
        org.apache.nifi.ldap.tenants.LdapUserGroupProvider
        SIMPLE

        cn=nifiadmin,ou=nifi-habr,ou=nifi,ou=test,ou=example,dc=com,dc=mycompany
        pass

         

        FOLLOW
        10 secs
        10 secs

        ldaps://mycompany.com:10109
        
        5 mins
        false

        DC=com,DC=mycompany
        user
        SUBTREE
        filter_users
        SamAccountName
        
        

        OU=nifi-habr,OU=nifi,OU=test,OU=example,DC=com,DC=mycompany
        group
        SUBTREE
        filter_groups
        cn
        member
        
    


    
        composite-configurable-user-group-provider
        org.apache.nifi.authorization.CompositeConfigurableUserGroupProvider
        file-user-group-provider
        ldap-user-group-provider
    

    
        file-access-policy-provider
        org.apache.nifi.authorization.FileAccessPolicyProvider
        composite-configurable-user-group-provider
        ./conf/authorizations.xml
        nifiadmin
        
        nifi_habr@test
        
        
    

    
        managed-authorizer
        org.apache.nifi.authorization.StandardManagedAuthorizer
        file-access-policy-provider
        nifiadmin
        
        nifi_habr@test
    


3) conf/login-identity-providers.xml

В данном файле мы указываем NiFi, какой провайдер будет использоваться для входа пользователей в систему. В данном случае мы используем LDAP.

login-identity-providers.xml


    
        ldap-provider
        org.apache.nifi.ldap.LdapProvider
        SIMPLE

        cn=nifiadmin,ou=nifi-habr,ou=nifi,ou=test,ou=example,dc=com,dc=mycompany
        pass

        

        FOLLOW
        10 secs
        10 secs

        ldaps://mycompany.com:10109
        DC=com,DC=mycompany
        (sAMAccountName={0})

        USE_USERNAME
        12 hours
    


При авторизации пользователя, NiFi будет обращаться к DC=com,DC=mycompany идентифицировать пользователя по его имени USE_USERNAME и хранить авторизацию данное время 12 hours. Но если данного пользователя не будет в authorizers.xml filter_users, то, скорее всего, у него не будет доступа даже к UI.

После настройки всех проблемных мест NiFi должен запуститься без особых проблем.

Настройка и запуск Apache NiFi Registry


Настройка и запуск NiFi Registry не отличается от настройки NiFi. Необходимо точно так же настроить все файлы конфигурации. 

Особое внимание следует обратить на параметры в nifi-registry.properties при связи NiFi и NiFi Registry. Именно в эти параметры влияют на их связь.

nifi-registry.properties
#...
# Identity Mapping Properties #
# Данные параметры необходимы для более быстрой нормализации идентификаторов пользователей
# Данная настройка зависит только от вашей организации. Подробная документация тут https://docs.cloudera.com/HDPDocuments/HDF3/HDF-3.2.0/nifi-system-properties/content/identity-mapping-properties.html
nifi.registry.security.identity.mapping.pattern.dn=^L=(.*?), ST=(.*?), C=(.*?), OU=(.*?), O=(.*?),.*?$
nifi.registry.security.identity.mapping.value.dn=$4@$5
nifi.registry.security.identity.mapping.transform.dn=LOWER
L=NLMK-IT, ST=Moscow, C=RU, OU=nifi, O=prod, EMAILADDRESS=sre-team@nlmk.com, CN=000_0


Запустим NiFi и NiFi registry.

Добавляем наш NiFi Registry в список доступных Settings → Controller Settings → Registry Clients.

Если при попытке сохранить изменения в NiFi Registry мы получаем ошибку: Unable to obtain listing of buckets: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target. При этом в пользовательском интерфейсе из доступных бакетов у вас будет «No Available Buckets». Чтобы убрать ошибку, здесь необходимо добавить truststore NiFi Registry в truststore NiFi и truststore NiFi в truststore NiFi Registry для запросов между кластерами (добавить доверительные сертификаты друг в друга).

Можете воспользоваться документацией. После этого данная ошибка у вас пропадет.

«No Available Buckets» самая распространенная ошибка, на которую нет нормального объяснения.
Попробую объяснить на пальцах, почему так происходит.

В официальной документации указано, что необходимо создать пользователя с правами Proxy User Request, но нет примера как этого пользователя создавать.

Рассмотрим сертификат NiFi, после его создания, владелец выглядит так:

L=mycompany, ST=Moscow, C=RU, OU=nifi_habr, O=test, EMAILADDRESS=nifihabr@mycompany.com, CN=nifi-test-node-1.mycompany
Подгоним данное значение под паттерн маппинга из файла nifi-registry.properties: 
^L=(.*?), ST=(.*?), C=(.*?), OU=(.*?), O=(.*?),.*?$
$4@$5


В итоге, когда наш кластер NiFi будет ходить в NiFi Registry, NiFi Registry, будет его аутентифицировать по значению nifi_habr@test, поэтому нам необходимо создать этого пользователя в NiFi Registry, выдать ему права Proxy User Request. Так же данный маппинг вы можете настроить по своему усмотрению, ведь теперь вы знаете, что это значит.

Настройка и запуск NiFi c протоколом взаимодействия Kerberos


Перед тем как настроить запуск NiFi c Kerberos необходимо запустить кластер zookeeper с Kerberos.

Допустим мы уже имеем созданные кейтабы для zookeeper и nifi такого вида.

zookeeper_server.keytab
Keytab name: FILE:/etc/security/keytabs/zookeeper_server.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   1 11.11.2021 15:45:18 zookeeper/nifi-test-node-1.mycompany@mycompany.com (aes256-cts-hmac-sha1-96)
   1 11.11.2021 16:13:04 zookeeper/nifi-test-node-1.mycompany@mycompany.com (aes128-cts-hmac-sha1-96)
nifi_server.keytab
Keytab name: FILE:/etc/security/keytabs/nifi_server.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   1 11.11.2021 16:52:43 nifi/nifi-test-node-1.mycompany@mycompany.com (aes256-cts-hmac-sha1-96)
   1 11.11.2021 16:52:43 nifi/nifi-test-node-1.mycompany@mycompany.com (aes128-cts-hmac-sha1-96)


Здесь я хочу заметить что тип шифрования должен совпадать с параметрами указанными в файле krb5.conf (у нас настроено так):

default_tgs_enctypes = aes256-cts aes128-cts rc4-hmac
default_tkt_enctypes = aes256-cts aes128-cts rc4-hmac
permitted_enctypes = aes256-cts aes128-cts rc4-hmac

Иначе соединения по протоколу Kerberos не произойдет.

В этом тоже есть некоторые сложности, выложу пример docker-compose файлов.

Разберем настройку Zookeeper.

docker-compose.yaml
---
version: '3.7'

services:
  zookeeper:
    image: zookeeper
    restart: always
    hostname: nifi-test-node-1.mycompany
    ports:
      - 2181:2181
      - 2888:2888
      - 3888:3888
    networks:
      - zk
    environment:
      JVMFLAGS: "-Djava.net.preferIPv4Stack=true -Djava.security.auth.login.config=/conf/jaas.conf -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.rmi.port=9010 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djute.maxbuffer=4194304 -Dsun.security.krb5.disableReferrals=true -Djdk.tls.ephemeralDHKeySize=2048 -Dzookeeper.multiAddress.enabled=true"
    volumes:
      - zk_data:/data
      - zk_datalog:/datalog
      - zk_logs:/logs
      - /etc/security/keytabs/zookeeper_server.keytab:/zookeeper.keytab:ro
      - /etc/krb5.conf:/etc/krb5.conf:ro
      - ./jaas.conf:/conf/jaas.conf:ro
      - ./zoo.cfg:/conf/zoo.cfg:ro

volumes:
  zk_data: {}
  zk_datalog: {}
  zk_logs: {}
networks:
  zk:
    name: zk
...


В данной настройке необходимо установить флаги JVM и прокинуть дополнительные конфигурационные файлы, связанные с Kerberos.

Можете взять файлы настройки в качестве примера, значения их можете посмотреть в документации.

jaas.conf
Server {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  keyTab="/zookeeper.keytab"
  storeKey=true
  useTicketCache=false
  principal="zookeeper/nifi-test-node-1.mycompany@mycompany.com";
};

 QuorumServer {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  keyTab="/zookeeper.keytab"
  storeKey=true
  useTicketCache=false
  principal="zookeeper/nifi-test-node-1.mycompany@mycompany.com";
};

 QuorumLearner {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  keyTab="/zookeeper.keytab"
  storeKey=true
  useTicketCache=false
  principal="zookeeper/nifi-test-node-1.mycompany@mycompany.com";
};
zoo.cfg
jaasLoginRenew=3600000
requireClientAuthScheme=sasl
tickTime=2000
initLimit=300
syncLimit=10
4lw.commands.whitelist=conf,cons,crst,dirs,dump,envi,gtmk,ruok,stmk,srst,srvr,stat,wchs,mntr,isro
dataDir=/data/
dataLogDir=/datalog/
clientPort=2181
maxClientCnxns=2000
minSessionTimeout=4000
maxSessionTimeout=60000000
autopurge.purgeInterval=1
autopurge.snapRetainCount=10
quorum.auth.enableSasl=true
quorum.cnxn.threads.size=20
admin.enableServer=false
admin.serverPort=5181
leaderServes=yes
authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
kerberos.removeHostFromPrincipal=true
kerberos.removeRealmFromPrincipal=true
quorum.auth.kerberos.servicePrincipal=zookeeper/_HOST
quorum.auth.learnerRequireSasl=true
quorum.auth.serverRequireSasl=true
preAllocSize=131072
snapCount=3000000
server.1=nifi-test-node-1.mycompany:2888:3888
server.2=nifi-test-node-2.mycompany:2888:3888
server.3=nifi-test-node-3.mycompany:2888:3888


Так же для вашей компании необходимо сконфигурировать krb5.conf файл, можно воспользоваться документацией. После этого можно запустить кластер Zookeeper дождаться соединения всех нод и идти настраивать NiFi.

Настройка и запуск Apache NiFi c Kerberos


Здесь я хочу сделать акцент на изменения, которые вам необходимо сделать. Авторизацию пользователя мы оставим через LDAP, но если вы хотите сделать через Kerberos  можете воспользоваться документацией. 

Пример конфигурации можете взять из настройки NiFi выше.

В настройке появляется файл клиента zookeeper-jaas.conf

zookeeper-jaas.conf
Client {
	com.sun.security.auth.module.Krb5LoginModule required debug=true
	useKeyTab=true
	storeKey=true
	doNotPrompt=true
	useTicketCache=false
	keyTab="/etc/security/keytabs/nifi.keytab"
	principal="nifi/nifi-test-node-1.mycompany@mycompany.com";
};


Данный файл прокидывается в аргументы запуска Java в файле bootstrap.conf

bootstrap.conf
# ...
java.arg.18=-Djava.security.auth.login.config=./conf/zookeeper-jaas.conf
# ...
В настройках nifi.properties необходимо указать параметры 
nifi.properties
# ...
nifi.zookeeper.auth.type=sasl
nifi.zookeeper.kerberos.removeHostFromPrincipal=true
nifi.zookeeper.kerberos.removeRealmFromPrincipal=true

# kerberos #
nifi.kerberos.krb5.file=/etc/krb5.conf

# kerberos service principal #
nifi.kerberos.service.principal=nifi/nifi-test-node-1.mycompany@AO.NLMK
nifi.kerberos.service.keytab.location=/etc/security/keytabs/nifi.keytab

# ...


Если не указать параметр nifi.kerberos.service.principal или указать его не корректно, NiFi не будет запускаться и будет выдавать данную ошибку java.lang.IllegalArgumentException: No Kerberos Principal configured for use with SASL Authentication Scheme.

Надеюсь, когда люди будут гуглить Exception в NiFi, они будут сразу попадать на эту статью, и это реально облегчит им жизнь.

© Habrahabr.ru