Skip to content

Commit 2e45ccf

Browse files
committed
Merge master: keep the wizard docs and restore the from-source path
master fixed three real problems in the manual build instructions — the clone URL still said YOUR_ORG, a Copy-Item step copied a dist folder Vite no longer produces, and the production connection string lacked Encrypt/TrustServerCertificate. This branch had rewritten that whole part of the README around the new setup wizard, and in doing so dropped the Setup, Development and Production Deployment sections entirely — while Prerequisites still advertised a "Building from source (Option 3)" path that no longer existed. Resolving in favour of either side would have lost something real. Both are kept: the wizard remains the primary install, and master's sections return as "Build from source (Option 3)" with all three of its fixes intact. SECURITY.md, docs/THREAT_MODEL.md and docs/PROJECT_SUMMARY.md merged cleanly and are taken from master unchanged.
2 parents bcaa25e + 742a915 commit 2e45ccf

4 files changed

Lines changed: 297 additions & 0 deletions

File tree

README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,117 @@ the resulting binaries would differ from the ones you tested.
206206

207207

208208

209+
## Build from source (Option 3)
210+
211+
Only needed if you are not using the setup wizard or Docker — for development,
212+
or to run Vigil365 on a host you build on yourself.
213+
214+
### 1. Clone and configure secrets
215+
216+
```powershell
217+
git clone https://github.com/sameerk27/vigil365.git
218+
cd vigil365
219+
220+
cd src\M365SecurityDashboard.Api
221+
dotnet user-secrets init
222+
dotnet user-secrets set "Graph:TenantId" "YOUR_TENANT_ID"
223+
dotnet user-secrets set "Graph:ClientId" "YOUR_CLIENT_ID"
224+
dotnet user-secrets set "Graph:ClientSecret" "YOUR_CLIENT_SECRET"
225+
```
226+
227+
> **Never put real credentials in `appsettings.json`** — use User Secrets for development and environment variables or `appsettings.Production.json` (gitignored) for production.
228+
229+
### 2. Set up the database
230+
231+
```powershell
232+
# Option A: let the API auto-create on first run (requires db-create rights)
233+
# Option B: pre-create manually
234+
sqlcmd -S .\SQLEXPRESS -E -I -i .\database\schema.sql
235+
```
236+
237+
### 3. Build the frontend
238+
239+
```powershell
240+
cd src\m365-security-dashboard-client
241+
npm install
242+
npm run build
243+
```
244+
245+
> `npm run build` outputs directly into `..\M365SecurityDashboard.Api\wwwroot`
246+
> (configured via Vite `outDir`) — no copy step needed.
247+
248+
### 4. Run the API
249+
250+
```powershell
251+
cd src\M365SecurityDashboard.Api
252+
$env:ASPNETCORE_ENVIRONMENT = "Development"
253+
dotnet run
254+
```
255+
256+
Open **http://localhost:5000**
257+
258+
---
259+
260+
## Development (hot-reload)
261+
262+
Run both simultaneously:
263+
264+
```powershell
265+
# Terminal 1 — backend
266+
cd src\M365SecurityDashboard.Api
267+
$env:ASPNETCORE_ENVIRONMENT = "Development"
268+
dotnet watch run
269+
270+
# Terminal 2 — frontend
271+
cd src\m365-security-dashboard-client
272+
npm run dev
273+
```
274+
275+
Frontend dev server: `http://localhost:5173` (proxies API calls to backend)
276+
277+
---
278+
279+
## Production Deployment (Windows Service)
280+
281+
```powershell
282+
# 1. Build frontend (outputs straight into the API's wwwroot)
283+
cd src\m365-security-dashboard-client
284+
npm install && npm run build
285+
286+
# 2. Publish API
287+
cd ..\M365SecurityDashboard.Api
288+
dotnet publish -c Release -o C:\Apps\M365SecurityDashboard
289+
290+
# 3. Create appsettings.Production.json in publish folder
291+
# (see template below — this file is gitignored)
292+
293+
# 4. Install as Windows Service
294+
sc.exe create M365SecurityDashboard `
295+
binPath= "C:\Apps\M365SecurityDashboard\M365SecurityDashboard.Api.exe --environment Production --urls http://localhost:8080" `
296+
start= auto
297+
sc.exe start M365SecurityDashboard
298+
```
299+
300+
**`appsettings.Production.json` template** (create this file manually, never commit it):
301+
302+
```json
303+
{
304+
"ConnectionStrings": {
305+
"DefaultConnection": "Server=.\\SQLEXPRESS;Database=M365SecurityDashboard;Trusted_Connection=True;Encrypt=True;TrustServerCertificate=True"
306+
},
307+
"Graph": {
308+
"TenantId": "YOUR_TENANT_ID",
309+
"ClientId": "YOUR_CLIENT_ID",
310+
"ClientSecret": "YOUR_CLIENT_SECRET",
311+
"CollectionIntervalMinutes": 15,
312+
"DevicesNotCheckedInDays": 7,
313+
"SignInLookbackHours": 24
314+
}
315+
}
316+
```
317+
318+
---
319+
209320
## HTTPS / TLS (required for production)
210321

211322
Outside Development the app enforces HTTPS (HSTS + redirect). Plain HTTP is only

SECURITY.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,45 @@
44

55
If you find a security issue (e.g. credentials being logged, an endpoint leaking data), please **do not open a public issue**. Open a [GitHub Security Advisory](https://github.com/sameerk27/vigil365/security/advisories/new) instead so it can be fixed before public disclosure.
66

7+
Please include the affected version/commit, reproduction steps, and potential impact. We aim to acknowledge reports within a few business days and ask for reasonable time to remediate before public disclosure.
8+
9+
---
10+
11+
## Supported Versions
12+
13+
Actively developed; security fixes target the latest `master`. Pin to a released commit for production and review changes before upgrading.
14+
15+
---
16+
17+
## Design & Deployment Model
18+
19+
Vigil365 is a **self-hosted, single-tenant** application meant to run on infrastructure the operating organisation controls — **not** a public multi-tenant SaaS.
20+
21+
- **Read-only against your tenant** — Graph access is app-only (client credentials) with `*.Read.All` permissions only; the app never writes to the M365 tenant.
22+
- **Data stays in-tenant** — collected data is stored in the operator's own SQL database; nothing is sent to any third-party service.
23+
- **Network isolation is a primary control** — designed to sit on a private network / behind a reverse proxy, not exposed directly to the internet.
24+
25+
---
26+
27+
## Current Security Controls
28+
29+
- **Secrets encrypted at rest** — SMTP password, webhook URLs, and the Graph client secret are DPAPI-encrypted; secrets are never returned by the API.
30+
- **Database transport encryption** — SQL connections use `Encrypt=True`.
31+
- **TLS in production** — HSTS + HTTPS redirection enforced outside Development; TLS via reverse proxy or Kestrel certificate (see README "HTTPS / TLS").
32+
- **Safe error handling** — API errors return generic messages; detail goes to server logs only.
33+
- **Security headers**`X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`.
34+
- **Least privilege** — read-only Graph permission set scoped to the monitored services.
35+
36+
## Hardening In Progress
37+
38+
Implemented on a development branch and rolling into releases: identity sign-in (Entra ID / MSAL), role-based access control (Admin/Analyst/Viewer), an append-only audit trail, and certificate-based Graph auth. See `docs/PROJECT_SUMMARY.md`.
39+
40+
## Operator Responsibilities
41+
42+
- Keep the app registration's client secret/certificate in a secret store; never commit credentials; rotate anything that may have been exposed.
43+
- Serve over HTTPS in production and restrict network exposure.
44+
- Apply OS, .NET, SQL Server, and dependency updates.
45+
746
---
847

948
## Reporting a Broken Graph API Endpoint

docs/PROJECT_SUMMARY.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Vigil365 — Project Summary
2+
3+
A self-hosted, open-source Microsoft 365 security dashboard. It aggregates
4+
security posture and alerts from across the Microsoft 365 stack — Defender XDR,
5+
Entra ID, Intune, Exchange Online, and Purview — into a single pane of glass.
6+
All data stays in the customer's own tenant/infrastructure; there is no
7+
third-party SaaS in the data path.
8+
9+
> **Status note:** the public `master` branch reflects the released app. A large
10+
> authentication / multi-user / setup update (sections marked 🆕 below) is on the
11+
> `feature/microsoft-login` branch, validated locally, not yet merged/published.
12+
13+
---
14+
15+
## What it does
16+
17+
| Area | Coverage |
18+
|------|----------|
19+
| Identity | Risky users, risky sign-ins, risk detections, MFA coverage, PIM, foreign sign-ins |
20+
| Devices | Intune compliance, non-compliant + stale devices, Defender endpoint alerts |
21+
| Email | Defender for Office 365 alerts (malware/phish/spam) |
22+
| Incidents | Unified Defender XDR incidents + alerts |
23+
| Compliance | DLP, MCAS, insider-risk, attack simulations |
24+
| Service Health | M365 service advisories |
25+
| Conditional Access | Policy inventory + state |
26+
| Audit / Sign-ins | Unified audit log, geographic sign-in view |
27+
| Alert Center | Custom alert policies, server-side evaluation, notifications (Teams/Email/webhook), per-alert snooze, silent auto-resolve |
28+
29+
## Architecture & stack
30+
31+
| Layer | Technology |
32+
|-------|-----------|
33+
| Backend | ASP.NET Core 8 Minimal API |
34+
| Frontend | React 18 + TypeScript + Vite (SPA) |
35+
| Data source | Microsoft Graph API — app-only (client credentials), **read-only** |
36+
| Scheduler | .NET BackgroundService, 15-minute collection cycle |
37+
| Storage | SQL Server Express by default; scales to SQL Server / Azure SQL (connection-string swap, no code change) |
38+
39+
## Security posture
40+
41+
- **Authentication** 🆕 — Microsoft/Entra ID login (MSAL); backend validates Bearer tokens (audience-scoped).
42+
- **Authorization** 🆕 — role-based access (Admin / Analyst / Viewer). Roles are app-managed (stored in-app), not Entra App Roles; enforced server-side via authorization policies and a claims transformation.
43+
- **User management** 🆕 — in-app admin UI to add/pre-provision, change roles, remove users, and send/resend access-notification emails. Last-admin lockout guards.
44+
- **Audit trail** 🆕 — append-only log of security-relevant actions (user add/role-change/remove/invite, settings, setup), with actor identity from the validated token.
45+
- **Encryption at rest** — secrets (SMTP password, webhook URLs, Graph client secret) DPAPI-encrypted; SQL connection uses `Encrypt=True`.
46+
- **Encryption in transit** 🆕 — HSTS + HTTPS redirection enforced outside Development; TLS via reverse proxy or Kestrel certificate (documented).
47+
- **Least privilege** — Graph permissions are all `*.Read.All`; the app never writes to the tenant.
48+
- **Network model** — designed as an internal/self-hosted tool; not a public multi-tenant SaaS.
49+
50+
## Install model 🆕
51+
52+
Reduced to ~3 steps:
53+
1. `install.ps1` — checks prerequisites, builds the frontend, publishes the API, optional Windows-service install.
54+
2. One-time Entra app registration (app-only Graph permissions + SPA redirect URI + `access_as_user` scope).
55+
3. Sign in (first user becomes Admin) → **in-app first-run setup wizard** to enter Graph credentials (stored encrypted; no JSON editing).
56+
57+
## Roadmap
58+
59+
**Recently landed (local branch):** Microsoft login, RBAC, in-app user management + invites, audit trail, production HTTPS enforcement, one-shot installer + first-run setup wizard.
60+
61+
**In progress / planned:**
62+
- Trends & history page — metric snapshots over time (risky users, compliance, secure score) with exec-friendly up/down/flat readouts.
63+
- Certificate-based Graph auth (replacing client secret) + secret-vault integration.
64+
- Data retention / pruning policies.
65+
- `register-app.ps1` to script the Entra app registration.
66+
- Optional SQLite backend to drop the SQL Server dependency.
67+
- Docker / docker-compose deployment.
68+
- CI with automated tests; dependency scanning.
69+
70+
## Scope & honest limitations
71+
72+
- Not a SIEM — no raw-log ingestion, KQL hunting, or SOAR. It complements tools like Microsoft Sentinel rather than replacing them.
73+
- Visibility is bounded by what Microsoft Graph exposes.
74+
- Single-tenant, self-hosted by design.
75+
- Historical trends accrue from when snapshotting begins (no retroactive history).
76+
77+
## Links
78+
79+
- Repository: https://github.com/sameerk27/vigil365
80+
- License: MIT

docs/THREAT_MODEL.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Vigil365 — Threat Model
2+
3+
A concise threat model covering trust boundaries, data flows, assets, and the
4+
controls that protect them. Scope is the self-hosted, single-tenant deployment
5+
described in `SECURITY.md`.
6+
7+
## Assets
8+
9+
| Asset | Sensitivity |
10+
|-------|-------------|
11+
| Graph API credentials (tenant/client ID, client secret/cert) | **Critical** — grant read access to tenant security data |
12+
| Collected M365 security data (alerts, risky users, devices, sign-ins) | High — reveals security posture |
13+
| Notification secrets (SMTP password, webhook URLs) | High |
14+
| User roles / access assignments | Medium |
15+
| Audit trail | Medium — integrity matters for accountability |
16+
17+
## Trust boundaries
18+
19+
```
20+
[ Operator's browser ] --HTTPS--> [ Reverse proxy / Kestrel TLS ]
21+
|
22+
[ Vigil365 API ] --app-only token--> [ Microsoft Graph ]
23+
|
24+
[ SQL database (in-tenant) ]
25+
```
26+
27+
1. **Browser ↔ App** — authenticated user session; should always be HTTPS in
28+
production. Untrusted input crosses here.
29+
2. **App ↔ Microsoft Graph** — outbound, app-only OAuth2; read-only scopes.
30+
3. **App ↔ Database** — trusted, same-network; transport-encrypted.
31+
4. **App ↔ SMTP/webhooks** — outbound notifications; secrets decrypted in memory
32+
only at send time.
33+
34+
## Data flows
35+
36+
- The background collector pulls current-state security data from Graph every
37+
~15 minutes and persists it to SQL.
38+
- The browser SPA reads that data through the API.
39+
- Privileged/mutating actions (acknowledge, snooze, settings, user management)
40+
are authenticated and, where applicable, role-gated server-side.
41+
42+
## Threats & mitigations (STRIDE-aligned)
43+
44+
| Threat | Mitigation |
45+
|--------|-----------|
46+
| **Spoofing** — unauthorised access to the dashboard | Entra ID sign-in (in progress); network isolation; tenant-scoped login |
47+
| **Tampering** — modifying data/config | Server-side authorization; read-only Graph (no tenant writes); append-only audit trail |
48+
| **Repudiation** — denying an action | Audit entries capture actor identity from the validated token |
49+
| **Information disclosure** — leaking secrets or data | Secrets DPAPI-encrypted at rest and never returned by the API; generic error messages; data stays in-tenant; HTTPS in production |
50+
| **Denial of service** | Self-hosted/internal exposure limits blast radius; Graph 429 handling with backoff |
51+
| **Elevation of privilege** | Role policies enforced on the server, not just hidden in the UI; last-admin lockout guards |
52+
53+
## Out of scope / assumptions
54+
55+
- The host OS, SQL Server, and network are administered and patched by the operator.
56+
- The Entra app registration is correctly configured with least-privilege,
57+
read-only permissions.
58+
- Vigil365 is **not** a SIEM and does not ingest raw logs; visibility is bounded
59+
by what Microsoft Graph exposes.
60+
- Physical security and tenant-admin trust are assumed.
61+
62+
## Residual risks
63+
64+
- A compromised Graph credential exposes read access to tenant security data —
65+
hence credential storage in a vault and rotation are operator responsibilities.
66+
- Until identity sign-in is merged to the released branch, network isolation is
67+
the primary access control for the public release.

0 commit comments

Comments
 (0)