Documentation

12. Setting up Authentication

Authentication methods help simplify logins for end users–offering single sign-ons using existing login information to sign into a third party website rather than creating a new login account specifically for that website.

Prior to Ansible Tower version 3.1, account authentication can only be configured in the /etc/tower/settings.py or the configuration files within /etc/tower/conf.d/. Starting with Ansible Tower version 3.1, instead of flat files, the configuration files are now saved to the Postgres database. Therefore, it is important that account authentication be configured in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.

Account authentication in Ansible Tower can be configured to centrally use OAuth2, while enterprise-level account authentication can be configured for SAML, RADIUS, or even LDAP as a source for authentication information.

For websites, such as Microsoft Azure, Google or GitHub, that provide account information, account information is often implemented using the OAuth standard. OAuth is a secure authorization protocol which is commonly used in conjunction with account authentication to grant 3rd party applications a “session token” allowing them to make API calls to providers on the user’s behalf.

SAML (Security Assertion Markup Language) is an XML-based, open-standard data format for exchanging account authentication and authorization data between an identity provider and a service provider.

The RADIUS distributed client/server system allows you to secure networks against unauthorized access and can be implemented in network environments requiring high levels of security while maintaining network access for remote users.

12.1. Azure Active Directory (AD)

  1. Create an organization-owned application at https://auth0.com/docs/connections/enterprise/azure-active-directory and obtain an OAuth2 key (Client ID) and secret (Client Secret). Each key and secret must belong to a unique application and cannot be shared or reused between different authentication backends.
  2. Access the Configure Tower feature in the Ansible Tower User Interface to complete the procedure. For instructions, refer to the Tower Configuration section.
  3. If not already pre-populated, provide the generated callback URL for your application through the Microsoft Azure portal from the first step.

For details on completing the mapping fields, see Organization and Team Mapping.

For application registering basics in Azure AD, refer to: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-scenarios#basics-of-registering-an-application-in-azure-ad

  1. Click Save when done.

12.2. Google OAuth2 Settings

  1. Create a project at https://console.developers.google.com/ and obtain an OAuth2 key and secret for a web application.
  2. If not already pre-populated, provide the following callback URL for your application, replacing “tower.example.com” with the FQDN to your Tower server: https://tower.example.com/sso/complete/google-oauth2/
  3. Complete the procedure in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.

Refer to the Python Social Auth documentation for advanced settings: https://python-social-auth.readthedocs.org/en/latest/backends/google.html#google-oauth2

For details on completing the mapping fields, see Organization and Team Mapping.

  1. Click Save when done.

12.3. Github OAuth2 Settings

  1. Create a developer application at https://github.com/settings/developers and obtain an OAuth2 key (Client ID) and secret (Client Secret).
  2. If not already pre-populated, provide the following callback URL for your application, replacing “tower.example.com” with the FQDN to your Tower server: https://tower.example.com/sso/complete/github/
  3. Complete the procedure in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.

For details on completing the mapping fields, see Organization and Team Mapping.

  1. Click Save when done.

12.3.1. Github Org Settings

When defining account authentication with either an organization or a team within an organization, you should use the specific organization and team settings. Account authentication can be limited by an organization as well as by a team within an organization.

You can also choose to allow all by specifying non-organization or non-team based settings (as shown above).

You can limit users who can login to Tower by limiting only those in an organization or on a team within an organization.

To setup account authentication for your organization:

  1. Create an organization-owned application at https://github.com/organizations/<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and secret (Client Secret). Each key and secret must belong to a unique application and cannot be shared or reused between different authentication backends.
  2. If not already pre-populated, provide the following callback URL for your application, replacing “tower.example.com” with the FQDN to your Tower server: https://tower.example.com/sso/complete/github-org/
  3. Complete the procedure in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.

For details on completing the mapping fields, see Organization and Team Mapping.

  1. Click Save when done.

12.3.2. Github Team Settings

To setup account authentication for your team:

  1. Create a team-owned application at https://github.com/organizations/<yourorg>/settings/applications and obtain an OAuth2 key (Client ID) and secret (Client Secret). Each key and secret must belong to a unique application and cannot be shared or reused between different authentication backends.
  2. If not already pre-populated, provide the following callback URL for your application, replacing “tower.example.com” with the FQDN to your Tower server: https://tower.example.com/sso/complete/github-team/
  3. Find the numeric team ID using the Github API: http://fabian-kostadinov.github.io/2015/01/16/how-to-find-a-github-team-id/
  4. Complete the procedure in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.

Refer to Python Social Auth documentation for advanced settings: https://python-social-auth.readthedocs.org/en/latest/backends/github.html

For details on completing the mapping fields, see Organization and Team Mapping.

  1. Click Save when done.

