Metis manages RFC 2307bis POSIX attributes (UID/GID numbers, login shells, home directories, group memberships) on Active Directory objects through a command-line tool.
Note
Metis follows the RFC 2307bis schema: posixGroup is treated as an auxiliary class layered onto existing AD objects, and group membership is resolved from DN-referenced member values (with support for nesting), falling back to legacy memberUid where present.
Important
Metis operates against a live directory. Point it at a lab or test domain before running any write commands.
Build the solution and run the CLI from the repository root:
dotnet build
dotnet run --project src/Metis.Cli -- user show jdoe --server dc01.example.com --search-base "DC=example,DC=com"
dotnet run --project src/Metis.Cli -- user list --search-base "OU=People,OU=Identities,DC=example,DC=com"
dotnet run --project src/Metis.Cli -- user set --base "OU=People,OU=Identities,DC=example,DC=com" --dry-run
dotnet run --project src/Metis.Cli -- group show writers --group-base "OU=Groups,DC=example,DC=com" --membersBy default the CLI binds with integrated authentication; see Authentication for explicit credentials and TLS.
Tip
The connection target can come from the environment instead of flags: METIS_SERVER and METIS_SEARCH_BASE back --server/--search-base (the flags win when both are set), and METIS_BIND_PASSWORD supplies the bind password.
- Inspect RFC 2307bis attributes (
uidNumber,loginShell,gecos) on users. Home directories are intentionally not managed — they are left to sssd/winbind. - Treat
sAMAccountNameas the POSIX login name by default, overridable with--login-attribute(e.g. to use the RFC 2307bisuidattribute). - Warn when a user is missing a
uidNumber(the minimum POSIX identity for UNIX login resolution). - Resolve group membership via the
memberOfback-link, scoped to one or more--member-basesubtrees, with--nestedfor transitive (nested-group) membership. - List users and groups with their POSIX attributes (
user list/group list), grouped by organisational unit, paged for large directories and POSIX-enabled by default (--allincludes objects withoutuidNumber/gidNumber). - Bulk-assign missing
uidNumber/gidNumber(user set/group set): objects are grouped by OU, each OU's starting number is prompted (prefilled from its highest existing value, or--default-base), values already in use are skipped, and the plan is previewed before a single confirmation writes it (--dry-runto preview,--yesto skip the prompt). - Set
loginShellacross an OU in one shot (user shell <shell> --base <DN>), with a previewed plan and confirmation (--dry-run/--yes). - Support directory layouts where groups and users live in separate subtrees: locate the group under
--group-base(defaulting to--search-base) while members are enumerated under--member-base. - Consistent, scriptable output suitable for automation pipelines.
Metis never binds anonymously. It supports two modes:
- Integrated (default) — when no
--bind-dnis supplied, Metis binds as the current user via Negotiate (Kerberos/NTLM). On Windows, unencrypted connections are protected with signing and sealing; on Linux/macOS the channel is protected through SASL. - Simple bind — supply
--bind-dn(a distinguished name or UPN) to authenticate with an explicit account.
The bind password is resolved in order of precedence: the --bind-password option, the METIS_BIND_PASSWORD environment variable, then an interactive hidden prompt.
Caution
A simple bind sends credentials to the server. Metis refuses a simple bind over an unencrypted connection unless you pass --tls (LDAPS) or explicitly opt in with --allow-insecure-simple-bind.
Tip
Prefer METIS_BIND_PASSWORD or the interactive prompt over --bind-password to keep credentials out of your shell history.
Integrated auth on Linux binds through OpenLDAP's SASL/GSSAPI. If a bind fails with A local error occurred and a Kerberos trace shows an SPN built from the server's IP address (e.g. ldap/fd0e:…) rather than its host name, libldap is reverse-resolving the connected socket. Stop it by adding to ldap.conf (or setting the environment variable):
SASL_NOCANON onThis makes libldap use the --server name verbatim to build the SPN (ldap/<host>). It resolves the failure regardless of credential-cache type (FILE or KEYRING). A simple bind (--bind-dn … --tls) needs none of this.
Metis separates directory and RFC 2307bis logic into a shared core, consumed by a Spectre.Console CLI front end.
flowchart LR
CLI[CLI - Spectre.Console] --> Core[Core - directory + RFC 2307bis logic]
Core --> AD[(Active Directory)]
| Component | Technology | Status |
|---|---|---|
| CLI | C# + Spectre.Console | In progress |
| Core library | C# | In progress |
- A web portal (an ASP.NET Core API, with a UI to be decided) is planned to reuse the core library once the CLI command surface stabilises.
Caution
RFC 2307bis attribute changes affect POSIX identity resolution. Validate UID/GID allocations against existing assignments to avoid collisions before applying changes at scale.
Note
RFC 2307bis is an IETF draft (draft-howard-rfc2307bis) rather than a published standard, but it is the schema implemented by Active Directory and common LDAP servers for POSIX identity.