Using LDAP or AD as the Identity Provider

This document describes how to use the Lightweight Directory Access Protocol (LDAP) for authenticating users with your Apcera cluster.

Overview of LDAP Support

Apcera supports the use of LDAP as the identity provider for your cluster. To use LDAP, it is assumed that you have your own LDAP server set up and configured. Apcera supports the lookup of LDAP groups and users.

Apcera supports Active Directory 2002 and later (tested against AD 2012) and LDAP version 3 (tested against Oracle Unified Directory server).

To enable LDAP authentication in your Apcera cluster you modify the auth_server.identity section of your cluster.conf.erb file (or cluster.conf file) to include the LDAP configuration settings, example of which follow.

Active Directory (AD) authentication

Apcera provides two out-of-box models for Active Directory: "AD" and "ADMulti". With "AD" the user logs in with an account name without needing to type in a domain name. With "ADMulti" the user logs in with their UserPrincipalName, typically in the format [accountName]@[domainName].

Example "AD" configuration:

"auth_server": {
  "identity": {
    "ldap_basic": {
      "enabled": true,
      "model_name": "AD",
      "default_domain": "ADATUM.COM"
      "search_dn": "cn=usersearch,ou=service_accounts,dc=adatum,dc=com",
      "search_passwd": "pass@word1",
      "base_dn": "cn=Users,dc=adatum,dc=com",
      "group_base_dn": "dc=adatum,dc=com"
      "uri": "ldaps://adhost.adatum.com",
      "port": "636",
      "users": [
          "user1",
          "user2",
          "john"
        ]
    },
  },
}

Example "ADMulti" configuration:

"auth_server": {
  identity": {
    "ldap_basic": {
      "enabled": true,
      "model_name": "ADMulti",
      "search_dn": "cn=usersearch,ou=service_accounts,dc=adatum,dc=com",
      "search_passwd": "pass@word1",
      "base_dn": "dc=com",
      "group_base_dn": "dc=com"
      "uri": "ldaps://adhost.adatum.com",
      "port": "636",
      "users": [
          "user1@adatum.com",
          "user2@adatum.com",
          "john@contoso.com"
        ]
    },
  },
}

Oracle and other LDAP server authentication

Example configuration:

"auth_server": {
  "identity": {
    "ldap_basic": {
      "enabled": true,
      "model_name": "basic",
      "search_dn": "cn=apcera_bind,ou=service_accounts,dc=company,dc=com",
      "search_passwd": "pass@word1",
      "base_dn": "ou=people,dc=company,dc=com",
      "group_base_dn": "ou=groups,dc=company,dc=com"
      "uri": "ldaps://172.99.163.1d",
      "port": "636",
      "users": [
          "one@company.com",
          "two.three@company.com",
          "xyz@apcera.com"
        ]
    },
  },
}

LDAP configuration parameters

The following table lists and describes the parameters for configuring LDAP and AD with Apcera. These configurations are placed in the cluster.conf.erb file (or cluster.conf) in the auth_server > identity > ldap_basic section.

Connection and Domain Configuration

Parameter Description
enabled Enable (true) or disable (false) LDAP authentication for the cluster.
model_name One of the out-of-box models ("AD", "ADMulti", "basic"} or a model defined in advanced configuration; defaults to "basic", which is the behavior supported in releases prior to Apcera Platform Release 2.3.
search_dn This is the fully-qualified Directory Distinguished Name (DN) of the account used to search for users and groups in the directory. See note below.
search_passwd Password of the admin_dn account in plain text format.
base_dn DN of the branch of the directory containing all user entries.
group_base_dn Optional. DN of the branch containing group entries. If not set the base_dn is used to query groups.
default_domain Required for AD model only. The domain of the Active Directory instance.
uri LDAP Server hostname or IP address. The protocol "ldaps:" is supported but is not required. For example: "uri": "<LDAP_SERVER_IP_ADDRESS>" and "uri": "ldaps://<LDAP_SERVER_IP_ADDRESS>" are both acceptable.
port LDAP service port (Info: the ldaps protocol uses well known port 636)

Policy Configuration

Parameter Description
users List of users granted permission to login during initial deploy. The identifier used in this list depends on the model_name, see the model table below for details. A user in this list who is also the "admins" list (of "auth-server") will be granted admin priviledges on the cluster.

Claims Configuration (optional)

Parameter Description
user_attributes Override the user claim map defined by the model_name. See model table below for the default attribute-to-claim mapping. This value holds pairs using the form ldapAttribute = claimType or ldapAttribute = "'[claimType1, claimType2]'".
group_attributes Override the group claim map defined by the model_name. See model table below for the default attribute-to-claim mapping. This value holds pairs using the form ldapAttribute = claimType or ldapAttribute = "'[claimType1, claimType2]'".

Note: As shown in description, when the parameter setting is a list of claimTypes rather than a single claimType, inner quotes and square brackets are required to indicate a list is being provided.

Testing Configuration (not for production environments)

Parameter Description
tls_insecure_skip_verify If set to true the system does not verify/validate the server certificate. If not set or set to false, proper CA (Certificate Authority) must be confirmed for LDAP to work properly. See Certificate Requirements. Setting this value to true would allow a man-in-the-middle spoof to get access to credentials
insecure_tls_disable If set to true then TLS is not used for the LDAP connection and user login credentials will be transmitted in the clear and could be captured by network sniffers. Note that the port must correspond to the TCP port (the well-known port for LDAP TCP is 389).

Advanced Configuration

Optional, used for overriding out-of-box models. Defined under the auth_server > identity > ldap_basic > model > *model_name* section.

