This script synchronizes group memberships from LDAP to OpenFGA using the diffsync library.
- Syncs group memberships from LDAP to OpenFGA
- Uses diffsync library to calculate and apply only the necessary changes
- Supports dry-run mode to preview changes before applying them
- Users are identified by a configurable LDAP attribute (default:
uid) - Comprehensive logging
- Python 3.8+
- LDAP server with group memberships
- OpenFGA instance
- Clone this repository:
git clone <repository-url>
cd ldap-openfga-sync- Create a virtual environment:
python3 -m venv .venv
source .venv/bin/activate # On Linux/Mac
# or
.venv\Scripts\activate # On Windows- Install dependencies:
pip install -r requirements.txt- Copy the example environment file and configure it:
cp .env.example .env
# Edit .env with your configurationEdit the .env file with your settings:
LDAP_SERVER: LDAP server URL (e.g.,ldap://localhost:389orldaps://ldap.example.com:636)LDAP_BIND_DN: DN to bind with (e.g.,cn=admin,dc=example,dc=com)LDAP_BIND_PASSWORD: Password for the bind DNLDAP_GROUP_BASE_DN: Base DN to search for groups (e.g.,ou=groups,dc=example,dc=com)LDAP_USER_BASE_DN: Base DN where users are located (formemberOfqueries). Only used whenLDAP_USE_MEMBEROF=true.LDAP_GROUP_FILTER: LDAP filter to find groups when discovering all groups (default:(objectClass=groupOfNames))LDAP_MEMBER_ATTRIBUTE: Attribute containing group members. Only used whenLDAP_USE_MEMBEROF=false(default:member)LDAP_USE_TLS: Whether to use TLS (true/false)LDAP_CA_CERT_FILE: Path to custom CA certificate file for TLS verification (optional, for self-signed certificates)LDAP_USE_MEMBEROF: UsememberOfattribute for reverse lookup (default:false)- When true: Queries users for
memberOfattribute. Recommended for FreeIPA/Active Directory. Supports inherited/nested groups automatically. - When false: Queries groups for
memberattribute. Works with any LDAP. Direct members only.
- When true: Queries users for
LDAP_USERNAME_ATTRIBUTE: LDAP attribute to use as username identifier (default:uid). This attribute is read from LDAP users and used to identify them in OpenFGA. Common values:uid,mail
OPENFGA_API_URL: OpenFGA API URL (e.g.,http://localhost:8080)OPENFGA_STORE_ID: Your OpenFGA store IDOPENFGA_API_TOKEN: API token for authentication (optional)OPENFGA_AUTHORIZATION_MODEL_ID: Authorization model ID (optional)
SYNC_GROUPS: Comma-separated list of groups to sync (e.g.,developers,operations,managers). If not specified or empty, all groups from LDAP will be synced.SYNC_INTERVAL_SECONDS: Sync interval in seconds (default:21600= 6 hours). Only used in Docker/containerized environments.SYNC_DRY_RUN: Set totruefor dry-run mode (preview changes without applying them)
-
Validate your configuration:
python validate_config.py
-
Test your connections:
python test_connections.py
-
Run a dry-run sync:
SYNC_DRY_RUN=true python sync.py
-
Run the actual sync:
python sync.py
Deploy using Docker for simpler setups. The container runs the sync automatically every 6 hours.
# Pull the image
docker pull ghcr.io/agdsn/ldap-openfga-sync:latest
# Create configuration
cp .env.example .env
# Edit .env with your settings
# Run the container
docker run -d \
--name ldap-openfga-sync \
--env-file .env \
-v $(pwd)/logs:/var/log/ldap-openfga-sync \
ghcr.io/agdsn/ldap-openfga-sync:latestRun the sync script:
python sync.pyTo preview changes without applying them:
# Set SYNC_DRY_RUN=true in .env, or:
SYNC_DRY_RUN=true python sync.pyBefore running the sync, you can test your connections:
python test_connections.pyThis will verify:
- LDAP connection and ability to query groups
- OpenFGA connection and ability to read tuples
- Connect to OpenFGA: The script connects to OpenFGA
- Connect to LDAP: Connects to LDAP and queries for group memberships
- Filter Groups: Only processes configured groups (or all groups if SYNC_GROUPS is empty)
- Extract Usernames: Queries the configured username attribute (default:
preferredUsername) from LDAP users - Load Data: Loads memberships from both LDAP and OpenFGA into diffsync adapters
- Calculate Diff: Uses diffsync to automatically calculate the differences
- Apply Changes: Uses diffsync's built-in CRUD operations (
create()anddelete()methods in the model) to queue changes - Execute Operations: Executes all queued operations asynchronously to update OpenFGA
The sync uses diffsync's native sync mechanism (sync_from()) which automatically:
- Detects new memberships that need to be created
- Identifies obsolete memberships that need to be deleted
- Invokes the model's
create()anddelete()methods - Maintains consistency between LDAP (source) and OpenFGA (target)
The script expects the following OpenFGA relationship structure:
user:username member group:groupname
Where:
- User type:
user(identified by username from LDAP, configurable viaLDAP_USERNAME_ATTRIBUTE) - Relation:
member - Object type:
group(identified by group name)
- Groups must have a
cnattribute (used as the group name) - Groups must have a member attribute (configurable via
LDAP_MEMBER_ATTRIBUTE, default:member) when using member attribute mode - Users must have the configured username attribute (configurable via
LDAP_USERNAME_ATTRIBUTE, default:uid)- Common attributes:
uid,mailA comprehensive test suite is included with Docker Compose environment:
- Common attributes:
# Start test environment (LDAP + OpenFGA)
./test.sh start
# Run all tests
./test.sh test
# Stop test environment
./test.sh stopSee TESTING.md for detailed testing documentation.
To contribute or modify the script:
- Install development dependencies
- Make your changes
- Run the test suite
- Test thoroughly in dry-run mode first
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.