Skip to content

docs: document Microsoft Entra Domain Services support BED-9245 - #386

Open
martinsohn wants to merge 13 commits into
mainfrom
microsoft-entra-domain-services
Open

docs: document Microsoft Entra Domain Services support BED-9245#386
martinsohn wants to merge 13 commits into
mainfrom
microsoft-entra-domain-services

Conversation

@martinsohn

@martinsohn martinsohn commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Description

Documents BloodHound support for Microsoft Entra Domain Services (Entra DS).

This PR:

  • Adds the AZEntraDS node reference and icon.
  • Documents AZEntraDSContributor, AZManageEntraDS, SyncedToEntraDSUser, SyncedToEntraDSGroup, AddEntraDSGroupMember, EntraDSFor, ManageEntraDSSync, and ManageEntraDSSyncFilter.
  • Documents collection requirements for AzureHound and SharpHoundCommon.
  • Updates the traversable-edge and post-processed-edge references.

Motivation and Context

Resolves: BED-9245

Entra DS spans Microsoft Entra ID, Azure Resource Manager, and a managed Active Directory domain. Users need documentation explaining how data from both collectors is correlated, which relationships are traversable, and how the resulting attack paths can be understood and remediated.

How Has This Been Tested?

  • Cross-checked node and relationship names against the BloodHound schema.
  • Cross-checked source and destination types against the valid-edge definitions.
  • Cross-checked traversability, post-processing, and composition against the BloodHound implementation.
  • Cross-checked collection requirements against the AzureHound and SharpHoundCommon branches.
  • Ran git diff --check origin/main...HEAD.
  • Ran just check-edges ../BloodHound; it reported no Entra DS mismatch. The command remains non-zero because of five pre-existing docs-only edges unrelated to this PR.

Related work

This PR should merge after the BloodHound PR is merged.

Summary by CodeRabbit

  • New Features

    • Added Microsoft Entra Domain Services support to AzureHound data collection and Azure permissions.
    • Added Entra Domain Services nodes and relationships to BloodHound documentation, including synchronization, management, membership, and identity-correlation paths.
    • Added guidance for traversable and post-processed Entra Domain Services relationships.
  • Documentation

    • Added detailed collection, analysis, schema, abuse, and operational guidance.
    • Expanded navigation and developer reference materials.
    • Added repository development and contribution guidance.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The pull request adds Microsoft Entra Domain Services documentation. It covers AzureHound permissions, SharpHound collection, the AZEntraDS node, related edges, schemas, procedures, references, navigation, and repository guidance.

Changes

Microsoft Entra Domain Services documentation

Layer / File(s) Summary
Collection permissions and resource model
docs/assets/azurehound-reader-role.json, docs/install-data-collector/..., docs/collect-data/*, docs/resources/nodes/az-entra-ds.mdx
Documents AzureHound permissions, SharpHound collection boundaries, the AZEntraDS node, its properties, containment, RBAC, and post-processing relationships.
Relationship behavior and schemas
docs/resources/edges/*, docs/resources/edges/az-contributor.mdx
Documents Entra Domain Services relationships, prerequisites, procedures, synchronization behavior, schemas, traversal status, and references.
Documentation indexes and repository guidance
docs/docs.json, docs/opengraph/developer/edges.mdx, docs/snippets/analysis/post-processed-edges.mdx, AGENTS.md
Adds resource and edge navigation entries, updates edge indexes, and documents repository development and validation practices.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested labels: data-collection

Suggested reviewers: jeff-matthews

Poem

A rabbit hops through docs so wide,
Entra Domain Services now described inside.
Edges, nodes, and roles align,
With schemas clear and references fine.
Thump, thump—the knowledge grows! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: documenting Microsoft Entra Domain Services support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch microsoft-entra-domain-services

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@AGENTS.md`:
- Around line 9-10: Update the Mintlify CLI instructions in AGENTS.md to install
the mint package and start the preview with mint dev instead of the deprecated
mintlify commands. State the supported Node.js range as 20.17.0 through 24.x,
while preserving the guidance to review changed pages and navigation entries.

In `@docs/resources/edges/manage-entra-ds-sync.mdx`:
- Line 28: Update the instructions around the filteredSync flow to distinguish
syncScope: when filteredSync=Enabled and syncScope=CloudOnly, first change
syncScope to All using the AZManageEntraDS ARM PUT workflow, then add the
attacker-controlled user’s direct-membership security group through
ManageEntraDSSyncFilter. Preserve the existing filter-only path for
filteredSync=Enabled with syncScope=All and the current handling for
filteredSync=Disabled.

In `@docs/resources/edges/synced-to-entra-ds-user.mdx`:
- Around line 22-29: Update the abuse description and procedure in the
synced-to-entra-ds-user content to explicitly exclude B2B external identities,
preserving the existing requirement that the target be an Entra
DS-authenticating user. Add this restriction to the abuse statement or as a
prerequisite in the first procedure step, and ensure all subsequent
authentication steps apply only to eligible non-B2B identities.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a4daf0d-f11a-46af-85a5-de4bbb1b8132

📥 Commits

Reviewing files that changed from the base of the PR and between 5cf81f7 and 17d033a.

⛔ Files ignored due to path filters (1)
  • docs/images/nodes/azure/az-entra-ds.svg is excluded by !**/*.svg
