Availability
The Active Directory connector is self-hosted and supports Windows and Linux.Capabilities
The Active Directory connector supports automatic account provisioning and deprovisioning. When a new account is created by C1, the account’s password is sent to a vault.
Highlights:
- Primary group memberships sync automatically via
primaryGroupID; AD’smemberOfdoesn’t include them. - Multi-domain and cross-forest sync in a single run via
additional-domainsconfig — see Multi-domain and cross-forest sync. - gMSA sync is opt-in via
enable-gmsa-sync; provisioning modifies themsDS-GroupMSAMembershipsecurity descriptor ACL. - Two connection modes: LDAP (default on Linux) and WinLDAP (default on Windows; uses
wldap32.dllfor Kerberos/GSSAPI). - Account provisioning (create/delete) requires LDAPS (
ldaps: true). - Provisioning is idempotent: re-granting a group membership a user already holds, revoking one they don’t have, or creating an account or group that already exists is treated as success rather than an error — so overlapping grants during a role change don’t fail. An account that already exists is returned unchanged (its password is not reset).
Connector actions
Connector actions are custom capabilities that extend C1 automations with app-specific operations. You can use connector actions in the Perform connector action automation step. Global actions (connector-level):
Resource actions (on user resources):
Resource actions (on group resources):
Custom PowerShell actions:
You can define additional actions backed by PowerShell scripts in the config file. See Custom PowerShell actions below.
Resources
- Official download center: For stable binaries (Windows/Linux) and container images.
Gather Active Directory credentials
Create a service account
1
Create a dedicated AD service account for the connector (for example,
svc-baton). A standard domain user account with read access is sufficient for sync-only operation.2
Grant the service account Log on as a service permission via local or domain Group Policy, depending on your environment.
Entitlement provisioning permissions
For entitlement provisioning support, the service account needs delegated rights to manage group membership.1
Open Active Directory Users and Computers (ADUC) or run
dsa.msc from the command line.2
Right-click on your forest root (or a specific OU if you only want to provision into groups in that OU) and select Delegate Control.
3
Add the service account running the
baton-active-directory service.4
From the tasks to delegate, check the box for Modify the membership of a group.
5
Click Next, then Finish.
1
For each protected group: right-click the group, click the Security tab, click Advanced, click Add, select the service account as the principal, and grant Write Members permission.
2
Run the following PowerShell script from a domain controller with domain admin credentials to ensure AdminSDHolder does not remove the permission after 60 minutes:
Account provisioning permissions
1
Open ADUC or run
dsa.msc from the command line.2
Right-click on your forest root (or a specific OU) and select Delegate Control.
3
Add the service account running the
baton-active-directory service.4
From the tasks to delegate, check the box for Create, delete, and manage user accounts.
5
Click Next, then Finish.
Configure the Active Directory connector
The Active Directory connector is self-hosted — it runs on a Windows or Linux server in your environment with direct network access to your domain controllers. Once installed and configured, Baton runs as a Windows service (or Linux daemon). The service maintains contact with C1, syncs and uploads data at regular intervals, and passes that data to the C1 UI for access reviews and access requests.Requirements
Host server (Windows Server or Linux):- 2-4 vCPU
- 4-8 GB RAM
- Minimum OS disk space for the binary (~60 MB) plus room for logs and the local sync database
- The connector runs as a Windows service or Linux daemon — a dedicated host is not required
- Outbound TCP/443 to your C1 tenant
- Outbound LDAP (TCP/UDP 389), LDAPS (TCP 636), and Kerberos (TCP/UDP 88) to each domain controller the connector talks to. Global Catalog adds TCP 3268 / 3269. For the full multi-domain port list, see Multi-domain and cross-forest sync.
- An Active Directory service account with appropriate permissions (see Gather Active Directory credentials above)
- The Connector Administrator or Super Administrator role in C1
File locations
Windows (the default install path;%PROGRAMDATA% is typically C:\ProgramData):
- Binary:
C:\Program Files\ConductorOne\baton-active-directory.exe - Config:
%PROGRAMDATA%\ConductorOne\baton-active-directory\config.yaml— auto-discovered at startup ifBATON_CONFIG_PATHis not set - Log:
%PROGRAMDATA%\ConductorOne\baton-active-directory\baton.log
%PROGRAMDATA%\ConductorOne so the connector can write to the log file. If the connector can’t write to this directory, the service will fail to start.
Linux: there is no default config location — set BATON_CONFIG_PATH (or pass --config-file) to wherever you deploy config.yaml. A common pattern is /etc/baton-active-directory/config.yaml with the log redirected via systemd journal or --file.
Step 1: Set up a new Active Directory connector in C1
1
In C1, navigate to Integrations > Connectors and click Add connector.
2
Search for Baton and click Add.
3
Choose how to set up the new Active Directory connector:
- Add the connector to a currently unmanaged app (select from the list of apps that were discovered in your identity, SSO, or federation provider that aren’t yet managed with C1)
- Add the connector to a managed app (select from the list of existing managed apps)
- Create a new managed app
4
Set the owner for this connector. You can manage the connector yourself, or choose someone else from the list of C1 users. Setting multiple owners is allowed.If you choose someone else, C1 will notify the new connector owner by email that their help is needed to complete the setup process.
5
Click Next.
6
In the Settings area of the page, click Edit.
7
Click Rotate to generate a new Client ID and Secret.Carefully copy and save these credentials. You will need them when configuring the connector.
8
Next to the Not Connected label, click on the word Baton to navigate to the application page. Click the pencil icon at the top of the page and rename the application to Active Directory. This updates the application name, connector name, and icon.
Step 2: Install and configure baton-active-directory
Option 1: MSI installer (recommended)
1
Download the latest Windows MSI from the C1 download center.
Security prompts during download and install. The Windows MSI and
.exe are not yet code-signed, so Microsoft Defender SmartScreen and some antivirus products may warn that the publisher is unknown or quarantine the download. This is expected for unsigned binaries — it is not an indication of tampering. To proceed safely:- On the SmartScreen prompt, click More info → Run anyway.
- Verify you downloaded from
dist.conductorone.comand, if your security policy requires it, confirm the file hash with ConductorOne support before running.
2
Run the MSI on the host designated to run the connector. The MSI installs
baton-active-directory.exe to C:\Program Files\ConductorOne\baton-active-directory and adds it to the system PATH.The MSI only installs the binary — it does not collect your configuration, write a config file, or register the Windows service, and there is no post-install configuration pop-up. All of that happens in the next step, when you run
setup.3
From an elevated Command Prompt (
cmd.exe), run baton-active-directory.exe setup to create the configuration and register the service. This is the same command described in Option 2 below — follow it from the setup step onward (the config editor opens automatically on this first run because no config exists yet).Option 2: CLI setup command
1
On the host designated to run the connector, create a folder:
C:\Program Files\ConductorOne.2
Copy
baton-active-directory.exe to the ConductorOne folder.3
From an elevated Command Prompt (The setup command checks for a config file, offers to copy the binary to Program Files, optionally configures a service account, and registers the Windows service with auto-start and recovery.First-run behavior: the GUI Configuration Editor launches automatically only on the first run, when no config file exists yet. Fill in your domain, base DN, and C1 credentials, click Save, and close the editor — For non-interactive setup (no prompts, LocalSystem account, no editor), use:
cmd.exe), run:setup resumes in cmd.exe and finishes registering the service. On subsequent runs the editor does not reappear; setup reuses the existing config.To review or change an existing config, either run
baton-active-directory.exe config-editor directly, or run baton-active-directory.exe setup --reconfigure to open the editor and then re-register the service in one step.baton-active-directory.exe setup -y4
Grant the service account Modify folder permissions to
C:\ProgramData\ConductorOne so it can write to the log file.baton-active-directory setup and the Windows installer now apply this grant automatically when you specify a non-LocalSystem service account. This step is only required if you change the service account later via services.msc or sc config.5
Launch the Services console, locate the service named baton-active-directory, and configure it:
- Double-click to open properties
- Change the Startup type to Automatic
- Navigate to the Log On tab and click This account
- Click Browse, enter your service account name, and click Check Names
- Enter the service account password and confirm it. For a gMSA, append
$to the account name (e.g.DOMAIN\svc-baton-ad$) and leave both password fields blank — Windows retrieves the managed password from the domain. - Click Apply
- Navigate back to the General tab and click Start
Step 3: Manage the Windows service
1
Use the following commands to manage the service (all require administrator privileges):
- To start the service:
baton-active-directory.exe start - To stop the service:
baton-active-directory.exe stop - To check the status:
baton-active-directory.exe status - To remove the service:
baton-active-directory.exe remove(config and binary are preserved)
2
The connector syncs current data, uploads it to C1, and prints a Task complete! message when finished.
3
Check that the connector data uploaded correctly. In C1, click Apps. On the Managed apps tab, locate and click the name of the application you added the Active Directory connector to. Active Directory data should be found on the Entitlements and Accounts tabs.
Validate the connector is working
A Connected status in C1 means the connector has registered and is sending heartbeats — it does not by itself confirm that the connector can reach a domain controller, bind, and sync. Use these checks to confirm it is actually functioning:1
Test LDAP connectivity. From an elevated This exercises the full path the connector uses — DC resolution, TCP connect, TLS handshake and certificate validation (for LDAPS), and the LDAP bind — for every configured domain, and prints actionable diagnostics for any step that fails.
cmd.exe, run:setup runs this check automatically at the end of installation (skip it with --no-verify).2
Confirm the service is running. Run
baton-active-directory.exe status and verify the state is Running and the account/binary/config paths are what you expect.3
Check the log. The connector writes to
C:\ProgramData\ConductorOne\baton-active-directory\baton.log. A healthy run logs sync progress and a completion message; an empty or error-filled log (for example open sink ".../baton.log": Access is denied) points to the permission issues described above.4
Confirm data in C1. In C1 → Apps → your AD app, the Accounts and Entitlements tabs should populate after the first successful sync. Counts that match your directory confirm an end-to-end working connector.
Reference
The sections below cover advanced configuration, troubleshooting, and customization. Skim them only when you need to tune the connector beyond defaults.Configuration reference
All fields below can be set in the YAML config file. Unless noted, each field also maps to an equivalent CLI flag (--field-name) and environment variable (BATON_FIELD_NAME).
Example minimal config:
Authentication:
Simple-bind example:
gMSA:
Actions & provisioning:
C1 credentials:
Multi-domain:
Run
baton-active-directory --help to see every flag with its current default.
Multi-domain and cross-forest sync
The connector can sync across multiple AD domains and forests in a single run. Add additional trusted domains to your config using native YAML syntax:rootDomainNamingContext): intra-forest references use the principal’s actual DN (matching what AD itself stores), and cross-forest references use a Foreign Security Principal DN in the target domain.
The
additional-domains field is YAML-only — it cannot be set via CLI flags or environment variables.Supported trust types
- Intra-forest parent/child or tree-root domains (single forest, multiple domains)
- 1-way outbound trust (primary trusts remote, or remote trusts primary)
- 2-way trust
- Cross-forest trust
- External (non-transitive) trust
Prerequisites
1. Active Directory trust. A trust relationship must exist between the domains. For Kerberos (bind-type: external), the connector’s domain must be trusted by the remote domain. For simple bind, any network connectivity is sufficient.
Verify with:
4. LDAPS certificate trust (if using LDAPS). The remote forest’s root CA certificate must be trusted on the connector machine:
- Option A — Automatic cross-forest trust: With a 2-way trust and Enterprise CAs in both forests, the remote root CA is typically published to AD automatically.
-
Option B — Manual import: Export the remote CA and import it into the connector machine’s Trusted Root CAs (machine store):
-
Option C — Skip validation (go-ldap mode only, lab/testing): Set
ldaps-skip-verify: true. This has no effect in WinLDAP mode, which always validates against the Windows certificate store. -
Option D — Plain LDAP with signing: Omit
ldaps: truefor the additional domain and connect over TCP/389 with LDAP signing.
bind-type: external). On Windows domain-joined hosts, cross-realm Kerberos is typically automatic when a forest or external trust exists. The connector targets the remote DC’s hostname (for example, DC01.remote-forest.example.com) rather than the domain FQDN, because the SPN (ldap/DC01…) is registered under the DC’s machine account.
On Linux, add the remote realm to /etc/krb5.conf:
Authenticated Users has read access to most AD objects by default, which is usually sufficient. For gMSA provisioning in an additional domain, set read-only: false on the domain entry and grant the bind account write access to msDS-GroupMSAMembership.
Additional domain fields
Each entry underadditional-domains supports the following fields:
read-only default: When omitted, read-only defaults to true unless bind-type is explicitly set (in which case it defaults to false). Providing domain-specific bind credentials signals that writes are intended. Set read-only explicitly to override.
How it works
- Resource enumeration: the connector paginates across all configured domains — the primary completes first, then each additional domain. All resources land in a single unified sync.
- Cross-domain DN lookups (group members, managers, Foreign Security Principals): the DN’s domain suffix is matched against your configured domains to route the lookup.
- Cross-domain SID lookups (gMSA ACLs, primary group SIDs): the SID is resolved against each configured domain in order until a match is found.
- NetBIOS names (needed for down-level logon display): each forest’s
configurationNamingContextis queried forcrossRefentries. On Windows, the primary domain also uses the nativeDsCrackNamesWAPI; additional domains always fall back to LDAPcrossRef.
Diagnosing issues
Run the built-in test harness to check DC resolution, TLS handshake, certificate validation, and LDAP bind for every configured domain:- LDAP error 81 (“Server Down”) on the remote domain — TLS handshake failure, almost always a missing CA trust. Import the remote root CA (Option B above) or use plain LDAP with signing.
- LDAP result code 32 (“No Such Object”) during the grants phase — the connector hit a DN or SID on a remote domain that isn’t configured. Add the missing domain to
additional-domains. - “baseDN auto-discovery failed” — can’t reach the remote rootDSE. Check DNS and network, or set
base-dnexplicitly. - “SASL bind failed” / “Cannot obtain Kerberos ticket” — cross-realm Kerberos isn’t working. Verify the trust, DNS SRV records, and that you’re targeting the DC hostname rather than the domain FQDN. As a fallback, switch that domain to
bind-type: simple. - “netbios domain is empty” warnings — the NetBIOS cache couldn’t load crossRef entries. Confirm read access to the remote
configurationNamingContext.
Performance
Each additional domain adds to the sync cycle. The connector completes one domain fully before moving on; LDAP pagination (1000 entries per page) is used throughout; total sync time scales linearly with the number of domains and objects.gMSA sync
To sync Group Managed Service Accounts, enable the flag in your config:password_retrieval entitlement representing which principals are authorized to retrieve the managed password. Grant and Revoke operations modify the gMSA’s msDS-GroupMSAMembership security descriptor ACL.
OU filtering
You can restrict which Organizational Units the connector syncs by usingskip-ous or only-ous (mutually exclusive):
Custom user attributes
By default, the connector syncs a standard set of AD user attributes. Usecustom-user-attributes to include additional AD attributes in the user profile for account correlation:
Casing: LDAP attribute names are case-insensitive (RFC 4512 §2.5), so configuring
mail, Mail, or MAIL all reference the same AD attribute. The connector matches the operator’s configured casing case-insensitively against the entry’s returned attribute names. The profile-map key preserves the operator’s configured casing — so a config of Mail produces profile["Mail"], not profile["mail"] — predictable for downstream consumers reading the C1 profile JSON.sync-extension-attributes: true instead of listing all 15 names manually:
Resource label (cn vs displayName)
By default, the connector uses the LDAP cn attribute as the C1 resource label. AD often stores cn in Last, First order while displayName carries the operator-curated First Last form. To use displayName as the C1 Identity Name, set:
cn when displayName is empty or whitespace. Applies to both user and gMSA resources. This setting is off by default to preserve existing Identity Names on upgrade — flipping it changes resource labels across access reviews and audit history.
Custom PowerShell actions
You can define additional connector actions backed by PowerShell scripts:string, int, or bool.
Arguments are delivered to the script’s param() block with their declared types — a bool binds a real boolean (works for [bool] and [switch]), an int binds a number, and a string binds a literal value. String values are passed as data (not spliced into the command line), so content such as quotes, $(...), or ; is inert and cannot inject PowerShell. Write your script with a param() block matching the declared argument names, and signal the outcome with an explicit exit code (exit 0 for success, a non-zero exit N for failure) — the connector reports that exit code back to C1.
User profile attributes
Synced user profiles carry the standard AD attributes (display name, email, manager, department, etc.) plus three groups of extra fields the connector populates from AD: read-only state booleans, FILETIME timestamps, and any custom attributes you list incustom-user-attributes.
Read-only state attributes
Six booleans are surfaced on every user profile:
The four static flags come from the stored UAC bits set by an admin. The two live-state flags come from AD’s server-computed UAC attribute, which is re-evaluated each time the connector reads the user.
By default, locked-out accounts also map to
STATUS_DISABLED in C1 (backwards-compatible). To keep locked accounts as STATUS_ENABLED and report lockout state solely via the account_locked field above, set:
Timestamp attributes
The connector parses every well-known AD time attribute to an RFC3339 (UTC) timestamp and surfaces it under a canonical*At profile key. The canonical naming convention is raw AD attribute name + At.
Sentinel handling: values that AD encodes as “never” (
0) or “never expires” (0x7FFFFFFFFFFFFFFF for FILETIME) cause the parsed *At key to be omitted — no year-1601 or year-30828 dates leak into a profile view.
Raw values for operator-configured attributes: if you include one of the source AD attribute names above in custom-user-attributes, the raw value is also surfaced under the operator-requested key (preserving the YAML contract for downstream tooling that reads by attribute name) — except when the value is a sentinel, in which case the raw is also suppressed (the meaningless 19-digit integer would only confuse reviewers).
pwdLastSet and lockoutTime are not replicated to the Global Catalog, so they may be missing under sync-scope: GlobalCatalog. badPasswordTime is local to each domain controller and not replicated at all — its value reflects the DC the connector talked to during the sync. lastLogon is also per-DC and not replicated; the connector prefers lastLogonTimestamp (replicated) when both are present.Backwards-compat aliases (v0.5.5 transition): for one release, the connector also emits each renamed FILETIME canonical key under its pre-v0.5.5 name —
passwordLastSet (alongside pwdLastSetAt), lockedOutAt (alongside lockoutTimeAt), and lastBadPasswordAt (alongside badPasswordTimeAt) — so downstream automations reading the older keys continue to work. The new generalizedTime keys (whenChangedAt, whenCreatedAt, lastLoginAt) have no legacy aliases since they’re introduced in this release. Legacy aliases will be dropped in a future release; new consumers should target the canonical *At form.Push attributes
Theupdate_profile resource action accepts 23 named string fields, each named after the canonical AD attribute it targets. The platform’s push-rule UI shows the AD attribute name in its “App attribute” column, so the value you map to in C1 corresponds directly to the attribute AD will receive. Attributes outside this list (including extensionAttribute1 through extensionAttribute15) must be set via the custom_attributes map field on update_profile, or via the update_user_attrs global action.
Pre-v0.5.5 push rules used snake_case field names (
first_name, display_name, email, etc.). Those rules continue to work — the connector resolves both the canonical AD names listed above and the legacy snake_case aliases to the same target attribute. New push rules should prefer the AD-canonical names so the C1 UI’s “App attribute” column matches what AD actually expects.update_user_attrs global action recognizes the 23 fields above (plus their legacy snake_case aliases for backwards compatibility), plus 15 extension attribute names (extensionAttribute1 through extensionAttribute15 — also accepted as extension_attribute_1–extension_attribute_15). Any attribute name not in the combined list is passed through as a raw AD attribute name, allowing direct access to any writable AD attribute.
Troubleshooting “search returned 0 entries”
When the connector logswinldap_ldap_search: search returned 0 entries at INFO level, it means a configured search base (typically user-search-dn or group-search-dn) produced no entries. The log line includes base, filter, and scope so you can correlate which search returned empty. There are three common causes:
-
The search filter is too narrow — verify with an
ldapsearchorGet-ADUser -LDAPFilterfrom the same DC the connector is bound to. If they also return zero, the filter or the DN is wrong. -
The DN doesn’t exist as written — the connector logs the exact
basestring sent to AD. Copy it verbatim intodsquery * "<base>" -limit 1on the DC to confirm. -
The bound DC isn’t authoritative for the search base — when you narrow
user-search-dnorgroup-search-dninto a delegated OU, a child-domain OU, or a Read-Only DC subtree, the bound DC may answer withLDAP_REFERRAL(result code 10) orLDAP_PARTIAL_RESULTS(9) instead of entries. The connector surfaces this case explicitly: alongside the zero-entries INFO, look for a WARN log of the formldap_ext_search: non-success result code_name=LDAP_REFERRAL r1=10. The same condition surfaces in the C1 sync-failure panel asLDAP error: LDAP_REFERRAL, so it’s identifiable from the platform side too without needing log access. The connector does not chase referrals. WinLDAP’s referral-chasing option (LDAP_OPT_REFERRALS) is explicitly disabled — it has to be, to work around an AD pagination bug where chased subordinate referrals confuse the paging control and corrupt the page cookie. Re-enabling chasing would also introduce an authentication-security risk (chased referrals can authenticate against arbitrary servers). The remediation is to adjust the search configuration so the bound DC is authoritative for the subtree:- Widen the search base (e.g. move from
OU=Sub,OU=Parent,DC=corp,DC=example,DC=comup toOU=Parent,...or to the partition rootDC=corp,DC=example,DC=com). - Configure a different bind DC that is authoritative for the OU — pass
--sitenameto scope discovery to a site that includes an authoritative DC, or set upadditional-domainsif the subtree belongs to a different partition. - For multi-domain forests, use
additional-domainsso the connector binds separately against each partition’s authoritative DC instead of chasing referrals from one DC.
- Widen the search base (e.g. move from
LDAPS troubleshooting
LDAPS settings (ldaps, ldaps-port, ldaps-skip-verify) live in the Configuration reference. This section covers the parts that don’t fit in a flag table: how the two connection modes treat certificate trust differently, and how to diagnose handshake failures.
Certificate trust depends on connection mode
Theldaps-skip-verify flag behaves differently depending on mode:
-
WinLDAP mode (default on Windows): TLS validation is delegated to the Windows certificate store.
ldaps-skip-verifyhas no effect — the OS always validates againstCert:\LocalMachine\Root. To trust a CA, import its root certificate into the Windows machine store: -
LDAP mode (Go library, default on Linux): TLS validation uses Go’s TLS stack.
ldaps-skip-verify: true(the default) disables hostname and chain validation, which lets self-signed AD certs work in lab environments. For production, setldaps-skip-verify: falseand either trust the CA at the OS level or import it into the connector machine.
mode: ldap doesn’t connect on a Windows host (typical when the AD server requires channel binding or LDAP signing), switch to mode: winldap.
Diagnose with test-ldaps
The connector ships a diagnostic command that exercises every configured domain end-to-end:
x509: certificate signed by unknown authority(go-ldap mode) — the connector machine doesn’t trust the CA that issued the DC certificate. Import the CA root or setldaps-skip-verify: truefor testing only.tls: failed to verify certificate: x509: certificate is valid for X, not Y— certificate Subject/SAN doesn’t include the hostname the connector is connecting to. Verify you’re targeting a DC hostname that matches the cert (DCs typically have multiple SAN entries).LDAP Result Code 81 "Server is unavailable"in WinLDAP mode — usually a TLS handshake failure where Schannel rejected the cert. Check the Windows event log underLDAP-ClientandSchannelsources for the rejection reason.- Connection times out on port 636 — port not open between the connector host and the DC, or LDAPS isn’t enabled on the DC. Confirm the DC has a Server Authentication EKU certificate in its Personal store.
test-ldaps checks every entry in additional-domains plus the primary, so a single run covers your whole topology.
DPAPI secrets encryption
On Windows, the connector can encrypt sensitive config values (client-id, client-secret, and bind-password) using Windows DPAPI machine-scoped encryption. Encrypted values are prefixed dpapi: in the YAML config and are decrypted transparently at startup. The GUI Configuration Editor encrypts secrets by default when you save; you can also encrypt an existing config manually:
GUI Configuration Editor
The connector includes a native Windows GUI for managing configuration without editing YAML files manually. It’s the same window thatsetup launches automatically on first run when no config exists (Option 2, Step 3) — you can also open it standalone at any time:
Lockout Status Behavior (locked-account-is-disabled), Sync Extension Attributes (sync-extension-attributes), and Use displayName as Resource Label (use-display-name). Secret fields (bind passwords, client secret) are write-only — entering a new value encrypts it via DPAPI on save; leaving a field blank preserves the existing encrypted value.