Skip to content

MG-Teban/e8-posture

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

E8 Posture

Essential Eight maturity assessment for Microsoft Entra ID / Microsoft 365 tenants.

E8 Posture connects to your tenant via the Microsoft Graph API, evaluates configuration against the ACSC Essential Eight Maturity Model (ML0–ML3), and produces an interactive executive dashboard plus a printable report with per-control remediation guidance.

Demo mode is on by default. No credentials required — explore the full UI against a realistic mock tenant before connecting a real environment.


Why Essential Eight

The ACSC Essential Eight is the baseline cyber security framework for Australian government agencies and the de-facto standard for private-sector organisations operating in or with the Australian market. Eight mitigation strategies are prioritised by their effectiveness against the most common attack techniques:

Strategy Focus
Multi-factor authentication Credential theft and account takeover
Restrict administrative privileges Privilege escalation and lateral movement
Patch operating systems Exploitation of known OS vulnerabilities
Application control Execution of malicious or unauthorised code
Patch applications Exploitation of known application vulnerabilities
Configure Microsoft Office macro settings Macro-based malware delivery
User application hardening Browser and PDF reader exploits
Regular backups Ransomware and destructive attacks

E8 Posture currently covers the four strategies assessable via the Microsoft Graph API (MFA, Admin, OS Patch, Application Control). The remaining four require endpoint agent data or on-premises tooling outside the scope of the API.


Check Coverage

Control Strategy What it measures ML signal
E8-MFA-01 Multi-factor Authentication Percentage of users with an MFA method registered ML1 / ML2
E8-MFA-02 Multi-factor Authentication Conditional Access policy enforcing MFA for all users ML2
E8-MFA-03 Multi-factor Authentication Conditional Access policy enforcing MFA for privileged roles ML2
E8-MFA-04 Multi-factor Authentication Conditional Access policy blocking legacy authentication clients ML1
E8-MFA-05 Multi-factor Authentication Admins with phishing-resistant methods (FIDO2 / WHfB) registered ML3
E8-ADMIN-01 Restrict Administrative Privileges Permanent Global Administrator count vs. absolute and ratio thresholds ML1
E8-ADMIN-02 Restrict Administrative Privileges Ratio of PIM-eligible to permanent role assignments ML2
E8-ADMIN-03 Restrict Administrative Privileges Global Administrators holding Microsoft 365 user licences ML1
E8-OSPATCH-01 Patch Operating Systems Proportion of Intune-managed devices in a compliant state ML1
E8-OSPATCH-02 Patch Operating Systems Presence of a compliance policy with a minimum OS version requirement ML1
E8-APPCTL-01 Application Control Intune WDAC enforcement profile (enforced vs. audit-only vs. absent) ML1

Maturity scoring

A strategy reaches maturity level L only when every control whose maturityLevelSignal === L has status pass. A partial or not_assessable result at any level blocks progression from that level upward. The overall posture score is a 0–100 normalisation of the equal-weighted average across all four assessed strategies: round(sum(mlVector) / (4 × 3) × 100).


Architecture

flowchart LR
    subgraph Client["Browser (React Server Components)"]
        Dashboard["/ Dashboard"]
        DrillDown["/strategy/[id]"]
        Report["/report/[scanId]"]
        Scans["/scans"]
    end

    subgraph Server["Next.js Server"]
        DemoClient["Demo Client\n(fixtures)"]
        GraphClient["Graph Client\n(typed fetch + retry)"]
        MSAL["MSAL token cache\n(ConfidentialClientApp)"]
        Runners["Check Runners\nMFA · Admin · OS Patch · App Control"]
        Engine["Scoring Engine\ncomputeStrategyMaturity()"]
        SupabaseLib["Supabase Client\n(RLS-enforced)"]
    end

    subgraph External["External Services"]
        GraphAPI["Microsoft Graph API\nv1.0 / beta"]
        Entra["Entra ID / M365 Tenant"]
        DB[("Supabase Postgres\nSydney ap-southeast-2")]
    end

    Client -->|"Server Component render"| Server
    DemoClient -->|"fixture JSON"| Runners
    GraphClient --> MSAL
    MSAL -->|"app-only Bearer token"| GraphAPI
    GraphAPI --> Entra
    GraphAPI --> Runners
    Runners --> Engine
    Engine -->|"PostureScore"| Client
    SupabaseLib -->|"RLS policies"| DB
Loading

Security

  • App-only permissions, no delegated access. The Graph app registration uses client_credentials flow; it never impersonates a user. Required permissions are Reports.Read.All, Policy.Read.All, RoleManagement.Read.Directory, DeviceManagementManagedDevices.Read.All, DeviceManagementConfiguration.Read.All, and User.Read.All.

  • Tenant PII is never persisted. The database stores aggregated counts, policy names, and configuration settings — not user identities, UPNs, or personal data.

  • Row-Level Security on every table. Every Supabase table enables RLS; rows are visible only to the authenticated user who created them. The service-role client (used only in server-side scan writes) bypasses RLS intentionally and is never exposed to the browser.

  • Secrets in environment variables only. The Azure client secret, Supabase service key, and credential encryption key are in .env.local and are never committed.

  • Graph throttle-aware. All Graph calls retry on HTTP 429 (respecting the Retry-After header) and 503, with exponential backoff up to three attempts.


Limitations

The following aspects of the ACSC Essential Eight cannot be verified solely via the Microsoft Graph API and require supplementary evidence:

Limitation Why
OS patch timing Intune compliance policies capture whether a minimum version is required, not whether patches were applied within the ACSC-mandated 48-hour / 1-month windows. Windows Update for Business or WSUS reports are needed.
Application control policy content Custom OMA-URI profiles (opaque to the Graph API) are flagged as not_assessable. The full WDAC allow-list cannot be inspected via API; manual review is required.
Phishing-resistant MFA enforcement The check verifies that admins have registered phishing-resistant methods, not that they are required by a Conditional Access authentication strength policy (Entra P2).
Break-glass account detection Accounts are identified as break-glass by a /break.?glass/i regex on displayName. Non-standard naming conventions will cause them to be counted as regular Global Administrators.
Four of the Essential Eight strategies Patch applications, Office macro settings, user application hardening, and regular backups are not in scope — they require endpoint agents or on-premises tooling unavailable via Graph.

Roadmap

  • Phase 2 — Live tenant connection: OAuth 2.0 client-credentials flow against a real Entra ID app registration; tenant onboarding UI; encrypted credential storage in Supabase.
  • Phase 3 — Scheduled scans: Cron-triggered background scans via Supabase Edge Functions; scan-to-scan diff view highlighting regressions.
  • Phase 4 — Remaining Essential Eight strategies: Patch applications (Intune apps compliance), Office macro settings (Intune configuration profiles), user application hardening (browser baseline policies).
  • Phase 5 — Multi-tenant SaaS: Supabase per-organisation RLS, billing, and a public API for exporting posture data to GRC platforms.

Local Setup

Prerequisites

  • Node.js 22+
  • pnpm 10+
  • A Microsoft Entra ID app registration with the Graph permissions listed in Security
  • A Supabase project in the Sydney region (ap-southeast-2)

1 — Clone and install

git clone https://github.com/MG-Teban/e8-posture.git
cd e8-posture
pnpm install

2 — Environment variables

Copy .env.example to .env.local and fill in the values:

cp .env.example .env.local
Variable Description
NEXT_PUBLIC_SUPABASE_URL Supabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEY Supabase anon (public) key
SUPABASE_SERVICE_ROLE_KEY Supabase service-role key (server-only)
CREDENTIALS_ENCRYPTION_KEY 32-byte hex AES-256-GCM key for tenant secret storage
AZURE_TENANT_ID Entra ID tenant ID
AZURE_CLIENT_ID App registration client ID
AZURE_CLIENT_SECRET App registration client secret
NEXT_PUBLIC_DEMO_MODE Set to true to use fixture data (default for production)

Leave NEXT_PUBLIC_DEMO_MODE=true to run the full UI without Graph credentials.

3 — Database migrations

Apply the Supabase migration to create the schema and RLS policies:

# With the Supabase CLI installed:
supabase db push

# Or apply the SQL file manually via the Supabase dashboard:
# supabase/migrations/20260616000000_init_schema.sql

4 — Run the dev server

pnpm dev

Open http://localhost:3000.

5 — Tests

pnpm test           # run once
pnpm test:watch     # watch mode
pnpm test:coverage  # v8 coverage report

All 48 tests run in Node (no browser required). The integration test in tests/integration/scan-pipeline.test.ts runs the full scan pipeline against the mock-tenant fixtures and snapshots the ML vector — update the snapshot with pnpm test -- --update-snapshots if you change the fixture data.


Azure App Registration

  1. In the Entra admin centre, go to App registrations → New registration.

  2. Name: e8-posture · Account type: This directory only · No redirect URI needed.

  3. After creation, copy the Application (client) ID and Directory (tenant) ID to your .env.local.

  4. Go to Certificates & secrets → New client secret. Copy the secret value (shown only once) to AZURE_CLIENT_SECRET.

  5. Go to API permissions → Add a permission → Microsoft Graph → Application permissions and add:

    Permission Reason
    Reports.Read.All MFA registration details
    Policy.Read.All Conditional Access policies
    RoleManagement.Read.Directory Directory role assignments (PIM + permanent)
    DeviceManagementManagedDevices.Read.All Intune device compliance state
    DeviceManagementConfiguration.Read.All Intune configuration profiles (WDAC)
    User.Read.All User count and assigned licences
  6. Click Grant admin consent for your directory.


Deploy to Vercel

Deploy with Vercel

  1. Import the repository in the Vercel dashboard.
  2. Add the environment variables from .env.example under Project → Settings → Environment Variables.
  3. Set NEXT_PUBLIC_DEMO_MODE=true for the production environment (demo mode is on by default — remove or set to false once you have live credentials).
  4. Deploy. The build runs pnpm build and the app is served as a Next.js serverless deployment.

License

MIT

About

Essential Eight maturity assessment dashboard for Microsoft Entra ID / Microsoft 365 tenants

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages