Skip to content

[Feature] Reverse feed — export the Identity Atlas graph to BloodHound via OpenGraph #941

Description

@WimvandenHeijkant

Summary

Run the integration the other way: export Identity Atlas's correlated, multi-system authorization graph as BloodHound OpenGraph JSON, so BloodHound can compute attack paths over our superset — on top of, or as a replacement for, its own collected data.

This is 3 of 3 companion feature requests from a feasibility study (docs/architecture/bloodhound-integration-feasibility.md,`` §5.6 / Option E). The three are related but independently buildable.

Why this is more than "the same thing backwards" — it's the platform play

Identity Atlas is a normalizing, identity-correlating superset: our Account Linking engine resolves accounts across systems to real people. BloodHound does not correlate identity across sources — it holds an AD graph, an Entra graph, a GitHub graph, an AWS graph as separate islands.

If we export our nodes/edges as OpenGraph with our identity links as the bridging edges, BloodHound can compute cross-system attack paths it structurally cannot derive on its own, e.g.:

"This GitHub identity is the same person (our link) as this Entra admin who holds GenericAll (our control edge) over an on-prem tier-zero group."

BloodHound alone can't draw that first hop; we can. This reframes Identity Atlas as the authorization system-of-record / shared graph, with our governance analytics and BloodHound's attack-path analytics as two consumers of one substrate — the concrete expression of "if we do our job right, we already have more data from more systems than any single collector."

How

  • Emit an OpenGraph payload: { "graph": { "nodes":[…], "edges":[…] }, "metadata": { "source_kind": … } }.
    • Nodes: { id, kinds:[…], properties:{…} }; edges: { kind, start:{value,match_by}, end:{…}, properties }.
    • Constraints to respect: ≤ 3 kinds per node, property values primitives or homogeneous arrays (no null), edge kind matches ^[A-Za-z0-9_]+$, objectid = our stable id (dedup key → idempotent re-ingestion).
  • Define custom OpenGraph node/edge kinds for our governance concepts (identities, business roles, governed assignments, our control edges), plus the identity-correlation bridge edges (e.g. a SameIdentity / member-of-Identity edge) that stitch the per-source graphs.
  • Deliver to BloodHound via file ingest (drop the JSON) or the /api/v2 upload API. Optionally register an OpenGraph extension-definition (custom kinds + icons + traversal rules) so our nodes render/traverse natively.
  • Support both modes: augment BloodHound's existing collected data, or replace it (be the sole source).

The gate — why this shares a dependency with #939 (but stays independent)

To feed BloodHound useful attack paths, our exported graph must carry the control edges at fidelity (GenericAll vs WriteDacl changes what's abusable). A coarse "has access" flag exports nodes and memberships but no abuse-relevant edges. So this depends on the fine-grained control-edge modelling (PrincipalRelationships / migration 057 + object-as-resource control assignments) — the same investment that lets #939 absorb control data. Model the control edges once; both directions light up. The exporter itself is independently buildable and can ship first for the membership/role/ownership subset.

Acceptance criteria

  • An OpenGraph exporter: Identity Atlas graph → valid OpenGraph JSON (kinds ≤ 3, primitives-only, no null, stable ids).
  • Custom node/edge-kind definitions for our governance concepts + identity-correlation bridge edges.
  • Output validated against the OpenGraph spec and ingestible by BloodHound CE (file ingest and/or /api/v2).
  • Augment and replace modes.
  • Demonstrated cross-system path enabled by our identity correlation (the multi-source bridge) that BloodHound could not derive from its own collectors alone.
  • Tests per repo conventions (coverage ratchet respected).

References

  • Feasibility study §5.6 (Option E), §4.3 (control-edge modelling), §4.4 (correlation is ours).
  • OpenGraph format: p0dalirius/bhopengraph; SpecterOps/OpenHound; BloodHound OpenGraph docs.

Related feature requests (BloodHound integration set — independent, not interdependent)

  1. Collector file ingestion (data in, no BloodHound needed) — [Feature] BloodHound collector file ingestion — one crawler, three dialects (AD / Entra / GitHub / AWS) #939.
  2. Attack-path risk scoring (plugs into [Refactor] Re-architect risk scoring into a plugin tier (findings + explainability + override) #672) — [Feature] BloodHound attack-path risk scoring — the attack-path risk plugin (external data) #940.
  3. This issuereverse feed (data out, via OpenGraph).

Cross-links in a comment below.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requeststate:awaiting-requestorUnder-specified — the requestor must answer clarification questions before it can move

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions