Knox - stanislawbartkowski/hdpactivedirectory GitHub Wiki

Knox and Active Directory

This page describes how to enable Knox for Active Directory. As a default, Knox is enabled for OpenLDAP demo provided with HDP which is enough for demonstration but not recommended for production.
There are two types of authentication in Knox which excludes themselves. The default is AD/LDAP authentication based on Shiro framework and the second one is SPNEGO.

HDP 2.6.5
https://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.6.5/bk_security/content/configuring_authentication_knox.html

HDP 3.1
https://docs.hortonworks.com/HDPDocuments/HDP3/HDP-3.1.0/configuring-proxy-knox/content/setting_up_ldap_authentication.html

Shiro AD/LDAP requires user/password specification because while accessing the service, the client should firstly authenticated in Knox and secondly authenticate in service requested. SPNEGO provides SSO authentication mechanism, after passing the Knox gateway, the user credentials are automatically passed on to the service.
From a practical point of view, if Shiro AD/LDAP is active, the command line curl command should be accompanied by -u user:password parameter. Having SPNEGO enabled passwordless connection is possible with Kerberos ticket and *curl --negotiate -u :" parameters.

Prerequisites for Active Directory/LDAP authentication.

Make sure that Knox host can access AD directory LDAP/LDAPS tree. It is described here https://github.com/stanislawbartkowski/wikis/wiki/HDP-2.6.5-and-Active-Directory
In Active Directory, create or identify a separate container for Knox users. Also, create a separate user with search permission able to scan the content of the container. Make sure that the user can bind and read the container.

ldapsearch -b "cn=centos,dc=fyre,dc=net" -W -D CN=hadoopsearch,CN=centos,DC=fyre,DC=net -H ldap://verse1.fyre.net

Enable secure LDAP connection.

ldapsearch -b "cn=centos,dc=fyre,dc=net" -W -D CN=hadoopsearch,CN=centos,DC=fyre,DC=net -H ldaps://verse1.fyre.net

Collect all necessary data:

Information Knox configuration key Example
Active Directory CA certificate for secure LDAP /root/ad.cert
AD container for Knox users main.ldapRealm.contextFactory.url CN=centos,DC=fyre,DC=net
AD read only account able to scan the container ain.ldapRealm.contextFactory.systemUsername CN=hadoopsearch,CN=centos,DC=fyre,DC=net
Password main.ldapRealm.contextFactory.systemPassword ****
AD LDAP URL main.ldapRealm.searchBase ldap://verse1.fyre.net

Enable Knox for non-secure AD LDAP

Configure

https://cwiki.apache.org/confluence/display/KNOX/Using+Apache+Knox+with+ActiveDirectory
Let's start with "Sample 3". This configuration allows AD user in CN=centos,DC=fyre,DC=net container to authenticate using over npn-secure LDAP connection. Prepare provider configuration.

 <provider>
      <role>authentication</role>
      <name>ShiroProvider</name>
      <enabled>true</enabled>
      <param name="main.ldapRealm" value="org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm"/>
      <param name="main.ldapContextFactory" value="org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory"/>
      <param name="main.ldapRealm.contextFactory"  value="$ldapContextFactory"/>

      <param name="main.ldapRealm.contextFactory.url"  value="ldap://verse1.fyre.net"/>
      <param name="main.ldapRealm.contextFactory.systemUsername"  value="CN=hadoopsearch,CN=centos,DC=fyre,DC=net"/>
      <param name="main.ldapRealm.contextFactory.systemPassword" value="*******"/>

      <param name="main.ldapRealm.searchBase" value="CN=centos,DC=fyre,DC=net"/>
      <param name="main.ldapRealm.userSearchAttributeName" value="sAMAccountName"/>
      <param name="main.ldapRealm.userObjectClass" value="person"/>

      <param name="urls./**" value="authcBasic"/>
    </provider>

OpenLDAP example

<provider>
      <role>authentication</role>
      <name>ShiroProvider</name>
      <enabled>true</enabled>
      <param name="main.ldapRealm" value="org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm"/>
      <param name="main.ldapContextFactory" value="org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory"/>
      <param name="main.ldapRealm.contextFactory"  value="$ldapContextFactory"/>

      <param name="main.ldapRealm.contextFactory.url"  value="ldap://ldap.sb.com"/>
      <param name="main.ldapRealm.contextFactory.systemUsername"  value="cn=proxy,dc=sb,dc=com"/>
      <param name="main.ldapRealm.contextFactory.systemPassword" value="*****"/>

      <param name="main.ldapRealm.searchBase" value="dc=sb,dc=com"/>
      <param name="main.ldapRealm.userSearchAttributeName" value="uid"/>
      <param name="main.ldapRealm.userObjectClass" value="posixAccount"/>

      <param name="urls./**" value="authcBasic"/>
    </provider>

Prepare, copy and paste the configuration into Ambari -> Knox -> Advanced topology. Replace existing provider definition valid for Demo OpenLDAP.
Restart Knox.

Test

Test the configuration using command line.

knoxcli.sh system-user-auth-test --cluster default

System LDAP Bind successful.

knoxcli.sh user-auth-test --u user1 --cluster default

Password: 
LDAP authentication successful!

Troubleshooting

Run knoxcli.sh command with --d parameters. It produces more verbose output.

knoxcli.sh system-user-auth-test --cluster default --d

Also, browse through Knox diagnostic log file.

ll -ltr /var/log/knox/

Knox and secure LDAP AD connection

https://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.6.5/bk_security/content/setting_up_ldap_authentication.html
Import AD CA into JVM keystore. Important: this command should be executed on the host where Knox is installed, not the Ambari server host.

keytool -import -trustcacerts --file /root/ad.cert -keystore /var/lib/knox/data-2.6.5.1050-37/security/keystores/gateway.jks

Replace JVM --keystore parameter with file path appropriate to your environment.
In Knox configuration panel replace ldap with ldaps and restart Knox service.

      <param name="main.ldapRealm.contextFactory.url"  value="ldaps://verse1.fyre.net"/>

Test Knox again.

knoxcli.sh system-user-auth-test --cluster default
knoxcli.sh user-auth-test --u user1 --cluster default

Enable Knox AD group membership.

So far, only user authentication is enabled. Next step is to allow authorization, assign a user to the groups. Before that, several additional information should be collected.

Information Knox configuration key Example
AD container for users main.ldapRealm.userSearchBase CN=centos,DC=fyre,DC=net
AD container for groups, could be the same or different as for users main.ldapRealm.groupSearchBase CN=centos,DC=fyre,DC=net
Pattern to extract user name from user DN main.ldapRealm.memberAttributeValueTemplate CN={0},CN=centos,DC=fyre,DC=net

Prepare, copy and paste configuration parameter to enable group membership. The parameters should be added to <provider> definition in "Advanced topology" tab.

<param name ="main.ldapGroupContextFactory" value="org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory" />
<param name="main.ldapRealm.memberAttributeValueTemplate" value="CN={0},CN=centos,DC=fyre,DC=net"/>
<param name="main.ldapRealm.authorizationEnabled" value="true"/>

<param name="main.ldapRealm.userSearchBase" value="CN=centos,DC=fyre,DC=net"/>
<param name="main.ldapRealm.groupSearchBase" value="CN=centos,DC=fyre,DC=net"/>
<param name="main.ldapRealm.groupObjectClass" value="group"/>
<param name="main.ldapRealm.groupIdAttribute" value="sAMAccountName"/>
<param name="main.ldapRealm.memberAttribute" value="member"/>

Example for OpenLDAP.

<param name ="main.ldapGroupContextFactory" value="org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory" />
<param name="main.ldapRealm.memberAttributeValueTemplate" value="cn={0},ou=users,dc=sb,dc=com"/>
<param name="main.ldapRealm.authorizationEnabled" value="true"/>

<param name="main.ldapRealm.userSearchBase" value="dc=sb,dc=com"/>
<param name="main.ldapRealm.groupSearchBase" value="dc=sb,dc=com"/>
<param name="main.ldapRealm.groupObjectClass" value="posixGroup"/>
<param name="main.ldapRealm.groupIdAttribute" value="cn"/>
<param name="main.ldapRealm.memberAttribute" value="memberUid"/>

Several explanations.

main.ldapRealm.memberAttributeValueTemplate can be deduced from AD account properties. alt DN for user1 account is CN=User1,CN=centos,DC=fyre,DC=net. So the template to extract the user name is CN={0},CN=centos,DC=fyre,DC=net

main.ldapRealm.memberAttribute is the LDAP attribute in AD group property where group members are stored. alt

  • Additional remark, group membership for OpenLDAP. The memberUid attribute of the group should contain values of uid attribute of the group. Below is an example of ldapusers group containing perf, user1 and user2 users. alt

Save the configuration and restart Knox. Run the test (mark --g option).

knoxcli.sh user-auth-test --u user1 --cluster default --g

Password: 
LDAP authentication successful!
user1 is a member of: centosgroup

LDAP search password encryption

No one is happy seeing a password as plain text. The solution is to encrypt the password in keystore.
https://community.hortonworks.com/content/supportkb/151104/how-to-encrypt-the-ldap-password-in-a-knox-topolog.html
Lesson learned: Password encryption is not recognized by knoxli.sh command line. After that, any attempt to test the user authentication ends up with the error message as below. There is no way to bypass it. Nevertheless, user/password authentication in any Knox enabled services is working whatsoever.

Unable to set property 'contextFactory.systemPassword' with value [S{ALIAS=ldapbinddnpassword}] on object of type org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm.  If 'S{ALIAS=ldapbinddnpassword}' is a reference to another (previously defined) object, prefix it with '$' to indicate that the referenced object should be used as the actual value.  For example, $S{ALIAS=ldapbinddnpassword}

The first thing to do is to import the password into Knox secure store. The password alias here is ldapbinddnpassword

knoxcli.sh create-alias ldapbinddnpassword --cluster default --value xxxxxxxx

ldapbinddnpassword has been successfully created.

Verify that alias is enlisted in keystore.

knoxcli.sh list-alias --cluster default

Listing aliases for default
ldapbinddnpassword
encryptquerystring

2 items.

In Knox configuration panel, replace plain password with the alias and restart Knox

<param>
        <name>main.ldapRealm.contextFactory.systemPassword</name>
        <value>${ALIAS=ldapbinddnpassword}</value>
</param>

Secure access to Knox services

Access to the services can be restricted in Knox. As a default, all users and hosts can access service. "Can access" here means only not to be rejected by Knox itself. Beyond Knox, the service is still guarded by security means appropriate to the service requested. Knox is only the first line of defence. The access to Knox service can be restricted by modifying Authorization Provider section.
https://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.6.5/bk_security/content/setting_up_authorization_provider.html
As a default, the provider is defined as:

  <provider>
    <role>authorization</role>
    <name>AclsAuthz</name>
    <enabled>true</enabled>
  </provider>

Default configuration does not impose any restriction. To limit the access, a more specific parameter should be added.

   <param>
       <name>$service_Name.acl</name>
      <value>$cluster_users;$groups_field;IP_field</value>
   </param>

For WebHDFS the $service_Name.acl should be webhdfs.acl. The value format is user;group;hostname or IP, it specifies the list of users, groups and/or hosts allowed to request WebHDFS service through Knox. It is only yes/no permission, Authorized or Not Authorized. Example:

  <provider>
    <role>authorization</role>
    <name>AclsAuthz</name>
    <enabled>true</enabled>

   <param>
     <name>webhdfs.acl</name>
     <value>*;dataadmin,datascience;*</value>
   </param>

  </provider>

Only users belonging to dataadmin or datascience groups can request the access to WebHDFS via Knox proxy. All other requestors are rejected at the gate.

SPNEGO authentication

HDFS proxy user

Verify HDFS Custom core-site.xml

Parameter Value
hadoop.proxyuser.knox.hosts {Knox host name }
hadoop.proxyuser.knox.groups *

Configure

https://docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.6.5/bk_security/content/setting_up_spnego_authentication.html
On Knox node, extract user principal from spnego Kerberos keytab.

klist -kt /etc/security/keytabs/spnego.service.keytab

Keytab name: FILE:/etc/security/keytabs/spnego.service.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   0 04.02.2019 13:44:39 HTTP/[email protected]
   0 04.02.2019 13:44:39 HTTP/[email protected]
   0 04.02.2019 13:44:39 HTTP/[email protected]
   0 04.02.2019 13:44:39 HTTP/[email protected]
   0 04.02.2019 13:44:39 HTTP/[email protected]

Prepare SPNEGO provider configuration. As the value of hadoop.auth.config.kerberos.principal, copy and paste the principal found in spnego.service.keytab

<provider>
  <role>authentication</role>
  <name>HadoopAuth</name>
  <enabled>true</enabled>
  <param>
    <name>config.prefix</name>
    <value>hadoop.auth.config</value>
  </param>
  <param>
    <name>hadoop.auth.config.signature.secret</name>
    <value>knox-signature-secret</value>
  </param>
  <param>
    <name>hadoop.auth.config.type</name>
    <value>kerberos</value>
  </param>
  <param>
    <name>hadoop.auth.config.simple.anonymous.allowed</name>
    <value>false</value>
  </param>
  <param>
    <name>hadoop.auth.config.token.validity</name>
    <value>1800</value>
  </param>
  <param>
    <name>hadoop.auth.config.cookie.domain</name>
    <value>novalocal</value>
  </param>
  <param>
    <name>hadoop.auth.config.cookie.path</name>
    <value>gateway/default</value>
  </param>
  <param>
    <name>hadoop.auth.config.kerberos.principal</name>
    <value>HTTP/[email protected]</value>
  </param>
  <param>
    <name>hadoop.auth.config.kerberos.keytab</name>
    <value>/etc/security/keytabs/spnego.service.keytab</value>
  </param>
  <param>
    <name>hadoop.auth.config.kerberos.name.rules</name>
    <value>DEFAULT</value>
  </param>
</provider>

In Knox -> Config -> Advance topology, copy and paste the provider replacing existing ShiroProvider. Restart Knox.

Assuming user1 can access HDFS, run Knox->WebHDFS command.

kinit user1
curl -ik --negotiate -u : -X GET "https://a1.fyre.ibm.com:8443/gateway/default/webhdfs/v1/?op=LISTSTATUS"

HTTP/1.1 401 Authentication required
Date: Mon, 11 Feb 2019 16:12:08 GMT
WWW-Authenticate: Negotiate
............
{"FileStatuses":{"FileStatus":[{"accessTime":0,"blockSize":0,"childrenNum":1,"fileId":16887,"group":"hdfs","length":0,"modificationTime":1549312341745,"owner":"hdfs","pathSuffix":"amshbase","permission":"755","replication":0,"storagePolicy":0,"type":"DIRECTORY"},{"accessTime":0,"blockSize":0,"childrenNum":2,"fileId":16392,"group":"hadoop","length":0,"modificationTime":1549369210165,"owner":"yarn","pathSuffix":"app-logs","permission":"777","replication":0,"storagePolicy":0,"type":"DIRECTORY"},
.....

HA for WebHDFS

If case of NameNode configured for HA, additional setting is required.
https://community.cloudera.com/t5/Community-Articles/How-to-configure-a-Knox-topology-for-namenode-HA/ta-p/244543
HA provider for WebHDFS should be added to default topology, gateway section.

<provider>
  <role>ha</role>
  <name>HaProvider</name>
  <enabled>true</enabled>
  <param>
    <name>WEBHDFS</name>
         <value>maxFailoverAttempts=3;failoverSleep=1000;maxRetryAttempts=300;retrySleep=1000;enabled=true</value>

  </param>
</provider>

Knox PAM authentication

Assuming CentOs or RedHat hosts integrated and registered in Active Directory, the option is to enable PAM Knox authentication. PAM authentication compromises local Linux and AD users or any authentication provider configured for PAM.
https://docs.hortonworks.com/HDPDocuments/HDP3/HDP-3.1.0/configuring-proxy-knox/content/setting_up_pam_authentication.html
To enable PAM authentication, specify Shiro PAM provider in Knox -> Config -> Advance topology.

<provider> 
   <role>authentication</role> 
   <name>ShiroProvider</name> 
   <enabled>true</enabled> 
   <param> 
        <name>sessionTimeout</name> 
        <value>30</value>
    </param>                                              
    <param>
        <name>main.pamRealm</name> 
        <value>org.apache.hadoop.gateway.shirorealm.KnoxPamRealm</value>
    </param> 
    <param>                                                    
       <name>main.pamRealm.service</name> 
       <value>login</value> </param>
    <param>                                                    
       <name>urls./**</name> 
       <value>authcBasic</value> 
   </param>
</provider>

Knox UI

Knox UI is controlled by Advanced knoxsso-topology panel. As a default, it is configured to use Demo OpenLDAP and is not impacted by "Advanced topology* settings

In order to switch Knox UI authentication to an external AD/LDAP, modify two parameters leaving all other untouched.

Parameter Description Sample value
main.ldapRealm.contextFactory.url AD/LDAP URL ldap://verse1.fyre.ibm.com:389 (non-secure)
main.ldapRealm.userDnTemplate Template to transform user login name into LDAP DN (AD example) CN={0},cn=centos,dc=fyre,dc=net

In the case of AD, it is also possible to authenticate using AD credentials directly.

Parameter Description Sample value
main.ldapRealm.userDnTemplate Template to transform user login name into AD credentails CN={0}@FYRE.NET

Another task is to specify users with *admin* authority. Otherwise, even after successful authentication, the non-admin user will be presented with almost dead Knox UI panel. As a default, only *admin* login name has *admin* privileges.

Advanced gateway-site

Parameter Description Sample value
gateway.knox.admin.users List of comma-separated user login names with admin authority admin,user1,guest
gateway.knox.admin.groups List of groups with admin authority, not used unless groups activated admin,users

Additional remarks

Command line knoxcli.sh is only partially enabled for PAM authentication.

  • knoxcli.sh user-auth-test --u <user> --cluster default : works
  • knoxcli.sh user-auth-test --u <user> --cluster default --g : group membership, fails
  • knoxcli.sh system-user-auth-test --cluster default : does not work
⚠️ **GitHub.com Fallback** ⚠️