670 lines
20 KiB
Markdown
670 lines
20 KiB
Markdown
# OpenLDAP Container Operations Guide
|
|
|
|
## Introduction
|
|
|
|
This document provides operational guidance for deploying and managing the Enterprise OpenLDAP container. It explains not just the how, but also the what and why behind each configuration decision.
|
|
|
|
### What This Container Provides
|
|
|
|
This is a purpose-built OpenLDAP container designed to serve as a central identity provider for an enterprise environment. It provides:
|
|
|
|
- **Centralized user authentication** for all services (Keycloak, Nextcloud, Gitea, mail, etc.)
|
|
- **POSIX account support** for Linux systems via SSSD integration
|
|
- **Group-based access control** with automatic membership tracking
|
|
- **Service account isolation** so each application has its own credentials with limited permissions
|
|
|
|
### Why OpenLDAP?
|
|
|
|
LDAP (Lightweight Directory Access Protocol) remains the standard for centralized identity management because:
|
|
|
|
1. **Universal support** - Nearly every enterprise application supports LDAP authentication
|
|
2. **Hierarchical organization** - Natural fit for organizational structures (users, groups, departments)
|
|
3. **Fine-grained access control** - Different applications can have different levels of access
|
|
4. **Proven reliability** - Decades of production use in demanding environments
|
|
|
|
### Key Design Decisions
|
|
|
|
**RFC2307bis instead of NIS schema**: Traditional LDAP setups use the NIS schema where `posixGroup` is a STRUCTURAL class. This prevents combining POSIX groups with other group types. We use RFC2307bis where `posixGroup` is AUXILIARY, allowing groups to have both POSIX attributes (gidNumber) and member tracking (member attribute). This is essential for the memberOf overlay to work correctly.
|
|
|
|
**Pre-configured overlays**: The container includes four overlays that are critical for enterprise use:
|
|
- **memberOf** - Automatically maintains reverse group membership on user objects
|
|
- **refint** - Maintains referential integrity when users are deleted
|
|
- **unique** - Prevents duplicate UIDs, email addresses, and ID numbers
|
|
- **ppolicy** - Enforces password complexity and expiration policies
|
|
|
|
**Service accounts**: Instead of sharing the admin password with applications, each service gets its own account with read-only access to the directory. This follows the principle of least privilege and provides audit trails.
|
|
|
|
---
|
|
|
|
## Architecture Overview
|
|
|
|
### Directory Structure
|
|
|
|
The container creates a directory tree optimized for enterprise use:
|
|
|
|
```
|
|
dc=example,dc=com ← Your organization's base
|
|
│
|
|
├── ou=People ← All user accounts live here
|
|
│ └── uid=jdoe ← Individual user
|
|
│
|
|
├── ou=Groups ← Authorization and access groups
|
|
│ ├── cn=admins ← LDAP administrators
|
|
│ └── cn=developers ← Example application group
|
|
│
|
|
├── ou=Services ← Application service accounts
|
|
│ ├── cn=keycloak ← For Keycloak LDAP federation
|
|
│ ├── cn=nextcloud ← For Nextcloud user backend
|
|
│ ├── cn=gitea ← For Gitea authentication
|
|
│ ├── cn=postfix ← For mail routing lookups
|
|
│ ├── cn=dovecot ← For mail authentication
|
|
│ └── cn=sssd ← For Linux PAM/NSS
|
|
│
|
|
├── ou=Domains ← Virtual mail domains (for mail server)
|
|
│
|
|
├── ou=Policies ← Password and security policies
|
|
│ └── cn=default ← Default password policy
|
|
│
|
|
└── ou=Kerberos ← Reserved for Kerberos integration
|
|
```
|
|
|
|
**Why this structure?**
|
|
|
|
- **Separate OUs for each purpose** makes ACLs (access control lists) simpler and more secure
|
|
- **Service accounts in their own OU** allows restricting what parts of the tree they can access
|
|
- **Policies OU** keeps password policies separate from user data
|
|
- **Domains OU** is specifically for mail server virtual domain configuration
|
|
|
|
### How Authentication Works
|
|
|
|
When an application authenticates a user:
|
|
|
|
1. Application connects to LDAP using its service account (e.g., `cn=keycloak,ou=Services,...`)
|
|
2. Application searches for the user in `ou=People` by uid or email
|
|
3. Application attempts to bind (authenticate) as that user with their password
|
|
4. LDAP verifies the password and returns success/failure
|
|
5. Application can then query the user's groups via the `memberOf` attribute
|
|
|
|
The service account never sees user passwords - it only searches for users. The actual password verification happens when the user's DN is used for a bind operation.
|
|
|
|
---
|
|
|
|
## Getting Started
|
|
|
|
### Prerequisites
|
|
|
|
Before deploying, ensure you have:
|
|
|
|
- Docker installed and running
|
|
- Decided on your domain name (this determines your base DN)
|
|
- Generated a strong admin password
|
|
- (Optional) TLS certificates if you need encrypted connections
|
|
|
|
### Step 1: Basic Deployment
|
|
|
|
The simplest deployment requires just three pieces of information:
|
|
|
|
```bash
|
|
docker run -d --name openldap \
|
|
-e LDAP_DOMAIN=example.com \
|
|
-e LDAP_ORGANISATION="Example Corporation" \
|
|
-e LDAP_ADMIN_PASSWORD=your-secure-password \
|
|
-p 389:389 \
|
|
enterprise-openldap:latest
|
|
```
|
|
|
|
**What happens on first run:**
|
|
|
|
1. The container detects this is a fresh start (no existing database)
|
|
2. It generates the base DN from your domain (`example.com` → `dc=example,dc=com`)
|
|
3. Creates the cn=config database with your settings
|
|
4. Loads all required schemas in the correct order
|
|
5. Configures the overlays (memberOf, refint, unique, ppolicy)
|
|
6. Creates the directory structure (OUs)
|
|
7. Sets up ACLs to protect sensitive data
|
|
8. Optionally creates service accounts
|
|
9. Starts the LDAP server
|
|
|
|
On subsequent restarts, steps 2-8 are skipped - the existing database is used.
|
|
|
|
### Step 2: Verify the Deployment
|
|
|
|
Test that the server is responding:
|
|
|
|
```bash
|
|
# Anonymous query to verify the server is up
|
|
ldapsearch -x -H ldap://localhost:389 -b "" -s base "(objectClass=*)"
|
|
```
|
|
|
|
Test admin authentication:
|
|
|
|
```bash
|
|
ldapsearch -x -H ldap://localhost:389 \
|
|
-D "cn=admin,dc=example,dc=com" \
|
|
-w "your-secure-password" \
|
|
-b "dc=example,dc=com" "(objectClass=organizationalUnit)"
|
|
```
|
|
|
|
You should see the OUs (People, Groups, Services, etc.) listed.
|
|
|
|
### Step 3: Enable Service Accounts (Recommended)
|
|
|
|
Service accounts allow applications to connect with limited, auditable credentials:
|
|
|
|
```bash
|
|
docker run -d --name openldap \
|
|
-e LDAP_DOMAIN=example.com \
|
|
-e LDAP_ORGANISATION="Example Corporation" \
|
|
-e LDAP_ADMIN_PASSWORD=your-secure-password \
|
|
-e LDAP_CREATE_SERVICE_ACCOUNTS=true \
|
|
-p 389:389 \
|
|
enterprise-openldap:latest
|
|
```
|
|
|
|
The generated passwords are saved to `/var/lib/openldap/service-passwords.txt` inside the container. Retrieve them:
|
|
|
|
```bash
|
|
docker exec openldap cat /var/lib/openldap/service-passwords.txt
|
|
```
|
|
|
|
**Important**: Save these passwords securely, then delete the file:
|
|
|
|
```bash
|
|
docker exec openldap rm /var/lib/openldap/service-passwords.txt
|
|
```
|
|
|
|
### Step 4: Add Persistence
|
|
|
|
Without volumes, your data is lost when the container is removed. For production, always use volumes:
|
|
|
|
```bash
|
|
docker run -d --name openldap \
|
|
-v openldap-data:/var/lib/openldap/openldap-data \
|
|
-v openldap-config:/etc/openldap/slapd.d \
|
|
-e LDAP_DOMAIN=example.com \
|
|
-e LDAP_ORGANISATION="Example Corporation" \
|
|
-e LDAP_ADMIN_PASSWORD=your-secure-password \
|
|
-e LDAP_CREATE_SERVICE_ACCOUNTS=true \
|
|
-p 389:389 \
|
|
enterprise-openldap:latest
|
|
```
|
|
|
|
**Volume purposes:**
|
|
|
|
| Volume | Contains | Why it matters |
|
|
|--------|----------|----------------|
|
|
| `/var/lib/openldap/openldap-data` | The actual LDAP database (MDB format) | All your users, groups, and data |
|
|
| `/etc/openldap/slapd.d` | The cn=config configuration | Schema, overlays, ACLs, indexes |
|
|
|
|
### Step 5: Enable TLS (Production)
|
|
|
|
For production environments, you should enable TLS to encrypt connections:
|
|
|
|
```bash
|
|
docker run -d --name openldap \
|
|
-v openldap-data:/var/lib/openldap/openldap-data \
|
|
-v openldap-config:/etc/openldap/slapd.d \
|
|
-v /path/to/certs:/certs:ro \
|
|
-e LDAP_DOMAIN=example.com \
|
|
-e LDAP_ORGANISATION="Example Corporation" \
|
|
-e LDAP_ADMIN_PASSWORD=your-secure-password \
|
|
-e LDAP_TLS_ENABLED=true \
|
|
-p 389:389 -p 636:636 \
|
|
enterprise-openldap:latest
|
|
```
|
|
|
|
The `/certs` directory must contain:
|
|
- `ldap.crt` - Server certificate
|
|
- `ldap.key` - Private key (readable only by root/ldap user)
|
|
- `ca.crt` - CA certificate (for client verification)
|
|
|
|
**Port 389 vs 636:**
|
|
- Port 389 (LDAP) - Unencrypted, but supports STARTTLS upgrade
|
|
- Port 636 (LDAPS) - TLS from the start, like HTTPS
|
|
|
|
Most modern applications support STARTTLS on port 389, which is generally preferred.
|
|
|
|
---
|
|
|
|
## Configuration Reference
|
|
|
|
### Required Environment Variables
|
|
|
|
These must be set for the container to start:
|
|
|
|
| Variable | Purpose | Example |
|
|
|----------|---------|---------|
|
|
| `LDAP_DOMAIN` | Your organization's domain. Converted to base DN automatically. | `example.com` → `dc=example,dc=com` |
|
|
| `LDAP_ORGANISATION` | Human-readable organization name, stored in the base entry. | `Example Corporation` |
|
|
| `LDAP_ADMIN_PASSWORD` | Password for the directory administrator account. **Use cleartext** - the container hashes it automatically with `slappasswd`. | `Str0ng!Passw0rd` |
|
|
|
|
### Optional Environment Variables
|
|
|
|
#### General Settings
|
|
|
|
| Variable | Default | Purpose |
|
|
|----------|---------|---------|
|
|
| `LDAP_BASE_DN` | Generated from domain | Override if you need a non-standard base DN |
|
|
| `LDAP_CONFIG_PASSWORD` | Random | Password for cn=config administrative access. Only needed for advanced configuration changes. |
|
|
| `LDAP_LOG_LEVEL` | `256` | Controls logging verbosity. `256` logs connections and operations. See [Log Levels](#understanding-log-levels). |
|
|
|
|
#### TLS Settings
|
|
|
|
| Variable | Default | Purpose |
|
|
|----------|---------|---------|
|
|
| `LDAP_TLS_ENABLED` | `true` | Master switch for TLS. Set `false` to disable completely. |
|
|
| `LDAP_TLS_CERT_FILE` | `/certs/ldap.crt` | Path to server certificate inside container |
|
|
| `LDAP_TLS_KEY_FILE` | `/certs/ldap.key` | Path to private key inside container |
|
|
| `LDAP_TLS_CA_FILE` | `/certs/ca.crt` | Path to CA certificate for client verification |
|
|
| `LDAP_TLS_VERIFY_CLIENT` | `try` | Client cert policy: `never` (don't ask), `try` (optional), `demand` (required) |
|
|
|
|
#### Service Account Settings
|
|
|
|
| Variable | Default | Purpose |
|
|
|----------|---------|---------|
|
|
| `LDAP_CREATE_SERVICE_ACCOUNTS` | `false` | Set `true` to create pre-configured service accounts |
|
|
| `LDAP_SERVICE_KEYCLOAK_PASSWORD` | Random | Explicit password for Keycloak account |
|
|
| `LDAP_SERVICE_NEXTCLOUD_PASSWORD` | Random | Explicit password for Nextcloud account |
|
|
| `LDAP_SERVICE_GITEA_PASSWORD` | Random | Explicit password for Gitea account |
|
|
| `LDAP_SERVICE_POSTFIX_PASSWORD` | Random | Explicit password for Postfix account |
|
|
| `LDAP_SERVICE_DOVECOT_PASSWORD` | Random | Explicit password for Dovecot account |
|
|
| `LDAP_SERVICE_SSSD_PASSWORD` | Random | Explicit password for SSSD account |
|
|
|
|
**When to set explicit passwords:** If you're deploying with configuration management (Ansible, Terraform) and need predictable credentials, set them explicitly. For manual deployments, random passwords are more secure.
|
|
|
|
---
|
|
|
|
## Day-to-Day Operations
|
|
|
|
### Adding Users
|
|
|
|
Users belong in `ou=People`. Here's a complete user entry:
|
|
|
|
```ldif
|
|
dn: uid=jdoe,ou=People,dc=example,dc=com
|
|
objectClass: inetOrgPerson
|
|
objectClass: posixAccount
|
|
objectClass: shadowAccount
|
|
uid: jdoe
|
|
cn: John Doe
|
|
sn: Doe
|
|
givenName: John
|
|
mail: john.doe@example.com
|
|
uidNumber: 10001
|
|
gidNumber: 10000
|
|
homeDirectory: /home/jdoe
|
|
loginShell: /bin/bash
|
|
userPassword: {SSHA}hashed-password
|
|
```
|
|
|
|
**Object classes explained:**
|
|
- `inetOrgPerson` - Standard LDAP person with email, phone, etc.
|
|
- `posixAccount` - UNIX account attributes (uid/gid numbers, home directory, shell)
|
|
- `shadowAccount` - Password aging and expiration
|
|
|
|
Add the user:
|
|
|
|
```bash
|
|
ldapadd -x -H ldap://localhost:389 \
|
|
-D "cn=admin,dc=example,dc=com" \
|
|
-w "admin-password" \
|
|
-f user.ldif
|
|
```
|
|
|
|
### Adding Groups
|
|
|
|
Groups use `groupOfMembers` (for member tracking) combined with `posixGroup` (for UNIX gidNumber):
|
|
|
|
```ldif
|
|
dn: cn=developers,ou=Groups,dc=example,dc=com
|
|
objectClass: groupOfMembers
|
|
objectClass: posixGroup
|
|
cn: developers
|
|
gidNumber: 10001
|
|
description: Development team
|
|
member: uid=jdoe,ou=People,dc=example,dc=com
|
|
```
|
|
|
|
**Why groupOfMembers instead of groupOfNames?**
|
|
|
|
`groupOfNames` requires at least one member - you can't have an empty group. `groupOfMembers` allows empty groups, which is often needed when setting up access control before adding members.
|
|
|
|
### Checking Group Membership
|
|
|
|
Thanks to the memberOf overlay, you can see a user's groups directly:
|
|
|
|
```bash
|
|
ldapsearch -x -H ldap://localhost:389 \
|
|
-D "cn=admin,dc=example,dc=com" \
|
|
-w "admin-password" \
|
|
-b "uid=jdoe,ou=People,dc=example,dc=com" \
|
|
memberOf
|
|
```
|
|
|
|
This returns all groups the user belongs to, without having to search each group.
|
|
|
|
### Modifying Entries
|
|
|
|
To change an attribute:
|
|
|
|
```ldif
|
|
dn: uid=jdoe,ou=People,dc=example,dc=com
|
|
changetype: modify
|
|
replace: mail
|
|
mail: j.doe@example.com
|
|
```
|
|
|
|
```bash
|
|
ldapmodify -x -H ldap://localhost:389 \
|
|
-D "cn=admin,dc=example,dc=com" \
|
|
-w "admin-password" \
|
|
-f modify.ldif
|
|
```
|
|
|
|
### Deleting Entries
|
|
|
|
```bash
|
|
ldapdelete -x -H ldap://localhost:389 \
|
|
-D "cn=admin,dc=example,dc=com" \
|
|
-w "admin-password" \
|
|
"uid=jdoe,ou=People,dc=example,dc=com"
|
|
```
|
|
|
|
The refint overlay automatically removes the user from any groups they belonged to.
|
|
|
|
---
|
|
|
|
## Connecting Applications
|
|
|
|
### Keycloak
|
|
|
|
Keycloak uses LDAP for user federation. Configure it with:
|
|
|
|
| Setting | Value |
|
|
|---------|-------|
|
|
| Connection URL | `ldap://openldap:389` |
|
|
| Bind DN | `cn=keycloak,ou=Services,dc=example,dc=com` |
|
|
| Bind Credential | (from service-passwords.txt) |
|
|
| Users DN | `ou=People,dc=example,dc=com` |
|
|
| Username Attribute | `uid` |
|
|
| RDN Attribute | `uid` |
|
|
| UUID Attribute | `entryUUID` |
|
|
|
|
### Nextcloud
|
|
|
|
In Nextcloud's LDAP settings:
|
|
|
|
| Setting | Value |
|
|
|---------|-------|
|
|
| Host | `openldap` |
|
|
| Port | `389` |
|
|
| User DN | `cn=nextcloud,ou=Services,dc=example,dc=com` |
|
|
| Password | (from service-passwords.txt) |
|
|
| Base DN | `dc=example,dc=com` |
|
|
| User Filter | `(&(objectClass=inetOrgPerson)(uid=%uid))` |
|
|
| Group Filter | `(objectClass=groupOfMembers)` |
|
|
|
|
### SSSD (Linux PAM/NSS)
|
|
|
|
For Linux systems to authenticate against LDAP:
|
|
|
|
```ini
|
|
# /etc/sssd/sssd.conf
|
|
[sssd]
|
|
services = nss, pam
|
|
domains = example.com
|
|
|
|
[domain/example.com]
|
|
id_provider = ldap
|
|
auth_provider = ldap
|
|
ldap_uri = ldap://openldap.example.com
|
|
ldap_search_base = dc=example,dc=com
|
|
ldap_default_bind_dn = cn=sssd,ou=Services,dc=example,dc=com
|
|
ldap_default_authtok = sssd-password-here
|
|
ldap_user_search_base = ou=People,dc=example,dc=com
|
|
ldap_group_search_base = ou=Groups,dc=example,dc=com
|
|
```
|
|
|
|
---
|
|
|
|
## Backup and Recovery
|
|
|
|
### Why Backups Matter
|
|
|
|
The LDAP directory contains:
|
|
- All user accounts and credentials
|
|
- Group memberships and access control
|
|
- Service account configurations
|
|
- Password policies
|
|
|
|
Losing this data means losing access to all integrated systems.
|
|
|
|
### Creating Backups
|
|
|
|
Export the directory to LDIF format:
|
|
|
|
```bash
|
|
# Backup user data (database 1)
|
|
docker exec openldap slapcat -n 1 > ldap-data-$(date +%Y%m%d).ldif
|
|
|
|
# Backup configuration (database 0) - optional but recommended
|
|
docker exec openldap slapcat -n 0 > ldap-config-$(date +%Y%m%d).ldif
|
|
```
|
|
|
|
**Backup frequency recommendation:**
|
|
- Daily for the data backup
|
|
- After any configuration changes for the config backup
|
|
|
|
### Restoring from Backup
|
|
|
|
**Warning**: This destroys all existing data!
|
|
|
|
```bash
|
|
# Stop the container
|
|
docker stop openldap
|
|
docker rm openldap
|
|
|
|
# Remove existing volumes
|
|
docker volume rm openldap-data openldap-config
|
|
|
|
# Create fresh container with backup
|
|
docker run --rm \
|
|
-v openldap-data:/var/lib/openldap/openldap-data \
|
|
-v $(pwd)/ldap-data-20240101.ldif:/backup.ldif:ro \
|
|
enterprise-openldap:latest \
|
|
sh -c "slapadd -n 1 -l /backup.ldif && chown -R ldap:ldap /var/lib/openldap"
|
|
|
|
# Start normally
|
|
docker run -d --name openldap \
|
|
-v openldap-data:/var/lib/openldap/openldap-data \
|
|
-v openldap-config:/etc/openldap/slapd.d \
|
|
... # your normal settings
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Understanding Log Levels
|
|
|
|
The `LDAP_LOG_LEVEL` controls what gets logged. Common values:
|
|
|
|
| Level | What it shows | When to use |
|
|
|-------|---------------|-------------|
|
|
| `0` | Nothing | Never in production |
|
|
| `256` | Connections, operations, results | Normal operation |
|
|
| `384` | Above + ACL decisions | Debugging access issues |
|
|
| `512` | Stats with entry counts | Performance analysis |
|
|
| `-1` | Everything | Last resort debugging |
|
|
|
|
Increase temporarily for debugging:
|
|
|
|
```bash
|
|
docker run -e LDAP_LOG_LEVEL=384 ...
|
|
```
|
|
|
|
### Common Issues
|
|
|
|
#### Container exits immediately
|
|
|
|
**Symptom**: Container starts and stops within seconds.
|
|
|
|
**Cause**: Missing required environment variables.
|
|
|
|
**Solution**: Check that `LDAP_DOMAIN`, `LDAP_ORGANISATION`, and `LDAP_ADMIN_PASSWORD` are all set.
|
|
|
|
```bash
|
|
docker logs openldap # Will show which variable is missing
|
|
```
|
|
|
|
#### Cannot authenticate as admin
|
|
|
|
**Symptom**: `ldap_bind: Invalid credentials (49)`
|
|
|
|
**Causes**:
|
|
1. Wrong password
|
|
2. Wrong bind DN (check the domain components match your LDAP_DOMAIN)
|
|
3. Typing `dc=example.com` instead of `dc=example,dc=com`
|
|
|
|
**Solution**: Verify the exact bind DN:
|
|
|
|
```bash
|
|
# Your bind DN is always: cn=admin,<your-base-dn>
|
|
# If LDAP_DOMAIN=example.com, then it's: cn=admin,dc=example,dc=com
|
|
```
|
|
|
|
#### TLS connection refused
|
|
|
|
**Symptom**: Cannot connect to port 636.
|
|
|
|
**Cause**: Certificates not found or not readable.
|
|
|
|
**Solution**: Check the logs for TLS errors:
|
|
|
|
```bash
|
|
docker logs openldap | grep -i tls
|
|
```
|
|
|
|
Verify certificates are mounted correctly:
|
|
|
|
```bash
|
|
docker exec openldap ls -la /certs/
|
|
```
|
|
|
|
#### Service account cannot search
|
|
|
|
**Symptom**: Service account binds successfully but searches return empty.
|
|
|
|
**Cause**: ACLs restrict what the service account can see.
|
|
|
|
**Solution**: Service accounts can only read specific OUs. Verify you're searching the correct base:
|
|
|
|
```bash
|
|
# Correct - searching People OU
|
|
ldapsearch -D "cn=keycloak,ou=Services,..." -b "ou=People,dc=example,dc=com" ...
|
|
|
|
# Wrong - searching the entire tree
|
|
ldapsearch -D "cn=keycloak,ou=Services,..." -b "dc=example,dc=com" ...
|
|
```
|
|
|
|
#### Users don't have memberOf attribute
|
|
|
|
**Symptom**: User exists in group but `memberOf` attribute is empty.
|
|
|
|
**Cause**: User was added before the memberOf overlay, or group uses wrong attribute.
|
|
|
|
**Solution**: The memberOf overlay only tracks `member` attribute on `groupOfMembers` objects. Verify:
|
|
|
|
1. Group has `objectClass: groupOfMembers`
|
|
2. Group uses `member` attribute (not `memberUid`)
|
|
|
|
To fix existing users, remove and re-add them to groups.
|
|
|
|
---
|
|
|
|
## Security Recommendations
|
|
|
|
### Password Security
|
|
|
|
1. **Use strong admin password** - At least 16 characters with mixed case, numbers, symbols
|
|
2. **Rotate service account passwords** periodically
|
|
3. **Delete service-passwords.txt** after retrieving the passwords
|
|
4. **Never commit passwords** to version control
|
|
|
|
### Network Security
|
|
|
|
1. **Use TLS** for all production deployments
|
|
2. **Restrict port access** - Only allow LDAP ports from trusted networks
|
|
3. **Use internal Docker networks** when possible:
|
|
|
|
```bash
|
|
docker network create ldap-net
|
|
docker run --network ldap-net --name openldap ...
|
|
# Other containers on ldap-net can access via hostname "openldap"
|
|
```
|
|
|
|
### Access Control
|
|
|
|
1. **Use service accounts** instead of sharing admin credentials
|
|
2. **Principle of least privilege** - Service accounts only get read access
|
|
3. **Audit regularly** - Check who has access to what
|
|
|
|
---
|
|
|
|
## Docker Compose Reference
|
|
|
|
Complete production-ready example:
|
|
|
|
```yaml
|
|
version: '3.8'
|
|
|
|
services:
|
|
openldap:
|
|
image: enterprise-openldap:latest
|
|
container_name: openldap
|
|
hostname: ldap.example.com
|
|
environment:
|
|
LDAP_DOMAIN: example.com
|
|
LDAP_ORGANISATION: "Example Corporation"
|
|
LDAP_ADMIN_PASSWORD: ${LDAP_ADMIN_PASSWORD:?Set LDAP_ADMIN_PASSWORD}
|
|
LDAP_TLS_ENABLED: "true"
|
|
LDAP_CREATE_SERVICE_ACCOUNTS: "true"
|
|
LDAP_LOG_LEVEL: "256"
|
|
volumes:
|
|
- openldap-data:/var/lib/openldap/openldap-data
|
|
- openldap-config:/etc/openldap/slapd.d
|
|
- ./certs:/certs:ro
|
|
ports:
|
|
- "389:389"
|
|
- "636:636"
|
|
networks:
|
|
- backend
|
|
restart: unless-stopped
|
|
healthcheck:
|
|
test: ["CMD", "ldapsearch", "-x", "-H", "ldap://localhost", "-b", "", "-s", "base"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 10s
|
|
|
|
networks:
|
|
backend:
|
|
driver: bridge
|
|
|
|
volumes:
|
|
openldap-data:
|
|
openldap-config:
|
|
```
|
|
|
|
Create a `.env` file:
|
|
|
|
```bash
|
|
LDAP_ADMIN_PASSWORD=your-secure-password-here
|
|
```
|
|
|
|
Start:
|
|
|
|
```bash
|
|
docker compose up -d
|
|
```
|