Turning realms into real users, one sudo at a time.
Entramox Reconciler syncs OIDC users from Proxmox VE into real Linux accounts, with optional enforcement from Microsoft Entra ID (Graph).
It creates local users, sets a random expired password, manages groups and sudoers idempotently, and handles leavers with a lock then delete lifecycle. It also keeps Proxmox (PVE) users aligned, including enable or disable state, ACL roles, and metadata.
Logs are written to:
/var/log/entramoxreconciler/thelog.log
The service is safe by default. Reserved system accounts are never touched, binaries are pinned, integrity is enforced, and runs are protected by a lockfile.
This script will refuse to start unless it is owned by
root:rootand has0700permissions. That is intentional, so nobody can swap it and mint sudo.The systemd service uses an ExecCondition integrity check.
A helper script verifies the SHA-256 checksum of:
/usr/local/sbin/entramoxreconciler.py/etc/entramoxreconciler.env/etc/entramoxreconciler.keyIf the script checksum does not match what was captured during install or update, the service will not run.
Before enabling the service or timer, ensure permissions are correct:
sudo chown root:root /usr/local/sbin/entramoxreconciler.py /usr/local/sbin/entramox_check.sh
sudo chmod 700 /usr/local/sbin/entramoxreconciler.py /usr/local/sbin/entramox_check.sh
sudo install -d -m 0750 -o root -g root /var/log/entramoxreconciler
sudo install -d -m 0750 -o root -g root /var/lib/entramoxreconcilerThe service must run as root. Do not place the script or env files in user writable locations.
To update the code, do not edit the installed file directly. Update from the repo and refresh the checksum:
sudo ./installer.py update --restartIf ownership, permissions, or checksums do not match, the script exits immediately to prevent privilege escalation.
For each run:
- Reads users from the configured Proxmox OIDC realm
- Optionally intersects them with one or more Entra ID groups
- Maps UPNs to local Unix usernames using configurable rules
- Creates missing local users and expires their passwords
- Manages baseline groups and sudo access idempotently
- Disables PVE users when Entra users are disabled
- Locks users removed from the desired set
- Deletes locked users after a configurable grace period
- Updates Proxmox user comments to reflect lifecycle state
Entramox Reconciler supports two Graph authentication modes:
-
Application credentials (recommended)
- Uses client credentials
- Safe for timers and unattended execution
-
Delegated access token
- Useful for testing
- Short lived and not suitable for timers
These are required when using client credentials:
- GroupMember.Read.All
- User.Read.All
- Optional: Member.Read.Hidden (only if group membership is hidden)
Admin consent is required.
Only needed for interactive testing:
- openid
- profile
- Optional: GroupMember.Read.All
-
Register an app Entra ID → App registrations → New registration Single tenant is sufficient
-
Create a client secret Certificates and secrets → New client secret
-
Add API permissions Microsoft Graph → Application permissions Grant admin consent
-
Collect the following values:
- Tenant ID
- Client ID
- Client secret
- Entra group Object IDs
sudo ./installer.py installThis will:
- Install Python dependencies
- Deploy the script and checker
- Generate an encryption key
- Create
/etc/entramoxreconciler.env - Write systemd service and timer
- Enable and start the timer
sudo ./installer.py update
sudo ./installer.py update --restartLegacy sudomatic5000 installs are detected and migrated automatically.
sudo ./installer.py uninstallTo fully purge config, logs, and state:
sudo ./installer.py uninstall --purgeEntramox Reconciler is env driven.
The primary config file is:
/etc/entramoxreconciler.env
It must be owned by root and have 0600 permissions.
Edit it safely:
sudoedit /etc/entramoxreconciler.env
sudo systemctl daemon-reload
sudo systemctl restart entramoxreconciler.serviceREALM='MY-REALM'
DEFAULT_SHELL='/bin/bash'
GRAPH_ENFORCE='true'
GRAPH_FAIL_OPEN='true'
ALLOWED_UPN_DOMAINS='example.com sub.example.com'
ENTRA_ALLUSERS_GROUP_ID='00000000-0000-0000-0000-000000000000'
ENTRA_ALLUSERS_PVE_ROLE='PVEUser'
ENTRA_SUPERADMIN_GROUP_ID='11111111-1111-1111-1111-111111111111'
ENTRA_SUPERADMIN_PVE_ROLE='Administrator'
ENTR_TENANT_ID='tenant-guid'
ENTR_CLNT_ID='client-guid'
ENTR_CLNT_SEC_ENC='fernet:...'Username mapping is configurable:
-
USERNAME_MODE=useronlyuser@domain.com→user -
USERNAME_MODE=upn_concatuser@domain.com→user_domain.com
Additional controls:
USERNAME_SEPARATORUSERNAME_LOWERCASEUSERNAME_MAXLEN
All usernames are sanitised before creation.
A user is desired if:
- They exist in the configured Proxmox realm
- AND they are a member of at least one enforced Entra group (when enabled)
- AND their UPN domain is allowed
If an Entra account is disabled but still in the group:
- Local account is locked
- Sudo is revoked
- PVE user is disabled
- No deletion countdown is started
This state is reversible.
If a user leaves all allowed groups:
- Local account is locked immediately
- Sudo is revoked
- PVE user is disabled
- User enters a grace period
- Proxmox comment is updated with remaining time
- User is deleted after
DELETE_AFTER
Logs are written to:
/var/log/entramoxreconciler/thelog.log
Journal view:
journalctl -u entramoxreconciler.service -fLogrotate is installed automatically.
- Root ownership enforcement
- Strict file permissions
- SHA-256 integrity checks
- Atomic file writes
- Lockfile to prevent concurrent runs
- Reserved users are never touched
- Fail open or fail closed Graph behaviour is configurable
-
No users synced Check
REALMmatches Proxmox exactly -
Graph 403 errors Verify permissions and admin consent
-
Users never deleted Check
GRAPH_FAIL_OPENand grace period -
Sudo not applied Confirm
GRANT_SUDO=trueand user is in superadmin group -
Service not reading env Run:
systemctl show entramoxreconciler.service -p EnvironmentFiles -p Environment
Enjoy the realm wrangling 🧙♂️