Note: This is not a question, I'm providing information that may help others.
Hi all,
I recently spent way too much time beating my head against the keyboard trying to work out how to connect Nifi to a Nifi registry in a corporate environment. After eventually working it out I thought I'd post my findings here to save the next poor soul that comes along seeking help with Nifi and Nifi registry.
Apologies in advance for the long post, but I thought the details would be useful.
I had a requirement to setup containerised instances of Nifi and Nifi-registry, both backed by LDAP, leveraging corporate SSL certificates and using an internal Container registry (no direct Internet access). As of this morning, this is now working, here's an overview of how I got it to work on RHEL 8 servers:
In a corporate environment the hosts need SSL certs setup for HTTPS, and to ensure they can communicate securely.
SSL Cert setup
Generate SSL private keys for each host in a Java keystore on the respective machines
Generate CSRs from the keystores, with appropriate SANs as required
Get CSRs Signed - Ensure that the "Client Auth" and "Server Auth" Extended Key Usage attributes are set for the Nifi cert (This is required for Nifi to successfully connect to a Nifi Registry). The registry cert just needs the Server Auth attribute.
Import corporate CA chain into the keystores, to ensure full trust chain of the signed cert is resolvable
Create a Java keystore (truststore) containing the CA cert chain
I can provide further details of the above steps if needed
Now that we have some SSL certs, the steps to setup the containers were as follows:
Container setup
Install podman (or docker if you prefer)
For Podman - Update the /etc/containers/registries.conf to turn off the default container registries
For Podman - Update /usr/share/containers/libpod.conf to replace the path to the pause container with the path the container in our internal registry
Setup folders for the containers, ensuring they have an SELinux file context of "container_file_t", and have permissions of 1000:1000 (UID & GID of nifi user in the containers).
Setup an ENV file to define all of the environment variables to pass to the containers (there's a lot for Nifi and the Registry, they each share this info). This saves a lot of CLI parameters, and stops passwords appearing in the process list (note password encryption for nifi is possible, but not covered in this post).
KEYSTORE_PATH=/path/to/keystore.jks
TRUSTSTORE_PATH=/path/to/truststore.jks
KEYSTORE_TYPE=JKS
TRUSTSTORE_TYPE=JKS
KEYSTORE_PASSWORD=InsertPasswordHere
TRUSTSTORE_PASSWORD=InsertPasswordHere
LDAP_AUTHENTICATION_STRATEGY=LDAPS
LDAP_MANAGER_DN=CN=service account,OU=folder its in,DC=domain,DC=com
LDAP_MANAGER_PASSWORD=InsertPasswordHere
LDAP_TLS_KEYSTORE=/path/to/keystore.jks
LDAP_TLS_TRUSTSTORE=/path/to/truststore.jks
LDAP_TLS_KEYSTORE_TYPE=JKS
LDAP_TLS_TRUSTSTORE_TYPE=JKS
LDAP_TLS_KEYSTORE_PASSWORD=InsertPasswordHere
LDAP_TLS_TRUSTSTORE_PASSWORD=InsertPasswordHere
LDAP_TLS_PROTOCOL=TLSv1.2
INITIAL_ADMIN_IDENTITY=YourUsername
AUTH=ldap
LDAP_URL=ldaps://dc.domain.com:636
LDAP_USER_SEARCH_BASE=OU=user folder,DC=domain,DC=com
LDAP_USER_SEARCH_FILTER=cn={0}
LDAP_IDENTITY_STRATEGY=USE_USERNAME
Start both the Nifi & Nifi-Registry containers, and copy out the contents of their respective conf folders to the host (/opt/nifi-registry/nifi-registry-current/conf and /opt/nifi/nifi-current/conf). This allows us to customise and persist the configuration.
Modify the conf/authorizers.xml file for both Nifi and the Nifi-registry
to setup LDAP authentication, and add a composite auth provider (allowing both local & ldap users). We need both in order to add user locals accounts for any Nifi nodes connecting to the registry (can be done via LDAP, but is easier this way).
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<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="Legacy Authorized Users File"></property>
<!--<property name="Initial User Identity 1"></property>-->
</userGroupProvider>
<userGroupProvider>
<identifier>ldap-user-group-provider</identifier>
<class>org.apache.nifi.ldap.tenants.LdapUserGroupProvider</class>
<property name="Authentication Strategy">LDAPS</property>
<property name="Manager DN">CN=service account,OU=folder its in,DC=domain,DC=com</property>
<property name="Manager Password">InsertPasswordHere</property>
<property name="TLS - Keystore">/path/to/keystore.jks</property>
<property name="TLS - Keystore Password">InsertPasswordHere</property>
<property name="TLS - Keystore Type">JKS</property>
<property name="TLS - Truststore">/path/to/truststore.jks</property>
<property name="TLS - Truststore Password">InsertPasswordHere</property>
<property name="TLS - Truststore Type">jks</property>
<property name="TLS - Client Auth">WANT</property>
<property name="TLS - Protocol">TLS</property>
<property name="TLS - Shutdown Gracefully">true</property>
<property name="Referral Strategy">FOLLOW</property>
<property name="Connect Timeout">10 secs</property>
<property name="Read Timeout">10 secs</property>
<property name="Url">ldaps://dc.domain.com:636</property>
<property name="Page Size"/>
<property name="Sync Interval">30 mins</property>
<property name="User Search Base">OU=user folder,DC=domain,DC=com</property>
<property name="User Object Class">user</property>
<property name="User Search Scope">ONE_LEVEL</property>
<property name="User Search Filter"/>
<property name="User Identity Attribute">cn</property>
<property name="Group Search Base">OU=group folder,DC=domain,DC=com</property>
<property name="Group Object Class">group</property>
<property name="Group Search Scope">ONE_LEVEL</property>
<property name="Group Search Filter"/>
<property name="Group Name Attribute">cn</property>
<property name="Group Member Attribute">member</property>
<property name="Group Member Attribute - Referenced User Attribute"/>
</userGroupProvider>
<userGroupProvider>
<identifier>composite-user-group-provider</identifier>
<class>org.apache.nifi.authorization.CompositeConfigurableUserGroupProvider</class>
<property name="Configurable User Group Provider">file-user-group-provider</property>
<property name="User Group Provider 1">ldap-user-group-provider</property>
</userGroupProvider>
<accessPolicyProvider>
<identifier>file-access-policy-provider</identifier>
<class>org.apache.nifi.authorization.FileAccessPolicyProvider</class>
<property name="User Group Provider">composite-user-group-provider</property>
<property name="Authorizations File">./conf/authorizations.xml</property>
<property name="Initial Admin Identity">YourUsername</property>
<property name="Legacy Authorized Users File"></property>
<property name="Node Identity 1">DN of Nifi Instance (OPTIONAL - more details on this later)</property>
<property name="Node Group"></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>
Performance Mod - Optional - Modify conf/bootstrap.conf to increase the Java Heap Size (if required). Also update Security limits (files & process limits).
Extract the OS Java keystore from the containers, and add the corporate cert chain to it. Note: Nifi and nifi-registry java keystores are in slightly different locations in the containers. I needed to inject CA certs into these keystores to ensure Nifi processors can resolve SSL trust chains (I needed this primarily for a number of custom nifi processors we wrote which interrogated LDAP).
Run the containers, mounting volumes for persistent data and include your certs folder and the OS Java keystores:
podman run --name nifi-registry \
--hostname=$(hostname) \
-p 18443:18443 \
--restart=always \
-v /path/to/certs:/path/to/certs \
-v /path/to/OS/Java/Keystore:/usr/local/openjdk-8/jre/lib/security/cacerts:ro \
-v /path/to/nifi-registry/conf:/opt/nifi-registry/nifi-registry-current/conf \
-v /path/to/nifi-registry/database:/opt/nifi-registry/nifi-registry-current/database \
-v /path/to/nifi-registry/extension_bundles:/opt/nifi-registry/nifi-registry-current/extension_bundles \
-v /path/to/nifi-registry/flow_storage:/opt/nifi-registry/nifi-registry-current/flow_storage \
-v /path/to/nifi-registry/logs:/opt/nifi-registry/nifi-registry-current/logs \
--env-file /path/to/.env/file \
-d \
corporate.container.registry/apache/nifi-registry:0.7.0
podman run --name nifi \
--hostname=$(hostname) \
-p 443:8443 \
--restart=always \
-v /path/to/certs:/path/to/certs \
-v /path/to/certs/cacerts:/usr/local/openjdk-8/lib/security/cacerts:ro \
-v /path/to/nifi/logs:/opt/nifi/nifi-current/logs \
-v /path/to/nifi/conf:/opt/nifi/nifi-current/conf \
-v /path/to/nifi/database_repository:/opt/nifi/nifi-current/database_repository \
-v /path/to/nifi/flowfile_repository:/opt/nifi/nifi-current/flowfile_repository \
-v /path/to/nifi/content_repository:/opt/nifi/nifi-current/content_repository \
-v /path/to/nifi/provenance_repository:/opt/nifi/nifi-current/provenance_repository \
-v /path/to/nifi/state:/opt/nifi/nifi-current/state \
-v /path/to/nifi/extensions:/opt/nifi/nifi-current/extensions \
--env-file /path/to/.env/file \
-d \
corporate.container.registry/apache/nifi:1.11.4
Note: Please ensure that the SELinux contexts (if applicable to your OS), and permissions (1000:1000) are correct for the mounted volumes prior to starting the containers.
Configuring the Containers
Browse to https://hostname.domain.com/nifi (we redirected 8443 to 443) and https://hostname2.domain.com:18443/nifi-registry
Login to both as the initial admin identity you provided in the config files
Add a new user account using the full DN of the SSL certificate, e.g. CN=machinename, OU=InfoTech, O=Big Company, C=US. This account is needed on both ends for Nifi & the registry to connect and getting the name correct is important. There's probably an easier way to determine the DN, but I reverse engineered after inspecting the cert in a browser. I took everything listed under the "Subject Name" heading and wrote it out from the bottom entry up.
Set permissions for the account in nifi, adding "Proxy User Request", "Access the controller (view)" and "Access the controller (modify)".
Set permissions for account in nifi registry, adding "Can proxy user request", "Read buckets".
Set other user/group permissions as needed
Setup and Connect to the Registry
Create a bucket in Nifi Registry
In Nifi (Controller Settings -> Registry Clients), add the url of the registry: https://hostname.domain.com:18443.
Select a Processor or Process group, right-click, Version -> Start Version Control
That should be it!
I found that Nifi is terrible at communicating errors when connecting to the registry. I got a range of errors whilst attempting to connect. The only way to get useful errors is to add a new entry to conf/bootstrap.conf on the nifi registry:
java.arg.XX=--Djavax.net.debug=ssl,handshake
After restarting the Nifi Registry container you should start seeing SSL debug information in logs/nifi-registry-bootstrap.log.
e.g. When Nifi was reporting "Unknown Certificate", the Nifi Registry debug logs contained:
INFO [NiFi logging handler] org.apache.nifi.registry.StdOut sun.security.validator.ValidatorException: Extended key usage does not permit use for TLS client authentication
I hope this is helpful.
I am deploying hive-metastore-3.0.0 using kerberos over DC/OS I have generated principal and keytab correctly and verified the same but while providing repective settings in metastore-site.xml still server showing error "Kerberos principal should have 3 parts:" its by default pickup my user "nobody or root" by which I run service but not the principal.
Rquest you to please help is there any addition property I have to set ?
My metastore-site.xml is:
<name>hive.metastore.sasl.enabled</name>
<value>true</value>
<description>If true, the metastore thrift interface will be secured with SASL. Clients must authenticate with Kerberos.</description>
</property>
<property>
<name>hive.metastore.kerberos.keytab.file</name>
<value>hive-metastore.keytab</value>
<description>The path to the Kerberos Keytab file containing the metastore thrift server's service principal.</description>
</property>
<property>
<name>hive.metastore.kerberos.principal</name>
<value>hive-metastore/node-0-server.hive-metastore.autoip.dcos.thisdcos.directory#LOCAL</value>
<description>The service principal for the metastore thrift server. The special string _HOST will be replaced automatically with the correct host name.</description>
</property>
<property>
<name>hive.metastore.authentication</name>
<value>KERBEROS</value>
<description>authenticationtype</description>
</property>```
I'm trying to setup SSL in Zeppelin and after following the instructions and all related Google searches, the zeppelin service status says it's ok but the web response is ERR_CONNECTION_REFUSED
These are the parts of the zeppelin-site.xml I modified
<property>
<name>zeppelin.ssl</name>
<value>true</value>
<description>Should SSL be used by the servers?</description>
</property>
<property>
<name>zeppelin.ssl.client.auth</name>
<value>false</value>
<description>Should client authentication be used for SSL connections?</description>
</property>
<property>
<name>zeppelin.ssl.keystore.path</name>
<value>/opt/zeppelin/lib/keystore</value>
<description>Path to keystore relative to Zeppelin configuration directory</description>
</property>
<property>
<name>zeppelin.ssl.keystore.type</name>
<value>JKS</value>
<description>The format of the given keystore (e.g. JKS or PKCS12)</description>
</property>
<property>
<name>zeppelin.ssl.keystore.password</name>
<value><super secret password></value>
<description>Keystore password. Can be obfuscated by the Jetty Password tool</description>
</property>
<property>
<name>zeppelin.ssl.truststore.path</name>
<value>/opt/zeppelin/lib/keystore</value>
<description>Path to truststore relative to Zeppelin configuration directory. Defaults to the keystore path</description>
</property>
<property>
<name>zeppelin.ssl.truststore.type</name>
<value>JKS</value>
<description>The format of the given truststore (e.g. JKS or PKCS12). Defaults to the same type as the keystore type</description>
</property>
Then this is the service status, which says I'm running but in actuality the web page returns an error:
● zeppelin.service - Zeppelin service
Loaded: loaded (/etc/systemd/system/zeppelin.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2019-05-09 18:26:41 UTC; 28s ago
Process: 347 ExecStop=/opt/zeppelin/bin/zeppelin-daemon.sh stop (code=exited, status=0/SUCCESS)
Process: 413 ExecStart=/opt/zeppelin/bin/zeppelin-daemon.sh start (code=exited, status=0/SUCCESS)
Main PID: 441 (java)
Tasks: 39 (limit: 4662)
CGroup: /system.slice/zeppelin.service
└─441 java -Dfile.encoding=UTF-8 -Xms1024m -Xmx1024m -XX:MaxPermSize=512m -Dlog4j.configuration=file:///opt/zeppelin/conf/log4j.properties -Dzeppelin.log.file=/opt/zeppelin/logs/zeppelin-zeppelin-myserver.log -cp ::/op
You should set zeppelin.ssl property to true :
<property>
<name>zeppelin.ssl</name>
<value>true</value>
<description>Should SSL be used by the servers?</description>
</property>
I am trying to connect Beeline with HiveServer2 and i am getting the below alert.
Need help to connect Beeline with HiveServer2.
[hdpsysuser#hdpmaster bin]$ beeline
which: no hbase in (/usr/local/bin:/usr/local/sbin:/enter code here usr/bin:/usr/sbin:/bin:/sbin:/home/hdpuser/.local/bin:/home/hdpuser/bin:/home/hdpsysuser/.local/bin:/home/hdpsysuser/bin:/usr/hadoopsw/hadoop-2.7.3/sbin:/usr/hadoopsw/hadoop-2.7.3/bin:/usr/hadoopsw/hive/bin:/usr/hadoopsw/db-derby-10.13.1.1-bin/bin)
Beeline version 2.1.1 by Apache Hive
beeline> show tables;
No current connection
beeline> !connect jdbc:hive2://hdpmaster:10000
Connecting to jdbc:hive2://hdpmaster:10000
Enter username for jdbc:hive2://hdpmaster:10000: hdpsysuser
Enter password for jdbc:hive2://hdpmaster:10000: **********
17/05/09 01:51:20 [main]: WARN jdbc.HiveConnection: Failed to connect to
hdpmaster:10000
Error: Could not open client transport with JDBC Uri:
jdbc:hive2://hdpmaster:10000: Failed to open new session: java.lang.RuntimeException:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hdpsysuser is not allowed to impersonate hdpsysuser (state=08S01,code=0)
add below property in hive-site.xml in hive conf
<property>
<name>hive.server2.enable.doAs</name>
<value>true</value>
</property>
Also if you want user ABC to impersonate all(*), add below properties to your
core-site.xml
<property>
<name>hadoop.proxyuser.ABC.groups</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.ABC.hosts</name>
<value>*</value>
</property>
Failed to open new session: java.lang.RuntimeException:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException):
User: hadoop is not allowed to impersonate cheng
User:hadoop is my hadoop install use,and cheng is ubuntu user.
I have already the following configuration in my core-site.xml:
<name>hadoop.proxyuser.hive.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hive.groups</name>
<value>*</value>
</property>
the hive user is not exist before,so I change the hadoop.proxyuser.hive.groups to
hadoop.proxyuser.hadoop.group and so on.in hue config hue.ini,set the hue user.
so the problem is solution.