Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions SampleApp/BackEnd/Models/BlastRadiusAnalysisRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace BackEnd.Models;

/// <summary>
/// Request model for blast radius security analysis
/// </summary>
public record BlastRadiusAnalysisRequest
{
/// <summary>
/// The target account name or identifier to analyze
/// </summary>
public string TargetName { get; init; } = string.Empty;

/// <summary>
/// Minimum path length for the analysis (default: 1)
/// </summary>
public int MinPathLength { get; init; } = 1;

/// <summary>
/// Maximum path length for the analysis (default: 5)
/// </summary>
public int MaxPathLength { get; init; } = 5;

/// <summary>
/// Maximum number of results to return (default: 1000)
/// </summary>
public int ResultsCountLimit { get; init; } = 1000;
}
78 changes: 78 additions & 0 deletions SampleApp/BackEnd/Models/BlastRadiusAnalysisResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
namespace BackEnd.Models;

/// <summary>
/// Response model for blast radius security analysis
/// </summary>
public record BlastRadiusAnalysisResponse
{
/// <summary>
/// The target that was analyzed
/// </summary>
public string TargetName { get; init; } = string.Empty;

/// <summary>
/// List of nodes in the blast radius
/// </summary>
public List<ExposureNode> Nodes { get; init; } = new();

/// <summary>
/// Total count of exposed nodes
/// </summary>
public int TotalExposedNodes { get; init; }

/// <summary>
/// Timestamp of the analysis
/// </summary>
public DateTime AnalysisTimestamp { get; init; } = DateTime.UtcNow;
}

/// <summary>
/// Represents a node in the exposure perimeter
/// </summary>
public record ExposureNode
{
/// <summary>
/// Unique identifier for the node
/// </summary>
public string NodeId { get; init; } = string.Empty;

/// <summary>
/// Name of the node
/// </summary>
public string NodeName { get; init; } = string.Empty;

/// <summary>
/// Type/label of the node
/// </summary>
public string NodeLabel { get; init; } = string.Empty;

/// <summary>
/// Entity identifiers associated with this node
/// </summary>
public string EntityIds { get; init; } = string.Empty;

/// <summary>
/// Criticality level of the node
/// </summary>
public string Criticality { get; init; } = string.Empty;

/// <summary>
/// Risk score of the node
/// </summary>
public string RiskScore { get; init; } = string.Empty;

/// <summary>
/// Whether the node has known vulnerabilities
/// </summary>
public bool HasVulnerabilities { get; init; }

/// <summary>
/// Number of neighboring nodes
/// </summary>
public long NumberOfAllNeighbors { get; init; }

/// <summary>
/// Edges connecting to this node
/// </summary>
public string Edges { get; init; } = string.Empty;
}
29 changes: 29 additions & 0 deletions SampleApp/BackEnd/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.OpenApi;
using Scalar.AspNetCore;
using BackEnd.Services;
using BackEnd.Models;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -16,6 +18,9 @@
});
});

// Register blast radius analysis service
builder.Services.AddSingleton<IBlastRadiusAnalysisService, BlastRadiusAnalysisService>();

var app = builder.Build();

// Configure the HTTP request pipeline.
Expand Down Expand Up @@ -69,6 +74,30 @@
})
.WithName("GetSunsetRange");

// Blast Radius Security Analysis Endpoints
app.MapGet("/security/blast-radius/alberto-polak", async (IBlastRadiusAnalysisService service) =>
{
var result = await service.GetAlbertoPolakBlastRadiusAsync();
return Results.Ok(result);
})
.WithName("GetAlbertoPolakBlastRadius")
.WithSummary("Get blast radius security analysis for Alberto Polak's account")
.WithDescription("Analyzes the exposure perimeter and blast radius for Alberto Polak's account, showing all resources and assets that could be impacted if the account is compromised.");

app.MapPost("/security/blast-radius", async (BlastRadiusAnalysisRequest request, IBlastRadiusAnalysisService service) =>
{
if (string.IsNullOrWhiteSpace(request.TargetName))
{
return Results.BadRequest(new { error = "TargetName is required" });
}

var result = await service.AnalyzeBlastRadiusAsync(request);
return Results.Ok(result);
})
.WithName("AnalyzeBlastRadius")
.WithSummary("Analyze blast radius for any target account")
.WithDescription("Performs a blast radius security analysis for a specified target account or resource, identifying the exposure perimeter and potential impact.");

app.Run();

static TimeOnly CalculateSunsetTime(DateOnly date)
Expand Down
152 changes: 152 additions & 0 deletions SampleApp/BackEnd/Services/BlastRadiusAnalysisService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using BackEnd.Models;
using System.Text.Json;

namespace BackEnd.Services;

/// <summary>
/// Service for performing blast radius security analysis
/// This service integrates with Microsoft Security Graph to analyze exposure perimeters
/// </summary>
public class BlastRadiusAnalysisService : IBlastRadiusAnalysisService
{
private readonly ILogger<BlastRadiusAnalysisService> _logger;

public BlastRadiusAnalysisService(ILogger<BlastRadiusAnalysisService> logger)
{
_logger = logger;
}

/// <summary>
/// Analyzes the blast radius for a given target
/// </summary>
public async Task<BlastRadiusAnalysisResponse> AnalyzeBlastRadiusAsync(BlastRadiusAnalysisRequest request)
{
_logger.LogInformation("Starting blast radius analysis for target: {TargetName}", request.TargetName);

try
{
// In a real-world scenario, this would call the Microsoft Security Graph API
// For this implementation, we're simulating the analysis
var nodes = await GetExposurePerimeterNodesAsync(request);

var response = new BlastRadiusAnalysisResponse
{
TargetName = request.TargetName,
Nodes = nodes,
TotalExposedNodes = nodes.Count,
AnalysisTimestamp = DateTime.UtcNow
};

_logger.LogInformation("Blast radius analysis completed for {TargetName}. Found {Count} exposed nodes",
request.TargetName, nodes.Count);

return response;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error performing blast radius analysis for {TargetName}", request.TargetName);
throw;
}
}

/// <summary>
/// Gets the blast radius for Alberto Polak's account
/// </summary>
public async Task<BlastRadiusAnalysisResponse> GetAlbertoPolakBlastRadiusAsync()
{
var request = new BlastRadiusAnalysisRequest
{
TargetName = "Alberto Polak",
MinPathLength = 1,
MaxPathLength = 5,
ResultsCountLimit = 1000
};

return await AnalyzeBlastRadiusAsync(request);
}

/// <summary>
/// Simulates querying the exposure perimeter from Microsoft Security Graph
/// In production, this would make actual API calls to the security graph service
/// </summary>
private async Task<List<ExposureNode>> GetExposurePerimeterNodesAsync(BlastRadiusAnalysisRequest request)
{
// Simulate async operation
await Task.Delay(100);

// Return mock data demonstrating the blast radius for Alberto Polak
// In production, this would be replaced with actual Microsoft Security Graph API calls
var nodes = new List<ExposureNode>();

if (request.TargetName.Equals("Alberto Polak", StringComparison.OrdinalIgnoreCase))
{
// Simulated exposure perimeter for Alberto Polak's account
nodes.Add(new ExposureNode
{
NodeId = "user-001",
NodeName = "Alberto Polak",
NodeLabel = "User",
EntityIds = "alberto.polak@contoso.com",
Criticality = "High",
RiskScore = "85",
HasVulnerabilities = false,
NumberOfAllNeighbors = 5,
Edges = "[]"
});

nodes.Add(new ExposureNode
{
NodeId = "vm-001",
NodeName = "ProductionWebServer01",
NodeLabel = "VirtualMachine",
EntityIds = "/subscriptions/sub-123/resourceGroups/rg-prod/providers/Microsoft.Compute/virtualMachines/vm-001",
Criticality = "Critical",
RiskScore = "95",
HasVulnerabilities = true,
NumberOfAllNeighbors = 12,
Edges = "[{\"source\":\"user-001\",\"target\":\"vm-001\",\"type\":\"CanAccess\"}]"
});

nodes.Add(new ExposureNode
{
NodeId = "storage-001",
NodeName = "CustomerDataStorage",
NodeLabel = "StorageAccount",
EntityIds = "/subscriptions/sub-123/resourceGroups/rg-prod/providers/Microsoft.Storage/storageAccounts/custdata001",
Criticality = "Critical",
RiskScore = "90",
HasVulnerabilities = false,
NumberOfAllNeighbors = 8,
Edges = "[{\"source\":\"user-001\",\"target\":\"storage-001\",\"type\":\"CanRead\"}]"
});

nodes.Add(new ExposureNode
{
NodeId = "db-001",
NodeName = "ProductionDatabase",
NodeLabel = "SqlDatabase",
EntityIds = "/subscriptions/sub-123/resourceGroups/rg-prod/providers/Microsoft.Sql/servers/sql-prod/databases/maindb",
Criticality = "Critical",
RiskScore = "92",
HasVulnerabilities = false,
NumberOfAllNeighbors = 6,
Edges = "[{\"source\":\"user-001\",\"target\":\"db-001\",\"type\":\"CanExecute\"}]"
});

nodes.Add(new ExposureNode
{
NodeId = "keyvault-001",
NodeName = "ProductionSecrets",
NodeLabel = "KeyVault",
EntityIds = "/subscriptions/sub-123/resourceGroups/rg-prod/providers/Microsoft.KeyVault/vaults/kv-prod-001",
Criticality = "Critical",
RiskScore = "88",
HasVulnerabilities = false,
NumberOfAllNeighbors = 15,
Edges = "[{\"source\":\"user-001\",\"target\":\"keyvault-001\",\"type\":\"CanListSecrets\"}]"
});
}

return nodes;
}
}
22 changes: 22 additions & 0 deletions SampleApp/BackEnd/Services/IBlastRadiusAnalysisService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using BackEnd.Models;

namespace BackEnd.Services;

/// <summary>
/// Interface for blast radius security analysis service
/// </summary>
public interface IBlastRadiusAnalysisService
{
/// <summary>
/// Analyzes the blast radius for a given target
/// </summary>
/// <param name="request">The analysis request parameters</param>
/// <returns>The blast radius analysis results</returns>
Task<BlastRadiusAnalysisResponse> AnalyzeBlastRadiusAsync(BlastRadiusAnalysisRequest request);

/// <summary>
/// Gets the blast radius for Alberto Polak's account
/// </summary>
/// <returns>The blast radius analysis for Alberto Polak</returns>
Task<BlastRadiusAnalysisResponse> GetAlbertoPolakBlastRadiusAsync();
}
60 changes: 60 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,66 @@ You can also run this repository locally by following these instructions:

![VS Code stop debuggin on both backend and frontend](images/StopRun.png)

## Features

### Blast Radius Security Analysis

This application includes a blast radius security analysis feature that analyzes the exposure perimeter for user accounts. The blast radius represents the potential impact if an account is compromised, showing all resources and assets that could be accessed.

#### Available Endpoints

**Get Alberto Polak's Blast Radius**
```
GET /security/blast-radius/alberto-polak
```

Returns the blast radius analysis for Alberto Polak's account, showing:
- All accessible resources (VMs, Storage Accounts, Databases, Key Vaults)
- Risk scores and criticality levels
- Vulnerability status
- Connection relationships

Example response:
```json
{
"targetName": "Alberto Polak",
"nodes": [
{
"nodeId": "user-001",
"nodeName": "Alberto Polak",
"nodeLabel": "User",
"criticality": "High",
"riskScore": "85",
"hasVulnerabilities": false
},
{
"nodeId": "vm-001",
"nodeName": "ProductionWebServer01",
"nodeLabel": "VirtualMachine",
"criticality": "Critical",
"riskScore": "95",
"hasVulnerabilities": true
}
],
"totalExposedNodes": 5,
"analysisTimestamp": "2026-01-08T23:39:35Z"
}
```

**Analyze Any Target**
```
POST /security/blast-radius
Content-Type: application/json

{
"targetName": "account-name",
"minPathLength": 1,
"maxPathLength": 5,
"resultsCountLimit": 1000
}
```

Performs a customizable blast radius analysis for any target account or resource.

## Contributing

Expand Down