Parameter Description
base_model Out-of-box model name on which this model is based; must be recognized out of box model_name. The base_model provides default values for any configurations that are left out of this custom model.
resolve_before_bind If true (default) then search based on user_lookup_filter is used to resolve the user account and get the DN which is then used for the bind (authentication) operation. This is the normal OpenLDAP behavior. If false then and the bind_name and default_domain are provided, then they provide the bind identifier, otherwise the Username is directly provided in the bind operation.
bind_name If resolve_before_bind is false, this provides the format string to use for composing the bind id using variables $APC_USERNAME, $APC_BASE_DN and $APC_DEFAULT_DOMAIN (from default_domain config key above). Taking Active Directory as an example, username can be the sAMAccountName and bind would be based on @. The AD model therefore uses a `bind_name` value of `$APC_USERNAME@$APC_DEFAULT_DOMAIN`. To bind to whatever literal the user types in, this field would be simply be set to `$APC_USERNAME`.
user_lookup_filter Override of base_model search to get the user entry. Available variables are $APC_USERNAME, $APC_BINDNAME, $APC_DEFAULT_DOMAIN and $APC_BASE_DN. Syntax is a valid LDAP filter including starting & ending parens.
group_lookup Override of base_model search to get the groups a user belongs to. Note that nested (or indirect) group membership resolution is not supported. This field must either be a valid LDAP filter (including starting & ending parens) or it can hold one or more comma separated result variables from the user lookup (result variables start with "APC_USER_" followed by the case-sensitive Attribute Type name) separated by commas (no starting/ending parens). When result variables are used instead of a search filter, the attribute referenced should hold a list of group membership DNs, for example the AD memberOf attribute. The DNs are then used to find group objects and the group_attributes are provided from these objects. Examples of user attribute variables are $APC_USER_DN, $APC_USER_memberOf — note that $APC_USER_ can used to prefix any user entity attributes, whether or not those attributes are included in the user_attributes claims map above. Additional variables supported for group search are $APC_USERNAME, $APC_DEFAULT_DOMAIN, $APC_BASE_DN and $APC_GROUP_BASE_DN. One additional variable, for Active Directory only, is supported for the use as a result variable $APC_PRIMARY_USER_GROUP (a group identifier derived from the user's primaryGroupID).

Note the following for LDAP and AD configurations

  • The account (search_dn and search_passwd) is used during LDAP authentication to find user and group records. It should have permissions to search the directory under base_dn and group_base_dn but otherwise should have the minimal privileges. Directory Administrator privileges are not required. We recommend using the ldapsearch command line tool to verify that the account you configure can find a existing user record under the base_dn and a group record under group_base_dn.
  • Obsolete configuration setting admin_dn has been replaced by search_dn.
  • Obsolete configuration setting admin_passwd has been replaced by search_passwd.
  • Obsolete configuration settings groups, group_member_field, dn_group_flag, and standard are no longer used and are ignored if present.
  • Each LDAP account expected to access the cluster must have a valid identifier attribute. The identifer used for login depends on the model_name. See model table below for details. When a user logs in, the directory is searched for a entry matching the username provided (via apc or console) within the scope of the base_dn.
  • User claims are attributes about the user pulled from the directory that are available for use in policy rules. Within policy a user claim is referenced as user->claimType where claimType is the name mapped in user_attributes.
  • Out-of-box model behaviors are implemented using typical schemas present in LDAP and Active Directory. As long as your environment corresponds to these typcial practicies, there is no need to enter advanced configurations in the cluster.conf.erb file (or cluster.conf). Simply configure the model_name corresponding to your environment.
  • The maximum number of groups per user supported by LDAP with policy is 1000. This applies both to LDAP and AD queries where the value contains all the groups associated with a single user. Previously LDAP groups per user/token were restricted by Max NATS payload. Now we have a maximum limit of 1000 groups a user can belong to. A user cannot login if he or she belongs to more than 1000 groups in an LDAP or AD directory. If the user is a member of more than 1000 groups, the system presents the error "LDAP groups count X exceeds groups limit of 1000."

Out-of-box Models

This section provides details on the default behaviors of the out of box models. First we describe what user attributes result in claims, then which group attributes result in claims. Note that attributes that have multiple values in the directory will result in multiple values in the claim unless otherwise noted. The last table describes how the out-of-box model implements authentication and search operations.

The following tables show the standard user claim names and the source of the value for each out of box model.

Model LDAP User Attribute Policy Claim Description
basic cn user->name User's common name assigned to user->name claim
basic cn LDAP->name Same, using deprecated issuer LDAP for backward compatibility.
basic mail user->email User's mail attribute assigned to user->email claim
basic mail LDAP->email Same, using deprecated issuer LDAP for backward compatibility.
basic mail auth_server@apcera.me->name In prior releaes, a standard policy rule mapped the email address to the general name claim used to create the default namespace.
AD sAMAccountName user->name User's sAMAccountName assigned to user->name claim
AD sAMAccountName user->relativeNamespace User's sAMAccountName used as basis for defaultNamespace assigned at login
AD mail user->email User's mail attribute assigned to user->email claim
ADMulti userPrincipalName user->name User's PrincipalName assigned to user->name claim
ADMulti userPrincipalName user->relativeNamespace User's PrincipalName used as basis for defaultNamespace assigned at login
ADMulti mail user->email User's mail attribute assigned to user->email claim
ADMulti sAMAccountName user->accountname sAMAccountName also available as user->accountname claim

Note: If there is no value in the user entry for the attribute, then the claim is not set.

Model LDAP Group Attribute Policy Claim Description
basic cn user->group Group common name assigned to user->group claim.
basic cn LDAP->group Same, using deprecated issuer LDAP for backward compatibility.
AD cn user->group Group common name assigned to user->group claim.
ADMulti cn user->group Group common name assigned to user->group claim.

Note: Multiple group memberships result in one claim for each LDAP group.

The following lists each behavior controlled by the choice of model, describes how each model implements that behavior and shows the equivalent advanced configuration setting.

  • Search for the user before or after checking the password?

    Model Description Advanced Config
    basic Uses the user_lookup_filter to find the user entry, then uses the DN of the entry to perform a bind operation to verify the password. "resolve_before_bind":true
    AD Uses the bind_name to perform a bind operation to verify the password, then (if correct password) finds the user entry using the user_lookup_filter. "resolve_before_bind":false
    ADMulti Same as AD. "resolve_before_bind":false
  • When checking password before user search, how is username presented via apc or console applied?

    Model Description Advanced Config
    basic Not used n/a
    AD Appends the AD domain to the entered username "bind_name":"$APC_USERNAME@$APC_DEFALT_DOMAIN"
    ADMulti Uses the bare username "bind_name":"$APC_USERNAME"
  • When finding a user entry, what keys should be used in search filter?

    Model Description Advanced Config
    basic Matches on the uid attribute. "user_lookup_filter":"(uid=$APC_USERNAME)"
    AD Matches on the sAMAccountName attribute. "user_lookup_filter":"(sAMAccountName=$APC_USERNAME)"
    ADMulti Matches on the userPrincipalName attribute. "user_lookup_filter":"(userPrincipalName=$APC_USERNAME)"
  • When determining what groups a user belongs to, what data or search should be used?

    Model Description Advanced Config
    basic Search for groups which have the user's DN as member. "group_lookup":"(member=$APC_USER_DN)"
    AD The user's MemberOf attribute provides list of groups (including PrimaryGroup). "group_lookup":"$APC_USER_memberOf, $APC_PRIMARY_USER_GROUP"
    ADMulti Same as AD. "group_lookup":"$APC_USER_memberOf, $APC_PRIMARY_USER_GROUP"

Writing policy to support LDAP/AD login

Policy is required to provide two claims for each user who will log in via LDAP authentication: permit issue and name.

The permit issue policy lets the Auth Server issue a token to the authenticated user. Even if a user enters the correct password for an account, access to the cluster will not be granted without issue permission. The following example policy shows how to enable token issuance using various criteria. See the model LDAP user attributes table above for information on what LDAP attribute corresponds to the claims used in this policy.

auth::/oauth2/http {
  if (user->name == "devuser") {
    permit issue
  }
  if (user->email == "user.1@maildomain.net") {
    permit issue
  }
  if (user->group == "devgroup") {
    permit issue
  }
}

The name policy instructs what user claim is used to populate the auth_server@apcera.me->name. The auth_server claim has been used in past releases to derive the user's default namespace.

Example implementing email for name for the basic model, avoiding the spaces that might be present in common name

auth::/oauth2/http {
  if (auth_server@apcera.me->authType == LDAPBasic) {
    name user->email
  }
}

Example of policy for the Active Directory models.

auth::/oauth2/http {
  if (auth_server@apcera.me->authType == LDAPBasic) {
    name user->name
  }
}

Advanced IAM cluster.conf Examples

Custom ADMulti Model using userPrincipalName as the email claim instead of the mail attribute, sAMAccountName for the name and relativeNamespace claims instead of userPrincipalName, and taking the group's sAMAccountName as the group identifier instead of its common name.

"auth_server": {
  "identity": {
    "ldap_basic": {
      "enabled":         true,
      "model_name":      "ADMulti",
      "search_dn":       "cn=ldaps,ou=ServiceAccounts,ou=Company,dc=adatum,dc=com",
      "search_passwd":   "<search account password>",
      "base_dn":         "dc=adatum,dc=com",
      "uri":             "ldaps://ad1.adatum.com",
      "port":            636,

      "user_attributes":  {
        "sAMAccountName":    "'[name, relativeNamespace]'",
        "userPrincipalName": "email"
      },
      "group_attributes":  {
        "sAMAccountName":    "group"
      }
    },
    ...
  }
}

Custom Model based on AD but using customized searches which avoids the use of default_domain

"auth_server": {
  "identity": {
    "ldap_basic": {
      "enabled":         true,
      "model_name":      "customAD",
      "search_dn":       "cn=ldaps,ou=ServiceAccounts,ou=Company,dc=adatum,dc=com",
      "search_passwd":   "<search account password>",
      "base_dn":         "dc=adatum,dc=com",
      "group_base_dn":   "ou=Company,dc=adatum,dc=com",
      "uri":             "ldaps://ad1.adatum.com",
      "port":            636,

      "model": {
        "customAD": {
          "base_model":  "AD",
          "resolve_before_bind":  true,
          "user_lookup_filter":  "(&(memberOf=CN=Engineering,OU=Departmental Groups,OU=Groups,OU=Company,DC=adatum,DC=com)(sAMAccountName=$APC_USERNAME))",
          "group_lookup":  "(&(objectClass=group)(member=$APC_USER_DN))",
	  "bind_name" : ""
        }
      }
    },
    ...
  }
}

Verifying LDAP authentication

Once the above configuration is in place, test and verify LDAP authentication using APC and the web console.

To test LDAP auth using APC, login to your cluster using the following APC command:

apc login --ldap-basic

Also, verify LDAP authentication by logging in to the web console using the LDAP option.

screenshot

Troubleshooting LDAP configuration

The following debug and error messages appear in the ldap_auth_server logs. Refer this knowledgebase article at the Apcera Support Site for guidance on accessing and reviewing cluster component logs. Or, you can collect all the component logs from the Orchestrator host using the command orchestrator-cli collect logs all.

  • "failed to connect to LDAP server LDAP Result Code 200 : x509: certificate signed by unknown authority"

    Displays if the TLS connection is not trusted, prevents the LDAP server from starting. See Certificate Requirements.

  • "LDAP Configuration: Connection Config: [details here] Claims Config: [details here] Model Config: [details here] Derived Settings: [details here]"

    Displays if configuration is valid and connection to LDAP server is successful (not an error message). Shows the configuration being used. Expected in log as final step in startup.

  • "User requested to authenticate with LDAP Basic auth, but server not properly configured"

    Displays if the auth_server configuration is incorrect or the Auth Server cannot connect to the LDAP server.

  • "Panicked during LDAP token request"

    Displays if the LDAP library code crashes (not common).

  • "Failed to lookup uid [testuid] from LDAP with configured credentials:"

    Displays if the username/uid is not found in the directory via a search rooted at base_dn.

  • "Admin account connected to LDAP. Attempting authentication with DN"

    Debug messages that displays when a user connects with admin credentials (not an error message).

  • "Failed to authenticate as user [testuser] with LDAP"

    Displays if the user password is invalid.

  • "Failed to lookup user [username] in LDAP Server: [detailed error here]"

    Displays if the search_dn user entry in LDAP is misconfigured or does not have sufficient bind permissions.

  • "User %q successfully authenticated via LDAP Basic Bind!"

    Indicates that the user was successfully authenticated with the LDAP server (not an error message).

  • "Error: Failed to look up user with LDAP: ldap: remote error (invalid credentials)"

    Check that the search_dn and search_pwd credentials are correct. The LDAP configuration in the cluster.conf must be lower case.

  • "Failed to retrieve group membership"

    Displays when the group_base_dn does not include group entries.

  • "User cannot retrieve a token: claim reference "permit issue" not found on "auth::/oauth2/http"

    Displays when the policy for permit issue is either missing or has a condition which is not met by the user's claims. The subsequent log lines provides details on the user's claims and the server policy rules. Solution: update policy to provide permit issue claim if the user should be allowed to log in.

  • "User cannot retrieve a token: claim reference "LDAP->email" [or other claim] not found on "auth::/oauth2/http"

    Displays when a rule under auth::/oauth2/http references a claim which isn't included in the user's claims, either because the user's account has no value or because the claim is not mapped in the user_attributes config. Note that the legacy hard-coded mapping puts the user "mail" attribute into LDAP->email, but if user_attributes have been customized then the "mail" attribute may not be available. Solution: change policy or user_attribute configuration so that they correspond and always reference claims that have values.