12.4. SAML Authentication Settings

Note

SAML authentication is a feature specific to Enterprise-level license holders.

To setup SAML authentication:

  1. Access the Configure Tower feature in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.
  2. You may optionally enter the URL for a domain name you own (does not need to be a valid URL as this value is only used as a unique ID) in the SAML Service Provider Entity ID field.
  3. Create a keypair for Tower to use as a service provider (SP) and include the certificate and private key contents.

As an example for public certs:

SOCIAL_AUTH_SAML_SP_PUBLIC_CERT = '''

-----BEGIN CERTIFICATE——
... cert text ...
-----END CERTIFICATE——

As an example for private keys:

SOCIAL_AUTH_SAML_SP_PRIVATE_KEY = '''
-----BEGIN PRIVATE KEY--
... key text ...
-----END PRIVATE KEY——
'''
  1. Configure the remaining settings with information about your application and contact information.
  2. Configure the entity ID, SSO URL and certificate for each identity provider (IdP) in use. Multiple SAML IdPs are supported.

Some IdPs may provide user data using attribute names that differ from the default OIDs (https://github.com/omab/python-social-auth/blob/master/social/backends/saml.py). Attribute names may be overridden for each IdP as shown below.

SOCIAL_AUTH_SAML_ENABLED_IDPS = {
    'myidp': {
        'entity_id': 'https://idp.example.com',
        'url': 'https://myidp.example.com/sso',
        'x509cert': '',
    },
    'onelogin': {
        'entity_id': 'https://app.onelogin.com/saml/metadata/123456',
        'url': 'https://example.onelogin.com/trust/saml2/http-post/sso/123456',
        'x509cert': '',
        'attr_user_permanent_id': 'name_id',
        'attr_first_name': 'User.FirstName',
        'attr_last_name': 'User.LastName',
        'attr_username': 'User.email',
        'attr_email': 'User.email',
    },
}

For details on completing the mapping fields, see Organization and Team Mapping.

  1. Click Save when done.

12.5. RADIUS Authentication Settings

Note

RADIUS account authentication is a feature specific to Enterprise-level license holders.

Ansible Tower can be configured to centrally use RADIUS as a source for authentication information.

  1. Access the Configure Tower feature in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.
  2. Enter in the appropriate RADIUS server settings (skipped when Radius Server field is blank).
  3. Click Save when done.

12.6. Using LDAP with Tower

Note

LDAP authentication is a feature specific to Enterprise-level license holders. You must have an active enterprise license before beginning the configuration process.

Administrators use LDAP as a source for account authentication information for Tower users. User authentication is provided, but not the synchronization of user permissions and credentials. Organization membership (as well as the organization admin) and team memberships can be synchronized.

When so configured, a user who logs in with an LDAP username and password automatically gets a Tower account created for them and they can be automatically placed into organizations as either regular users or organization administrators.

Users created via an LDAP login cannot change their username, first name, last name, or set a local password for themselves. This is also tunable to restrict editing of other field names.

To configure LDAP integration for Tower:

  1. 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, where josie and Josie4Cloud are replaced by attributes that work for your setup:

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.

  1. Access the Configure Tower feature in the Ansible Tower User Interface. For instructions, refer to the Tower Configuration section.
  2. Enter the Distinguished Name in the LDAP BIND DN text field to specify the user that Tower uses to connect (Bind) to the LDAP server.
  3. Enter the password to use for the Binding user in the LDAP BIND PASSWORD text field. In this example, the password is ‘passme’.
  4. The LDAP USER SEARCH field defines where to search for users while authenticating. In this example, 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
  1. If that name is stored in key sAMAccountName, the LDAP USER DN TEMPLATE populates with '(sAMAccountName=%(user)s)'. Similarly, for OpenLDAP, the key is uid–hence the line becomes '(uid=%(user)s)',.
  2. In the LDAP GROUP SEARCH text field, specify which groups should be searched and how to search them. In this example, use:
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
    'DC=website,DC=com',    # Base DN
    ldap.SCOPE_SUBTREE,     # SCOPE_BASE, SCOPE_ONELEVEL, SCOPE_SUBTREE
    '(objectClass=group)',  # Query
)
  • The first line specifies the BASE DN where the groups should be searched.
  • The second lines specifies the scope and is the same as that for the user directive.
  • The third line specifies what the 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
  1. Click to select a group type from the LDAP GROUP TYPE drop-down menu list.
  2. Specify the group distinguish name in the LDAP REQUIRE GROUP in order to allow users within that group to access Tower.
  3. Specify the group distinguish name in the LDAP DENY GROUP in order to prevent users within that group to access Tower.
  4. To enable TLS when the LDAP connection is not using SSL, click the LDAP START TLS toggle to ON. By default, TLS is disabled, with the toggle set to OFF.
  5. Specify the user attributes in the LDAP USER ATTRIBUTES MAP text field. In this example, use:
AUTH_LDAP_USER_ATTR_MAP = {
    'first_name': 'givenName',
    'last_name': 'sn',
    'email': 'mail',
}

The above example retrieves users by last name 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.

For details on completing the mapping fields, see Organization and Team Mapping.

  1. Click Save when done.

With these values entered on this form, you can now make a successful authentication with LDAP.

Note

Tower does not actively sync users, but they are created during their initial login.

12.6.1. LDAPS

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,
}

12.6.2. Debugging

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'

12.6.3. Referrals

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.

For details on completing the mapping fields, see Organization and Team Mapping.

12.6.4. Enabling Logging for LDAP

To enable logging for LDAP, you must set the level to DEBUG in the LDAP configuration file, /etc/tower/conf/ldap.py:

LOGGING['handlers']['tower_warnings']['level'] =  'DEBUG'

12.7. Organization and Team Mapping

Next, you will need to control which users are placed into which Tower organizations based on their username and email address (mapping out your organization admins/users from social or enterprise-level authentication accounts).

Dictionary keys are organization names. Organizations will be created, if not already present and if the license allows for multiple organizations. Otherwise, the single default organization is used regardless of the key.

Values are dictionaries defining the options for each organization’s membership. For each organization, it is possible to specify which users are automatically users of the organization and also which users can administer the organization.

admins: None, True/False, string or list/tuple of strings.

  • If None, organization admins will not be updated.
  • If True, all users using account authentication will automatically be added as admins of the organization.
  • If False, no account authentication users will be automatically added as admins of the organization.
  • If a string or list of strings, specifies the usernames and emails for users who will be added to the organization. Compiled regular expressions may also be used instead of string literals.

remove_admins: True/False. Defaults to True.

  • When True, a user who does not match is removed from the organization’s administrative list.

users: None, True/False, string or list/tuple of strings.

  • When True, a user who does not match is removed from the organization’s administrative list.

remove_users: True/False. Defaults to True.

  • When True, a user who does not match is removed from the organization’s administrative list.
SOCIAL_AUTH_ORGANIZATION_MAP = {
 Add all users to the default organization.
'Default': {
    'users': True,
},
'Test Org': {
    'admins': ['[email protected]'],
    'users': True,
},
'Test Org 2': {
    'admins': ['[email protected]', re.compile(r'^tower-[^@]+*?@.*$],
    'users': re.compile(r'^[^@].[email protected]\.com$'),
},
}

Organization mappings may be specified separately for each account authentication backend. If defined, these configurations will take precedence over the global configuration above.

SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP = {}
SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP = {}
SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP = {}
SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP = {}
SOCIAL_AUTH_SAML_ORGANIZATION_MAP = {}

Mapping of team members (users) from social auth accounts. Keys are team names (will be created if not present). Values are dictionaries of options for each team’s membership, where each can contain the following parameters:

organization: string. The name of the organization to which the team belongs. The team will be created if the combination of organization and team name does not exist. The organization will first be created if it does not exist. If the license does not allow for multiple organizations, the team will always be assigned to the single default organization.

users: None, True/False, string or list/tuple of strings.

  • If None, team members will not be updated.
  • If True/False, all social auth users will be added/removed as team members.
  • If a string or list of strings, specifies expressions used to match users. User will be added as a team member if the username or email matches. Compiled regular expressions may also be used instead of string literals.

remove: True/False. Defaults to True. When True, a user who does not match the rules above is removed from the team.

SOCIAL_AUTH_TEAM_MAP = {
'My Team': {
    'organization': 'Test Org',
    'users': ['re.compile(r'^[^@][email protected]\.example\.com$')'],
    'remove': True,
},
'Other Team': {
    'organization': 'Test Org 2',
    'users': re.compile(r'^[^@][email protected]\.example\.com$'),
    'remove': False,
},
}

Team mappings may be specified separately for each account authentication backend, based on which of these you setup. When defined, these configurations take precedence over the the global configuration above.

SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP = {}
SOCIAL_AUTH_GITHUB_TEAM_MAP = {}
SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP = {}
SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP = {}
SOCIAL_AUTH_SAML_TEAM_MAP = {}

Uncomment the line below (i.e. set SOCIAL_AUTH_USER_FIELDS to an empty list) to prevent new user accounts from being created. Only users who have previously logged in to Tower using social or enterprise-level authentication or have a user account with a matching email address will be able to login.

SOCIAL_AUTH_USER_FIELDS = []