Docs menu

Identity Bridge: Collect Active Directory over LDAPS, Outbound-Only

Connect GraphnAI to your on-premises Active Directory without opening inbound firewall ports. The bridge collects over LDAPS and SMB, and connects out to GraphnAI with mutual TLS (mTLS).

Roles
Admin (create and configure bridges), Operator (view bridge pages, start and stop syncs)
Applies to
Active Directory
Updated
On this page

Overview

The Identity Bridge is an agent that runs inside your network, usually as a Docker container, and collects identity data from Active Directory. It connects out to GraphnAI over a mutual TLS (mTLS) connection. You open no inbound firewall ports and need no VPN.

The bridge collects users, groups, computers, organizational units, security descriptors and Group Policy data. GraphnAI builds the identity graph's edges (memberships and permissions) from that data, at the Theoretical and Constrained fidelity levels. The bridge also carries out remediation actions that GraphnAI sends, such as disabling a user or removing a group membership, with safety checks before each change.

The bridge keeps one outbound WebSocket connection to GraphnAI and sends a heartbeat every 30 seconds. If the connection drops, the bridge tries to reconnect every 30 seconds.

Prerequisites

  • Admin role in GraphnAI to create the bridge.
  • A host with Docker (recommended), or a Linux or Windows host for the binary. Plan 2 to 4 GB of RAM and 2 to 4 CPU cores. See Hardware Sizing.
  • An Active Directory service account with read access to the directory. See Service Account Requirements.
  • Network paths from the bridge host:
    • To your domain controllers on port 636 (LDAPS) or 389 (LDAP), and on port 445 (SMB) for Group Policy collection.
    • To GraphnAI on port 8443, outbound only.

Service Account Requirements

The service account the bridge uses must have:

  • Read access to every identity object: users, groups, computers, OUs and containers.
  • Read access to the nTSecurityDescriptor attribute on every object. GraphnAI needs it to find who holds which permissions.
  • Access to the SYSVOL share for Group Policy collection. Standard domain member access is enough.
  • No write permissions, unless you plan to use remediation actions.

A standard domain user with "Read all properties" delegated at the domain root is enough for most environments. Don't use a Domain Admin or another privileged account.

Create a Bridge

Creating a bridge gives it an identity and the certificates it uses to prove that identity to GraphnAI. You do this once for each bridge. It takes the Admin role.

  1. Select Admin > Bridges in the sidebar.
  2. Select Deploy bridge.
  3. Enter a Bridge ID, such as bridge-nyc-01. Use letters, numbers, hyphens and underscores. You can't change the ID later.
  4. Select Create and download.

A ZIP file named bridge-<id>-setup.zip downloads. It contains:

File Contents
cert.pem The bridge's client certificate
key.pem The bridge's private key
ca.crt GraphnAI's root certificate, which the bridge uses to verify the server
docker-compose.yml A ready-to-use Docker Compose file
README.md Quick-start steps

The new bridge's page opens with its status Offline until the bridge connects.

The Deploy bridge dialog with the Bridge ID field

[!IMPORTANT] Store the ZIP file securely. It holds the bridge's private key (key.pem), and GraphnAI keeps no copy. If you lose it, select Download setup bundle on the bridge's page for a new bundle with a new key and certificate. A bundle's certificate is valid for one year. A new bundle doesn't revoke the old certificate, which stays valid until it expires.

Deployment

The Compose file in the bundle already sets the bridge ID, the server address and the certificate paths.

  1. Copy the ZIP file to the host that will run the bridge.
  2. Extract it into a directory, such as /opt/graphnai-bridge/.
  3. Start the bridge:
cd /opt/graphnai-bridge
docker compose up -d
  1. Check that it connected:
docker compose logs -f

Look for a log line like this one:

{"level":"INFO","msg":"Connected to Cloud C2"}

Within 30 seconds, Status on the bridge's page reads Online.

A bridge page with the Online status, the domain table and sync history

State Across Restarts

The bridge saves its sync position for each domain (the USN watermark) in state.json. After a restart, it resumes with a delta sync instead of a full sync. It also keeps the certificates you trust in GraphnAI in trusted_cas.pem.

The bundle's Compose file keeps both on the bridge-data volume, mounted at /app/data:

volumes:
  - ./cert.pem:/app/cert.pem:ro
  - ./key.pem:/app/key.pem:ro
  - ./ca.crt:/app/ca.crt:ro
  - bridge-data:/app/data   # Persists state.json and trusted_cas.pem

Keep that volume when you recreate the container. If it's lost, the bridge gets its sync positions and trusted certificates back from GraphnAI when it reconnects.

Option B: Standalone Binary

Where Docker isn't available, run the bridge binary directly.

  1. Download the graphnai-bridge binary for your platform from the releases page.
  2. Put cert.pem, key.pem and ca.crt in the binary's directory.
  3. Set the bridge ID and server address from the bundle. See Configuration.
  4. Run the binary:
./graphnai-bridge

In production, run the binary as a service (systemd on Linux, NSSM or Task Scheduler on Windows) so it restarts on its own.

Configuration

The bridge reads its settings from its environment when it starts. The setup bundle's docker-compose.yml fills in the bridge ID, the server address and the certificate paths. The bridge exits at startup if the bridge ID or the server address is missing.

Required Settings

Setting Description Example
Bridge ID The bridge's ID. The bundle's docker-compose.yml sets it. prod-corp-dc01
Server address GraphnAI's bridge address. The bundle sets it. wss://graphnai.example.com:8443

Certificate Files (mTLS)

File Default Description
Bridge certificate cert.pem Path to the bridge's client certificate
Bridge private key key.pem Path to the bridge's private key
GraphnAI root certificate ca.crt Path to GraphnAI's root certificate, used to verify the server

Safety and Security Settings

Setting Default Description
Read-only mode Off Turn it on to skip every remediation action. The bridge makes no LDAP writes. See Read-Only Mode.
Insecure LDAP Off Turn it on to allow unencrypted LDAP on port 389. For lab use only.
Trust store path trusted_cas.pem Where the bridge keeps the certificates you trust in GraphnAI. The bundle sets it to /app/data/trusted_cas.pem. The bridge rewrites the file with GraphnAI's list each time it receives its settings, so don't edit it.
Operator trust store path None A PEM file of extra CA certificates for LDAPS, which you place on the bridge host. The bridge reads it and never changes it. Use it to pre-provision an air-gapped bridge. Otherwise, trust certificates in GraphnAI.

Legacy Single-Domain Settings

These settings set up one domain for standalone or development use. In production, you add domains in GraphnAI and it sends them to the bridge after it connects. See Configuring Domains. You don't need these settings then.

Setting Description Example
LDAP URL LDAP URL of the domain controller ldaps://dc01.corp.local:636
Bind DN Service account distinguished name or UPN CN=svc-graphnai,OU=Service Accounts,DC=corp,DC=local
Bind password Service account password. In production, read it from a file.
Base DN Base distinguished name for directory searches DC=corp,DC=local

The bind DN and bind password can also come from a file, for Docker and Kubernetes secrets. The bridge reads the file at startup and trims whitespace from both ends.

mTLS Certificate Setup

The bridge and GraphnAI verify each other with mutual TLS (mTLS). Each presents a certificate signed by GraphnAI's internal certificate authority. The setup bundle holds everything the bridge needs, so you create no certificates by hand.

What Each File Does

File Purpose
cert.pem The bridge's identity certificate, signed by GraphnAI's certificate authority. It names this bridge.
key.pem The private key for cert.pem. Keep it secret: it proves the bridge is who it claims to be.
ca.crt GraphnAI's root certificate. The bridge uses it to check that it's talking to your GraphnAI server.

Trusting Custom Enterprise CAs (for LDAPS)

If your domain controllers use LDAPS certificates from an internal certificate authority, the bridge must trust that authority. Trust it in GraphnAI:

  1. On the bridge's page, add or edit a domain and select Test connection.
  2. If the test reports an untrusted certificate, select Review certificate. The bridge reads the controller's chain and completes it to the root certificate authority where it can.
  3. Compare the root's SHA-256 fingerprint with your certificate authority's, then select Trust root certificate.

Certificate chain completed to the root certificate authority

Trust the certificate authority itself. A controller's own certificate stops working when Windows renews it, every year. When the bridge can't find the root, the dialog asks you to paste or upload it. For the whole flow and the Trusted certificates list, see Trust the Certificate Authority for LDAPS.

Pre-Provision an Air-Gapped Bridge

If the bridge must trust a certificate authority before it can reach GraphnAI, put the CA certificate in a PEM file on the bridge host, mount it, and set the operator trust store path to it. The bridge reads that file and never changes it. The Trusted certificates list doesn't show those certificates. It says how many the bridge trusts from its host.

Upgrade a Bridge From an Earlier Version

Nothing in docker-compose.yml changes. The first time an upgraded bridge receives its settings, its trusted certificates become exactly GraphnAI's list. If trusted_cas.pem held a certificate GraphnAI doesn't list, such as one added to the file by hand, the bridge stops trusting it and logs a warning that names it. To keep it, trust it in GraphnAI, or put it in the operator trust store file.

Earlier versions of this guide suggested mounting your own CA file and pointing the trust store path at it. If you did, move that file to the operator trust store path before you upgrade, and point the trust store path at a file the bridge can write. With a read-only file, a trust change lasts only until the bridge restarts, and GraphnAI says so when you trust or remove a certificate. Don't point both settings at the same file. The bridge then ignores the operator trust store and never writes that file.

Configuring Domains

After the bridge connects, add the Active Directory domains it collects from. You add them in GraphnAI, which sends them to the bridge. The bridge doesn't restart. This takes the Admin role.

  1. On the bridge's page, select Add domain.
  2. Enter the domain name, the domain controllers, the service account and its password. Keep Use TLS (LDAPS) on.
  3. Select Test connection.
  4. Select Add domain.

GraphnAI encrypts the password and sends the settings to the bridge over its existing connection. For every field and message, see Bridge Configuration.

Domain form with the Test connection button

Discover Domains

Select Discover above the domain table to have the bridge look up domain controllers in DNS. It tests each one it finds, and you add the ones you pick through the domain form. See Domain Auto-Discovery.

Discovery results with domains, their domain controllers and LDAPS badges

Multi-Domain Support

Select Add domain once for each domain. The bridge keeps a separate LDAP connection for each domain and syncs its domains one after another. Each domain has its own sync history, USN watermark and Group Policy collection state.

The bridge sends each remediation action to the domain named in the target's distinguished name. For example, an action on CN=john.doe,DC=corp,DC=local goes to the corp.local domain.

Sync Behavior

Sync Types

The bridge uses two kinds of sync to keep the identity graph current.

Full sync reads every directory object, page by page. A domain's first sync is a full sync, and a scheduled sync becomes a full sync when the full sync interval has passed.

Delta sync reads only the objects that changed since the last sync, using Active Directory's change tracking (update sequence numbers, or USNs). It's much faster than a full sync and runs every hour by default.

To set the schedule, see Sync Scheduling.

Reconciliation

A delta sync can't see a deleted object. Active Directory moves deleted objects to its Deleted Objects container, outside the range a delta sync reads. A full sync handles deletions.

During a full sync, the bridge sends GraphnAI the IDs of every live directory object. GraphnAI compares that list with the graph and removes the objects that are gone. The row in Sync history shows how many it removed.

On-Demand Sync

Operators and Admins can start a sync now:

  1. On the bridge's page, select Delta sync or Full sync.
  2. The sync runs in the background, and Sync history updates as it runs.

To stop a running sync, select Stop. The bridge stops the collection cleanly.

What the Bridge Collects

Identity Objects

The bridge maps these Active Directory object classes to identity types in the graph:

AD object class Graph type Key attributes collected
user (not a computer) User sAMAccountName, adminCount, servicePrincipalName, userAccountControl
msDS-GroupManagedServiceAccount, msDS-ManagedServiceAccount ServiceAccount sAMAccountName, servicePrincipalName, msDS-GroupMSAMembership
group Group sAMAccountName, memberOf
computer Computer sAMAccountName, servicePrincipalName
organizationalUnit OU name, distinguishedName
container Container name, distinguishedName
builtinDomain BuiltinDomain name
domainDNS Domain name
groupPolicyContainer GPO displayName, gPCFileSysPath

To choose which other attributes the bridge collects, see Attribute Sync Configuration.

Relationships

The bridge sends only objects. GraphnAI builds the graph's edges (relationships) from their attributes:

Edge Between How it's determined
MemberOf A user, group or computer and a group The memberOf attribute
MemberOf (primary group) A user and its primary group The primaryGroupID attribute and the domain SID
ContainedIn Any object and its parent The parent in the object's distinguished name
GPLink A GPO and the OU or domain it's linked to The gPLink attribute
OwnerOf An owner and the object The owner SID in the object's security descriptor
AllowedToDelegate An account and a service it can delegate to The msDS-AllowedToDelegateTo attribute
AllowedToAct An account and a resource that trusts it for delegation The msDS-AllowedToActOnBehalfOfOtherIdentity attribute
HasSIDHistory An account and the SID it carries from a migration The sIDHistory attribute

Permission Edges (ACL Analysis)

The bridge reads every object's Windows security descriptor (the nTSecurityDescriptor attribute). GraphnAI turns its access control entries (ACEs) into permission edges that show who can do what to each object. They include:

Permission edge What it means
GenericAll Full control over the object
GenericWrite Can write any property on the object
WriteDacl Can change the object's DACL (its permission list)
WriteOwner Can take ownership of the object
AllExtendedRights Every extended right, including password resets and directory replication
ForceChangePassword Can reset the user's password without knowing the current one
AddMember Can add members to the group
DCSync Holds the replication rights (GetChanges and GetChangesAll) that copy password data from a domain controller

Others include AddSelf, WriteSPN, AddKeyCredentialLink, ReadLAPSPassword and ReadGMSAPassword. GraphnAI uses these edges to find toxic combinations and attack paths.

GPO Policy Data

The bridge connects to the SYSVOL share on a domain controller and reads each Group Policy Object. It authenticates with Kerberos and falls back to NTLMv2. For each GPO, it reads:

  • GptTmpl.inf (Security Settings): User rights assignments such as "Deny log on locally" (SeDenyInteractiveLogonRight), "Deny access to this computer from the network" (SeDenyNetworkLogonRight) and "Deny log on through Remote Desktop Services" (SeDenyRemoteInteractiveLogonRight), plus restricted group memberships and audit settings.
  • Groups.xml (Group Policy Preferences): Local group memberships the policy sets on computers.

GraphnAI uses the local group settings to find who is a local administrator on which computers, on the Local Administrators page. It also uses the Deny log on rights. When the GPO that wins on a computer denies an account the logons its access needs, that access is marked blocked, and attack paths through it rank last. See Blocked by a Deny log on right.

On a delta sync, the bridge skips GPO files that haven't changed since the last policy sync.

Read-Only Mode

With read-only mode on, the bridge makes no changes to the directory:

  • Directory collection (LDAP sync and Group Policy collection) runs as usual.
  • The bridge skips every remediation action GraphnAI sends, such as disabling a user or removing a member. It makes no LDAP write.
  • Remediation history records the action as Read-only bridge.

Use this mode for a first deployment, to check collection before you allow changes. It also suits a service account that has no write permissions on purpose.

Sync History and Monitoring

The Sync history table on the bridge's page shows each sync with its status, type, domain, start time, duration, and the counts of objects collected and relationships (edges) built. Select a row for its phase timing and counts by type. See Sync History.

Sync history with a selected sync's phase timing and object counts

Troubleshooting

The Bridge Doesn't Show Online

Check the container logs:

docker compose logs -f

