What the LDAP parameters do is described in Overview; where the entries are written and how a change is applied is described on Configuration.

LDAP servers

The key of a server entry is the server name. What each connection parameter does is described in LDAP synchronization; the group_sync section, which creates the groups and assigns the roles, is described in Groups and access rights and role_mapping section. The group_sync section is taken into account only for the server under the main key (see Synchronization scope).

  • Linux package
  • Omnibus Docker
  • Helm Chart
  • Deckhouse Kubernetes Platform module

Signing in through LDAP is turned on by gitlab_rails['ldap_enabled']. The servers are described in gitlab_rails['ldap_servers'], whose value is a YAML document.

The value is parsed as YAML, so the indentation inside the block is significant and tab characters break it.

gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
  main:
    label: 'Head office'
    host: ldap-main.example.com
    port: 3389
    uid: 'cn'
    bind_dn: 'uid=viewer,ou=People,dc=example,dc=com'
    password: 'viewer123'
    base: 'ou=People,dc=example,dc=com'
    # Ignore users blocked in the directory (optional).
    user_filter: '(!(nsAccountLock=TRUE))'
    # The user is found in LDAP — sign-in is allowed immediately.
    block_auto_created_users: false
    sync_name: true
    group_sync:
      create_groups: true
      base: 'ou=Groups,dc=example,dc=com'
      filter: '(objectClass=groupOfNames)'
      prefix:
        attribute: 'businessCategory'
        default: 'default-program'
      top_level_group: 'LdapGroups'
      name_mask: '(?<=-)[A-z0-9]*$'
      owner: 'root'
      role_mapping:
        - by_name: '.*-project_manager-.*'
          gitlab_role: 'maintainer'
        - by_name: '.*-developer-.*'
          gitlab_role: 'developer'
        - by_name: '.*-participant-.*'
          gitlab_role: 'reporter'
  contractors:
    label: 'Contractors'
    host: ldap-contractors.example.com
    port: 3389
    uid: 'cn'
    bind_dn: 'uid=viewer,ou=People,dc=contractors,dc=example,dc=com'
    password: 'viewer123'
    base: 'ou=People,dc=contractors,dc=example,dc=com'
EOS
The keys are gitlab_rails['ldap_enabled'] and gitlab_rails['ldap_servers'] of the Linux package tab. The value of gitlab_rails['ldap_servers'] spans several lines, so write it in /srv/code/config/gitlab.rb on the configuration volume.

The servers are values under global.appConfig.ldap.servers, with the same keys the product reads. The bind password is taken from a Secret:

d8 k -n code create secret generic code-ldap-password \
  --from-literal=password='viewer123'
global:
  appConfig:
    ldap:
      servers:
        main:
          label: 'Head office'
          host: ldap-main.example.com
          port: 3389
          uid: 'cn'
          bind_dn: 'uid=viewer,ou=People,dc=example,dc=com'
          password:
            secret: code-ldap-password
            key: password
          base: 'ou=People,dc=example,dc=com'
          user_filter: '(!(nsAccountLock=TRUE))'
          block_auto_created_users: false
          sync_name: true
          group_sync:
            create_groups: true
            base: 'ou=Groups,dc=example,dc=com'
            filter: '(objectClass=groupOfNames)'
            top_level_group: 'LdapGroups'
            owner: 'root'
            role_mapping:
              - by_name: '.*-developer-.*'
                gitlab_role: 'developer'
        contractors:
          label: 'Contractors'
          host: ldap-contractors.example.com
          port: 3389
          uid: 'cn'
          bind_dn: 'uid=viewer,ou=People,dc=contractors,dc=example,dc=com'
          password:
            secret: code-ldap-password
            key: password
          base: 'ou=People,dc=contractors,dc=example,dc=com'

The servers are keys of the servers parameter in the spec.appConfig.ldap section:

servers:
  main:
    label: ldap
    host: 127.0.0.1
    port: 3389
    bindDn: 'uid=viewer,ou=People,dc=example,dc=com'
    base: 'ou=People,dc=example,dc=com'
    uid: 'cn'
    password: 'viewer123'
    syncName: true
    groupSync:
      createGroups: true
      base: 'ou=Groups,dc=example,dc=com'
      filter: '(objectClass=groupOfNames)'
      prefix:
        attribute: 'businessCategory'
        default: 'default-program'
      topLevelGroup: 'LdapGroups'
      nameMask: '(?<=-)[A-z0-9]*$'
      owner: 'root'
      roleMapping:
        - byName: '.*-project_manager-.*'
          gitlabRole: 'Maintainer'
        - byName: '.*-developer-.*'
          gitlabRole: 'Developer'
        - byName: '.*-participant-.*'
          gitlabRole: 'Reporter'

Multiple LDAP servers

Several servers are described by repeating the server entry under another key. Each server has its own connection parameters; the group_sync section with everything in it is taken into account only for the server under the main key (see Synchronization scope). How a user is identified and how the access decision is taken when the same user is found on several servers is described in Multiple LDAP servers.

  • Linux package
  • Omnibus Docker
  • Helm Chart
  • Deckhouse Kubernetes Platform module
The entries are keys of the same YAML document in gitlab_rails['ldap_servers'], as main and contractors in the LDAP servers section above.
The entries are the ones of the Linux package tab, written in /srv/code/config/gitlab.rb on the configuration volume.
The entries are keys under global.appConfig.ldap.servers, as main and contractors in the LDAP servers section above.

The entries are keys of the servers parameter in the spec.appConfig.ldap section:

servers:
  main:
    label: 'Head office'
    host: ldap-main.example.com
    base: 'ou=People,dc=example,dc=com'
    uid: 'cn'
    # Other connection parameters.
    groupSync:
      base: 'ou=Groups,dc=example,dc=com'
      roleMapping:
        - byName: '.*-developer-.*'
          gitlabRole: 'Developer'
  contractors:
    label: 'Contractors'
    host: ldap-contractors.example.com
    base: 'ou=People,dc=contractors,dc=example,dc=com'
    uid: 'cn'
    # Other connection parameters.

Linking OIDC accounts to LDAP

Automatic linking of the OIDC account to the LDAP account is turned on by the auto_link_ldap_user parameter. How the LDAP account is found, and what happens on the first and the subsequent sign-ins, is described in Linking OIDC accounts to LDAP.

  • Linux package
  • Omnibus Docker
  • Helm Chart
  • Deckhouse Kubernetes Platform module
gitlab_rails['omniauth_auto_link_ldap_user'] = true
The key is the one of the Linux package tab. Its value is a single line, so it fits into GITLAB_OMNIBUS_CONFIG as well as into /srv/code/config/gitlab.rb.
global:
  appConfig:
    omniauth:
      autoLinkLdapUser: true

The parameter is set in the spec.appConfig.omniauth section:

autoLinkLdapUser: true

LDAP as the source of truth

To allow users found in LDAP to sign in immediately and to send everyone else for administrator approval, combine auto_link_ldap_user and block_auto_created_users of the OmniAuth parameters with block_auto_created_users of the main LDAP server (see LDAP as the source of truth).

  • Linux package
  • Omnibus Docker
  • Helm Chart
  • Deckhouse Kubernetes Platform module
gitlab_rails['omniauth_auto_link_ldap_user'] = true
# The user is not found in LDAP — the account is created blocked,
# pending administrator approval.
gitlab_rails['omniauth_block_auto_created_users'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
  main:
    # The user is found in LDAP — sign-in is allowed immediately.
    block_auto_created_users: false
    # Other connection parameters.
EOS
The keys are the ones of the Linux package tab, written in /srv/code/config/gitlab.rb on the configuration volume.
global:
  appConfig:
    omniauth:
      autoLinkLdapUser: true
      # The user is not found in LDAP — the account is created blocked,
      # pending administrator approval.
      blockAutoCreatedUsers: true
    ldap:
      servers:
        main:
          # The user is found in LDAP — sign-in is allowed immediately.
          block_auto_created_users: false

The parameters are set in the spec.appConfig section:

omniauth:
  autoLinkLdapUser: true
  # The user is not found in LDAP — the account is created blocked,
  # pending administrator approval.
  blockAutoCreatedUsers: true
ldap:
  servers:
    main:
      # The user is found in LDAP — sign-in is allowed immediately.
      blockAutoCreatedUsers: false

Synchronization schedule

The schedule of the synchronization job is written in cron format. What the job does on each run is described in LDAP synchronization; a run started by hand is described in Manual synchronization run.

  • Linux package
  • Omnibus Docker
  • Helm Chart
  • Deckhouse Kubernetes Platform module
gitlab_rails['ldap_sync_worker_cron'] = "0 * * * *"
The key is the one of the Linux package tab. Its value is a single line, so it fits into GITLAB_OMNIBUS_CONFIG as well as into /srv/code/config/gitlab.rb.
global:
  appConfig:
    cron_jobs:
      ldap_sync_worker:
        cron: "0 * * * *"

The interval is set by the cronJobs parameter of the spec.appConfig section:

cronJobs:
  ldapSyncWorker:
    cron: "0 * * * *"

Complete example: signing in through OIDC with permissions from LDAP

The steps below describe a setup where users sign in through an OIDC provider (for example, Keycloak), while groups, memberships, and roles come from LDAP.

The setup includes the following steps:

  1. Configure the LDAP provider.
  2. Configure the OIDC provider and enable the LDAP integration.
  3. Verify the integration upon first login.
  4. Synchronize permissions.

Prerequisites

To set this up, you’ll need:

  • An OIDC provider.
  • An LDAP directory with the same users and with groups whose names allow determining the role.
  • An LDAP service account with read access to the directory (the bind_dn and password parameters).

The uid or email value in the OIDC provider must match the value of the corresponding attribute in LDAP, otherwise linking will not work.

How the account is matched is described in How the LDAP account is found.

Configure the LDAP provider

The server entry names the directory, the search base and the service account, and its group_sync section turns the group names into roles.

  • Linux package
  • Omnibus Docker
  • Helm Chart
  • Deckhouse Kubernetes Platform module
gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
  main:
    label: ldap
    host: ldap.example.com
    port: 3389
    bind_dn: 'uid=viewer,ou=People,dc=example,dc=com'
    password: 'viewer123'
    base: 'ou=People,dc=example,dc=com'
    uid: 'cn'
    sync_name: true
    # Ignore users blocked in the directory (optional).
    user_filter: '(!(nsAccountLock=TRUE))'
    # The user is found in LDAP — sign-in is allowed immediately.
    block_auto_created_users: false
    group_sync:
      create_groups: true
      base: 'ou=Groups,dc=example,dc=com'
      filter: '(objectClass=groupOfNames)'
      top_level_group: 'LdapGroups'
      name_mask: '(?<=-)[A-z0-9]*$'
      owner: 'root'
      role_mapping:
        - by_name: '.*-maintainer-.*'
          gitlab_role: 'maintainer'
        - by_name: '.*-developer-.*'
          gitlab_role: 'developer'
        - by_name: '.*-participant-.*'
          gitlab_role: 'reporter'
EOS
The keys are gitlab_rails['ldap_enabled'] and gitlab_rails['ldap_servers'] of the Linux package tab, written in /srv/code/config/gitlab.rb on the configuration volume.
global:
  appConfig:
    ldap:
      servers:
        main:
          label: ldap
          host: ldap.example.com
          port: 3389
          bind_dn: 'uid=viewer,ou=People,dc=example,dc=com'
          password:
            secret: code-ldap-password
            key: password
          base: 'ou=People,dc=example,dc=com'
          uid: 'cn'
          sync_name: true
          # Ignore users blocked in the directory (optional).
          user_filter: '(!(nsAccountLock=TRUE))'
          # The user is found in LDAP — sign-in is allowed immediately.
          block_auto_created_users: false
          group_sync:
            create_groups: true
            base: 'ou=Groups,dc=example,dc=com'
            filter: '(objectClass=groupOfNames)'
            top_level_group: 'LdapGroups'
            name_mask: '(?<=-)[A-z0-9]*$'
            owner: 'root'
            role_mapping:
              - by_name: '.*-maintainer-.*'
                gitlab_role: 'maintainer'
              - by_name: '.*-developer-.*'
                gitlab_role: 'developer'
              - by_name: '.*-participant-.*'
                gitlab_role: 'reporter'

Set up the configuration in the servers parameter of the spec.appConfig.ldap section:

servers:
  main:
    label: ldap
    host: ldap.example.com
    port: 3389
    bindDn: 'uid=viewer,ou=People,dc=example,dc=com'
    password: 'viewer123'
    base: 'ou=People,dc=example,dc=com'
    uid: 'cn'
    syncName: true
    # Ignore users blocked in the directory (optional).
    userFilter: '(!(nsAccountLock=TRUE))'
    # The user is found in LDAP — sign-in is allowed immediately.
    blockAutoCreatedUsers: false
    groupSync:
      createGroups: true
      base: 'ou=Groups,dc=example,dc=com'
      filter: '(objectClass=groupOfNames)'
      topLevelGroup: 'LdapGroups'
      nameMask: '(?<=-)[A-z0-9]*$'
      owner: 'root'
      roleMapping:
        - byName: '.*-maintainer-.*'
          gitlabRole: 'Maintainer'
        - byName: '.*-developer-.*'
          gitlabRole: 'Developer'
        - byName: '.*-participant-.*'
          gitlabRole: 'Reporter'

Configure the OIDC provider and enable linking to LDAP

Pay attention to the uid_field parameter: the field it points to becomes the account uid, and this value is used when looking the user up in LDAP. It must match the value of the attribute specified in the LDAP server uid parameter (cn in this example), or the email address — for details, see How the LDAP account is found.

The remaining provider parameters are described in the OpenID Connect (OIDC) section.

  • Linux package
  • Omnibus Docker
  • Helm Chart
  • Deckhouse Kubernetes Platform module
gitlab_rails['omniauth_enabled'] = true
gitlab_rails['omniauth_auto_link_ldap_user'] = true
gitlab_rails['omniauth_providers'] = [
  {
    name: 'openid_connect',   # Do not change this value.
    label: 'Keycloak',        # Sign-in button label.
    groups_attribute: 'gitlab_group',
    args: {
      name: 'openid_connect',
      scope: ['openid', 'profile', 'email'],
      response_type: 'code',
      issuer: 'https://keycloak.example.com/realms/example',
      discovery: true,
      client_auth_method: 'query',
      uid_field: 'preferred_username',
      send_scope_to_token_endpoint: false,
      pkce: true,
      client_options: {
        identifier: '<client_id>',
        secret: '<client_secret>',
        redirect_uri: 'https://code.example.com/users/auth/openid_connect/callback'
      }
    }
  }
]
The keys are gitlab_rails['omniauth_enabled'], gitlab_rails['omniauth_auto_link_ldap_user'] and gitlab_rails['omniauth_providers'] of the Linux package tab, written in /srv/code/config/gitlab.rb on the configuration volume.

The provider entry of this example is stored in a Secret and referenced from the values, with linking turned on beside it:

global:
  appConfig:
    omniauth:
      enabled: true
      autoLinkLdapUser: true
      providers:
        - secret: code-omniauth-keycloak
          key: provider

Set up the configuration in the spec.appConfig.omniauth section:

autoLinkLdapUser: true
providers:
  - name: 'openid_connect'   # Do not change this value.
    label: 'Keycloak'        # Sign-in button label.
    groupsAttribute: 'gitlab_group'
    args:
      name: 'openid_connect'
      scope:
        - 'openid'
        - 'profile'
        - 'email'
      response_type: 'code'
      issuer: 'https://keycloak.example.com/realms/example'
      discovery: true
      client_auth_method: 'query'
      uid_field: 'preferred_username'
      send_scope_to_token_endpoint: false
      pkce: true
      client_options:
        identifier: '<client_id>'
        secret: '<client_secret>'
        redirect_uri: 'https://code.example.com/users/auth/openid_connect/callback'

Verify linking on the first sign-in

To verify linking, follow these steps:

  1. Sign in with a test user through the OIDC provider.
  2. Open the user page in the admin area (/admin/users/<username>/identities). A linked account must have two identities: openid_connect and ldapmain (the LDAP identity name consists of the ldap prefix and the LDAP server name, main in this example).

If the LDAP identity is missing, check the following:

  • the uid or email values match in the OIDC provider and in LDAP;
  • the user falls within the base search scope and is not filtered out by user_filter;
  • the auto_link_ldap_user parameter is enabled.

Rights synchronization

Right after the first sign-in, the user has an account but no group or project memberships. Wait for the next synchronization or run it manually (see Manual synchronization run), then check that:

  • the groups are created inside the group specified in group_sync.top_level_group;
  • the user is added to them with the role matching role_mapping.