📒 Files selected for processing (19)
  • AGENTS.md
  • docs/assets/azurehound-reader-role.json
  • docs/collect-data/azurehound-data-permissions.mdx
  • docs/collect-data/sharphound-data-permissions.mdx
  • docs/docs.json
  • docs/install-data-collector/install-azurehound/azure-configuration.mdx
  • docs/opengraph/developer/edges.mdx
  • docs/resources/edges/add-entra-ds-group-member.mdx
  • docs/resources/edges/az-contributor.mdx
  • docs/resources/edges/az-entra-ds-contributor.mdx
  • docs/resources/edges/az-manage-entra-ds.mdx
  • docs/resources/edges/entra-ds-for.mdx
  • docs/resources/edges/manage-entra-ds-sync-filter.mdx
  • docs/resources/edges/manage-entra-ds-sync.mdx
  • docs/resources/edges/synced-to-entra-ds-group.mdx
  • docs/resources/edges/synced-to-entra-ds-user.mdx
  • docs/resources/edges/traversable-edges.mdx
  • docs/resources/nodes/az-entra-ds.mdx
  • docs/snippets/analysis/post-processed-edges.mdx

Comment thread AGENTS.md
Comment on lines +9 to +10
- `npm i -g mintlify` installs the documentation CLI (Node.js 19 or newer is required).
- `cd docs && mintlify dev` starts the local preview. Review every changed page and navigation entry before submitting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
npm view mintlify version engines --json

Repository: SpecterOps/bloodhound-docs

Length of output: 109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- AGENTS.md ---'
cat -n AGENTS.md

printf '%s\n' '--- package manifests and Mintlify references ---'
git ls-files | grep -E '(^|/)(package\.json|package-lock\.json|npm-shrinkwrap\.json|yarn\.lock|pnpm-lock\.yaml|AGENTS\.md)$' || true
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'mintlify|Node\.js|node-version|NODE_VERSION' . || true

Repository: SpecterOps/bloodhound-docs

Length of output: 1941


🌐 Web query:

npm mintlify package engines Node.js 20.17 25 unsupported

💡 Result:

The Mintlify CLI requires Node.js version 20.17.0 or higher [1][2][3]. Official documentation and package metadata explicitly state that Node.js 25 and newer versions are currently unsupported [1][4][5][6]. It is recommended to use an LTS (Long-Term Support) version of Node.js for stability [2][7][3]. If you are encountering issues related to your Node.js version, ensure you are using a supported version (20.17.0+) and that you have installed the correct package, as the CLI is distributed via the mint package (and not mintlify) [2][8][5]. To resolve installation or compatibility problems, the recommended process is to uninstall the deprecated mintlify package, clear the npm cache, and install the current mint package [2][8][3]: npm uninstall -g mintlify npm cache clean --force npm i -g mint

Citations:


🌐 Web query:

site:mintlify.com/docs/cli/install "npm i -g" mint Node.js 20.17

💡 Result:

The command npm i -g mint is used to install the Mintlify CLI globally [1]. Mintlify is a documentation platform, and their official documentation specifies that this CLI requires Node.js v20.17.0 or newer to function correctly [1]. To install the CLI and ensure compatibility with Node.js 20.17, follow these steps: 1. Verify your Node.js version: Run the following command in your terminal to ensure you are using Node.js v20.17.0 or later: node --version [1] 2. Install the Mintlify CLI: If your Node.js version meets the requirement, run the following command to install the CLI globally: npm i -g mint [1] 3. Verify the installation: After the installation completes, confirm it was successful by checking the version: mint --version [1] If you encounter a permissions error during installation, the documentation suggests running the command with elevated privileges using sudo (e.g., sudo npm i -g mint) [1]. Additionally, if you run into issues, ensure any older or conflicting packages (such as a previous mintlify package) are uninstalled first using npm uninstall -g mint [1].

Citations:


🌐 Web query:

site:mintlify.com/docs/cli "mint dev" local preview

💡 Result:

The command to start a local preview of your documentation using the Mintlify CLI is mint dev [1][2]. To run this command, navigate to your documentation directory (which must contain a docs.json file) in your terminal and execute: mint dev Key details for using the local preview: 1. Requirements: You must have the Mintlify CLI installed globally or use npx mint dev to run it without a global installation [1]. 2. Live Editing: The local server runs at http://localhost:3000 by default, and changes to your files will appear in real time [1][3]. 3. Features: To enable search and the AI assistant in your local environment, run the mint login command to authenticate your CLI with your Mintlify account [1]. 4. Useful Flags: --port : Change the port from the default 3000 [1][2]. --no-open: Prevent the browser from opening automatically [1][2]. --disable-prefetch: Improve performance for very large sites by disabling navigation prefetching [1][2]. --disable-openapi: Skip OpenAPI file processing to speed up the preview [2]. --groups : Provide a comma-separated list of user groups to mock for the preview [2].

Citations:


Update the Mintlify CLI instructions.

Install mint, not the deprecated mintlify package. Use mint dev for the local preview. Document Node.js 20.17.0 through 24.x.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@AGENTS.md` around lines 9 - 10, Update the Mintlify CLI instructions in
AGENTS.md to install the mint package and start the preview with mint dev
instead of the deprecated mintlify commands. State the supported Node.js range
as 20.17.0 through 24.x, while preserving the guidance to review changed pages
and navigation entries.


### Procedure

1. Read the Microsoft Entra Domain Services (Entra DS) managed domain's current `filteredSync` and `syncScope` values. If `filteredSync=Enabled`, add an Entra security group of which the attacker-controlled user is a direct member to the filter, as described for [ManageEntraDSSyncFilter](/resources/edges/manage-entra-ds-sync-filter). If `filteredSync=Disabled` but `syncScope=CloudOnly`, change `syncScope` to `All` with the ARM `PUT` workflow described for [AZManageEntraDS](/resources/edges/az-manage-entra-ds).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Handle filteredSync=Enabled with syncScope=CloudOnly.

Line 28 directs every enabled filtered-sync state to ManageEntraDSSyncFilter. That relationship also requires syncScope=All.

If syncScope=CloudOnly, first change it to All. Then add the security group to the filter.

Proposed clarification
-1. Read the Microsoft Entra Domain Services (Entra DS) managed domain's current `filteredSync` and `syncScope` values. If `filteredSync=Enabled`, add an Entra security group of which the attacker-controlled user is a direct member to the filter, as described for [ManageEntraDSSyncFilter](/resources/edges/manage-entra-ds-sync-filter). If `filteredSync=Disabled` but `syncScope=CloudOnly`, change `syncScope` to `All` with the ARM `PUT` workflow described for [AZManageEntraDS](/resources/edges/az-manage-entra-ds).
+1. Read the Microsoft Entra Domain Services (Entra DS) managed domain's current `filteredSync` and `syncScope` values. If `syncScope=CloudOnly`, change `syncScope` to `All` with the ARM `PUT` workflow described for [AZManageEntraDS](/resources/edges/az-manage-entra-ds). If `filteredSync=Enabled`, then add an Entra security group of which the attacker-controlled user is a direct member to the filter, as described for [ManageEntraDSSyncFilter](/resources/edges/manage-entra-ds-sync-filter).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
1. Read the Microsoft Entra Domain Services (Entra DS) managed domain's current `filteredSync` and `syncScope` values. If `filteredSync=Enabled`, add an Entra security group of which the attacker-controlled user is a direct member to the filter, as described for [ManageEntraDSSyncFilter](/resources/edges/manage-entra-ds-sync-filter). If `filteredSync=Disabled` but `syncScope=CloudOnly`, change `syncScope` to `All` with the ARM `PUT` workflow described for [AZManageEntraDS](/resources/edges/az-manage-entra-ds).
1. Read the Microsoft Entra Domain Services (Entra DS) managed domain's current `filteredSync` and `syncScope` values. If `syncScope=CloudOnly`, change `syncScope` to `All` with the ARM `PUT` workflow described for [AZManageEntraDS](/resources/edges/az-manage-entra-ds). If `filteredSync=Enabled`, then add an Entra security group of which the attacker-controlled user is a direct member to the filter, as described for [ManageEntraDSSyncFilter](/resources/edges/manage-entra-ds-sync-filter).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/resources/edges/manage-entra-ds-sync.mdx` at line 28, Update the
instructions around the filteredSync flow to distinguish syncScope: when
filteredSync=Enabled and syncScope=CloudOnly, first change syncScope to All
using the AZManageEntraDS ARM PUT workflow, then add the attacker-controlled
user’s direct-membership security group through ManageEntraDSSyncFilter.
Preserve the existing filter-only path for filteredSync=Enabled with
syncScope=All and the current handling for filteredSync=Disabled.