Possible causes and fixes:

  • FATAL: required environment variable ... is not set: The Compose file doesn't set a required setting. Check that the file wasn't changed after you extracted it from the ZIP file.

  • websocket dial: ...: The bridge can't reach GraphnAI. Check that:

    1. The host reaches the server on port 8443: nc -zv graphnai.example.com 8443
    2. The server address in the Compose file starts with wss://.
    3. No firewall rule blocks outbound connections on port 8443.
  • Failed to load mTLS KeyPair: cert.pem or key.pem is missing, or the container user can't read it. Check the files and their permissions.

  • Failed to parse Root CA PEM: ca.crt is empty or corrupt. Select Download setup bundle on the bridge's page and replace all three certificate files from the new bundle.

Test Connection Fails

When you select Test connection, the bridge connects to the domain controller and makes an LDAP bind with the service account. The message names what failed:

  • Rejected the service account: The account name or password is wrong, or the account is locked or disabled. Use the UPN form ([email protected]) or a distinguished name (CN=user,...).
  • Couldn't reach the domain controller: Check the controller name, and that the bridge host reaches it on port 636 (LDAPS) or 389 (LDAP).
  • Doesn't trust the certificate: Select Review certificate and trust the root certificate authority. See Trusting Custom Enterprise CAs.

Every message and its fix: Test a Connection.

A domain that fails the check stays configured. The next sync tries each of its listed controllers in order.

The Sync Finishes but No Objects Appear in the Graph

Check that the sync ran: In Sync history, check that the sync reads Success or Partial, and read its Objects count.

Check the domain name: If the sync succeeds with zero objects, the search may have covered an empty part of the directory. The bridge reads the domain's naming context from the directory, and falls back to the configured domain name if it can't. Check that the domain name matches your real Active Directory domain.

Wait for processing: After collection, GraphnAI processes the data in steps. The row reads Running until they finish, and the Phase column shows the current step. A large full sync can take several minutes.

Changes in Active Directory Don't Show in the Graph

A delta sync picks up changes at the next delta interval (1 hour by default). To pick them up now:

  1. Open the bridge's page.
  2. Select Delta sync.

An object deleted from Active Directory stays in the graph until the next full sync. Select Full sync to remove it now.

SYSVOL or GPO Collection Fails

domain config not found in the bridge log: The domain wasn't configured when the policy collection ran. Add the domain and let its first sync finish.

smb ntlm session: ...: SMB authentication failed. The bridge tries Kerberos first, then NTLMv2. If both fail, check that the service account can open the SYSVOL share on the domain controller.

mount sysvol: ...: The bridge connected to the domain controller but couldn't open the SYSVOL share. Check that SMB (port 445) is open from the bridge host: nc -zv dc01.corp.local 445.

If your environment needs a custom Kerberos configuration, put a krb5.conf file in the bridge's working directory: the binary's directory, or /app in the container. The bridge loads it before it authenticates.

Access Denied (403 Forbidden)

Cause: Your account doesn't have the role the action needs.

  • Viewing bridges and starting syncs takes the Operator role.
  • Creating bridges, saving settings, and trusting or removing certificates takes the Admin role.

Fix: Ask an Admin to change your role on Admin > Users.

Best Practices

  1. Deploy one bridge per network segment. For isolated segments, such as a perimeter network or an OT network, deploy a bridge inside each one. Don't open firewall paths between segments.

  2. Start in read-only mode. Turn on read-only mode for the first week to check collection before you allow remediation.

  3. Always use LDAPS (port 636). Plain LDAP (port 389) sends credentials and directory data unencrypted. Keep the insecure LDAP setting for isolated labs with no network exposure.

  4. Protect key.pem with file permissions. The private key is the bridge's identity. On Linux, restrict it: chmod 600 key.pem.

  5. Keep the bridge's data volume. It holds state.json and the trusted certificates. For the standalone binary, keep its working directory. A bridge that loses them gets them back from GraphnAI when it reconnects.

  6. Match the delta interval to how often your directory changes. With frequent provisioning, use 15 minutes. In a stable directory, the default 1 hour is enough. The bridge never syncs more often than once a minute.

  7. Review sync history weekly. Repeated failures point to a connection or credential problem. Fix it before the graph goes stale.

    ↑↓ to move, Enter to open