Apache Nifi 是一个非常强大的信息流管理工具。它自带的UI界面以及其所使用的流程图构建信息流的方式都使得一般用户很容易上手。除此之外Nifi还有更多强大的功能,例如用户验证授权,集群模式,等等。正因为有那么多的功能,可能会使刚上手的管理员有点手足无措。今天我们就来看看,如何通过设置Nifi的用户验证及授权来保护你的Nifi信息流。本篇先着重介绍身份验证模块。授权验证模块以及更多内容会在下篇描述。
概述
首先要解释清楚的是,身份验证(Authentication)以及授权验证(Authorization)在Nifi里面是两个相当独立的模块。其中身份验证主要的任务是确认当前操作用户是否真的是声称的身份。当用户的身份被证实以后,它的用户名会被传递到授权验证模块,而授权验证模块会在它的数据库里面查找该用户名,并确认该用户有什么权限。打个比喻,如果你想进入一个商业写字楼,门口保安可能会拦住你要查看你的身份证(身份验证)。然后他会从一个员工名册上查找你的名字(授权验证)。只有当你的名字出现在名册上时你才会被放行。
下图表明了Nifi中这两个系统间的关系。当用户试图访问Nifi时,他必须首先通过身份验证。身份验证的时候Nifi可能需要参考一个外部的身份数据库(Identity Provider),如LDAP,Kerberos,OpenID Connect等。当确认你的身份后,你的用户名会被送到授权验证模块进一步核对。授权模块在确认你的权限时也需要参考一个身份数据库(可以是一个文档,或者是LDAP服务器)以及一个记录着用户身份与权限对应关系的数据库。
从上图可以看出,身份验证和权限验证是完全可以采用不同的身份数据库的。所以我们说这两个系统相当独立,唯一把他们连接在一起的就是用户名的传递。我们今天先着重讲身份验证部分。
基本设置
Nifi支持好几种用户验证方式:TLS
, LDAP
, Kerberos
, OpenID Connect
, Apache Knox
等。今天我们主要介绍TLS
以及LDAP
两种方式。只要弄明白这两种,其余方式的设置都很类似。
要开启用户验证功能,我们首先必须设置Nifi,使之只接受https
安全连接。要达到这个目的,我们需要更改位于./conf
目录下的nifi.properties
设置文件里的以下几项属性:
-
nifi.web.http.port
:去除原来的8080
,使该行变为nifi.web.http.port=
,防止用户从非加密的http端口访问 -
nifi.web.https.host
:设为运行Nifi的主机名字,例如host-01
-
nifi.web.https.port
:我们用8443
作为https
端口 -
nifi.security.keystore
:keystore的路径,例如/opt/nifi/secrets/keystore.jks
-
nifi.security.keystoreType
:设为JKS
-
nifi.security.keystorePasswd
:keystore的密码。 -
nifi.security.truststore
:truststore的路径,例如/opt/nifi/secrets/truststore.jks
-
nifi.security.truststoreType
:设为JKS
-
nifi.security.truststorePasswd
:truststore的密码。 -
nifi.remote.input.secure
:设为true
,使得Nifi之间的Site-to-Site通信也用加密的方式。
关于如何为 Nifi 生成 keystore 和 truststore,请看我的另一篇文章。
当这一切都设置好以后,重启Nifi,你会发现原来的http端口无法访问了,当你试图访问https的端口的时候,却出现如下的错误信息。这是为什么呢?
TLS 身份验证
出现错误信息的原因是你没通过Nifi的身份验证。当你通过以上这种最基础的设置方式来开启Nifi加密模式以后,Nifi会使用TLS方式来验证访问的用户。这种方式是通过对访问用户进行TLS客户端证书验证来实现的。我们知道,当访问https网站的时候,浏览器会进行服务器证书验证。验证内容包括证书是否由可信的CA签署,是否被篡改,是否对应我们正在访问的网址等等。大多数情况这些网站不会要求验证我们的客户端证书。然而Nifi的UI不一样,它需要通过你的客户端证书来验证你的身份。你的客户端证书必须是由被truststore
信任的证书所签署的才会被Nifi认为有效。而你的用户名则来自你证书的Subject
一栏,通常是以CN=user, OU=nifi, C=DE
这样的形式出现。需要注意的是,这种身份验证方法并不依靠外部的身份数据库。实际上,只要你的证书是经过truststore
里面的证书所签署的,无论你的用户名是什么,身份验证都会通过。
参考上述关于生成Java keystore的文章,假设我们已经进行好了基本设置,并且也生成了一个受信任的客户端证书并导入到了浏览器中。如果你现在去访问之前发生错误的https端口,你会发现现在能够进入Nifi的界面了,但是又出现了一个新的错误:
造成这个错误的原因是,即使我们通过了身份验证,但是授权验证失败了。我们的用户名CN=user, OU=nifi
被认为没有访问UI的权限,所以出现了上图的错误信息。关于如何给予该用户权限,请看本文的下篇。
LDAP 身份验证
TLS验证虽然设置简单,但是用户多的话管理难度大。为此 Nifi 提供了其他的验证方式。LDAP是其中的一种方法。这种验证方式不需要进行TLS客户端证书验证,而是采用我们平时最常用的用户名密码登录方式。它的用户名和密码数据库来自于一个LDAP服务器。LDAP (Lightweight Directory Access Protocol) 是一种用于获取目录信息的通讯协议。企业中很常用LDAP服务器储存组织结构及人员信息。与TLS验证不同,当Nifi使用LDAP作为身份验证的时候,用户必须提供存在于LDAP服务器数据库里的用户名及密码才能验证成功。当用户验证成功后,该用户条目的Distinguished Name(DN)会被作为用户名送到授权模块去进行验证。在LDAP中,一个用户的DN一般有与客户端证书Subject
栏相似的形式,例如CN=john,OU=development,DC=example,DC=com
。
想要使用LDAP验证,首先你需要在./conf/nifi.properties
设置一下属性:
nifi.security.user.login.identity.provider=ldap-provider
这相当于告诉Nifi,你要使用一个外部的LDAP服务器来对用户进行身份验证。但是你怎么告诉Nifi你的服务器地址以及如何跟它建立连接呢?Nifi默认会从./conf/login-identity-provider.xml
这个文件中寻找这些设置。相关的有以下所列的属性:
<provider>
<identifier>ldap-provider</identifier>
<class>org.apache.nifi.ldap.LdapProvider</class>
<property name="Authentication Strategy"></property>
<property name="Manager DN"></property>
<property name="Manager Password"></property>
<property name="TLS - Keystore"></property>
<property name="TLS - Keystore Password"></property>
<property name="TLS - Keystore Type"></property>
<property name="TLS - Truststore"></property>
<property name="TLS - Truststore Password"></property>
<property name="TLS - Truststore Type"></property>
<property name="TLS - Client Auth"></property>
<property name="TLS - Protocol"></property>
<property name="TLS - Shutdown Gracefully"></property>
<property name="Referral Strategy">FOLLOW</property>
<property name="Connect Timeout">10 secs</property>
<property name="Read Timeout">10 secs</property>
<property name="Url"></property>
<property name="User Search Base"></property>
<property name="User Search Filter"></property>
<property name="Identity Strategy">USE_DN</property>
<property name="Authentication Expiration">12 hours</property>
</provider>
其中这里选取几项常用属性进行说明。
属性名称 | 说明 |
---|---|
Authentication Strategy | 验证策略。指的是Nifi如何与LDAP服务器连接。可以选择 - ANONYMOUS : 匿名连接- SIMPLE :使用已存在于LDAP服务器中的用户名-密码连接- LDAPS :LDAPS协议连接- START_TLS :使用TLS连接 |
Manager DN | 如果验证策略不是ANONYMOUS ,那么Nifi将以Manager DN 这个身份来跟LDAP服务器进行bind连接,例如cn=admin,dc=example,dc=com 。该用户必须已存在于LDAP服务器中。 |
Manager Password | Manager用户的密码 |
Url | LDAP服务器的Url,可以设置多个Url,要用空格相互隔开。 |
User Search Base | 用于搜索用户的基本DN(Base DN),如ou=people,dc=example,dc=com 。 |
User Search Filter | 用于搜索用户的标准,例如可以设置为uid={0} ,其中{0} 指的是用户在UI界面登录Nifi时所输入的用户名。这样,结合User Search Base ,Nifi将会查找DN为uid={0},ou=people,dc=example,dc=com 的用户。 |
Identity Strategy | 可选USE_DN 或者USE_USERNAME 。如果选USE_DN ,则用户的完整DN会被送到权限验证模块;如果选择USE_USERNAME ,那么只有用户输入到UI界面的用户名会被送到权限验证模块。 |
以下示例展示了一些基本设置。该设置会使Nifi连接位于ldap:389
的非加密LDAP服务器。
<provider>
<identifier>ldap-provider</identifier>
<class>org.apache.nifi.ldap.LdapProvider</class>
<property name="Authentication Strategy">SIMPLE</property>
<property name="Manager DN">cn=admin,dc=example,dc=com</property>
<property name="Manager Password">SuperSecret</property>
<property name="TLS - Keystore"></property>
<property name="TLS - Keystore Password"></property>
<property name="TLS - Keystore Type"></property>
<property name="TLS - Truststore"></property>
<property name="TLS - Truststore Password"></property>
<property name="TLS - Truststore Type"></property>
<property name="TLS - Client Auth"></property>
<property name="TLS - Protocol"></property>
<property name="TLS - Shutdown Gracefully"></property>
<property name="Referral Strategy">FOLLOW</property>
<property name="Connect Timeout">10 secs</property>
<property name="Read Timeout">10 secs</property>
<property name="Url">ldap://ldap:389</property>
<property name="User Search Base">ou=people,dc=example,dc=com</property>
<property name="User Search Filter">uid={0}</property>
<property name="Identity Strategy">USE_DN</property>
<property name="Authentication Expiration">12 hours</property>
</provider>
LDAP服务器上应该有以下的条目:
# LDAP default admin user
dn: cn=admin,dc=example,dc=com
objectclass:top
objectclass:person
cn: admin
sn: Admin
userPassword:SuperSecret
# entry for the user container
dn: ou=people,dc=example,dc=com
objectclass:top
objectclass:organizationalUnit
ou: people
# entry for Nifi user
dn: uid=user,ou=people,dc=example,dc=com
objectclass:top
objectclass:person
objectclass:organizationalPerson
objectclass:inetOrgPerson
cn: User
sn: User
uid: user
userPassword:UserSecret
这样,当你访问Nifi的UI时,输入用户名user
,密码UserSecret
(如下图),你就能够通过Nifi的身份验证 。
然而,正如前一小节结尾处所说,即使你通过了身份验证,但是你还是会遇到以下错误信息:
该错误信息产生的原因正是因为你的用户只通过了身份验证,但是没通过权限验证。因此,我们的用户被拒绝访问Nifi的主界面。在下一篇文章,我们将继续来看看如何在Nifi中设置用户权限。