Comment on lines +22 to +29
An attacker may authenticate as the Entra DS user using the Entra user's credentials. For a cloud-only user that has not changed its password while the managed domain is active, changing the Entra user's password and waiting for Entra DS synchronization to complete generates the password material required for authentication.

### Procedure

1. Obtain the Entra user's current password, or use the control represented by the path to change or reset it to a known value.
2. If the account is cloud-only and has not completed a qualifying password change while the managed domain is active, perform that change. When a reset operation permits it, set `forceChangePasswordNextSignIn` to `false`; otherwise complete the required interactive password change before proceeding.
3. Wait for the legacy Kerberos and NTLM password material to synchronize. Do not treat the AD user's existence alone as proof that its credential is usable; poll with a harmless authentication attempt when `pwdLastSet` or equivalent synchronization evidence is unavailable.
4. Authenticate with the Entra UPN and the changed password through Kerberos, NTLM, LDAP, or a domain logon.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Exclude B2B external identities from the abuse procedure.

Line 16 states that a B2B external identity cannot authenticate to Entra DS. Lines 22-29 present authentication without this restriction.

Add the restriction to the abuse information or the first procedure step.

Proposed clarification
-An attacker may authenticate as the Entra DS user using the Entra user's credentials.
+For a non-B2B Entra user, an attacker may authenticate as the Entra DS user using the Entra user's credentials.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
An attacker may authenticate as the Entra DS user using the Entra user's credentials. For a cloud-only user that has not changed its password while the managed domain is active, changing the Entra user's password and waiting for Entra DS synchronization to complete generates the password material required for authentication.
### Procedure
1. Obtain the Entra user's current password, or use the control represented by the path to change or reset it to a known value.
2. If the account is cloud-only and has not completed a qualifying password change while the managed domain is active, perform that change. When a reset operation permits it, set `forceChangePasswordNextSignIn` to `false`; otherwise complete the required interactive password change before proceeding.
3. Wait for the legacy Kerberos and NTLM password material to synchronize. Do not treat the AD user's existence alone as proof that its credential is usable; poll with a harmless authentication attempt when `pwdLastSet` or equivalent synchronization evidence is unavailable.
4. Authenticate with the Entra UPN and the changed password through Kerberos, NTLM, LDAP, or a domain logon.
For a non-B2B Entra user, an attacker may authenticate as the Entra DS user using the Entra user's credentials. For a cloud-only user that has not changed its password while the managed domain is active, changing the Entra user's password and waiting for Entra DS synchronization to complete generates the password material required for authentication.
### Procedure
1. Obtain the Entra user's current password, or use the control represented by the path to change or reset it to a known value.
2. If the account is cloud-only and has not completed a qualifying password change while the managed domain is active, perform that change. When a reset operation permits it, set `forceChangePasswordNextSignIn` to `false`; otherwise complete the required interactive password change before proceeding.
3. Wait for the legacy Kerberos and NTLM password material to synchronize. Do not treat the AD user's existence alone as proof that its credential is usable; poll with a harmless authentication attempt when `pwdLastSet` or equivalent synchronization evidence is unavailable.
4. Authenticate with the Entra UPN and the changed password through Kerberos, NTLM, LDAP, or a domain logon.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/resources/edges/synced-to-entra-ds-user.mdx` around lines 22 - 29,
Update the abuse description and procedure in the synced-to-entra-ds-user
content to explicitly exclude B2B external identities, preserving the existing
requirement that the target be an Entra DS-authenticating user. Add this
restriction to the abuse statement or as a prerequisite in the first procedure
step, and ensure all subsequent authentication steps apply only to eligible
non-B2B identities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant