
Recolector OpenGraph para BloodHound que mapea rutas de ataque desde infraestructura DevOps a MLOps, recopilando recursos de pipeline CI/CD, service principal y plataforma ML para análisis de movimiento lateral.
Un recolector OpenGraph de prueba de concepto para BloodHound que mapea rutas de ataque desde infraestructura DevOps hasta MLOps.
Basado en Pipelines of Privilege: Attack Paths from DevOps to MLOps Infrastructure de Brett Hawkins (@h4wkst3r).
Dop2Mop recolecta datos de plataformas DevOps y MLOps para identificar rutas de ataque que permiten movimiento lateral desde pipelines CI/CD hasta infraestructura de entrenamiento de machine learning. Genera JSON OpenGraph compatible con BloodHound para visualización y análisis.
| Plataformas DevOps | Plataformas MLOps | Proveedores de Identidad |
|---|---|---|
| GitHub (Actions, Repos, Secrets) | Azure Machine Learning | Azure AD Service Principals |
| Azure DevOps (Pipelines, Service Connections) | Amazon SageMaker | AWS IAM Roles OIDC/Federated Identity |
Dop2Mop modela los cinco límites de confianza críticos identificados en la investigación:
git clone https://github.com/h4wkst3r/dop2mop.git cd dop2mop pip install -r requirements.txt pip install -e .
## Lo que se recopila
Cada recopilador reúne recursos específicos de la plataforma y mapea los límites de confianza entre ellos:
| Recopilador | Recursos Recopilados |
|-----------|-------------------|
| **GitHub** | Organizaciones, repositorios, flujos de trabajo, secretos, reglas de protección de ramas, configuraciones OIDC, referencias de imágenes de contenedores, referencias de buckets S3 |
| **Azure DevOps** | Organizaciones, proyectos, pipelines (YAML), conexiones de servicio (con detalles de ámbito), grupos de variables, pools de agentes, repositorios |
| **Azure ML** | Espacios de trabajo, clústeres/instancias de cómputo, almacenes de datos, entornos de ML, modelos registrados, trabajos/experimentos, endpoints en línea y por lotes |
| **SageMaker** | Trabajos de entrenamiento, modelos, endpoints, dominios, instancias de notebook, roles de ejecución de IAM (con análisis de políticas), repositorios/imágenes de ECR, buckets de S3 (filtrados para relevantes de ML) |
## Inicio Rápido
### Generar Datos de Demostración
La forma más rápida de ver Dop2Mop en acción es generar datos de demostración que muestren los escenarios de ataque de la investigación:```bash
dop2mop demo -o demo.json
MATCH (n) RETURN n LIMIT 100
``````cypher
// Azure DevOps to Azure ML Lateral Movement
MATCH p=(repo)-[:TriggersPipeline]->(pipeline)-[:UsesServiceConnection]->(svcconn)-[:AuthenticatesAs]->(workspace)-[:CodeExecution]->(compute)
RETURN p
// Container Image Poisoning (Supply Chain Attack)
MATCH p=(workflow)-[:CanPoisonImage]->(image)<-[:PullsImage]-(job)
RETURN p
// OIDC/Federated Identity Abuse (confirmed edges)
MATCH p=(workflow)-[:OIDCTrust]->(oidc)-[:CanAssumeRole]->(role)-[:SubmitsJob]->(job)
RETURN p
// OIDC abuse including inferred paths
MATCH p=(workflow)-[:OIDCTrust]->(oidc)-[:InferredCanAssumeRole]->(role)
RETURN p
// Dataset Poisoning via Pickle Deserialization
MATCH p=(workflow)-[:CanPoisonDataset]->(dataset)<-[:LoadsDataset]-(job)
RETURN p
// Find repos with weak/no branch protection (TB1 exploitable)
MATCH (repo)-[:BypassesProtection]->(repo)
RETURN repo.name, repo.default_branch
// Find overprivileged SageMaker IAM roles
MATCH (role:IAMRole) WHERE role.is_admin = true OR role.has_s3_full_access = true
RETURN role.name, role.attached_policies
// Find SageMaker notebooks with root + internet access
MATCH (nb:SMNotebook) WHERE nb.root_access = 'Enabled' AND nb.direct_internet_access = 'Enabled'
RETURN nb.name, nb.status
// Find self-hosted ADO agent pools
MATCH (agent:ADOAgent) WHERE agent.is_hosted = false
RETURN agent.name, agent.pool_type
En lugar de pasar credenciales en cada ejecución, puedes guardarlas en un archivo de configuración. Copia el ejemplo incluido y completa tus valores:```bash cp dop2mop.yaml.example dop2mop.yaml
Dop2Mop comprueba estas ubicaciones en orden:
1. Ruta especificada por `--config`
2. `dop2mop.yaml` / `dop2mop.yml` / `.dop2mop.yaml` en el directorio actual
3. `~/.dop2mop.yaml`
> **Nota:** `dop2mop.yaml` está en `.gitignore` para evitar confirmar credenciales accidentalmente. El archivo de ejemplo (`dop2mop.yaml.example`) es seguro para confirmar.
Consulta [dop2mop.yaml.example](https://github.com/h4wkst3r/dop2mop/blob/HEAD/dop2mop.yaml.example) para conocer todas las opciones disponibles con comentarios.
**Orden de prioridad:** Argumentos de CLI > archivo de configuración > variables de entorno.
### Validación de credenciales
Prueba las credenciales antes de ejecutar una recolección completa:```bash
# Validate all configured collectors
dop2mop collect --validate -v
# Validate specific collectors
dop2mop collect --validate --collectors github,sagemaker -v
Esto realiza una llamada ligera a la API por plataforma para verificar que los tokens sean válidos antes de iniciar la recopilación.
Puede usar nombres cortos en lugar de nombres de clase completos con --collectors:
dop2mop collect --collectors GitHubCollector,SageMakerCollector dop2mop collect --collectors github,sagemaker dop2mop collect --collectors gh,sm
---
## Referencia de CLI
### Descripción general de comandos```
dop2mop <command> [options]
Commands:
collect Collect data from DevOps/MLOps platforms
demo Generate demo data with attack scenarios
| Opción | Descripción |
|---|---|
-v, --verbose | Habilitar salida detallada (registro a nivel INFO) |
--debug | Habilitar salida de depuración (registro a nivel DEBUG) |
dop2mop collectRecolectar datos de plataformas DevOps y MLOps configuradas.```bash dop2mop collect [OPTIONS]
#### Opciones generales
| Opción | Descripción |
|--------|-------------|
| `-o, --output FILE` | Ruta del archivo de salida (predeterminado: `dop2mop_output.json`) |
| `--zip` | Comprimir la salida en un archivo ZIP |
| `--config FILE` | Ruta al archivo de configuración YAML/JSON |
| `--validate` | Validar credenciales antes de la recolección |
| `--collectors LIST` | Lista separada por comas de recolectores o alias (p. ej., `github,sm`) |
| `--max-items N` | Número máximo de elementos a recolectar por tipo |
| `--no-secrets` | Omitir enumeración de secretos/credenciales |
#### Opciones de GitHub
| Opción | Descripción |
|--------|-------------|
| `--github-token TOKEN` | Token de acceso personal de GitHub |
| `--github-org ORG` | Nombre de la organización de GitHub |
| `--github-enterprise-url URL` | URL del servidor de GitHub Enterprise |
#### Opciones de Azure DevOps
| Opción | Descripción |
|--------|-------------|
| `--azure-devops-token TOKEN` | Token de acceso personal (PAT) de Azure DevOps |
| `--azure-devops-access-token TOKEN` | Token de acceso de Azure DevOps (autenticación Bearer, opcional) |
| `--azure-devops-org ORG` | Nombre de la organización de Azure DevOps |
#### Opciones de Azure ML
| Opción | Descripción |
|--------|-------------|
| `--azure-subscription-id ID` | ID de suscripción de Azure |
| `--azure-tenant-id ID` | ID de inquilino de Azure AD |
| `--azure-client-id ID` | ID de cliente de la entidad de servicio (opcional) |
| `--azure-client-secret SECRET` | Secreto de cliente de la entidad de servicio (opcional) |
| `--azure-access-token TOKEN` | Token de acceso de Azure para autenticación de Azure ML (opcional) |
#### Opciones de AWS SageMaker
| Opción | Descripción |
|--------|-------------|
| `--aws-access-key-id KEY` | ID de clave de acceso de AWS |
| `--aws-secret-access-key SECRET` | Clave de acceso secreta de AWS |
| `--aws-region REGION` | Región de AWS (predeterminado: `us-east-1`) |
| `--aws-profile PROFILE` | Nombre del perfil de AWS CLI |
#### Recolectores disponibles
| Nombre del recolector | Plataforma | Credenciales requeridas |
|----------------|----------|---------------------|
| `GitHubCollector` | GitHub | `--github-token`, `--github-org` |
| `AzureDevOpsCollector` | Azure DevOps | `--azure-devops-token` o `--azure-devops-access-token`, `--azure-devops-org` |
| `AzureMLCollector` | Azure ML | `--azure-subscription-id`, `--azure-tenant-id` |
| `SageMakerCollector` | AWS SageMaker | `--aws-profile` o `--aws-access-key-id` |
---
### `dop2mop demo`
Generar datos de demostración que muestren los cuatro escenarios de ataque de la investigación.```bash
dop2mop demo [OPTIONS]
| Option | Description |
|---|---|
-o, --output FILE | Ruta del archivo de salida (por defecto: dop2mop_demo.json) |
dop2mop iconsGenera configuración de iconos personalizados para los tipos de nodos de BloodHound.```bash dop2mop icons [OPTIONS]
| Opción | Descripción |
|--------|-------------|
| `-o, --output FILE` | Ruta del archivo de salida (por defecto: `dop2mop_icons.json`) |
---
## Ejemplos de uso de CLI
### Colección básica```bash
# Collect from all configured platforms (uses environment variables)
dop2mop collect -o output.json
# Use a config file
dop2mop collect --config dop2mop.yaml -o output.json -v
# Validate credentials first, then collect
dop2mop collect --validate -o output.json -v
# Collect with verbose logging
dop2mop collect -o output.json -v
# Collect with debug logging
dop2mop collect -o output.json --debug
# Collect and compress to ZIP
dop2mop collect -o output.json --zip
# Limit collection size
dop2mop collect --max-items 100 -o output.json
# Skip secret enumeration
dop2mop collect --no-secrets -o output.json
dop2mop collect --collectors github -o github.json -v
dop2mop collect --collectors ado -o ado.json -v
dop2mop collect --collectors azureml -o azureml.json -v
dop2mop collect --collectors sm -o sagemaker.json -v
### Colección multiplataforma```bash
# GitHub + SageMaker
dop2mop collect --collectors github,sagemaker -o output.json -v
# GitHub + Azure DevOps
dop2mop collect --collectors github,ado -o output.json -v
# Azure DevOps + Azure ML (full Azure stack)
dop2mop collect --collectors ado,azureml -o azure.json -v
# All collectors explicitly
dop2mop collect --collectors github,ado,azureml,sagemaker -o full.json -v
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx" export GITHUB_ORG="your-org" dop2mop collect --collectors GitHubCollector -o github.json -v
dop2mop collect --collectors GitHubCollector
--github-token ghp_xxxxxxxxxxxx
--github-org your-org
-o github.json -v
dop2mop collect --collectors GitHubCollector
--github-token ghp_xxxxxxxxxxxx
--github-org your-org
--github-enterprise-url https://github.yourcompany.com/api/v3
-o github.json -v
dop2mop collect --collectors GitHubCollector
--github-token ghp_xxxxxxxxxxxx
--github-org your-org
--no-secrets
-o github.json -v
dop2mop collect --collectors GitHubCollector
--github-token ghp_xxxxxxxxxxxx
--github-org your-org
--max-items 50
-o github.json -v
### Ejemplos de la colección de Azure DevOps```bash
# Using environment variables
export AZURE_DEVOPS_TOKEN="your-pat"
export AZURE_DEVOPS_ORG="your-org"
dop2mop collect --collectors AzureDevOpsCollector -o ado.json -v
# Using command-line arguments (PAT)
dop2mop collect --collectors AzureDevOpsCollector \
--azure-devops-token your-pat \
--azure-devops-org your-org \
-o ado.json -v
# Using access token (Bearer auth)
dop2mop collect --collectors AzureDevOpsCollector \
--azure-devops-access-token eyJ0... \
--azure-devops-org your-org \
-o ado.json -v
Nota: Prioridad de autenticación de Azure DevOps: token de acceso (Bearer) > PAT (Básico). Los tokens de acceso se pueden obtener mediante
az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798.
export AZURE_SUBSCRIPTION_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" export AZURE_TENANT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" dop2mop collect --collectors AzureMLCollector -o azureml.json -v
dop2mop collect --collectors AzureMLCollector
--azure-subscription-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
--azure-tenant-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
-o azureml.json -v
dop2mop collect --collectors AzureMLCollector
--azure-subscription-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
--azure-tenant-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
--azure-client-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
--azure-client-secret your-secret
-o azureml.json -v
dop2mop collect --collectors AzureMLCollector
--azure-subscription-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
--azure-tenant-id xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
--azure-access-token eyJ0...
-o azureml.json -v
> **Nota:** Prioridad de autenticación de Azure ML: token de acceso > entidad de servicio > DefaultAzureCredential (az login).
> Los tokens de acceso se pueden obtener mediante `az account get-access-token --resource https://management.azure.com/`.
### Ejemplos de Colección de AWS SageMaker```bash
# Using AWS profile (environment variable)
export AWS_PROFILE="your-profile"
dop2mop collect --collectors SageMakerCollector -o sagemaker.json -v
# Using AWS profile (command-line)
dop2mop collect --collectors SageMakerCollector \
--aws-profile your-profile \
-o sagemaker.json -v
# Using access keys
dop2mop collect --collectors SageMakerCollector \
--aws-access-key-id AKIAXXXXXXXXXXXXXXXX \
--aws-secret-access-key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
--aws-region us-east-1 \
-o sagemaker.json -v
# Different AWS region
dop2mop collect --collectors SageMakerCollector \
--aws-profile your-profile \
--aws-region us-west-2 \
-o sagemaker.json -v
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx" export GITHUB_ORG="your-org" export AZURE_DEVOPS_TOKEN="your-pat" export AZURE_DEVOPS_ORG="your-org" export AZURE_SUBSCRIPTION_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" export AZURE_TENANT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" export AWS_PROFILE="your-profile"
dop2mop collect -o full_collection.json -v
dop2mop collect
--collectors GitHubCollector,AzureDevOpsCollector,AzureMLCollector,SageMakerCollector
-o full_collection.json -v
---
## Variables de Entorno
Todas las opciones de línea de comandos se pueden configurar mediante variables de entorno:
| Variable de Entorno | Equivalente CLI | Descripción |
|---------------------|----------------|-------------|
| `GITHUB_TOKEN` | `--github-token` | Token de acceso personal de GitHub |
| `GITHUB_ORG` | `--github-org` | Nombre de la organización de GitHub |
| `GITHUB_ENTERPRISE_URL` | `--github-enterprise-url` | URL de GitHub Enterprise Server |
| `AZURE_DEVOPS_TOKEN` | `--azure-devops-token` | PAT de Azure DevOps |
| `AZURE_DEVOPS_ACCESS_TOKEN` | `--azure-devops-access-token` | Token de acceso de Azure DevOps (Bearer) |
| `AZURE_DEVOPS_ORG` | `--azure-devops-org` | Organización de Azure DevOps |
| `AZURE_SUBSCRIPTION_ID` | `--azure-subscription-id` | ID de suscripción de Azure |
| `AZURE_TENANT_ID` | `--azure-tenant-id` | ID de inquilino de Azure AD |
| `AZURE_CLIENT_ID` | `--azure-client-id` | ID de cliente de la entidad de servicio de Azure |
| `AZURE_CLIENT_SECRET` | `--azure-client-secret` | Secreto de la entidad de servicio de Azure |
| `AZURE_ACCESS_TOKEN` | `--azure-access-token` | Token de acceso de Azure para Azure ML |
| `AWS_ACCESS_KEY_ID` | `--aws-access-key-id` | ID de clave de acceso de AWS |
| `AWS_SECRET_ACCESS_KEY` | `--aws-secret-access-key` | Clave de acceso secreta de AWS |
| `AWS_REGION` | `--aws-region` | Región de AWS (predeterminada: us-east-1) |
| `AWS_PROFILE` | `--aws-profile` | Nombre del perfil de AWS CLI |
**Prioridad:** argumentos CLI > archivo de configuración > variables de entorno.
---
## Tipos de Nodo
### Nodos de DevOps
| Tipo | Descripción |
|------|-------------|
| `GHOrganization` | Organización de GitHub |
| `GHRepository` | Repositorio de GitHub |
| `GHWorkflow` | Flujo de trabajo de GitHub Actions |
| `GHSecret` | Secreto de GitHub Actions |
| `ADOOrganization` | Organización de Azure DevOps |
| `ADOProject` | Proyecto de Azure DevOps |
| `ADOPipeline` | Pipeline de Azure DevOps |
| `ADOServiceConnection` | Conexión de servicio de Azure DevOps (NHI) con detalles de ámbito |
| `ADOAgent` | Grupo de agentes de Azure DevOps (alojado o autogestionado) |
| `ADOVariableGroup` | Grupo de variables de Azure DevOps |
### Nodos de MLOps
| Tipo | Descripción |
|------|-------------|
| `AzMLWorkspace` | Área de trabajo de Azure ML |
| `AzMLCompute` | Clúster/instancia de cómputo de Azure ML |
| `AzMLExperiment` | Trabajo/experimento de Azure ML |
| `AzMLDatastore` | Almacén de datos de Azure ML |
| `AzMLEnvironment` | Entorno de Azure ML (definición de contenedor) |
| `AzMLModel` | Modelo registrado de Azure ML |
| `SMDomain` | Dominio de SageMaker Studio |
| `SMTrainingJob` | Trabajo de entrenamiento de SageMaker |
| `SMModel` | Modelo de SageMaker |
| `SMEndpoint` | Punto de conexión de SageMaker (también usado para puntos de conexión de Azure ML) |
| `SMNotebook` | Instancia de cuaderno de SageMaker |
### Nodos de Identidad
| Tipo | Descripción |
|------|-------------|
| `ServicePrincipal` | Entidad de servicio de Azure AD |
| `IAMRole` | Rol de IAM de AWS |
| `OIDCIdentity` | Identidad federada OIDC |
| `ManagedIdentity` | Identidad administrada de Azure |
### Nodos de Artefacto
| Tipo | Descripción |
|------|-------------|
| `ContainerRegistry` | Registro de contenedores (ECR, ACR) |
| `ContainerImage` | Imagen de contenedor |
| `S3Bucket` | Bucket S3 de AWS |
| `Dataset` | Conjunto de datos de ML |
## Tipos de Arista
### Aristas de Ruta de Ataque
| Tipo | Límite de Confianza | Descripción |
|------|---------------------|-------------|
| `TriggersPipeline` | TB1 | El commit de código activa CI/CD |
| `HasBranchProtection` | TB1 | El repositorio tiene reglas de protección de ramas |
| `BypassesProtection` | TB1 | Protección de ramas débil/ausente (explotable) |
| `AuthenticatesAs` | TB2 | El pipeline usa una entidad de servicio |
| `CanAssumeRole` | TB2 | La identidad OIDC puede asumir un rol de IAM |
| `OIDCTrust` | TB2 | El flujo de trabajo usa federación OIDC |
| `UsesServiceConnection` | TB2 | El pipeline usa una conexión de servicio de ADO |
| `PullsImage` | TB3 | El trabajo de entrenamiento extrae una imagen de contenedor |
| `CanPoisonImage` | TB3 | El pipeline puede modificar la imagen de contenedor |
| `SubmitsJob` | TB4 | La entidad de servicio envía un trabajo de ML |
| `CodeExecution` | TB4 | El trabajo ejecuta código en el cómputo |
| `LoadsDataset` | TB5 | El trabajo de entrenamiento carga un conjunto de datos |
| `CanPoisonDataset` | TB5 | El pipeline puede modificar el conjunto de datos |
| `Deserializes` | TB5 | Deserialización no segura |
### Aristas Inferidas
Estas aristas se crean mediante análisis heurístico cuando no están disponibles datos explícitos de la API (por ejemplo, ARN de roles almacenados en secretos). Utilizan tipos de arista distintos para que puedas filtrarlos en las consultas de BloodHound.
| Tipo | Descripción |
|------|-------------|
| `InferredCanAssumeRole` | La identidad OIDC podría poder asumir un rol (inferido) |
| `InferredSubmitsJob` | El flujo de trabajo podría enviar un trabajo de entrenamiento mediante OIDC (inferido) |
| `InferredPullsImage` | El trabajo de entrenamiento podría extraer una imagen de contenedor envenenada (inferido) |
| `InferredLoadsDataset` | El trabajo de entrenamiento podría cargar un conjunto de datos envenenado (inferido) |
### Aristas Estructurales
| Tipo | Descripción |
|------|-------------|
| `Contains` | Relación padre-hijo |
| `MemberOf` | Pertenencia a grupo |
| `HasAccessTo` | Permiso para acceder a un recurso |
| `HasExecutionRole` | El recurso usa un rol de IAM/ejecución |
| `Owns` | Relación de propiedad |
## Consultas de Ejemplo
Consulta [queries/dop2mop_queries.cypher](https://github.com/h4wkst3r/dop2mop/blob/HEAD/queries/dop2mop_queries.cypher) para ejemplos completos de consultas.
---
## Iconos Personalizados
Dop2Mop incluye un archivo de iconos preconfigurado para tipos de nodo personalizados de BloodHound en [data/custom_icons.json](https://github.com/h4wkst3r/dop2mop/blob/HEAD/data/custom_icons.json).
### Subir Iconos a BloodHound
#### Opción 1: Explorador de API (Más Sencilla)
1. Abre BloodHound CE y ve a **Configuración** → **Explorador de API**
2. Busca **POST /api/v2/custom-nodes**
3. Haz clic en "Probar"
4. Pega el contenido de `custom_icons.json`
5. Haz clic en "Ejecutar"
#### Opción 2: Autenticación HMAC (Recomendada para Automatización)
Primero, crea un token de API en BloodHound:
1. Ve a **Configuración** → **Administración** → **Gestionar Usuarios**
2. Haz clic en tu usuario → **Crear Token**
3. Guarda el **ID de Token** y la **Clave de Token**
Luego, usa este script de Python para subir:```python
#!/usr/bin/env python3
"""Upload custom icons to BloodHound CE using HMAC authentication."""
import base64
import hashlib
import hmac
import json
from datetime import datetime, timezone
import requests
# Configuration
BLOODHOUND_URL = "http://localhost:8080"
TOKEN_ID = "your-token-id"
TOKEN_KEY = "your-token-key"
ICONS_FILE = "custom_icons.json"
def hmac_auth(method: str, uri: str, body: bytes = b"") -> dict:
"""Generate HMAC authentication headers."""
digester = hmac.new(
base64.b64decode(TOKEN_KEY),
msg=None,
digestmod=hashlib.sha256
)
now = datetime.now(timezone.utc)
timestamp = now.strftime("%Y-%m-%dT%H:%M:%SZ")
digester.update(f"{method}".encode())
digester.update(f"{uri}".encode())
digester.update(timestamp.encode())
if body:
digester.update(body)
signature = base64.b64encode(digester.digest()).decode()
return {
"Authorization": f"bhesignature {TOKEN_ID}",
"RequestDate": timestamp,
"Signature": signature,
"Content-Type": "application/json",
}
def upload_icons():
"""Upload custom icons to BloodHound."""
uri = "/api/v2/custom-nodes"
url = f"{BLOODHOUND_URL}{uri}"
with open(ICONS_FILE, "rb") as f:
body = f.read()
headers = hmac_auth("POST", uri, body)
response = requests.post(url, headers=headers, data=body)
print(f"Status: {response.status_code}")
print(f"Response: {response.text}")
return response.status_code == 200
if __name__ == "__main__":
upload_icons()
Obtén un JWT desde la pestaña Red de DevTools de tu navegador mientras estás conectado a BloodHound:```bash
curl -X POST http://localhost:8080/api/v2/custom-nodes
-H "Authorization: Bearer eyJ..."
-H "Content-Type: application/json"
-d @custom_icons.json
---
## Python API```python
from dop2mop import Dop2MopCollector, CollectorConfig
# Configure collection
config = CollectorConfig(
github_token="ghp_xxx",
github_org="myorg",
aws_profile="default",
)
# Validate credentials first
collector = Dop2MopCollector(config)
results = collector.validate_all()
print(results) # {'GitHubCollector': True, 'SageMakerCollector': True, ...}
# Run collection (supports aliases)
collector.run(collectors=["github", "sm"])
# Save output
collector.save("output.json")
# Get statistics
print(collector.get_stats())
# Get per-collector failure/skip details
print(collector.get_collection_summary())
from dop2mop import CollectorConfig, GitHubCollector, SageMakerCollector from dop2mop.graph import OpenGraphBuilder
builder = OpenGraphBuilder(source_kind="MLOpsBase")
config = CollectorConfig( github_token="ghp_xxx", github_org="myorg", aws_profile="default", )
github = GitHubCollector(config, builder) github.collect()
sagemaker = SageMakerCollector(config, builder) sagemaker.collect()
builder.save("combined.json")
### Construyendo gráficos personalizados```python
from dop2mop.graph import OpenGraphBuilder
from dop2mop.models import NodeKind, EdgeType
builder = OpenGraphBuilder(source_kind="CustomSource")
# Add nodes
builder.create_node(
id="my-pipeline",
kinds=[NodeKind.AZURE_DEVOPS_PIPELINE.value],
name="My Pipeline",
displayname="Production Pipeline",
)
builder.create_node(
id="my-ml-workspace",
kinds=[NodeKind.AZURE_ML_WORKSPACE.value],
name="ML Workspace",
displayname="Training Workspace",
)
# Add edge
builder.create_edge(
start_id="my-pipeline",
end_id="my-ml-workspace",
kind=EdgeType.SUBMITS_JOB,
properties={"trust_boundary": "TB4"}
)
# Export
builder.save("custom_graph.json")
Comience siempre con la validación de credenciales para detectar problemas de autenticación de forma temprana:```bash dop2mop collect --validate --collectors github,sm -v
La salida mostrará OK/FAILED por recolector antes de que comience cualquier recolección.
### Resumen de recolección
Después de cada ejecución, Dop2Mop imprime un resumen que muestra lo que se recolectó y lo que falló:```
============================================================
Dop2Mop Collection Summary
============================================================
Total Nodes: 142
DevOps: 45
MLOps: 38
Identity: 12
Artifact: 47
Total Edges: 201
Contains: 62
TriggersPipeline: 15
...
────────────────────────────────────────────────────────
Collection Issues:
GitHubCollector: 45 collected, 3 failed, 1 skipped
FAIL: branch_protection:org/repo - 404 Not Found
SKIP: branch_protection:org/private - Insufficient permissions
Output: output.json
============================================================
"Colector de GitHub no configurado, omitiendo"
GITHUB_TOKEN y GITHUB_ORG estén configuradas, o pasa --github-token y --github-org"Colector de Azure ML no configurado, omitiendo"
AZURE_SUBSCRIPTION_ID y AZURE_TENANT_ID estén configuradasaz login si usas DefaultAzureCredential--azure-access-token con un token válido de az account get-access-token"Colector de SageMaker no configurado, omitiendo"
AWS_PROFILE o ambas AWS_ACCESS_KEY_ID y AWS_SECRET_ACCESS_KEYLa protección de rama devuelve 403
Límite de velocidad (errores 429)
--max-items para reducir las llamadas a la APISin resultados en la consola Cypher de BloodHound
RETURN a, b) no propiedades (RETURN a.name, b.name)Filtrar aristas inferidas vs. recopiladas
InferredCanAssumeRole en lugar de CanAssumeRole)MATCH p=()-[:CanAssumeRole]->() RETURN pMATCH p=()-[:InferredCanAssumeRole]->() RETURN pLicencia MIT - Consulta LICENSE para más detalles.
| Alias | Collector |
|---|
github, gh | GitHubCollector |
ado, azuredevops, azure-devops | AzureDevOpsCollector |
azureml, azure-ml | AzureMLCollector |
sagemaker, sm | SageMakerCollector |