Skip to main content

Active Directory Integration

The Ledger Active Directory integration finds the service accounts in your on-premises Active Directory Domain Services (AD DS) domains and scores the risk of their passwords. Service accounts are the user accounts that applications, scheduled tasks, and Windows services sign in as. Their passwords are often old, never expire, and are shared between hosts, which makes them a common path to a domain.

The integration runs in your network. It reads your domains over LDAPS (LDAP over TLS) with a read-only account and sends the account data to the Defakto Control Plane. Ledger then decides which accounts are service accounts, records the services each one runs, and scores each password.

The integration never reads account passwords from the directory. The bind account's credentials and the connection settings stay on your host. Scan results include the names of your domains and forest, and the host names of the domain controllers and global catalog servers that answered.

What Data is Collected?​

  1. Identities - Service accounts: user accounts that match a detection rule, group managed service accounts (gMSAs), and standalone managed service accounts (MSAs).
  2. Secrets - Metadata about the password of each service account. Ledger records when the password was set, when the account last signed in, and how the account authenticates, but never the password itself.
  3. Applications - The services an account is registered to run. Each service class on a host is one Application, such as MSSQLSvc on sql01.corp.example.com.

To decide which accounts are service accounts, the integration sends Ledger the directory attributes of every user account it can read, including people's names, email addresses, managers, employee IDs, descriptions, and group memberships. Ledger keeps only the service accounts in your inventory.

How Service Accounts Are Detected​

Ledger applies a list of rules that mark an account as a service account. An account that matches at least one rule is a service account, and the rules it matched are shown in the Console.

RuleMatches an account that
Managed service accountIs a gMSA or an MSA.
Service principal nameHas a service principal name (SPN), so a Kerberos service runs as it.
Kerberos delegationIs trusted for Kerberos delegation.
Service account OUIs in an organizational unit (OU) named for service accounts, such as Service Accounts, SVC, or Managed Service Accounts.
Name patternHas a name that follows a common service-account convention, such as svc-, sa_, sql-, or -service, or one of your own name patterns.
Description keywordHas a description that mentions a phrase such as "service account", "used by", "scheduled task", or "do not disable".
Password never expiresHas a password that never expires, and has no mailbox or no manager.

Ledger leaves out these accounts:

  • The accounts every domain is created with: Administrator, Guest, krbtgt, and DefaultAccount.
  • Trust accounts, which represent a trust with another domain.
  • The sync accounts Microsoft Entra Connect creates (MSOL_ and AAD_ followed by 12 hexadecimal characters), unless the account is in a privileged group, has an SPN, or is trusted for delegation.

Supported Remediations​

This integration does not yet support remediations.

Integration Permissions​

Bind Account​

The integration signs in to each domain controller with a domain account that needs read access only. By default, a standard domain user can read every attribute the integration uses, so the account needs no group memberships beyond Domain Users and no delegated rights. We recommend a dedicated account used only by the integration. The account must be able to read the user accounts of the domain.

The integration reads the password file at each scan, so to rotate the password, change it in Active Directory and then update the file. No restart is needed.

Network​

The integration only makes outbound connections and needs no inbound access.

  • To your domain controllers: LDAPS on port 636.
  • To your forest's global catalog servers: LDAPS on port 3269. These can be domain controllers of other domains in the forest.
  • To DNS: The integration finds each domain's controllers and the forest's global catalog servers through DNS SRV records, unless you name them.
  • To Defakto: HTTPS on port 443 to the endpoints the Console lists when you create the integration.

Installation​

This integration supports only a Runtime installation mode. The integration runs as a container in your network, and data is transmitted back to the Defakto Control Plane.

Prerequisites​

  • A Linux host with Docker that can reach your domain controllers and the Defakto endpoints.
  • A read-only domain account for the integration, and its password.
  • LDAPS enabled on your domain controllers.
  • The PEM-encoded certificate of the certificate authority (CA) that issued your domain controllers' certificates, if it is not a public CA. For example, your Active Directory Certificate Services root CA.

Installation Steps​

The following steps are also available as spirlctl ledger integration active-directory add in the CLI if programmatic setup is preferred. The command writes the integration key to a file and prints the same commands as the Console.

  1. Visit the "Integrations" page in the Defakto Console. Click "Create Integration".
  2. Select "Active Directory" from the list of available integrations. Configure the following fields, then click "Next Step" to continue.
    • Integration Name: A unique name for this integration. This will be used to identify the integration in the Console and CLI. (required)
  3. Download the key file. The integration authenticates to Defakto with this key.
    warning

    The key exists only in the browser session that created the integration. Defakto does not keep it. If you leave the page without downloading it, delete the integration and create it again.

  4. Save the bind password. Run the provided command on the host, in the directory that holds the key. The command prompts for the bind account's password and writes it to a file only you can read, without the password reaching your shell history. The password stays on your host.
  5. Choose who issued the domain controller certificate.
    • A public certificate authority: The integration trusts it through the system roots of its image.
    • Your own certificate authority: Save the CA's PEM certificate as ad-ca.pem next to the key. The run command mounts it into the container.
  6. Copy the docker run command, replace the domain and the bind account with your own, and run it from the directory that holds the files.
    • Repeat --ad-domain for each domain of the forest to scan.
    • If you scan a single domain, add --ad-host to specify the domain controller, so that the integration doesn't look it up in DNS. This is safer, because DNS otherwise decides which server receives the bind password.
  7. Allow the listed Defakto endpoints through your firewall, along with LDAPS (636) to your domain controllers and LDAPS (3269) to your forest's global catalog servers.
  8. Under "Checking integration status", wait for the integration to connect, then click "Run first scan". Unlike other integrations, an Active Directory integration does not start a scan when it is created, since it is not running yet. The page refreshes when the integration connects, and then shows whether the scan completed.

After the first scan, the integration scans once a day, at a time of day fixed for each integration. Use the "Run now" button on the integration details page to trigger an immediate scan and refresh the inventory from this integration at any time.

Example Run Command​

The following is only an example. Use the command that the Console or CLI generates, because it contains your integration's IDs and endpoints.

docker run -d --restart unless-stopped --name defakto-ledger-sc-abc123 \
--mount type=bind,source="$PWD"/'corp-ad.key',target=/run/defakto/scanner.key,readonly \
--mount type=bind,source="$PWD/ad-bind-password",target=/run/defakto/ad-bind-password,readonly \
--mount type=bind,source="$PWD/ad-ca.pem",target=/run/defakto/ad-ca.pem,readonly \
--env SPIRL_ENV=prod \
ghcr.io/spirl/spirl-controller:latest \
ledger run --platform activedirectory \
--scanner-id sc-abc123 \
--auth-key-id skc-abc123 \
--auth-key-file /run/defakto/scanner.key \
--auth-endpoint auth.cp.spirl.com:443 \
--relay-endpoint relay-web.cp.spirl.com:443 \
--relay-spiffe-id-prefix spiffe://spirl.internal/us-west-2/spirl/relay \
--ingest-endpoint ledger.edge.defakto.security:443 \
--ad-domain corp.example.com \
--ad-domain emea.corp.example.com \
--ad-bind-user scanner@corp.example.com \
--ad-bind-password-file /run/defakto/ad-bind-password \
--ad-ca-file /run/defakto/ad-ca.pem

Integration Settings​

FlagDescription
--ad-domainDNS name of a domain to scan, such as corp.example.com. Repeat it, or give a comma-separated list, to scan several domains of a forest. (required)
--ad-bind-userThe read-only account to sign in as: a user principal name such as scanner@corp.example.com, or a distinguished name. DOMAIN\name is not accepted. (required)
--ad-bind-password-filePath to the file that holds the bind account's password. There is no flag for the password itself, so that it is not visible to other processes on the host. (required)
--ad-ca-filePath to the PEM-encoded certificate of the CA that issued your domain controllers' certificates. (default: the system roots)
--ad-hostHost name of the domain controller to read, with a single --ad-domain. (default: looked up in DNS)
--ad-portLDAPS port of the domain controller, with a single --ad-domain. (default: 636)
--ad-tls-server-nameName the domain controller's certificate is verified against. (default: --ad-host)
--ad-global-catalog-hostHost name of the global catalog server to ask about the forest. Not used for the forest root domain. (default: --ad-host, then looked up in DNS)
--ad-global-catalog-portLDAPS port of the global catalog server. (default: 3269)
--ad-global-catalog-tls-server-nameName the global catalog server's certificate is verified against. (default: its host name)
--ad-base-dnDistinguished name to search under, with a single --ad-domain. (default: the whole domain)
--ad-name-patternA regular expression that matches your own service-account naming convention, in addition to the built-in conventions. Repeatable.
--ad-redact-spn-hostsWhen set, sends only the service class of each SPN, without its host name. Ledger then records no Applications for the accounts and doesn't score Reuse.
--ad-page-sizeAccounts to read per page. (default: 500)
--ad-page-delayPause between pages, which bounds the load on the domain controller. (default: 20ms)

Risk Scoring​

Ledger scores each service account's password with the factors described in Risk Scoring, using what Active Directory records:

  • Age: From when the password was last set.
  • Last Used: From the account's last sign-in.
  • Reuse: From the number of services the account is registered to run.
  • Exposure: Reflects how the account authenticates, such as whether it runs a Kerberos service, allows weak encryption, or doesn't require Kerberos pre-authentication.
  • Authorization Scope: Reflects membership in privileged groups such as Domain Admins, directly or through nested groups, and whether the account is trusted for unconstrained Kerberos delegation.

Your risk-scoring configuration doesn't change the Exposure and Authorization Scope levels of Active Directory accounts.

Caveats​

  1. The integration connects only over LDAPS. Plain LDAP on port 389 and StartTLS are not supported.
  2. An Active Directory integration does not scan until you run its first scan.
  3. Active Directory records the last sign-in to within about 14 days, so a recent sign-in may not show yet.
  4. Active Directory silently leaves out the attributes the bind account can't read. If more than 1% of a domain's accounts can't be read, the scan of that domain fails, and the Console asks you to give the bind account read access. Below that, Ledger scores the affected accounts with what it could read.
  5. The integration refuses to start if a name pattern is not a valid regular expression. Ledger ignores, without warning, a pattern that is too long or too complex, uses characters beyond ASCII, or matches any name, such as .*.