docs: document Microsoft Entra Domain Services support BED-9245 - #386
docs: document Microsoft Entra Domain Services support BED-9245#386martinsohn wants to merge 13 commits into
Conversation
WalkthroughThe pull request adds Microsoft Entra Domain Services documentation. It covers AzureHound permissions, SharpHound collection, the ChangesMicrosoft Entra Domain Services documentation
Estimated code review effort: 3 (Moderate) | ~25 minutes Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
docs/images/nodes/azure/az-entra-ds.svgis excluded by!**/*.svg
📒 Files selected for processing (19)
AGENTS.mddocs/assets/azurehound-reader-role.jsondocs/collect-data/azurehound-data-permissions.mdxdocs/collect-data/sharphound-data-permissions.mdxdocs/docs.jsondocs/install-data-collector/install-azurehound/azure-configuration.mdxdocs/opengraph/developer/edges.mdxdocs/resources/edges/add-entra-ds-group-member.mdxdocs/resources/edges/az-contributor.mdxdocs/resources/edges/az-entra-ds-contributor.mdxdocs/resources/edges/az-manage-entra-ds.mdxdocs/resources/edges/entra-ds-for.mdxdocs/resources/edges/manage-entra-ds-sync-filter.mdxdocs/resources/edges/manage-entra-ds-sync.mdxdocs/resources/edges/synced-to-entra-ds-group.mdxdocs/resources/edges/synced-to-entra-ds-user.mdxdocs/resources/edges/traversable-edges.mdxdocs/resources/nodes/az-entra-ds.mdxdocs/snippets/analysis/post-processed-edges.mdx
| - `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. |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
npm view mintlify version engines --jsonRepository: 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' . || trueRepository: 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:
- 1: https://www.npmjs.com/package/mintlify
- 2: https://mintlify.mintlify.app/cli/install
- 3: https://www.mintlify.com/docs/cli/install
- 4: https://registry.npmjs.org/mintlify
- 5: https://www.npmjs.com/package/mint
- 6: https://registry.npmjs.org/mint
- 7: https://mintlify.mintlify.app/quickstart
- 8: https://mintlify.mintlify.dev/docs/cli/install
🌐 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:
- 1: https://www.mintlify.com/docs/cli/preview
- 2: https://www.mintlify.com/docs/cli/commands
- 3: https://www.mintlify.com/docs/cli
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). |
There was a problem hiding this comment.
🎯 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.
| 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.
| 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. |
There was a problem hiding this comment.
🎯 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.
| 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.
Description
Documents BloodHound support for Microsoft Entra Domain Services (Entra DS).
This PR:
AZEntraDSnode reference and icon.AZEntraDSContributor,AZManageEntraDS,SyncedToEntraDSUser,SyncedToEntraDSGroup,AddEntraDSGroupMember,EntraDSFor,ManageEntraDSSync, andManageEntraDSSyncFilter.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?
git diff --check origin/main...HEAD.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
Documentation