Skip to content

Configure LDAP / Active Directory

Repod supports authenticating users against an LDAP directory or Microsoft Active Directory. Once configured, users can log in with their existing corporate credentials. Repod uses the ldap3 Python library for all LDAP communication.


1. Prerequisites

Before you open the Repod settings screen, gather the following information from your directory administrator:

Information needed Example
LDAP server hostname or IP ldap.example.com
Port 389 (LDAP), 636 (LDAPS), 3268 (AD Global Catalog)
Transport security Plain, STARTTLS, or SSL/TLS
Bind DN cn=repod-svc,ou=service-accounts,dc=example,dc=com
Bind password The password for the bind account
Base DN ou=users,dc=example,dc=com
User search filter (objectClass=person) or (objectClass=user)
Username attribute uid (OpenLDAP) or sAMAccountName (AD)
Email attribute mail
Group base DN (if using group-role mapping) ou=groups,dc=example,dc=com

Tip

Use a dedicated read-only service account as the bind DN. This account only needs read permission on the user and group subtrees. Never use a domain administrator account as the bind account.


2. Step 1 — Open LDAP settings

  1. Log in to the Repod web interface at http://repod.example.com:3003 as an administrator.
  2. Navigate to Settings → LDAP.
  3. The LDAP configuration panel appears. LDAP is disabled by default until you save a valid configuration and toggle it on.

3. Step 2 — Configure the connection

Fill in the connection fields using the information you gathered in the prerequisites section.

Field Description
Host Hostname or IP address of your LDAP server. Do not include a scheme (ldap://) — that is controlled by the SSL/STARTTLS toggles below.
Port TCP port. Defaults to 389 for unencrypted/STARTTLS and 636 for LDAPS.
SSL / LDAPS Enable to wrap the entire connection in TLS (connect on port 636). Mutually exclusive with STARTTLS.
STARTTLS Enable to upgrade a plain connection to TLS after the initial handshake (port 389). Preferred over unencrypted when LDAPS is not available.
Verify TLS certificate Enabled by default (verify_cert=true). Repod validates the server certificate against the system CA bundle. Disable only in test environments — never in production.
CA bundle path Optional. Path to a custom CA certificate file (PEM format) inside the backend container, for internal CAs not in the system bundle.
Bind DN The full distinguished name of the service account used to search the directory.
Bind password Password for the bind account. Stored encrypted at rest.
Base DN The root of the directory subtree to search for users.
User filter LDAP search filter applied when looking up a user. Combined with the username attribute at login time. Example: (objectClass=person)
Username attribute The LDAP attribute that holds the login name. uid for OpenLDAP, sAMAccountName for Active Directory.
Email attribute The LDAP attribute that holds the user's email address. Usually mail.

Never disable certificate verification in production

Setting Verify TLS certificate to off disables all certificate validation. A man-in-the-middle attacker on your network could intercept credentials. This setting exists only for isolated test environments with self-signed certificates. In production, install your CA certificate in the CA bundle path instead.


4. Step 3 — Map groups to roles

Repod can assign roles to users automatically based on their LDAP group membership. Configure the mapping in the Group → Role mapping table.

LDAP group DN Repod role
cn=repod-admins,ou=groups,dc=example,dc=com admin
cn=repod-publishers,ou=groups,dc=example,dc=com uploader
cn=repod-viewers,ou=groups,dc=example,dc=com viewer

Repod roles:

Role Permissions
admin Full access including settings, user management, GPG, LDAP configuration.
uploader Can upload and import packages. Cannot modify settings or manage users.
viewer Read-only access to package listings and dashboard. Cannot upload.

If a user belongs to multiple mapped groups, the highest-privilege role is applied. If a user belongs to no mapped group, they are assigned the viewer role by default (configurable).

Note

Group membership is evaluated at login time. If you add a user to a group in LDAP, they receive the corresponding Repod role on their next login — no manual role assignment is needed.


5. Step 4 — Enable auto-provisioning

When Auto-provision accounts is toggled on, Repod creates a local user record the first time a person successfully authenticates via LDAP. The local record stores:

  • Username (from the username attribute)
  • Email (from the email attribute)
  • Role (from group mapping, or the default role if no mapping matches)
  • A flag marking the account as LDAP-managed

LDAP-managed accounts cannot have their password changed in Repod — authentication always defers to the LDAP directory.

If auto-provisioning is off, a Repod administrator must create the user account manually before the person can log in via LDAP.


6. Step 5 — Test the connection

Before saving and enabling LDAP, use the Test connection button at the bottom of the settings panel.

What the test does:

  1. Opens a TCP connection to the LDAP server on the configured host and port.
  2. Negotiates TLS if SSL or STARTTLS is enabled.
  3. Binds as the service account using the bind DN and password.
  4. Performs a search for one user matching the configured base DN and user filter.
  5. Returns success or a structured error.

Interpreting the result:

Result Meaning
"Connection successful" All fields are correct. Click Save and enable LDAP.
CERTIFICATE_VERIFY_FAILED The server's TLS certificate is not trusted. See troubleshooting below.
INVALID_CREDENTIALS The bind DN or bind password is wrong.
NO_SUCH_OBJECT The base DN does not exist in the directory.
CONNECTION_REFUSED Wrong host or port, or a firewall is blocking the connection.
SERVER_DOWN The LDAP server is unreachable from the Repod backend container.

Tip

If the test fails with a network error, verify connectivity from inside the backend container: docker compose exec backend nc -zv ldap.example.com 389


7. Step 6 — First LDAP login

Once LDAP is enabled and the configuration is saved:

  1. Open the Repod login page.
  2. Enter your LDAP username (the value of sAMAccountName or uid, not the full DN).
  3. Enter your LDAP password.
  4. Click Sign in.

Repod binds to the directory as the service account, searches for the user, verifies the credentials, evaluates group membership, and creates or updates the local user record.

The JWT issued after a successful LDAP login is identical to one issued after a local login — all API calls use the same Authorization: Bearer <token> header regardless of authentication method.


8. OpenLDAP example configuration

A typical OpenLDAP deployment using uid as the username attribute:

Field Value
Host openldap.example.com
Port 636
SSL Enabled
STARTTLS Disabled
Verify TLS certificate Enabled
Bind DN cn=repod-svc,ou=service-accounts,dc=example,dc=com
Bind password s3cr3tpassword
Base DN ou=users,dc=example,dc=com
User filter (objectClass=inetOrgPerson)
Username attribute uid
Email attribute mail

Group mapping:

LDAP group DN Repod role
cn=repod-admins,ou=groups,dc=example,dc=com admin
cn=developers,ou=groups,dc=example,dc=com uploader

9. Active Directory example configuration

Active Directory uses sAMAccountName for short-form usernames or userPrincipalName for UPN-style (user@domain) logins.

Field Value
Host dc01.corp.example.com
Port 636
SSL Enabled
STARTTLS Disabled
Verify TLS certificate Enabled
Bind DN CN=repod-svc,OU=Service Accounts,DC=corp,DC=example,DC=com
Bind password s3cr3tpassword
Base DN OU=Employees,DC=corp,DC=example,DC=com
User filter (objectClass=user)
Username attribute sAMAccountName
Email attribute mail

sAMAccountName vs userPrincipalName

Use sAMAccountName if your users log in with their short username (jsmith). Use userPrincipalName if they log in with their UPN ([email protected]). The attribute name must match exactly what your users type into the Repod login field — there is no automatic normalisation.

Group mapping for AD security groups:

LDAP group DN Repod role
CN=Repod-Admins,OU=Groups,DC=corp,DC=example,DC=com admin
CN=Repod-Publishers,OU=Groups,DC=corp,DC=example,DC=com uploader
CN=All-Staff,OU=Groups,DC=corp,DC=example,DC=com viewer

For Active Directory Global Catalog queries (searching across multiple domains), use port 3268 (plain) or 3269 (SSL) instead of the standard LDAP ports.


10. Troubleshooting

CERTIFICATE_VERIFY_FAILED

The LDAP server's TLS certificate is not signed by a CA in the backend container's system bundle.

Options: 1. Recommended: Mount your internal CA certificate into the backend container and set the CA bundle path field to its location.

# In docker-compose.yaml, under the backend service:
volumes:
  - /etc/ssl/certs/internal-ca.pem:/etc/ssl/certs/internal-ca.pem:ro
Then set CA bundle path to /etc/ssl/certs/internal-ca.pem.

  1. Test environments only: Disable Verify TLS certificate in the LDAP settings. Never do this in production.

INVALID_CREDENTIALS

The bind DN or bind password is incorrect.

  • Double-check the bind DN format. Active Directory requires the full CN=...,DC=... form, not just the username.
  • Verify the service account password has not expired. AD service accounts should have password expiry disabled.
  • Confirm the service account has not been locked out due to failed login attempts from a previous misconfigured connection test.

NO_SUCH_OBJECT

The base DN does not exist in the directory, or the bind account does not have permission to read it.

  • Verify the base DN by connecting with ldapsearch from the Repod backend container:
    docker compose exec backend \
      ldapsearch -H ldaps://ldap.example.com \
        -D "cn=repod-svc,ou=service-accounts,dc=example,dc=com" \
        -w "s3cr3tpassword" \
        -b "ou=users,dc=example,dc=com" \
        "(uid=testuser)"
    
  • If the command returns results, the base DN is correct and the issue is in Repod's configuration. If it returns No such object, the base DN itself is wrong.

Group mapping not applied

Users log in successfully but receive the wrong role.

  • Verify the group DN in the mapping table is exactly correct, including the case of each component.
  • Check that the user is actually a member of the group in LDAP:
    docker compose exec backend \
      ldapsearch -H ldaps://ldap.example.com \
        -D "cn=repod-svc,ou=service-accounts,dc=example,dc=com" \
        -w "s3cr3tpassword" \
        -b "cn=repod-admins,ou=groups,dc=example,dc=com" \
        "(member=uid=testuser,ou=users,dc=example,dc=com)"
    
  • In Active Directory, memberOf is on the user object; in OpenLDAP, member is on the group object. Repod queries the group object — ensure the group's member attribute contains the user's full DN.