Note
LDAP is an enterprise-level feature. You must have an active enterprise license before beginning the configuration process.
First, create a user in LDAP that has access to read the entire LDAP structure.
To test if you can make successful queries to the LDAP server, use the following command:
ldapsearch -x -H ldap://win -D "CN=josie,CN=Users,DC=website,DC=com" -b "dc=website,dc=com" -w Josie4Cloud
Here CN=josie,CN=users,DC=website,DC=com
is the Distinguished Name of the connecting user.
This can be added to the Parameter AUTH_LDAP_BIND_DN =
to specify the user that Tower uses to connect (Bind) to the LDAP server.
Note
LDAP and Active Directory integration is controlled by the settings defined in the /etc/tower/conf.d/ldap.py
file. In versions of Tower older than 2.2, these settings lived in /etc/tower/settings.py
.
The next parameter specifies which password to use for the Binding user:
AUTH_LDAP_BIND_PASSWORD = 'passme'
To define where to search for users while authenticating, use:
AUTH_LDAP_USER_SEARCH = LDAPSearch(
'DC=WEBSITE,DC=COM', # Base DN
ldap.SCOPE_SUBTREE, # SCOPE_BASE, SCOPE_ONELEVEL, SCOPE_SUBTREE
'(sAMAccountName=%(user)s)', # Query
)
The first line specifies where to search for users in the LDAP tree. In the above example, the users are searched recursively starting from DC=WEBSITE,DC=COM
.
The second line specifies the scope where the users should be searched:
- SCOPE_BASE: This value is used to indicate searching only the entry at the base DN, resulting in only that entry being returned
- SCOPE_ONELEVEL: This value is used to indicate searching all entries one level under the base DN - but not including the base DN and not including any entries under that one level under the base DN.
- SCOPE_SUBTREE: This value is used to indicate searching of all entries at all levels under and including the specified base DN.
The third line specifies the key name where the user name is stored. For example, to query the AD LDAP using ldapsearch
with a filter for the user, use something like:
ldapsearch -x -H ldap://win -D "CN=josie,CN=Users,DC=website,DC=com" -b "dc=website,dc=com" -w Josie4Cloud objectClass=user
Which returns something like:
# Administrator, Users, website.com
dn: CN=Administrator,CN=Users,DC=website,DC=com
objectClass: user
cn: Administrator
description: Built-in account for administering the computer/domain
distinguishedName: CN=Administrator,CN=Users,DC=website,DC=com
instanceType: 4
objectGUID:: lEphZCrQQUKedwWDg/KciQ==
accountExpires: 0
logonCount: 162
sAMAccountName: Administrator
sAMAccountType: 805306368
Here we see that name is stored in key sAMAccountName
–hence the line becomes
'(sAMAccountName=%(user)s)'
.
Similarly, for OpenLDAP, the key is uid
–hence the line becomes '(uid=%(user)s)',
.
The next directives specifies the user attributes.
AUTH_LDAP_USER_ATTR_MAP = {
'first_name': 'givenName',
'last_name': 'sn',
'email': 'mail',
}
The above example says that the users last name can be retrieved from the key sn
in the ldapsearch
. You can use the same LDAP query for the user to figure out what keys they are stored under.
The next directive specifies the where the groups should be searched and how to search them.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
'DC=website,DC=com', # Base DN
ldap.SCOPE_SUBTREE, # SCOPE_BASE, SCOPE_ONELEVEL, SCOPE_SUBTREE
'(objectClass=group)', # Query
)
objectclass
of a group object is in the LDAP you are using.You could make another ldapsearch
and check in one group, which is the objectclass
to which it belongs. For example:
# admin, grp, website.com
dn: CN=admin,OU=grp,DC=website,DC=com
objectClass: top
objectClass: group
cn: admin
member: CN=both,CN=Users,DC=website,DC=com
distinguishedName: CN=admin,OU=grp,DC=website,DC=com
The next directive specifies the type of group. Supported group types are listed here: http://pythonhosted.org/django-auth-ldap/groups.html#types-of-groups
AUTH_LDAP_GROUP_TYPE = ActiveDirectoryGroupType()
With these directives filled in and others commented, you now should be able to make a successful authentication with LDAP.
Note
Tower does not actively sync users, but they are created during their initial login.
To enable secure LDAP communication with the LDAP server change the LDAP URL to LDAPS in the AUTH_LDAP_SERVER_URI
directive. Make sure the server name in the URI matches the name in the certificate. Finally, add the server certificate to your Tower instance by adding the path which in CentOS is /etc/openldap/ldap.conf
and the directive is TLS_CACERT /etc/openldap/certs/cert.pem
.
To disable the certificate check, add the following lines to the /etc/tower/conf.d/ldap.py
file:
AUTH_LDAP_GLOBAL_OPTIONS = {
ldap.OPT_X_TLS_REQUIRE_CERT: False,
}
Debugging LDAP connections can be enabled by adding the below lines in the /etc/tower/conf.d/ldap.py
file.
LOGGING['handlers']['syslog'] = {
'level': 'DEBUG',
'filters': ['require_debug_false'],
'class': 'logging.handlers.SysLogHandler',
'address': '/dev/log',
'facility': 'local0',
'formatter': 'simple',
}
LOGGING['loggers']['django_auth_ldap']['handlers'] = ['syslog']
LOGGING['loggers']['django_auth_ldap']['level'] = 'DEBUG'
Active Directory uses “referrals” in case the queried object is not available in its database. It has been noted that this does not work properly with the django LDAP client and, most of the time, it helps to disable referrals. Disable LDAP referrals by adding the following lines to your /etc/tower/conf.d/ldap.py
file:
AUTH_LDAP_GLOBAL_OPTIONS = {
ldap.OPT_REFERRALS: False,
}
Note
“Referrals” are disabled by default in Ansible Tower version 2.4.3 and above. If you are running an earlier version of Tower, you should consider adding this parameter to your configuration file.