NiFi 의 프로세스 그룹에서 버전 관리를 시작하려고 하면 다음이 뜬다.
Unable to obtain listing of buckets:
java.net.ConnectException: Connection refused (Connection refused)
이 오류는 NiFi 노드에서 Registry 로 나가는 연결이 실패한 것이다. 브라우저에서 Registry UI 가 열리는 것과는 무관하다. 브라우저는 사용자의 PC 에서, 이 연결은 NiFi 노드에서 나간다.
NiFi 노드에서 직접 확인한다.
curl -kv https://<REGISTRY_HOST>:18443/nifi-registry-api/buckets
nc -vz <REGISTRY_HOST> 18443
기본 포트는 HTTP 18080, HTTPS 18443 이다. Registry 가 특정 주소에만 바인딩돼 있으면 다른 노드에서 닿지 않는다.
grep -n 'nifi.registry.web' /etc/nifi-registry/conf/nifi-registry.properties
ss -lntp | grep 1808
Cloudera Manager 로 관리하는 구성에서 nifi.registry.client.url 을 비워 두면 기본값이 들어가는 것이 아니라 빈 값 그대로 반영된다. NiFi UI 의 Registry Client 목록에는 항목이 보이지만 주소가 없어 모든 호출이 실패한다. 화면에 등록된 것처럼 보이므로 원인을 찾기 어렵다.
NiFi 가 실제로 무엇을 보고 있는지는 REST 로 확인하는 것이 확실하다.
curl -sk -u '<USER>:${PASSWORD}' \
https://<NIFI_HOST>:8443/nifi-api/controller/registry-clients | python3 -m json.tool
NiFi 화면에 보이는 버킷 목록과 Registry 화면의 버킷이 다르다면 서로 다른 Registry 인스턴스를 보고 있는 것이다. 위 출력의 URL 을 그대로 curl 로 두드려 어느 쪽인지 확정한다.
curl -sk https://<REGISTRY_HOST>:18443/nifi-registry-api/buckets | python3 -m json.tool
curl: (51) SSL: no alternative certificate subject name matches target host name
javax.net.ssl.SSLPeerUnverifiedException: No subject alternative DNS name matching <HOST> found
접속에 쓰는 이름이 서버 인증서의 SAN 에 없다는 뜻이다. CN 에만 있고 SAN 에 없으면 요즘 클라이언트는 모두 거부한다.
인증서에 무엇이 들어 있는지 본다.
openssl s_client -connect <REGISTRY_HOST>:18443 -servername <REGISTRY_HOST> </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates -ext subjectAltName
openssl s_client 는 TLS 클라이언트로 실제 핸드셰이크를 해 보는 도구다. 서버가 보내는 인증서 체인을 그대로 볼 수 있어, 파일로 가지고 있는 인증서와 서버가 실제로 내주는 인증서가 같은지 대조할 때 쓴다.
해결은 둘 중 하나다. 접속 URL 을 SAN 에 있는 이름으로 바꾸거나, 그 이름을 SAN 에 포함한 인증서를 다시 발급한다. NiFi 쪽에서는 Registry Client 에 지정한 SSLContextService 가 Registry 의 인증서를 신뢰하는 truststore 를 가리켜야 한다.
keytool -list -v -keystore /etc/nifi/conf/truststore.jks -storepass "${TRUSTSTORE_PASSWORD}" | grep -i 'alias\|owner'
SSLContextService 를 지정하지 않으면 NiFi 는 HTTP 로만 Registry 에 붙을 수 있다. HTTPS Registry 를 쓰면서 이것을 비워 두는 것이 연결 실패의 흔한 원인이다.
FileAccessPolicyProvider 를 쓰면 사용자와 정책이 두 XML 파일에 저장된다.
| 파일 | 내용 |
|---|---|
users.xml |
사용자와 그룹 |
authorizations.xml |
정책 |
경로는 nifi-registry.properties 가 아니라 authorizers.xml 에서 제공자별로 지정한다. 여기를 혼동하면 "설정했는데 반영되지 않는다" 가 된다.
<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">/var/lib/nifiregistry/authorizations.xml</property>
<property name="Initial Admin Identity">CN=admin, OU=NIFI</property>
</accessPolicyProvider>
두 파일 모두 NiFi Registry 프로세스 계정이 읽고 쓸 수 있어야 한다. 읽기 전용으로 두면 초기 생성 단계에서 실패한다.
ls -l /var/lib/nifiregistry/{users,authorizations}.xml
chown nifiregistry:nifiregistry /var/lib/nifiregistry/{users,authorizations}.xml
chmod 640 /var/lib/nifiregistry/{users,authorizations}.xml
users.xml 을 열면 사용자 식별자가 사람이 읽을 수 없는 값이다.
<tenants>
<groups/>
<users>
<user identifier="885285a4-55f9-3e55-94df-2f0377861732" identity="etladmin"/>
</users>
</tenants>
identity 가 실제 신원이고 identifier 는 내부 참조용 UUID 다. 정책 파일은 이 UUID 로 사용자를 가리키므로, 두 파일의 값이 서로 맞아야 한다. 손으로 UUID 를 지어내 넣으면 정책이 아무에게도 적용되지 않는다.
그래서 이 파일들은 직접 편집하기보다 다음 중 하나로 다룬다. Registry UI 에서 사용자와 정책을 추가한다. 또는 초기 구성이라면 두 파일을 지우고 Initial Admin Identity 만 지정해 다시 생성시킨 뒤 UI 로 마저 설정한다.
systemctl stop nifi-registry
mv /var/lib/nifiregistry/users.xml{,.bak}
mv /var/lib/nifiregistry/authorizations.xml{,.bak}
systemctl start nifi-registry
Initial Admin Identity 는 최초 생성 때만 반영된다. 이미 파일이 있으면 값을 바꿔도 아무 일도 일어나지 않는다.
그룹을 지정하지 않아도 NiFi 연동 자체에는 문제가 없다. 다만 NiFi 노드가 Registry 에 접근할 때 쓰는 신원(노드 인증서의 DN 또는 Kerberos principal)에 프록시·읽기 권한이 없으면 버킷 목록이 비어 보인다. 사용자만 등록하고 NiFi 노드 신원을 빠뜨리는 실수가 흔하다.