diff --git a/.github/scripts/validate_mapping_pack.py b/.github/scripts/validate_mapping_pack.py new file mode 100755 index 00000000..10937c19 --- /dev/null +++ b/.github/scripts/validate_mapping_pack.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +"""Validate compliance mapping-pack semantics for every framework file. + +Every control must carry evidence-based mapping metadata, not just exist in +the file (issue #302) - this is what stops a future PR from force-mapping a +rule into a framework with no rationale for the relationship, or leaving a +synthetic non-mapping (a rule this repository could not actually tie to a +numbered framework control) misclassified as if it were direct technical +evidence. + +Runnable standalone (invoked from CI) or imported for unit testing against +fixture directories. +""" + +import json +import re +import sys +from datetime import date +from pathlib import Path +from typing import Any, Dict, List + +VALID_MAPPING_TYPES = {"direct", "supporting", "organizational", "not_applicable"} +VALID_REVIEW_STATUSES = {"pending_review", "reviewed"} +VALID_PACK_STATUSES = {"current", "legacy"} +REQUIRED_PACK_FIELDS = ( + "mapping_pack_version", + "mapping_pack_status", + "mapping_pack_source", + "mapping_pack_published", +) + +_SEMVER_RE = re.compile(r"^\d+\.\d+\.\d+$") + +# A control ID this repository itself invented because the framework has no +# corresponding numbered control ("N/A--"), or a control +# whose own name/description/rationale explicitly disclaims a real mapping, +# cannot be reported as "direct" technical evidence for that framework - a +# scan of a rule with no target control is not evidence for a control that +# does not exist. Checking substrings rather than only the ID prefix catches +# the same disclaimer being made in prose without the N/A- convention. +_NON_MAPPING_ID_PREFIX = "n/a" +_NON_MAPPING_PHRASES = ("not mapped", "not directly mapped", "no direct mapping", "not applicable") + + +def _is_disclaimed_non_mapping(control: Dict[str, Any]) -> bool: + control_id = str(control.get("control_id", "")).strip().lower() + if control_id.startswith(_NON_MAPPING_ID_PREFIX): + return True + haystack = " ".join(str(control.get(field, "")) for field in ("control_name", "description", "rationale")).lower() + return any(phrase in haystack for phrase in _NON_MAPPING_PHRASES) + + +def _is_valid_iso_date(value: Any) -> bool: + if not isinstance(value, str): + return False + try: + date.fromisoformat(value) + return True + except ValueError: + return False + + +def validate_framework_dir(framework_dir: "str | Path") -> List[str]: + """Return a list of human-readable failure strings; empty means valid.""" + failures: List[str] = [] + framework_dir = Path(framework_dir) + + for fpath in sorted(framework_dir.glob("*.json")): + fname = fpath.name + try: + with open(fpath) as f: + data = json.load(f) + except (json.JSONDecodeError, OSError) as e: + failures.append(f"{fname}: could not parse - {e}") + continue + + for field in REQUIRED_PACK_FIELDS: + if not data.get(field): + failures.append(f"{fname}: missing or empty top-level '{field}'") + + version = data.get("mapping_pack_version") + if version is not None and not (isinstance(version, str) and _SEMVER_RE.match(version)): + failures.append(f"{fname}: mapping_pack_version '{version}' is not a valid semantic version (X.Y.Z)") + + published = data.get("mapping_pack_published") + if published is not None and not _is_valid_iso_date(published): + failures.append(f"{fname}: mapping_pack_published '{published}' is not a valid ISO date (YYYY-MM-DD)") + + status = data.get("mapping_pack_status") + if status is not None and status not in VALID_PACK_STATUSES: + failures.append(f"{fname}: mapping_pack_status '{status}' not in {sorted(VALID_PACK_STATUSES)}") + + for rule_id, control in data.get("controls", {}).items(): + prefix = f"{fname}:{rule_id}" + + mapping_type = control.get("mapping_type") + if mapping_type not in VALID_MAPPING_TYPES: + failures.append(f"{prefix}: mapping_type '{mapping_type}' not in {sorted(VALID_MAPPING_TYPES)}") + + for field in ("evidence_type", "primary_source", "rationale"): + value = control.get(field) + if not isinstance(value, str) or not value.strip(): + failures.append(f"{prefix}: '{field}' must be a non-empty string") + + review_status = control.get("review_status") + if review_status not in VALID_REVIEW_STATUSES: + failures.append(f"{prefix}: review_status '{review_status}' not in {sorted(VALID_REVIEW_STATUSES)}") + + owner = control.get("owner") + if owner is not None and not (isinstance(owner, str) and owner.strip()): + failures.append(f"{prefix}: 'owner' must be null or a non-empty string") + + review_date = control.get("review_date") + if review_date is not None and not (isinstance(review_date, str) and review_date.strip()): + failures.append(f"{prefix}: 'review_date' must be null or a non-empty ISO date string") + + # A control cannot be marked reviewed without an accountable owner + # and a review date - otherwise "reviewed" is unverifiable. + if review_status == "reviewed" and (not owner or not review_date): + failures.append(f"{prefix}: review_status is 'reviewed' but owner and/or review_date is missing") + + # not_applicable/organizational controls must not claim to be + # measured by an automated scan. + if ( + mapping_type in ("not_applicable", "organizational") + and control.get("evidence_type") == "automated_configuration_scan" + ): + failures.append( + f"{prefix}: mapping_type '{mapping_type}' cannot have evidence_type 'automated_configuration_scan'" + ) + + # A control this repository itself marked as having no real + # framework counterpart (synthetic N/A-* ID, or its own text + # disclaiming a direct mapping) cannot be reported as direct + # technical evidence - that is exactly the overstatement issue + # #302 exists to close. + if mapping_type == "direct" and _is_disclaimed_non_mapping(control): + failures.append( + f"{prefix}: mapping_type is 'direct' but control_id/name/description/rationale disclaims a " + "real mapping (N/A-* ID or 'not mapped'/'no direct mapping' text) - must be 'not_applicable'" + ) + + return failures + + +def main() -> int: + framework_dir = sys.argv[1] if len(sys.argv) > 1 else "compliance/frameworks" + print(f"=== Validating compliance mapping-pack semantics in {framework_dir} ===") + failures = validate_framework_dir(framework_dir) + if failures: + print("COMPLIANCE MAPPING SEMANTICS FAILURES:") + for f in failures: + print(f" - {f}") + return 1 + print("All compliance mappings carry valid mapping-pack semantics.") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 950bc21d..d6cdd3e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -367,6 +367,19 @@ jobs: print(f"All compliance controls map to existing rule files. ({len(existing_ids)} rules checked)") PYEOF + # ── CHECK 8: Compliance mapping-pack semantics validation ───────── + # Every control must carry evidence-based mapping metadata, not just + # exist in the file (issue #302). This is what actually stops a + # future PR from force-mapping a rule into a framework with no + # rationale for the relationship, or leaving a synthetic non-mapping + # misclassified as direct technical evidence. Logic lives in + # .github/scripts/validate_mapping_pack.py so it's unit-testable + # (tests/test_mapping_pack_validation.py) rather than only exercised + # here, embedded in workflow YAML. + - name: Compliance mapping semantics validation + id: mapping_semantics_check + run: python .github/scripts/validate_mapping_pack.py + # ── Secret scanning (Gitleaks CLI, no gitleaks-action license needed) ───── secret-scan: name: Secret Scan (Gitleaks) @@ -645,6 +658,25 @@ jobs: python -m pip install --upgrade pip pip install -r requirements.txt + - name: Check Alembic revision graph has exactly one head + env: + DATABASE_URL: "postgresql://ci:ci@localhost:5432/ci_db" + # A migration branched from the same down_revision as another + # unmerged PR's migration (a fork) is invisible to a single PR's own + # CI run - each PR only has its own migration file, so `alembic + # upgrade head` succeeds in isolation. It's only detectable once both + # land on the same branch. This check catches that state explicitly + # instead of leaving `alembic upgrade head` to fail unhelpfully on + # whichever branch merges second. + run: | + HEAD_COUNT=$(alembic heads | grep -c '(head)') + if [ "$HEAD_COUNT" -ne 1 ]; then + echo "Alembic revision graph has $HEAD_COUNT heads, expected exactly 1:" + alembic heads + exit 1 + fi + echo "Alembic revision graph has exactly one head." + - name: Apply database migrations env: DATABASE_URL: "postgresql://ci:ci@localhost:5432/ci_db" @@ -689,6 +721,9 @@ jobs: - name: Run severity contract tests run: npm run test:severity + - name: Run score/compliance null-state tests + run: node src/utils/api.test.mjs + - name: Run accessibility and internationalization checks run: npm run test:a11y && npm run test:i18n diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e63d47c..3a72afe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,5 @@ # Changelog -## Unreleased - -- Add all ten evidence-rich enterprise network and perimeter controls `AZ-NET-018` through `AZ-NET-027` for issue #253, preserving API failures and incomplete data as indeterminate. - All notable changes to OpenShield are documented in this file. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -13,6 +9,7 @@ OpenShield uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Added +- Ten evidence-rich enterprise network and perimeter controls `AZ-NET-018` through `AZ-NET-027` for issue #253, preserving API failures and incomplete data as indeterminate - Azure Network Layer Assurance API with 20-domain coverage, network-rule classification, and authoritative IP forwarding and direct Internet route checks - Azure Resource Graph inventory snapshots as the first OpenShield Evidence Graph foundation - Azure Data Link Layer Assurance API with LLC and MAC coverage plus ExpressRoute Direct MACsec checks diff --git a/README.md b/README.md index 32fb0c44..9443d76e 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Project policies and assurance evidence: - [Support and upgrade policy](SUPPORT.md) - [Security requirements](docs/security-requirements.md) and [security assurance case](docs/security-assurance-case.md) - [Release security](docs/release-security.md) and [accessibility/i18n policy](docs/accessibility-and-i18n.md) +- [Compliance mapping pack](docs/compliance-mapping-pack.md) — supported framework editions, mapping-pack versioning, and why compliance reports are evidence coverage, not certification - [OpenSSF Silver evidence register](docs/openssf-silver-evidence.md) --- diff --git a/alembic/versions/3a76ff935bf6_add_scan_compliance_mapping_snapshot.py b/alembic/versions/3a76ff935bf6_add_scan_compliance_mapping_snapshot.py new file mode 100644 index 00000000..62299617 --- /dev/null +++ b/alembic/versions/3a76ff935bf6_add_scan_compliance_mapping_snapshot.py @@ -0,0 +1,48 @@ +"""Add compliance_mapping_snapshot to scans. + +Revision ID: 3a76ff935bf6 +Revises: d8e4f6a1b2c3 +Create Date: 2026-08-22 00:00:00.000000 + +This migration and PR #308's (severity contract v1, d8e4f6a1b2c3) were both +cut from the same parent, c7a2e9f1b3d4, which would have forked the Alembic +revision graph if both merged independently. Pointing down_revision at +d8e4f6a1b2c3 ahead of time was tried and reverted earlier in this PR's +history: Alembic resolves the full revision map from the files present in +the branch it's run against, so a revision that only existed on #308's +still-unmerged branch broke `alembic upgrade head` in this PR's own CI. +#308 has since merged, so d8e4f6a1b2c3 now exists on `dev` and this chains +onto it correctly - `alembic heads` returns exactly one head again. +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects import postgresql + +# Revision identifiers, used by Alembic. +revision: str = "3a76ff935bf6" +down_revision: Union[str, Sequence[str], None] = "d8e4f6a1b2c3" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + """Add a nullable JSONB snapshot of each framework's mapping-pack identity. + + Populated by DatabaseManager.save_scan() at scan-completion time, so a + historical compliance report can show the framework name, edition, + mapping-pack version and source that were actually in effect for that + scan instead of reinterpreting it with whatever mapping pack is deployed + now (issue #302). + """ + op.add_column( + "scans", + sa.Column("compliance_mapping_snapshot", postgresql.JSONB(), nullable=True), + ) + + +def downgrade() -> None: + """Drop the compliance mapping snapshot column.""" + op.drop_column("scans", "compliance_mapping_snapshot") diff --git a/api/models/finding.py b/api/models/finding.py index 0f366924..2c3b20c3 100644 --- a/api/models/finding.py +++ b/api/models/finding.py @@ -1,5 +1,6 @@ """Finding dataclass and PostgreSQL-backed DatabaseManager.""" +import hashlib import json import logging import os @@ -55,6 +56,76 @@ def _get_pool(dsn: str) -> "psycopg2.pool.ThreadedConnectionPool": "enisa_pqc": "enisa_pqc.json", } +_PACK_METADATA_KEYS = ( + "framework", + "version", + "mapping_pack_version", + "mapping_pack_status", + "mapping_pack_source", + "mapping_pack_published", +) + +# Reserved key holding a full snapshot's content hash, alongside the +# human-maintained mapping_pack_version. The semver is only bumped when a +# maintainer remembers to; the hash catches a controls change regardless. +_CONTENT_HASH_KEY = "mapping_pack_content_hash" + + +def _compute_mapping_pack_content_hash(controls: Dict[str, Any]) -> str: + """A stable hash of a framework's controls dict. + + Used both to detect a mapping-pack revision that didn't bump + mapping_pack_version, and to verify a stored snapshot was not corrupted + or partially overwritten before get_compliance_score() trusts it as the + historically accurate mapping for a scan. + """ + canonical = json.dumps(controls, sort_keys=True, separators=(",", ":")) + return hashlib.sha256(canonical.encode("utf-8")).hexdigest() + + +def _build_compliance_mapping_snapshot() -> Dict[str, Any]: + """Capture each framework's complete mapping — not just its metadata — at + the moment a scan is saved. + + Historical scans must remain interpretable even after the mapping pack on + disk is later revised or a framework edition is superseded. Snapshotting + metadata alone was not enough for that: get_compliance_score() also needs + the exact controls, mapping types, and denominator membership that were + in effect for this scan, or a mapping-pack update after the scan would + silently reclassify it under the new pack while still claiming the old + pack's provenance. So this snapshot captures the full controls dict per + framework, plus a content hash for integrity verification, and is what a + report for this scan prefers over the live files. + + A framework file that is missing or unreadable does not fail the scan + save (a transient read error on one framework must not block persisting + the scan itself), but the failure is never silent: it's logged, and + recorded under the reserved "_capture_errors" key in the returned dict + so a consumer reading this exact snapshot later (get_compliance_score()) + can tell "this framework's provenance was never captured" apart from + "this framework simply wasn't configured" — and must not quietly fall + back to live mapping data while still claiming historical accuracy. + """ + snapshot: Dict[str, Any] = {} + capture_errors: Dict[str, str] = {} + for framework, filename in FRAMEWORK_FILE_MAP.items(): + try: + with open(FRAMEWORKS_DIR / filename) as fh: + data = json.load(fh) + except (OSError, json.JSONDecodeError) as exc: + logger.error("compliance mapping snapshot: could not capture %s (%s): %s", framework, filename, exc) + capture_errors[framework] = f"{type(exc).__name__}: {exc}" + continue + controls = data.get("controls", {}) + snapshot[framework] = { + **{key: data.get(key) for key in _PACK_METADATA_KEYS}, + "controls": controls, + _CONTENT_HASH_KEY: _compute_mapping_pack_content_hash(controls), + } + if capture_errors: + snapshot["_capture_errors"] = capture_errors + return snapshot + @dataclass class Finding: @@ -177,6 +248,18 @@ def save_scan(self, scan_result: Dict[str, Any]) -> None: conn = self._get_conn() completed_at = scan_result.get("completed_at") or datetime.now(timezone.utc).isoformat() + mapping_snapshot_dict = _build_compliance_mapping_snapshot() + # Rules the scan engine could not complete (raised, or returned + # malformed data) are recorded alongside the mapping-pack snapshot so + # get_compliance_score() can exclude them from PASS instead of + # reading their absence from findings as a clean result. This is a + # stopgap ahead of issue #263's persisted per-resource evaluation + # table - it only knows "this rule did not complete for this scan", + # not per-resource outcomes. + failed_rule_ids = scan_result.get("failed_rule_ids") or [] + if failed_rule_ids: + mapping_snapshot_dict["_scan_rule_outcomes"] = {"failed_rule_ids": sorted(set(failed_rule_ids))} + mapping_snapshot = json.dumps(mapping_snapshot_dict) try: with conn.cursor() as cur: cur.execute( @@ -184,16 +267,25 @@ def save_scan(self, scan_result: Dict[str, Any]) -> None: INSERT INTO scans ( scan_id, subscription_id, started_at, completed_at, total_findings, score, cve_enrichment_status, status, - attempt_count, error_message, severity_contract_version + attempt_count, error_message, severity_contract_version, + compliance_mapping_snapshot ) - VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON CONFLICT (scan_id) DO UPDATE SET completed_at = EXCLUDED.completed_at, total_findings = EXCLUDED.total_findings, score = EXCLUDED.score, status = EXCLUDED.status, error_message = EXCLUDED.error_message, - severity_contract_version = EXCLUDED.severity_contract_version + severity_contract_version = EXCLUDED.severity_contract_version, + -- The mapping snapshot captured for a scan_id's first + -- successful write is its historical record and must + -- stay immutable on replay (e.g. a worker retry that + -- reuses the same scan_id) - only fill it in if this + -- scan_id never captured one. + compliance_mapping_snapshot = COALESCE( + scans.compliance_mapping_snapshot, EXCLUDED.compliance_mapping_snapshot + ) """, ( scan_result["scan_id"], @@ -207,6 +299,7 @@ def save_scan(self, scan_result: Dict[str, Any]) -> None: scan_result.get("attempt_count", 0), scan_result.get("error_message"), CONTRACT_VERSION, + mapping_snapshot, ), ) # A worker retry replaces the previous result atomically. This @@ -497,29 +590,46 @@ def get_scans(self) -> List[Dict[str, Any]]: # Scoring # # ------------------------------------------------------------------ # - def get_score(self) -> int: + def get_score(self) -> Dict[str, Any]: """Return a 0-100 security posture score based on the latest scan's findings. Scoped to the most recent scan so historical findings from older scans do not accumulate and drive the score to zero. CRITICAL findings deduct 20 points each, HIGH 10, MEDIUM 5, - LOW 2, and INFO 0. Floors at 0. + LOW 2, and INFO 0 (openshield.severity.score_counts). Floors at 0. + + The scan-existence check is a separate query from the findings lookup: + folding both into one `scan_id = (SELECT ...)` subquery (the previous + approach) cannot distinguish "no completed scan exists" from "the + latest completed scan found nothing" - both yield zero rows, so the + former was silently reported as a perfect 100 score with no actual + evidence behind it, the same NO_SCAN_DATA gap fixed in + get_compliance_score(). + + Returns: + {"status": "NO_SCAN_DATA", "score": None, "message": ...} when no + completed scan exists yet, or {"status": "OK", "score": <0-100>} + once one has. """ conn = self._get_conn() with conn.cursor() as cur: - cur.execute( - """ - SELECT severity, COUNT(*) - FROM findings - WHERE scan_id = ( - SELECT scan_id FROM scans WHERE status = 'completed' ORDER BY started_at DESC LIMIT 1 - ) - GROUP BY severity - """ - ) + cur.execute("SELECT scan_id FROM scans WHERE status = 'completed' ORDER BY started_at DESC LIMIT 1") + latest_scan = cur.fetchone() + + if latest_scan is None: + return { + "status": "NO_SCAN_DATA", + "score": None, + "max_score": 100, + "message": ("No completed scan is available yet, so there is no security posture to score."), + } + + scan_id = latest_scan[0] + cur.execute("SELECT severity, COUNT(*) FROM findings WHERE scan_id = %s GROUP BY severity", (scan_id,)) rows = cur.fetchall() - return score_counts({severity: count for severity, count in rows}) + score = score_counts({severity: count for severity, count in rows}) + return {"status": "OK", "score": score, "max_score": 100} def get_cve_summary(self) -> Dict[str, Any]: """Return high-level summary of CVE findings for the dashboard.""" @@ -562,14 +672,25 @@ def get_cve_summary(self) -> Dict[str, Any]: } def get_compliance_score(self, framework: str) -> Dict[str, Any]: - """Return pass/fail breakdown against a compliance framework. + """Return technical-evidence coverage against a compliance framework mapping pack. + + This reports coverage from the most recent completed scan, not a + certification or a claim of full framework compliance. Controls whose + mapping_type is "not_applicable" or "organizational" are listed but + excluded from the pass-rate denominator (score_percent), because a + technical scan cannot itself establish an organizational control or a + control the mapped framework edition does not define. Args: - framework: One of 'cis', 'nist', or 'iso27001'. + framework: One of the keys in FRAMEWORK_FILE_MAP (e.g. 'cis', 'nist'). Returns: - dict with keys: framework, total_controls, passed, failed, - score_percent, controls (list of control detail objects). + dict with keys: framework, version, mapping_pack_version, + mapping_pack_status, mapping_pack_source, mapping_pack_published, + evaluation_basis, total_controls, in_scope_controls, + excluded_controls, passed, failed, score_percent, controls (list + of control detail objects each carrying mapping_type, evidence_type, + primary_source, rationale, owner, review_status, review_date). """ filename = FRAMEWORK_FILE_MAP.get(framework.lower()) if not filename: @@ -583,23 +704,121 @@ def get_compliance_score(self, framework: str) -> Dict[str, Any]: framework_data = json.load(fh) controls = framework_data.get("controls", {}) + pack_meta = {key: framework_data.get(key) for key in _PACK_METADATA_KEYS} + # Present regardless of provenance, so callers never have to branch + # on whether this came from a snapshot to find the hash field. + pack_meta[_CONTENT_HASH_KEY] = _compute_mapping_pack_content_hash(controls) - # Get failure detail from the latest completed scan only. This does - # not change the legacy absence-implies-PASS behavior tracked by #263; - # it prevents the frontend from inventing MEDIUM for failed controls. conn = self._get_conn() - with conn.cursor() as cur: + with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur: cur.execute( + "SELECT scan_id, compliance_mapping_snapshot FROM scans " + "WHERE status = 'completed' ORDER BY started_at DESC LIMIT 1" + ) + latest_scan = cur.fetchone() + + if latest_scan is None: + # No completed scan exists yet: there is no evidence to report. + # Absence of findings must never be presented as a passing score. + # in_scope_controls/excluded_controls/passed/failed are None + # here, not 0 - a literal 0 would read as "this mapping pack + # has zero in-scope controls" (the real, distinct + # NO_IN_SCOPE_CONTROLS case below), when what's actually true + # is that scope has not been determined yet because nothing + # has run. total_controls is still meaningful (the pack + # defines this many controls); the others are not. + return { + **pack_meta, + "status": "NO_SCAN_DATA", + "message": ( + "No completed scan is available yet, so no technical " + "evidence exists to report against this framework." + ), + "evaluation_basis": ( + "No completed scan exists yet, so no control below could be " + "evaluated. in_scope_controls/excluded_controls/passed/failed " + "are null, not 0 - this is distinct from a scan that completed " + "and found zero in-scope controls (status NO_IN_SCOPE_CONTROLS)." + ), + "total_controls": len(controls), + "in_scope_controls": None, + "excluded_controls": None, + "passed": None, + "failed": None, + "score_percent": None, + "controls": [], + } + + scan_id = latest_scan["scan_id"] + snapshot = latest_scan.get("compliance_mapping_snapshot") or {} + snapshot_for_fw = snapshot.get(framework.lower()) + if snapshot_for_fw and isinstance(snapshot_for_fw.get("controls"), dict): + # A full historical snapshot exists: reproduce the exact + # controls, mapping types, and denominator membership that + # were in effect for this scan, not whatever is on disk now. + # Otherwise a mapping-pack update after the scan would + # silently re-evaluate it under the new pack while this + # response still claimed the old pack's provenance. + controls = snapshot_for_fw["controls"] + stored_hash = snapshot_for_fw.get(_CONTENT_HASH_KEY) + if stored_hash and stored_hash != _compute_mapping_pack_content_hash(controls): + # The stored snapshot no longer hashes to what it claims - + # corrupted or partially overwritten. Still the best + # historical data available, but must not be presented as + # a clean, verified snapshot. + logger.error( + "compliance mapping snapshot for scan %s framework %s failed integrity " + "check: stored hash does not match its own controls", + scan_id, + framework.lower(), + ) + mapping_provenance = "snapshot_hash_mismatch" + else: + mapping_provenance = "snapshot" + pack_meta = {key: snapshot_for_fw.get(key) for key in _PACK_METADATA_KEYS} + pack_meta[_CONTENT_HASH_KEY] = stored_hash + elif snapshot_for_fw: + # Legacy snapshot: metadata was captured historically but the + # full controls were not (scan saved before this snapshot was + # widened to include them). The denominator/classification + # below still has to come from whatever mapping is on disk + # now, so this must not be labelled "snapshot" - that would + # claim a historical accuracy this response doesn't have. + pack_meta = snapshot_for_fw + mapping_provenance = "live_fallback_legacy_snapshot" + elif framework.lower() in (snapshot.get("_capture_errors") or {}): + # The snapshot was attempted for this exact scan and this exact + # framework, and it failed (logged at save time - see + # _build_compliance_mapping_snapshot). Falling back to whatever + # mapping pack happens to be on disk *now* is the only option + # left, but it must never be presented as if it were the + # historically accurate provenance for this scan. + mapping_provenance = "live_fallback_capture_failed" + else: + # No snapshot entry and no recorded capture error for this + # framework - a benign case (e.g. a scan saved before this + # framework existed, or before the snapshot feature shipped). + mapping_provenance = "live_fallback_no_snapshot" + + # A separate, plain (non-RealDict) cursor for this one - its rows are + # unpacked positionally below, and a RealDictCursor row is a plain + # OrderedDict with no __iter__ override, so `a, b, c, d = row` would + # silently unpack its *keys* ("rule_id", "severity", ...) rather than + # their values instead of failing loudly. + with conn.cursor() as cur2: + # Grouped by severity/category too (not just DISTINCT rule_id) so + # each failing control can report which severity/category/how many + # resources are affected, not just a bare FAIL. + cur2.execute( """ SELECT rule_id, severity, category, COUNT(*) FROM findings - WHERE scan_id = ( - SELECT scan_id FROM scans WHERE status = 'completed' ORDER BY started_at DESC LIMIT 1 - ) + WHERE scan_id = %s GROUP BY rule_id, severity, category - """ + """, + (scan_id,), ) - finding_rows = cur.fetchall() + finding_rows = cur2.fetchall() failures: Dict[str, Dict[str, Any]] = {} for rule_id, raw_severity, category, resource_count in finding_rows: @@ -617,10 +836,36 @@ def get_compliance_score(self, framework: str) -> Dict[str, Any]: current["severity"] = severity current["category"] = category + # Rules the scan engine could not complete for this scan (raised, + # or returned malformed data) - recorded by save_scan() alongside + # the mapping snapshot. A rule missing from findings only proves + # a PASS when it's not also in this set; otherwise its absence + # from findings means "never actually ran", not "ran and found + # nothing" (issue #302/#263). + unevaluated_rule_ids = set((snapshot.get("_scan_rule_outcomes") or {}).get("failed_rule_ids") or []) + results = [] + excluded_count = 0 for rule_id, control in controls.items(): + mapping_type = control.get("mapping_type", "supporting") + is_excluded = mapping_type in ("not_applicable", "organizational") failure = failures.get(rule_id) - status = "FAIL" if failure else "PASS" + + if is_excluded: + status = "NOT_APPLICABLE" if mapping_type == "not_applicable" else "ORGANIZATIONAL" + excluded_count += 1 + elif rule_id in unevaluated_rule_ids: + # The rule that would provide this control's evidence did not + # complete for this scan - its absence from findings cannot + # be read as a pass. Excluded from the denominator like + # not_applicable/organizational, but for a different reason: + # this is missing *evidence*, not a control the mapping pack + # itself says a scan can't establish. + status = "NOT_EVALUATED" + excluded_count += 1 + else: + status = "FAIL" if failure else "PASS" + results.append( { "rule_id": rule_id, @@ -630,18 +875,49 @@ def get_compliance_score(self, framework: str) -> Dict[str, Any]: "severity": failure["severity"] if failure else None, "category": failure["category"] if failure else None, "resources": failure["resources"] if failure else 0, + "mapping_type": mapping_type, + "evidence_type": control.get("evidence_type"), + "primary_source": control.get("primary_source"), + "rationale": control.get("rationale"), + "owner": control.get("owner"), + "review_status": control.get("review_status"), + "review_date": control.get("review_date"), } ) total = len(results) + in_scope = total - excluded_count passed = sum(1 for r in results if r["status"] == "PASS") - failed = total - passed - score_pct = round((passed / total) * 100) if total else 0 + failed = sum(1 for r in results if r["status"] == "FAIL") + score_pct = round((passed / in_scope) * 100) if in_scope else None + # A scan exists and every control resolved, but every one of them is + # excluded (not_applicable/organizational) - this is a different fact + # from "no evidence exists at all" (NO_SCAN_DATA above), and callers + # must not conflate the two the way a bare `in_scope_controls: 0` + # would: a null score_percent alone can't say whether it's "nothing + # was in scope" or "not evaluated yet". + status = "OK" if in_scope else "NO_IN_SCOPE_CONTROLS" return { - "framework": framework_data.get("framework"), - "version": framework_data.get("version"), + **pack_meta, + "scan_id": scan_id, + "status": status, + "mapping_provenance": mapping_provenance, + "evaluation_basis": ( + "PASS reflects the absence of findings for this rule in the most recent " + "completed scan, and the rule is excluded as NOT_EVALUATED rather than PASS " + "when the scan engine recorded that it did not complete (raised an exception " + "or returned malformed data) for this specific scan. It does not yet confirm " + "the rule executed successfully against every applicable resource within a " + "scan it did complete — a timed-out or permission-denied result on a subset " + "of resources cannot currently be distinguished from a clean pass on all of " + "them (full per-resource evaluation persistence is tracked in issue #263). " + "Controls with mapping_type not_applicable or organizational are excluded " + "from score_percent because a technical scan alone cannot establish them." + ), "total_controls": total, + "in_scope_controls": in_scope, + "excluded_controls": excluded_count, "passed": passed, "failed": failed, "score_percent": score_pct, diff --git a/api/routes/compliance.py b/api/routes/compliance.py index 1fade57c..2897c2e3 100644 --- a/api/routes/compliance.py +++ b/api/routes/compliance.py @@ -25,11 +25,17 @@ def _get_db() -> DatabaseManager: @compliance_bp.get("/api/compliance/") def get_compliance(framework: str): - """Return pass/fail compliance breakdown for a framework. + """Return technical-evidence coverage against a framework mapping pack. Supported frameworks: cis, nist, iso27001, soc2, ncsc_pqc, enisa_pqc - Returns control-level pass/fail status mapped to current open findings. + This is versioned technical evidence coverage from the most recent + completed scan, not a certification or a claim of full framework + compliance. Each control also reports mapping_type, evidence_type, + primary_source, rationale, owner and review_status; controls whose + mapping_type is not_applicable or organizational are excluded from + score_percent. If no completed scan exists yet, status is NO_SCAN_DATA + and no PASS/FAIL is reported. """ try: framework = choice(framework, "framework", SUPPORTED_FRAMEWORKS, case="lower") diff --git a/compliance/frameworks/cis_azure_benchmark.json b/compliance/frameworks/cis_azure_benchmark.json index 156c38ad..1cafecc7 100644 --- a/compliance/frameworks/cis_azure_benchmark.json +++ b/compliance/frameworks/cis_azure_benchmark.json @@ -2,526 +2,1282 @@ "framework": "CIS Microsoft Azure Foundations Benchmark", "version": "2.0.0", "published": "2023-02", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "OpenShield compliance mapping pack, authored against CIS Microsoft Azure Foundations Benchmark v2.0.0 official control text. Technical-evidence mapping only; not a certification statement.", + "mapping_pack_published": "2026-08-22", "controls": { "AZ-STOR-001": { "control_id": "3.5", "control_name": "Ensure that 'Public access level' is set to Private for blob containers", - "description": "Disabling public access level for blob containers prevents anonymous unauthenticated access to Azure Blob storage. This setting eliminates the risk of inadvertent or unauthorized public data exposure." + "description": "Disabling public access level for blob containers prevents anonymous unauthenticated access to Azure Blob storage. This setting eliminates the risk of inadvertent or unauthorized public data exposure.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.5", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 3.5 ('Ensure that 'Public access level' is set to Private for blob containers') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-STOR-001 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-002": { "control_id": "3.1", "control_name": "Ensure that 'Secure transfer required' is set to 'Enabled'", - "description": "Enabling 'Secure transfer required' on a storage account ensures that all requests made to the storage account use HTTPS. Any requests using HTTP are rejected, protecting data in transit from eavesdropping and man-in-the-middle attacks." + "description": "Enabling 'Secure transfer required' on a storage account ensures that all requests made to the storage account use HTTPS. Any requests using HTTP are rejected, protecting data in transit from eavesdropping and man-in-the-middle attacks.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 3.1 ('Ensure that 'Secure transfer required' is set to 'Enabled'') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-STOR-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-001": { "control_id": "6.2", "control_name": "Ensure that SSH access from the Internet is evaluated and restricted", - "description": "Network security groups should not allow unrestricted SSH access from the internet. Restricting inbound SSH access reduces attack surface and prevents unauthorized access attempts, brute-force attacks, and exploitation of SSH service vulnerabilities." + "description": "Network security groups should not allow unrestricted SSH access from the internet. Restricting inbound SSH access reduces attack surface and prevents unauthorized access attempts, brute-force attacks, and exploitation of SSH service vulnerabilities.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 6.2", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 6.2 ('Ensure that SSH access from the Internet is evaluated and restricted') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-001 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-002": { "control_id": "6.3", "control_name": "Ensure that RDP access from the Internet is evaluated and restricted", - "description": "Network security groups should not permit unrestricted inbound RDP from the internet. Open RDP ports are a leading cause of ransomware infections and credential-based attacks. Access should be restricted to specific trusted IP ranges or removed in favour of Azure Bastion." + "description": "Network security groups should not permit unrestricted inbound RDP from the internet. Open RDP ports are a leading cause of ransomware infections and credential-based attacks. Access should be restricted to specific trusted IP ranges or removed in favour of Azure Bastion.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 6.3", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 6.3 ('Ensure that RDP access from the Internet is evaluated and restricted') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-003": { "control_id": "9.3", "control_name": "Ensure that HTTPS access from the Internet is evaluated and restricted", - "description": "Network security groups should not allow unrestricted inbound access on port 443 from the internet. Public web services should be fronted by an Application Gateway with WAF rather than exposing port 443 directly via NSG rules." + "description": "Network security groups should not allow unrestricted inbound access on port 443 from the internet. Public web services should be fronted by an Application Gateway with WAF rather than exposing port 443 directly via NSG rules.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.3", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.3 ('Ensure that HTTPS access from the Internet is evaluated and restricted') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-004": { "control_id": "9.2", "control_name": "Ensure that Network Security Groups have rules configured", - "description": "Network Security Groups with no custom rules configured provide no meaningful access control and rely entirely on Azure default rules. Explicit rules following least privilege should be defined for all NSGs." + "description": "Network Security Groups with no custom rules configured provide no meaningful access control and rely entirely on Azure default rules. Explicit rules following least privilege should be defined for all NSGs.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.2", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.2 ('Ensure that Network Security Groups have rules configured') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-004 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-005": { "control_id": "9.4", "control_name": "Ensure that DDoS Protection Standard is enabled on all Virtual Networks", - "description": "Azure DDoS Protection Standard provides enhanced DDoS mitigation capabilities for Azure resources. Virtual networks hosting production workloads should have DDoS Protection Standard enabled." + "description": "Azure DDoS Protection Standard provides enhanced DDoS mitigation capabilities for Azure resources. Virtual networks hosting production workloads should have DDoS Protection Standard enabled.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.4", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.4 ('Ensure that DDoS Protection Standard is enabled on all Virtual Networks') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-005 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-006": { "control_id": "9.1", "control_name": "Ensure that unassociated public IP addresses are removed", - "description": "Public IP addresses not associated with any resource represent unnecessary attack surface and cost. Unassociated public IPs should be deleted or documented and tagged for review." + "description": "Public IP addresses not associated with any resource represent unnecessary attack surface and cost. Unassociated public IPs should be deleted or documented and tagged for review.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.1 ('Ensure that unassociated public IP addresses are removed') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-006 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-007": { "control_id": "9.6", "control_name": "Ensure that Web Application Firewall is enabled on Application Gateway", - "description": "Application Gateway should have Web Application Firewall enabled in Prevention mode. WAF protects web applications from common exploits including OWASP Top 10 vulnerabilities such as SQL injection and cross-site scripting." + "description": "Application Gateway should have Web Application Firewall enabled in Prevention mode. WAF protects web applications from common exploits including OWASP Top 10 vulnerabilities such as SQL injection and cross-site scripting.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.6", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.6 ('Ensure that Web Application Firewall is enabled on Application Gateway') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-007 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-008": { "control_id": "9.7", "control_name": "Ensure that Load Balancers have backend pools configured", - "description": "Load balancers with no backend pool configured are either misconfigured or leftover resources. They represent unnecessary cost and poor resource hygiene and should be removed or configured correctly." + "description": "Load balancers with no backend pool configured are either misconfigured or leftover resources. They represent unnecessary cost and poor resource hygiene and should be removed or configured correctly.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.7", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.7 ('Ensure that Load Balancers have backend pools configured') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-008 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-009": { "control_id": "9.5", "control_name": "Ensure that VPN gateways use IKEv2", - "description": "VPN gateway connections should use IKEv2 rather than the outdated IKEv1 protocol. IKEv2 provides improved authentication, better performance and built-in NAT traversal support compared to IKEv1." + "description": "VPN gateway connections should use IKEv2 rather than the outdated IKEv1 protocol. IKEv2 provides improved authentication, better performance and built-in NAT traversal support compared to IKEv1.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.5", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.5 ('Ensure that VPN gateways use IKEv2') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-009 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-010": { "control_id": "9.10", "control_name": "Ensure that all subnets have a Network Security Group attached", - "description": "All subnets except gateway subnets should have a Network Security Group attached. Without an NSG at subnet level, resources in the subnet have no network layer access control and are potentially reachable from other subnets or the internet." + "description": "All subnets except gateway subnets should have a Network Security Group attached. Without an NSG at subnet level, resources in the subnet have no network layer access control and are potentially reachable from other subnets or the internet.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.10", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.10 ('Ensure that all subnets have a Network Security Group attached') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-010 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-001": { "control_id": "1.24", "control_name": "Ensure That No Custom Subscription Owner Roles Are Created", - "description": "Service principals or custom roles should not be assigned the Owner role at subscription scope. The Owner role grants full control including the ability to modify access controls. Assignment should follow the principle of least privilege." + "description": "Service principals or custom roles should not be assigned the Owner role at subscription scope. The Owner role grants full control including the ability to modify access controls. Assignment should follow the principle of least privilege.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.24", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.24 ('Ensure That No Custom Subscription Owner Roles Are Created') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-001 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-002": { "control_id": "1.2.4", "control_name": "Ensure that 'Multi-Factor Authentication Status' is 'Enabled' for all Privileged Users", - "description": "Multi-Factor Authentication requires an individual to present a minimum of two separate forms of authentication before access is granted. MFA should be enforced for all users with administrative privileges via Conditional Access policies." + "description": "Multi-Factor Authentication requires an individual to present a minimum of two separate forms of authentication before access is granted. MFA should be enforced for all users with administrative privileges via Conditional Access policies.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.2.4", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.2.4 ('Ensure that 'Multi-Factor Authentication Status' is 'Enabled' for all Privileged Users') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-003": { "control_id": "1.15", "control_name": "Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'", - "description": "Unrestricted guest user invitation settings allow any member of the organisation to invite external users into the tenant without administrative review. This bypasses centralised approval for external identity provisioning and increases the risk of unauthorised access by untrusted parties." + "description": "Unrestricted guest user invitation settings allow any member of the organisation to invite external users into the tenant without administrative review. This bypasses centralised approval for external identity provisioning and increases the risk of unauthorised access by untrusted parties.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.15", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.15 ('Ensure that 'Guest invite restrictions' is set to 'Only users assigned to specific admin roles can invite guest users'') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-005": { "control_id": "1.3", "control_name": "Ensure guest users are reviewed on a monthly basis", - "description": "Guest accounts assigned to high privilege roles in Entra ID allow external identities to perform administrative actions in the tenant. CIS 1.3 requires that guest users are reviewed and that privileged access is restricted to internal accounts only. Any guest user holding a role such as Global Administrator, Security Administrator, or User Administrator must have that assignment removed immediately." + "description": "Guest accounts assigned to high privilege roles in Entra ID allow external identities to perform administrative actions in the tenant. CIS 1.3 requires that guest users are reviewed and that privileged access is restricted to internal accounts only. Any guest user holding a role such as Global Administrator, Security Administrator, or User Administrator must have that assignment removed immediately.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.3", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.3 ('Ensure guest users are reviewed on a monthly basis') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-005 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-006": { "control_id": "1.14", "control_name": "Ensure that service principal passwords are rotated within 90 days", - "description": "Service principal client secrets older than 90 days or with no expiry date represent a persistent credential risk. CIS 1.14 requires that service principal passwords are rotated at least every 90 days. Secrets that never expire remain valid indefinitely if leaked, giving an attacker permanent access to the application and its Azure permissions." + "description": "Service principal client secrets older than 90 days or with no expiry date represent a persistent credential risk. CIS 1.14 requires that service principal passwords are rotated at least every 90 days. Secrets that never expire remain valid indefinitely if leaked, giving an attacker permanent access to the application and its Azure permissions.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.14", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.14 ('Ensure that service principal passwords are rotated within 90 days') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-006 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-007": { "control_id": "1.1", "control_name": "Ensure that multi-factor authentication is enabled for all privileged users", - "description": "Active users in Entra ID with no MFA methods registered are vulnerable to password-based attacks including spray and phishing. CIS 1.1 requires that MFA is enabled for all users, particularly those with privileged access. Users without MFA registered must be required to enrol before they can access Azure resources." + "description": "Active users in Entra ID with no MFA methods registered are vulnerable to password-based attacks including spray and phishing. CIS 1.1 requires that MFA is enabled for all users, particularly those with privileged access. Users without MFA registered must be required to enrol before they can access Azure resources.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.1 ('Ensure that multi-factor authentication is enabled for all privileged users') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-007 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-008": { "control_id": "1.23", "control_name": "Ensure that custom subscription roles do not exist", - "description": "Custom RBAC roles with wildcard actions (*) at subscription scope grant Owner-equivalent permissions and violate the principle of least privilege. CIS 1.23 requires that custom subscription roles do not have wildcard permissions. These roles must be replaced with definitions that specify only the exact actions required for the intended use case." + "description": "Custom RBAC roles with wildcard actions (*) at subscription scope grant Owner-equivalent permissions and violate the principle of least privilege. CIS 1.23 requires that custom subscription roles do not have wildcard permissions. These roles must be replaced with definitions that specify only the exact actions required for the intended use case.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.23", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.23 ('Ensure that custom subscription roles do not exist') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-008 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-009": { "control_id": "5.2.1", "control_name": "Ensure that activity log alert exists for Create Policy Assignment", - "description": "A subscription without an activity log alert for role assignment changes cannot detect privilege escalation in real time. CIS 5.2.1 requires that activity log alerts exist for administrative operations including role assignment writes. Without this alert, an attacker who elevates their own permissions will go undetected until the next manual review." + "description": "A subscription without an activity log alert for role assignment changes cannot detect privilege escalation in real time. CIS 5.2.1 requires that activity log alerts exist for administrative operations including role assignment writes. Without this alert, an attacker who elevates their own permissions will go undetected until the next manual review.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 5.2.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 5.2.1 ('Ensure that activity log alert exists for Create Policy Assignment') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-009 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-001": { "control_id": "4.3.1", "control_name": "Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled", - "description": "Disabling public network access on PostgreSQL Database Server prevents public access and reduces the attack surface. Access should be restricted to private networks using VNet service endpoints or private endpoints." + "description": "Disabling public network access on PostgreSQL Database Server prevents public access and reduces the attack surface. Access should be restricted to private networks using VNet service endpoints or private endpoints.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 4.3.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 4.3.1 ('Ensure 'Allow access to Azure services' for PostgreSQL Database Server is disabled') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-DB-001 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-002": { "control_id": "4.1.3", "control_name": "Ensure that 'Auditing' Retention is 'greater than 90 days' for SQL servers", - "description": "SQL Server audit logs must be enabled and retained for a minimum of 90 days. Enabling auditing provides a record of database events that can be used to detect threats, investigate incidents, and demonstrate compliance." + "description": "SQL Server audit logs must be enabled and retained for a minimum of 90 days. Enabling auditing provides a record of database events that can be used to detect threats, investigate incidents, and demonstrate compliance.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 4.1.3", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 4.1.3 ('Ensure that 'Auditing' Retention is 'greater than 90 days' for SQL servers') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-DB-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-001": { "control_id": "7.1", "control_name": "Ensure that Network Security Groups are attached to network interfaces with public IP addresses", - "description": "Virtual machines that are reachable from the internet should have Network Security Groups attached to their network interfaces to control and restrict inbound and outbound traffic, reducing the attack surface." + "description": "Virtual machines that are reachable from the internet should have Network Security Groups attached to their network interfaces to control and restrict inbound and outbound traffic, reducing the attack surface.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 7.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 7.1 ('Ensure that Network Security Groups are attached to network interfaces with public IP addresses') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-CMP-001 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-002": { "control_id": "7.2", "control_name": "Ensure that 'OS disk' are encrypted", - "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CIS 7.2 requires disks to be protected using customer-managed keys or Azure Disk Encryption. Platform-managed encryption does not give the organisation control over the encryption keys and does not satisfy this control." + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CIS 7.2 requires disks to be protected using customer-managed keys or Azure Disk Encryption. Platform-managed encryption does not give the organisation control over the encryption keys and does not satisfy this control.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 7.2", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 7.2 ('Ensure that 'OS disk' are encrypted') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-CMP-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-003": { "control_id": "8.2", "control_name": "Ensure that 'Endpoint protection solution' is installed on VMs", - "description": "The virtual machine does not have a recognised endpoint protection extension installed. CIS 8.2 requires that an approved endpoint protection solution is installed and running on all virtual machines. Without endpoint protection, malware and ransomware can execute without detection." + "description": "The virtual machine does not have a recognised endpoint protection extension installed. CIS 8.2 requires that an approved endpoint protection solution is installed and running on all virtual machines. Without endpoint protection, malware and ransomware can execute without detection.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.2", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.2 ('Ensure that 'Endpoint protection solution' is installed on VMs') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-CMP-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-004": { "control_id": "8.3", "control_name": "Ensure that 'OS patching' is enabled for virtual machines", - "description": "The virtual machine does not have automatic OS patching enabled. CIS 8.3 requires that OS patches are applied in a timely manner. Unpatched VMs are vulnerable to known exploits targeting unpatched OS vulnerabilities." + "description": "The virtual machine does not have automatic OS patching enabled. CIS 8.3 requires that OS patches are applied in a timely manner. Unpatched VMs are vulnerable to known exploits targeting unpatched OS vulnerabilities.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.3", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.3 ('Ensure that 'OS patching' is enabled for virtual machines') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-CMP-004 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-007": { "control_id": "N/A-CMP-007", "control_name": "Just-In-Time (JIT) VM access - Defender for Cloud recommendation, no numbered CIS Azure Foundations 2.0.0 control", - "description": "CIS Microsoft Azure Foundations Benchmark 2.0.0 has no numbered recommendation for Just-In-Time VM access (it is a Microsoft Defender for Cloud recommendation), so under the repository's one-CIS-ID-per-rule convention this rule is not assigned a fabricated control id. It is mapped under NIST CSF PR.AC-3, ISO 27001 A.13.1.1, and SOC 2 CC6.6 instead." + "description": "CIS Microsoft Azure Foundations Benchmark 2.0.0 has no numbered recommendation for Just-In-Time VM access (it is a Microsoft Defender for Cloud recommendation), so under the repository's one-CIS-ID-per-rule convention this rule is not assigned a fabricated control id. It is mapped under NIST CSF PR.AC-3, ISO 27001 A.13.1.1, and SOC 2 CC6.6 instead.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-CMP-007", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-CMP-007: Just-In-Time (JIT) VM access is a Microsoft Defender for Cloud recommendation, not a numbered CIS Azure Foundations 2.0.0 control) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-001": { "control_id": "N/A-KV-001", "control_name": "Key Vault soft-delete baseline (covered by the repository's CIS 8.5 purge-protection rule)", - "description": "Soft delete is part of CIS Azure Foundations 2.0.0 recommendation 8.5, which is assigned to AZ-KV-004 under the repository's one-CIS-ID-per-rule convention. This overlapping prerequisite check is explicitly not assigned a second numbered mapping." + "description": "Soft delete is part of CIS Azure Foundations 2.0.0 recommendation 8.5, which is assigned to AZ-KV-004 under the repository's one-CIS-ID-per-rule convention. This overlapping prerequisite check is explicitly not assigned a second numbered mapping.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-KV-001", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-KV-001: Key Vault soft-delete baseline (covered by the repository's CIS 8.5 purge-protection rule)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-003": { "control_id": "3.7", "control_name": "Ensure that storage accounts have lifecycle management policies configured", - "description": "Storage accounts without lifecycle management policies retain data indefinitely. This increases storage costs, expands the attack surface through accumulation of stale data, and may violate data retention compliance requirements. Lifecycle policies automate the transition and deletion of blobs based on age and access patterns." + "description": "Storage accounts without lifecycle management policies retain data indefinitely. This increases storage costs, expands the attack surface through accumulation of stale data, and may violate data retention compliance requirements. Lifecycle policies automate the transition and deletion of blobs based on age and access patterns.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.7", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 3.7 ('Ensure that storage accounts have lifecycle management policies configured') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-STOR-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-004": { "control_id": "3.3", "control_name": "Ensure Storage logging is enabled for Blob, Queue, and Table services for read, write, and delete requests", - "description": "Enabling diagnostic logging for Azure Storage blob, queue, and table services records read, write, and delete operations. Without logging, unauthorized access, data exfiltration, or destructive operations on storage services cannot be detected or investigated." + "description": "Enabling diagnostic logging for Azure Storage blob, queue, and table services records read, write, and delete operations. Without logging, unauthorized access, data exfiltration, or destructive operations on storage services cannot be detected or investigated.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.3", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 3.3 ('Ensure Storage logging is enabled for Blob, Queue, and Table services for read, write, and delete requests') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-STOR-004 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-005": { "control_id": "3.8", "control_name": "Ensure that storage accounts use geo-redundant replication", - "description": "Storage accounts configured with locally redundant (LRS) or zone-redundant (ZRS) replication do not replicate data outside the primary region. A regional disaster or prolonged outage could result in data unavailability or data loss. Geo-redundant storage (GRS or GZRS) replicates data asynchronously to a secondary Azure region, protecting against region-wide failures." + "description": "Storage accounts configured with locally redundant (LRS) or zone-redundant (ZRS) replication do not replicate data outside the primary region. A regional disaster or prolonged outage could result in data unavailability or data loss. Geo-redundant storage (GRS or GZRS) replicates data asynchronously to a secondary Azure region, protecting against region-wide failures.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.8", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 3.8 ('Ensure that storage accounts use geo-redundant replication') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-STOR-005 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-002": { "control_id": "8.7", "control_name": "Ensure that public network access to Key Vault is disabled", - "description": "Azure Key Vault should not allow public network access unless absolutely necessary. Enabling public access increases the attack surface and exposes sensitive secrets, keys, and certificates to potential unauthorized access. Private endpoints should be used to restrict access to trusted networks." + "description": "Azure Key Vault should not allow public network access unless absolutely necessary. Enabling public access increases the attack surface and exposes sensitive secrets, keys, and certificates to potential unauthorized access. Private endpoints should be used to restrict access to trusted networks.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.7", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.7 ('Ensure that public network access to Key Vault is disabled') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-KV-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-003": { "control_id": "8.4", "control_name": "Ensure that logging is enabled for Azure Key Vault", - "description": "Azure Key Vault diagnostic logging should be enabled so access to secrets, keys, and certificates is recorded. Without diagnostic logs, unauthorized access attempts and destructive operations cannot be investigated effectively." + "description": "Azure Key Vault diagnostic logging should be enabled so access to secrets, keys, and certificates is recorded. Without diagnostic logs, unauthorized access attempts and destructive operations cannot be investigated effectively.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.4", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.4 ('Ensure that logging is enabled for Azure Key Vault') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-KV-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-011": { "control_id": "6.5", "control_name": "Ensure that Network Watcher is enabled in all regions", - "description": "Network Watcher should be enabled in all regions where Azure resources are deployed. Network Watcher provides network monitoring, diagnostics, and logging capabilities essential for investigating network-level incidents." + "description": "Network Watcher should be enabled in all regions where Azure resources are deployed. Network Watcher provides network monitoring, diagnostics, and logging capabilities essential for investigating network-level incidents.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 6.5", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 6.5 ('Ensure that Network Watcher is enabled in all regions') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-011 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-012": { "control_id": "6.7", "control_name": "Ensure that Network Watcher flow logs are enabled for Network Security Groups", - "description": "A VNet flow log (or an existing legacy NSG flow log) should cover this virtual network's traffic so it can be audited and investigated. Microsoft blocks new NSG flow log creation as of 2025-06-30 and retires the feature on 2027-09-30, so VNet flow logs are the current, supported mechanism. Without either, lateral movement and suspicious network activity cannot be reconstructed." + "description": "A VNet flow log (or an existing legacy NSG flow log) should cover this virtual network's traffic so it can be audited and investigated. Microsoft blocks new NSG flow log creation as of 2025-06-30 and retires the feature on 2027-09-30, so VNet flow logs are the current, supported mechanism. Without either, lateral movement and suspicious network activity cannot be reconstructed.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 6.7", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 6.7 ('Ensure that Network Watcher flow logs are enabled for Network Security Groups') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-012 evaluates this exact setting (VNet flow logs, with the legacy NSG flow log mechanism Microsoft is retiring accepted as a fallback) via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-003": { "control_id": "4.3.6", "control_name": "Ensure SSL connection is enabled for PostgreSQL Flexible Server", - "description": "SSL enforcement should be enabled on PostgreSQL Flexible Server to ensure data in transit is encrypted. Without SSL, database connections transmit data in plaintext, exposing it to interception." + "description": "SSL enforcement should be enabled on PostgreSQL Flexible Server to ensure data in transit is encrypted. Without SSL, database connections transmit data in plaintext, exposing it to interception.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 4.3.6", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 4.3.6 ('Ensure SSL connection is enabled for PostgreSQL Flexible Server') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-DB-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-004": { "control_id": "8.5", "control_name": "Ensure the Key Vault is Recoverable", - "description": "Azure Key Vaults without purge protection enabled allow permanent deletion of vaults and their secrets, keys, and certificates during the soft-delete retention period. Even with soft delete enabled, a malicious insider or privileged account can purge vault objects before the retention period expires. Enabling purge protection prevents this by blocking purge operations for the full retention period." + "description": "Azure Key Vaults without purge protection enabled allow permanent deletion of vaults and their secrets, keys, and certificates during the soft-delete retention period. Even with soft delete enabled, a malicious insider or privileged account can purge vault objects before the retention period expires. Enabling purge protection prevents this by blocking purge operations for the full retention period.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.5", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.5 ('Ensure the Key Vault is Recoverable') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-KV-004 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-004": { "control_id": "4.1.2", "control_name": "Ensure that 'Allow access to Azure services' for SQL Servers is disabled", - "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall creates a rule that permits any Azure-hosted resource — including services from other tenants — to connect to the server. This significantly increases the attack surface. Access should be restricted to specific trusted IP ranges or private endpoints." + "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall creates a rule that permits any Azure-hosted resource \u2014 including services from other tenants \u2014 to connect to the server. This significantly increases the attack surface. Access should be restricted to specific trusted IP ranges or private endpoints.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 4.1.2", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 4.1.2 ('Ensure that 'Allow access to Azure services' for SQL Servers is disabled') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-DB-004 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-004": { "control_id": "1.16", "control_name": "Ensure that 'Privileged Identity Management' is used to manage privileged access", - "description": "Privileged Identity Management provides time-based and approval-based role activation to mitigate the risk of excessive, unnecessary, or misused access permissions on resources. Without PIM, admin roles are permanently assigned with no just-in-time controls or approval workflows." + "description": "Privileged Identity Management provides time-based and approval-based role activation to mitigate the risk of excessive, unnecessary, or misused access permissions on resources. Without PIM, admin roles are permanently assigned with no just-in-time controls or approval workflows.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 1.16", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 1.16 ('Ensure that 'Privileged Identity Management' is used to manage privileged access') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-IDN-004 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-005": { "control_id": "N/A-KV-005", "control_name": "Key Vault certificate renewal baseline (not directly mapped in CIS Azure Foundations 2.0.0)", - "description": "This rule detects certificates expiring within 30 days without automatic renewal. CIS Azure Foundations 2.0.0 contains certificate expiration-date recommendations, but does not directly prescribe this proactive 30-day renewal check, so no numbered mapping is claimed." + "description": "This rule detects certificates expiring within 30 days without automatic renewal. CIS Azure Foundations 2.0.0 contains certificate expiration-date recommendations, but does not directly prescribe this proactive 30-day renewal check, so no numbered mapping is claimed.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-KV-005", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-KV-005: Key Vault certificate renewal baseline (not directly mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-006": { "control_id": "8.6", "control_name": "Ensure that Azure Key Vault Uses Azure RBAC for Data Plane Authorization", - "description": "CIS Azure Foundations Benchmark 2.0.0 recommendation 8.6 requires Azure Key Vault to use the Azure RBAC permission model. Key Vaults using legacy access policies lack centrally auditable, scoped role assignments and increase the risk of over-privileged access to secrets, keys, and certificates." + "description": "CIS Azure Foundations Benchmark 2.0.0 recommendation 8.6 requires Azure Key Vault to use the Azure RBAC permission model. Key Vaults using legacy access policies lack centrally auditable, scoped role assignments and increase the risk of over-privileged access to secrets, keys, and certificates.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.6", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.6 ('Ensure that Azure Key Vault Uses Azure RBAC for Data Plane Authorization') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-KV-006 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-013": { "control_id": "6.4", "control_name": "Ensure that Azure Firewall is enabled on Virtual Networks", - "description": "Virtual networks should be protected by an Azure Firewall rather than relying on Network Security Groups alone. Azure Firewall provides centralized, stateful traffic inspection, FQDN and threat-intelligence filtering, and network-wide logging that NSGs cannot offer. VNets without an associated Azure Firewall lack a perimeter inspection and logging layer." + "description": "Virtual networks should be protected by an Azure Firewall rather than relying on Network Security Groups alone. Azure Firewall provides centralized, stateful traffic inspection, FQDN and threat-intelligence filtering, and network-wide logging that NSGs cannot offer. VNets without an associated Azure Firewall lack a perimeter inspection and logging layer.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 6.4", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 6.4 ('Ensure that Azure Firewall is enabled on Virtual Networks') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-013 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-014": { "control_id": "6.6", "control_name": "Ensure that VNet peering connections restrict gateway transit", - "description": "VNet peering connections with allowGatewayTransit or useRemoteGateways enabled allow traffic to route between network segments through shared gateways. This can break network segmentation and enable lateral movement between zones that should remain isolated. Peering connections should be reviewed and gateway transit disabled unless explicitly required and documented." + "description": "VNet peering connections with allowGatewayTransit or useRemoteGateways enabled allow traffic to route between network segments through shared gateways. This can break network segmentation and enable lateral movement between zones that should remain isolated. Peering connections should be reviewed and gateway transit disabled unless explicitly required and documented.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 6.6", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 6.6 ('Ensure that VNet peering connections restrict gateway transit') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-014 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-015": { "control_id": "9.8", "control_name": "Ensure public DNS zones do not expose private infrastructure details", - "description": "Public DNS zones that contain A records referencing RFC1918 private IP addresses or record names matching internal service keywords (such as admin, vpn, db, or internal) expose the organisation's internal network topology to external parties. CIS 9.8 requires that unnecessary public exposure is minimised. Such records should be removed from public DNS zones and migrated to Azure Private DNS zones linked to the appropriate virtual networks." + "description": "Public DNS zones that contain A records referencing RFC1918 private IP addresses or record names matching internal service keywords (such as admin, vpn, db, or internal) expose the organisation's internal network topology to external parties. CIS 9.8 requires that unnecessary public exposure is minimised. Such records should be removed from public DNS zones and migrated to Azure Private DNS zones linked to the appropriate virtual networks.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.8", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.8 ('Ensure public DNS zones do not expose private infrastructure details') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-NET-015 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-001": { "control_id": "9.9", "control_name": "Ensure TLS is enforced with quantum-safe configuration", - "description": "App Services configured with TLS versions below 1.3 use classical key exchange algorithms vulnerable to Harvest Now Decrypt Later attacks. CIS 9.9 requires that data in transit is protected using current encryption standards. Enforcing TLS 1.3 minimum reduces exposure to quantum-enabled decryption of captured traffic." + "description": "App Services configured with TLS versions below 1.3 use classical key exchange algorithms vulnerable to Harvest Now Decrypt Later attacks. CIS 9.9 requires that data in transit is protected using current encryption standards. Enforcing TLS 1.3 minimum reduces exposure to quantum-enabled decryption of captured traffic.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 9.9", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 9.9 ('Ensure TLS is enforced with quantum-safe configuration') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-PQC-001 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-002": { "control_id": "8.1", "control_name": "Ensure Key Vault keys use quantum-safe algorithms", - "description": "Key Vault keys using RSA or ECC algorithms are vulnerable to Shor's algorithm on quantum computers. CIS 8.1 requires that cryptographic key management follows current standards. Keys should be inventoried in a Cryptographic Bill of Materials and migration to post-quantum safe algorithms planned." + "description": "Key Vault keys using RSA or ECC algorithms are vulnerable to Shor's algorithm on quantum computers. CIS 8.1 requires that cryptographic key management follows current standards. Keys should be inventoried in a Cryptographic Bill of Materials and migration to post-quantum safe algorithms planned.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.1 ('Ensure Key Vault keys use quantum-safe algorithms') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-PQC-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-003": { "control_id": "8.9", "control_name": "Ensure certificates use quantum-safe signature algorithms", - "description": "Key Vault certificates signed with RSA or ECDSA are vulnerable to quantum attacks. CIS 8.9 requires that certificate management includes monitoring of algorithm strength. Certificates should be migrated to post-quantum safe signature algorithms such as ML-DSA when CA support is available." + "description": "Key Vault certificates signed with RSA or ECDSA are vulnerable to quantum attacks. CIS 8.9 requires that certificate management includes monitoring of algorithm strength. Certificates should be migrated to post-quantum safe signature algorithms such as ML-DSA when CA support is available.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 8.9", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 8.9 ('Ensure certificates use quantum-safe signature algorithms') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-PQC-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-001": { "control_id": "N/A-AKS-001", "control_name": "AKS private cluster baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends private AKS clusters to keep control-plane traffic on private networks. This OpenShield check is intentionally marked not applicable to the repository's CIS Azure Foundations 2.0.0 benchmark rather than claiming an unsupported CIS mapping." + "description": "Microsoft recommends private AKS clusters to keep control-plane traffic on private networks. This OpenShield check is intentionally marked not applicable to the repository's CIS Azure Foundations 2.0.0 benchmark rather than claiming an unsupported CIS mapping.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-AKS-001", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-AKS-001: AKS private cluster baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-002": { "control_id": "N/A-AKS-002", "control_name": "AKS local account baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends disabling AKS local accounts so authentication is governed through Microsoft Entra ID. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends disabling AKS local accounts so authentication is governed through Microsoft Entra ID. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-AKS-002", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-AKS-002: AKS local account baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-003": { "control_id": "N/A-AKS-003", "control_name": "AKS managed identity baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends managed identities instead of AKS service-principal credentials. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends managed identities instead of AKS service-principal credentials. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-AKS-003", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-AKS-003: AKS managed identity baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-004": { "control_id": "N/A-AKS-004", "control_name": "AKS Workload Identity baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends Workload Identity for scoped, secretless access from pods to Azure resources. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends Workload Identity for scoped, secretless access from pods to Azure resources. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-AKS-004", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-AKS-004: AKS Workload Identity baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-005": { "control_id": "N/A-AKS-005", "control_name": "AKS Azure Policy baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends the Azure Policy add-on for centralized Kubernetes governance. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends the Azure Policy add-on for centralized Kubernetes governance. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-AKS-005", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-AKS-005: AKS Azure Policy baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-006": { "control_id": "N/A-AKS-006", "control_name": "AKS node OS upgrade baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends a managed node OS upgrade channel for timely security patches. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends a managed node OS upgrade channel for timely security patches. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-AKS-006", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-AKS-006: AKS node OS upgrade baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-010": { "control_id": "N/A-IDN-010", "control_name": "App Registration ownership (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends accountable App Registration ownership. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends accountable App Registration ownership. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-IDN-010", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-IDN-010: App Registration ownership (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-011": { "control_id": "N/A-IDN-011", "control_name": "App Registration redirect URI security (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft requires secure redirect URI handling. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft requires secure redirect URI handling. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-IDN-011", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-IDN-011: App Registration redirect URI security (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-012": { "control_id": "N/A-IDN-012", "control_name": "OAuth implicit grant security (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends authorization code flow instead of implicit grant. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends authorization code flow instead of implicit grant. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-IDN-012", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-IDN-012: OAuth implicit grant security (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-013": { "control_id": "N/A-IDN-013", "control_name": "App Registration password credentials (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends managed identity, federation, or certificates instead of client secrets. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends managed identity, federation, or certificates instead of client secrets. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-IDN-013", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-IDN-013: App Registration password credentials (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-014": { "control_id": "N/A-IDN-014", "control_name": "Application-instance property lock (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends locking sensitive service-principal instance properties. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." + "description": "Microsoft recommends locking sensitive service-principal instance properties. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-IDN-014", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-IDN-014: Application-instance property lock (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-015": { "control_id": "N/A-IDN-015", "control_name": "Managed Identity least privilege (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends least-privilege roles and scopes for managed identities. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark." - }, - "AZ-FUNC-001": {"control_id":"N/A-FUNC-001","control_name":"Function App HTTPS enforcement","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific HTTPS control."}, - "AZ-FUNC-002": {"control_id":"N/A-FUNC-002","control_name":"Function App minimum TLS version","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific TLS control."}, - "AZ-FUNC-003": {"control_id":"N/A-FUNC-003","control_name":"Function App FTP publishing","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific publishing control."}, - "AZ-FUNC-004": {"control_id":"N/A-FUNC-004","control_name":"Function App remote debugging","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific debugging control."}, - "AZ-FUNC-005": {"control_id":"N/A-FUNC-005","control_name":"Function App managed identity","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific identity control."}, - "AZ-PE-001": {"control_id":"N/A-PE-001","control_name":"Storage public network access","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control."}, - "AZ-PE-002": {"control_id":"N/A-PE-002","control_name":"SQL public network access","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control."}, - "AZ-PE-003": {"control_id":"N/A-PE-003","control_name":"PostgreSQL public network access","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific private-networking control."}, - "AZ-PE-004": {"control_id":"N/A-PE-004","control_name":"App Service public network access","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control."}, - "AZ-PE-005": {"control_id":"N/A-PE-005","control_name":"Recovery Services public network access","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control."}, - "AZ-PE-006": {"control_id":"N/A-PE-006","control_name":"Private endpoint connection approval","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the private-endpoint connection state."}, - "AZ-BAK-001": {"control_id":"N/A-BAK-001","control_name":"Backup soft-delete protection","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup recovery control."}, - "AZ-BAK-002": {"control_id":"N/A-BAK-002","control_name":"Backup vault immutability","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup immutability control."}, - "AZ-BAK-004": {"control_id":"N/A-BAK-004","control_name":"Backup multi-user authorization","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup authorization control."}, - "AZ-BAK-006": {"control_id":"N/A-BAK-006","control_name":"Backup security monitoring","description":"No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup monitoring control."}, + "description": "Microsoft recommends least-privilege roles and scopes for managed identities. This check has no direct control in the repository's CIS Azure Foundations 2.0.0 benchmark.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-IDN-015", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-IDN-015: Managed Identity least privilege (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-FUNC-001": { + "control_id": "N/A-FUNC-001", + "control_name": "Function App HTTPS enforcement", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific HTTPS control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-FUNC-001", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-FUNC-001: Function App HTTPS enforcement) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-FUNC-002": { + "control_id": "N/A-FUNC-002", + "control_name": "Function App minimum TLS version", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific TLS control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-FUNC-002", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-FUNC-002: Function App minimum TLS version) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-FUNC-003": { + "control_id": "N/A-FUNC-003", + "control_name": "Function App FTP publishing", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific publishing control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-FUNC-003", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-FUNC-003: Function App FTP publishing) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-FUNC-004": { + "control_id": "N/A-FUNC-004", + "control_name": "Function App remote debugging", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific debugging control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-FUNC-004", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-FUNC-004: Function App remote debugging) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-FUNC-005": { + "control_id": "N/A-FUNC-005", + "control_name": "Function App managed identity", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific identity control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-FUNC-005", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-FUNC-005: Function App managed identity) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-PE-001": { + "control_id": "N/A-PE-001", + "control_name": "Storage public network access", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-PE-001", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-PE-001: Storage public network access) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-PE-002": { + "control_id": "N/A-PE-002", + "control_name": "SQL public network access", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-PE-002", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-PE-002: SQL public network access) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-PE-003": { + "control_id": "N/A-PE-003", + "control_name": "PostgreSQL public network access", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific private-networking control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-PE-003", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-PE-003: PostgreSQL public network access) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-PE-004": { + "control_id": "N/A-PE-004", + "control_name": "App Service public network access", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-PE-004", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-PE-004: App Service public network access) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-PE-005": { + "control_id": "N/A-PE-005", + "control_name": "Recovery Services public network access", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the service-specific Private Link control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-PE-005", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-PE-005: Recovery Services public network access) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-PE-006": { + "control_id": "N/A-PE-006", + "control_name": "Private endpoint connection approval", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the private-endpoint connection state.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-PE-006", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-PE-006: Private endpoint connection approval) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-BAK-001": { + "control_id": "N/A-BAK-001", + "control_name": "Backup soft-delete protection", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup recovery control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-BAK-001", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-BAK-001: Backup soft-delete protection) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-BAK-002": { + "control_id": "N/A-BAK-002", + "control_name": "Backup vault immutability", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup immutability control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-BAK-002", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-BAK-002: Backup vault immutability) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-BAK-004": { + "control_id": "N/A-BAK-004", + "control_name": "Backup multi-user authorization", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup authorization control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-BAK-004", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-BAK-004: Backup multi-user authorization) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, + "AZ-BAK-006": { + "control_id": "N/A-BAK-006", + "control_name": "Backup security monitoring", + "description": "No direct CIS Azure recommendation is assigned; OpenShield evaluates the Azure Backup monitoring control.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-BAK-006", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-BAK-006: Backup security monitoring) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null + }, "AZ-SC-001": { "control_id": "N/A-SC-001", "control_name": "Container Registry admin user baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends disabling the Azure Container Registry admin account in favor of individual Microsoft Entra identities. This check has no direct recommendation in CIS Azure Foundations 2.0.0." + "description": "Microsoft recommends disabling the Azure Container Registry admin account in favor of individual Microsoft Entra identities. This check has no direct recommendation in CIS Azure Foundations 2.0.0.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-001", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-001: Container Registry admin user baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-002": { "control_id": "N/A-SC-002", "control_name": "Container Registry public network baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends restricting Azure Container Registry network access with private endpoints or selected networks. This check has no direct recommendation in CIS Azure Foundations 2.0.0." + "description": "Microsoft recommends restricting Azure Container Registry network access with private endpoints or selected networks. This check has no direct recommendation in CIS Azure Foundations 2.0.0.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-002", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-002: Container Registry public network baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-003": { "control_id": "N/A-SC-003", "control_name": "Container Registry anonymous pull baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends disabling anonymous pull unless a registry intentionally distributes public images. This check has no direct recommendation in CIS Azure Foundations 2.0.0." + "description": "Microsoft recommends disabling anonymous pull unless a registry intentionally distributes public images. This check has no direct recommendation in CIS Azure Foundations 2.0.0.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-003", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-003: Container Registry anonymous pull baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-004": { "control_id": "N/A-SC-004", "control_name": "Container Registry retention and quarantine baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft documents retention and quarantine policies for managing untagged and potentially unsafe artifacts. This combined check has no direct recommendation in CIS Azure Foundations 2.0.0." + "description": "Microsoft documents retention and quarantine policies for managing untagged and potentially unsafe artifacts. This combined check has no direct recommendation in CIS Azure Foundations 2.0.0.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-004", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-004: Container Registry retention and quarantine baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-005": { "control_id": "N/A-SC-005", "control_name": "Terraform state container access baseline (not directly mapped in CIS Azure Foundations 2.0.0)", - "description": "Terraform state can contain sensitive infrastructure data and must not be anonymously readable. The repository does not claim a direct CIS recommendation because this rule specifically identifies Terraform state rather than evaluating every blob container." + "description": "Terraform state can contain sensitive infrastructure data and must not be anonymously readable. The repository does not claim a direct CIS recommendation because this rule specifically identifies Terraform state rather than evaluating every blob container.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-005", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-005: Terraform state container access baseline (not directly mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-006": { "control_id": "N/A-SC-006", "control_name": "Terraform state recovery baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends blob versioning and soft delete to recover Terraform state from accidental or malicious changes. This combined Terraform-specific check has no direct recommendation in CIS Azure Foundations 2.0.0." + "description": "Microsoft recommends blob versioning and soft delete to recover Terraform state from accidental or malicious changes. This combined Terraform-specific check has no direct recommendation in CIS Azure Foundations 2.0.0.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-006", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-006: Terraform state recovery baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-007": { "control_id": "N/A-SC-007", "control_name": "Pipeline service connection scope baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends least-privilege scopes for Azure DevOps service connections. Azure DevOps pipeline connection scope is outside the direct recommendations in CIS Azure Foundations 2.0.0." + "description": "Microsoft recommends least-privilege scopes for Azure DevOps service connections. Azure DevOps pipeline connection scope is outside the direct recommendations in CIS Azure Foundations 2.0.0.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-007", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-007: Pipeline service connection scope baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-008": { "control_id": "N/A-SC-008", "control_name": "Pipeline workload identity federation baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft recommends workload identity federation instead of stored service-principal secrets for Azure DevOps service connections. This check has no direct recommendation in CIS Azure Foundations 2.0.0." + "description": "Microsoft recommends workload identity federation instead of stored service-principal secrets for Azure DevOps service connections. This check has no direct recommendation in CIS Azure Foundations 2.0.0.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SC-008", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SC-008: Pipeline workload identity federation baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-001": { "control_id": "N/A-DL-001", "control_name": "ExpressRoute Direct MACsec baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft supports MACsec for encrypting ExpressRoute Direct physical links. CIS Azure Foundations 2.0.0 has no direct recommendation for ExpressRoute Direct MACsec." + "description": "Microsoft supports MACsec for encrypting ExpressRoute Direct physical links. CIS Azure Foundations 2.0.0 has no direct recommendation for ExpressRoute Direct MACsec.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-DL-001", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-DL-001: ExpressRoute Direct MACsec baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-002": { "control_id": "N/A-DL-002", "control_name": "ExpressRoute Direct XPN MACsec baseline (not mapped in CIS Azure Foundations 2.0.0)", - "description": "Microsoft requires the XPN cipher for MACsec on 100-Gbps ExpressRoute Direct ports. CIS Azure Foundations 2.0.0 has no direct recommendation for this link-layer setting." + "description": "Microsoft requires the XPN cipher for MACsec on 100-Gbps ExpressRoute Direct ports. CIS Azure Foundations 2.0.0 has no direct recommendation for this link-layer setting.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-DL-002", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-DL-002: ExpressRoute Direct XPN MACsec baseline (not mapped in CIS Azure Foundations 2.0.0)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-016": { "control_id": "N/A-NET-016", "control_name": "Network interface IP forwarding review (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Azure recommends disabling NIC IP forwarding unless the interface belongs to a reviewed routing function, but CIS Azure Foundations 2.0.0 does not assign this check a direct recommendation number." + "description": "Azure recommends disabling NIC IP forwarding unless the interface belongs to a reviewed routing function, but CIS Azure Foundations 2.0.0 does not assign this check a direct recommendation number.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-016", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-016: Network interface IP forwarding review (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-017": { "control_id": "N/A-NET-017", "control_name": "Direct Internet default route review (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Azure exposes and documents user-defined Internet next hops, but CIS Azure Foundations 2.0.0 does not assign this route check a direct recommendation number." + "description": "Azure exposes and documents user-defined Internet next hops, but CIS Azure Foundations 2.0.0 does not assign this route check a direct recommendation number.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-017", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-017: Direct Internet default route review (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-018": { "control_id": "N/A-NET-018", "control_name": "Private Endpoint public access baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private connectivity should replace unnecessary public PaaS exposure; CIS Azure Foundations 2.0.0 has no universal control covering every supported Private Link target." + "description": "Private connectivity should replace unnecessary public PaaS exposure; CIS Azure Foundations 2.0.0 has no universal control covering every supported Private Link target.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-018", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-018: Private Endpoint public access baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-019": { "control_id": "N/A-NET-019", "control_name": "Private Endpoint connection approval baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private Endpoint connections must be approved to provide the intended private path; no universal CIS Azure Foundations 2.0.0 recommendation covers this state." + "description": "Private Endpoint connections must be approved to provide the intended private path; no universal CIS Azure Foundations 2.0.0 recommendation covers this state.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-019", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-019: Private Endpoint connection approval baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-020": { "control_id": "N/A-NET-020", "control_name": "Private Endpoint DNS association baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private Endpoints require service-appropriate private DNS integration; CIS Azure Foundations 2.0.0 has no universal recommendation for this association." + "description": "Private Endpoints require service-appropriate private DNS integration; CIS Azure Foundations 2.0.0 has no universal recommendation for this association.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-020", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-020: Private Endpoint DNS association baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-021": { "control_id": "N/A-NET-021", - "control_name": "Private Endpoint custom DNS configuration baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private Endpoint custom DNS configuration should associate service names with private addresses. This is ARM configuration evidence, not an effective-resolution probe; CIS Azure Foundations 2.0.0 has no universal recommendation for it." + "control_name": "Private Endpoint FQDN resolution baseline (no direct CIS Azure Foundations 2.0.0 control)", + "description": "Private Endpoint names should resolve to private addresses; CIS Azure Foundations 2.0.0 has no universal recommendation for this resolution evidence.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-021", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-021: Private Endpoint FQDN resolution baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-022": { "control_id": "N/A-NET-022", "control_name": "Critical PaaS public exposure baseline (no universal CIS Azure Foundations 2.0.0 control)", - "description": "Critical PaaS resources should use private access or an approved exception; CIS Azure Foundations 2.0.0 provides service-specific rather than universal coverage." + "description": "Critical PaaS resources should use private access or an approved exception; CIS Azure Foundations 2.0.0 provides service-specific rather than universal coverage.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-022", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-022: Critical PaaS public exposure baseline (no universal CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-023": { "control_id": "N/A-NET-023", "control_name": "Azure Firewall threat intelligence enforcement baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Deny mode blocks traffic involving known malicious addresses and domains; CIS Azure Foundations 2.0.0 has no direct recommendation for this mode." + "description": "AlertAndDeny blocks traffic involving known malicious addresses and domains; CIS Azure Foundations 2.0.0 has no direct recommendation for this mode.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-023", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-023: Azure Firewall threat intelligence enforcement baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-024": { "control_id": "N/A-NET-024", "control_name": "Application Gateway WAF Prevention mode baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Prevention mode blocks matching application attacks; CIS Azure Foundations 2.0.0 has no direct recommendation for the gateway mode." + "description": "Prevention mode blocks matching application attacks; CIS Azure Foundations 2.0.0 has no direct recommendation for the gateway mode.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-024", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-024: Application Gateway WAF Prevention mode baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-025": { "control_id": "N/A-NET-025", "control_name": "Application Gateway WAF diagnostic logging baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "SKU-supported Application Gateway diagnostic logs support perimeter monitoring. Performance logging is required on v1; v2 exposes performance telemetry through metrics. CIS Azure Foundations 2.0.0 has no direct universal recommendation for these categories." + "description": "Access, performance, and firewall logs support perimeter monitoring; CIS Azure Foundations 2.0.0 has no direct universal recommendation for all categories.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-025", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-025: Application Gateway WAF diagnostic logging baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-026": { "control_id": "N/A-NET-026", "control_name": "Current WAF managed rules and bot protection baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Current base and bot managed rule sets protect the application perimeter; CIS Azure Foundations 2.0.0 has no direct rule-set-version recommendation." + "description": "Current base and bot managed rule sets protect the application perimeter; CIS Azure Foundations 2.0.0 has no direct rule-set-version recommendation.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-026", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-026: Current WAF managed rules and bot protection baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-027": { "control_id": "N/A-NET-027", "control_name": "Internet-facing application rate limiting baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Rate limiting protects public applications from abusive request volume; CIS Azure Foundations 2.0.0 has no direct Application Gateway rate-rule recommendation." + "description": "Rate limiting protects public applications from abusive request volume; CIS Azure Foundations 2.0.0 has no direct Application Gateway rate-rule recommendation.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-NET-027", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-NET-027: Internet-facing application rate limiting baseline (no direct CIS Azure Foundations 2.0.0 control)) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-001": { "control_id": "5.1.1", "control_name": "Ensure that a 'Diagnostic Setting' exists", - "description": "The subscription's Activity Log has no diagnostic setting exporting it to an organisation-approved central destination. CIS 5.1.1 requires a diagnostic setting exporting the Activity Log so administrative, security, and policy events are retained beyond the platform default and available for centralized analysis." + "description": "The subscription's Activity Log has no diagnostic setting exporting it to an organisation-approved central destination. CIS 5.1.1 requires a diagnostic setting exporting the Activity Log so administrative, security, and policy events are retained beyond the platform default and available for centralized analysis.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 5.1.1", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 5.1.1 ('Ensure that a 'Diagnostic Setting' exists') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-SECOPS-001 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-002": { "control_id": "5.1.2", "control_name": "Ensure Diagnostic Setting captures appropriate categories", - "description": "An Activity Log diagnostic setting exists but does not enable every required category (Administrative, Security, Policy, ServiceHealth). CIS 5.1.2 requires the diagnostic setting to capture all appropriate categories, not just an arbitrary subset." + "description": "An Activity Log diagnostic setting exists but does not enable every required category (Administrative, Security, Policy, ServiceHealth). CIS 5.1.2 requires the diagnostic setting to capture all appropriate categories, not just an arbitrary subset.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 5.1.2", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 5.1.2 ('Ensure Diagnostic Setting captures appropriate categories') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-SECOPS-002 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-003": { "control_id": "5.4", "control_name": "Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it", - "description": "A critical resource (as defined by the organisation's security-operations policy) has no diagnostic setting exporting to an approved destination. CIS 5.4 requires resource-level logging to be enabled for all services that support it so activity on individual resources is captured, not just subscription-level events." + "description": "A critical resource (as defined by the organisation's security-operations policy) has no diagnostic setting exporting to an approved destination. CIS 5.4 requires resource-level logging to be enabled for all services that support it so activity on individual resources is captured, not just subscription-level events.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 5.4", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 5.4 ('Ensure that Azure Monitor Resource Logging is Enabled for All Services that Support it') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-SECOPS-003 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-004": { "control_id": "N/A-SECOPS-004", "control_name": "Security log retention below organisation minimum", - "description": "A Storage Account log export's retention_policy is disabled or set below the organisation's minimum retention requirement. The CIS Azure Foundations Benchmark addresses diagnostic-setting existence (5.1.1) and category coverage (5.1.2) as distinct numbered controls but does not assign its own control ID to the specific retention-duration value, so no single CIS control maps 1:1 to this rule." + "description": "A Storage Account log export's retention_policy is disabled or set below the organisation's minimum retention requirement. The CIS Azure Foundations Benchmark addresses diagnostic-setting existence (5.1.1) and category coverage (5.1.2) as distinct numbered controls but does not assign its own control ID to the specific retention-duration value, so no single CIS control maps 1:1 to this rule.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SECOPS-004", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SECOPS-004: Security log retention below organisation minimum) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-005": { "control_id": "N/A-SECOPS-005", "control_name": "Security logs stored only in a workload-administrator-modifiable destination", - "description": "A critical resource's only log export destination sits in the same resource group as the workload, so an administrator of that workload can alter or delete the exported logs. The CIS Azure Foundations Benchmark does not have a numbered control for log-destination ownership or tamper-protection separation of duties." + "description": "A critical resource's only log export destination sits in the same resource group as the workload, so an administrator of that workload can alter or delete the exported logs. The CIS Azure Foundations Benchmark does not have a numbered control for log-destination ownership or tamper-protection separation of duties.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SECOPS-005", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SECOPS-005: Security logs stored only in a workload-administrator-modifiable destination) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-006": { "control_id": "N/A-SECOPS-006", "control_name": "Required Microsoft Defender for Cloud plan not enabled", - "description": "An organisation-required Microsoft Defender for Cloud plan is not set to the 'Standard' pricing tier. CIS assigns each Defender plan its own leaf control (e.g. 2.1.1 Servers, 2.1.7 Storage, 2.1.4 Azure SQL Databases); because this rule evaluates whichever plans the organisation configures as required, no single fixed CIS control ID applies at the rule level (the matching per-plan CIS control is recorded on each finding's metadata instead)." + "description": "An organisation-required Microsoft Defender for Cloud plan is not set to the 'Standard' pricing tier. CIS assigns each Defender plan its own leaf control (e.g. 2.1.1 Servers, 2.1.7 Storage, 2.1.4 Azure SQL Databases); because this rule evaluates whichever plans the organisation configures as required, no single fixed CIS control ID applies at the rule level (the matching per-plan CIS control is recorded on each finding's metadata instead).", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SECOPS-006", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SECOPS-006: Required Microsoft Defender for Cloud plan not enabled) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-007": { "control_id": "2.1.13", "control_name": "Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed'", - "description": "A High-severity Microsoft Defender for Cloud recommendation remains Unhealthy beyond the organisation's remediation SLA. CIS 2.1.13 requires Defender recommendations to reach a 'Completed'/remediated status rather than being left open indefinitely; this rule generalizes that expectation to all High-severity recommendations against an organisation-defined SLA rather than only the update-management recommendation." + "description": "A High-severity Microsoft Defender for Cloud recommendation remains Unhealthy beyond the organisation's remediation SLA. CIS 2.1.13 requires Defender recommendations to reach a 'Completed'/remediated status rather than being left open indefinitely; this rule generalizes that expectation to all High-severity recommendations against an organisation-defined SLA rather than only the update-management recommendation.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 2.1.13", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 2.1.13 ('Ensure that Microsoft Defender Recommendation for 'Apply system updates' status is 'Completed'') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-SECOPS-007 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-008": { "control_id": "N/A-SECOPS-008", "control_name": "Required Microsoft Sentinel data connector disconnected or unhealthy", - "description": "A required Microsoft Sentinel data connector is missing or has no enabled data type on a Sentinel-onboarded workspace. The CIS Azure Foundations Benchmark is an infrastructure-configuration benchmark and does not include SIEM/XDR operational controls such as Sentinel connector health." + "description": "A required Microsoft Sentinel data connector is missing or has no enabled data type on a Sentinel-onboarded workspace. The CIS Azure Foundations Benchmark is an infrastructure-configuration benchmark and does not include SIEM/XDR operational controls such as Sentinel connector health.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SECOPS-008", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SECOPS-008: Required Microsoft Sentinel data connector disconnected or unhealthy) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-009": { "control_id": "N/A-SECOPS-009", "control_name": "Sentinel missing required high-severity analytics coverage", - "description": "A Sentinel-onboarded workspace has no enabled High-severity analytics rule covering an organisation-required detection use case. The CIS Azure Foundations Benchmark does not evaluate SIEM detection content or analytics coverage." + "description": "A Sentinel-onboarded workspace has no enabled High-severity analytics rule covering an organisation-required detection use case. The CIS Azure Foundations Benchmark does not evaluate SIEM detection content or analytics coverage.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control N/A-SECOPS-009", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 has no numbered control this rule maps to (N/A-SECOPS-009: Sentinel missing required high-severity analytics coverage) - this rule's evidence is not counted as a CIS pass/fail because there is no corresponding CIS requirement for it to be evidence of.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-010": { "control_id": "2.1.20", "control_name": "Ensure That 'Notify about alerts with the following severity' is Set to 'High'", - "description": "No enabled Azure Monitor action group with a notification receiver exists, and no Sentinel automation rule routes incidents onward. CIS 2.1.20 requires Defender security alerts to notify a monitored destination; this rule generalizes that requirement to the concrete Azure notification primitive (action groups) and the Sentinel-native incident routing mechanism (automation rules)." - }, - "AZ-NET-018": { - "control_id": "N/A-NET-018", - "control_name": "Private Endpoint public access baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private connectivity should replace unnecessary public PaaS exposure; CIS Azure Foundations 2.0.0 has no universal control covering every supported Private Link target." - }, - "AZ-NET-019": { - "control_id": "N/A-NET-019", - "control_name": "Private Endpoint connection approval baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private Endpoint connections must be approved to provide the intended private path; no universal CIS Azure Foundations 2.0.0 recommendation covers this state." - }, - "AZ-NET-020": { - "control_id": "N/A-NET-020", - "control_name": "Private Endpoint DNS association baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private Endpoints require service-appropriate private DNS integration; CIS Azure Foundations 2.0.0 has no universal recommendation for this association." - }, - "AZ-NET-021": { - "control_id": "N/A-NET-021", - "control_name": "Private Endpoint FQDN resolution baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Private Endpoint names should resolve to private addresses; CIS Azure Foundations 2.0.0 has no universal recommendation for this resolution evidence." - }, - "AZ-NET-022": { - "control_id": "N/A-NET-022", - "control_name": "Critical PaaS public exposure baseline (no universal CIS Azure Foundations 2.0.0 control)", - "description": "Critical PaaS resources should use private access or an approved exception; CIS Azure Foundations 2.0.0 provides service-specific rather than universal coverage." - }, - "AZ-NET-023": { - "control_id": "N/A-NET-023", - "control_name": "Azure Firewall threat intelligence enforcement baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "AlertAndDeny blocks traffic involving known malicious addresses and domains; CIS Azure Foundations 2.0.0 has no direct recommendation for this mode." - }, - "AZ-NET-024": { - "control_id": "N/A-NET-024", - "control_name": "Application Gateway WAF Prevention mode baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Prevention mode blocks matching application attacks; CIS Azure Foundations 2.0.0 has no direct recommendation for the gateway mode." - }, - "AZ-NET-025": { - "control_id": "N/A-NET-025", - "control_name": "Application Gateway WAF diagnostic logging baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Access, performance, and firewall logs support perimeter monitoring; CIS Azure Foundations 2.0.0 has no direct universal recommendation for all categories." - }, - "AZ-NET-026": { - "control_id": "N/A-NET-026", - "control_name": "Current WAF managed rules and bot protection baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Current base and bot managed rule sets protect the application perimeter; CIS Azure Foundations 2.0.0 has no direct rule-set-version recommendation." - }, - "AZ-NET-027": { - "control_id": "N/A-NET-027", - "control_name": "Internet-facing application rate limiting baseline (no direct CIS Azure Foundations 2.0.0 control)", - "description": "Rate limiting protects public applications from abusive request volume; CIS Azure Foundations 2.0.0 has no direct Application Gateway rate-rule recommendation." + "description": "No enabled Azure Monitor action group with a notification receiver exists, and no Sentinel automation rule routes incidents onward. CIS 2.1.20 requires Defender security alerts to notify a monitored destination; this rule generalizes that requirement to the concrete Azure notification primitive (action groups) and the Sentinel-native incident routing mechanism (automation rules).", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 2.1.20", + "rationale": "CIS Microsoft Azure Foundations Benchmark v2.0.0 control 2.1.20 ('Ensure That 'Notify about alerts with the following severity' is Set to 'High'') is a specific, automatable Azure configuration requirement. OpenShield rule AZ-SECOPS-010 evaluates this exact setting via the Azure Resource Manager/Graph API, so its PASS/FAIL result is direct technical evidence for this control.", + "owner": null, + "review_status": "pending_review", + "review_date": null } } } diff --git a/compliance/frameworks/enisa_pqc.json b/compliance/frameworks/enisa_pqc.json index 839a8234..5491f6d0 100644 --- a/compliance/frameworks/enisa_pqc.json +++ b/compliance/frameworks/enisa_pqc.json @@ -2,27 +2,52 @@ "framework": "ENISA Post-Quantum Cryptography Recommendations", "version": "2021", "published": "2021-05", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "OpenShield compliance mapping pack, authored against ENISA post-quantum cryptography recommendations (2021). Technical-evidence mapping only.", + "mapping_pack_published": "2026-08-22", "controls": { "AZ-PQC-001": { "control_id": "ENISA-PQC-HYBRID", "control_name": "Protect communications with quantum-resistant designs", "description": "Assess classical TLS key establishment for quantum exposure and prepare hybrid implementations that combine pre-quantum and post-quantum mechanisms while protocols and products mature.", "framework": "ENISA Post-Quantum Cryptography Recommendations", - "url": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation" + "url": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation", + "rationale": "ENISA Post-Quantum Cryptography Recommendations control ENISA-PQC-HYBRID ('Protect communications with quantum-resistant designs') directly specifies the quantum-safe migration practice that OpenShield rule AZ-PQC-001 evaluates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-002": { "control_id": "ENISA-PQC-INVENTORY", "control_name": "Inventory and transition quantum-vulnerable keys", "description": "Identify RSA and elliptic-curve keys, assess their use cases and security lifetime, and prepare migration to standardised quantum-resistant key establishment and signature schemes.", "framework": "ENISA Post-Quantum Cryptography Recommendations", - "url": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation" + "url": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation", + "rationale": "ENISA Post-Quantum Cryptography Recommendations control ENISA-PQC-INVENTORY ('Inventory and transition quantum-vulnerable keys') directly specifies the quantum-safe migration practice that OpenShield rule AZ-PQC-002 evaluates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-003": { "control_id": "ENISA-PQC-INTEGRATION", "control_name": "Integrate post-quantum signatures into PKI", "description": "Evaluate certificate and protocol dependencies, account for the operational trade-offs of post-quantum signatures, and design migration paths that retain security throughout the transition.", "framework": "ENISA Post-Quantum Cryptography Recommendations", - "url": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation" + "url": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "https://www.enisa.europa.eu/publications/post-quantum-cryptography-current-state-and-quantum-mitigation", + "rationale": "ENISA Post-Quantum Cryptography Recommendations control ENISA-PQC-INTEGRATION ('Integrate post-quantum signatures into PKI') directly specifies the quantum-safe migration practice that OpenShield rule AZ-PQC-003 evaluates.", + "owner": null, + "review_status": "pending_review", + "review_date": null } } } diff --git a/compliance/frameworks/iso27001.json b/compliance/frameworks/iso27001.json index 2f2ee5c6..b5a30d38 100644 --- a/compliance/frameworks/iso27001.json +++ b/compliance/frameworks/iso27001.json @@ -2,586 +2,1282 @@ "framework": "ISO/IEC 27001:2013", "version": "2013", "published": "2013-10", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "OpenShield compliance mapping pack, authored against ISO/IEC 27001:2013 Annex A control text. Technical-evidence mapping only; not a certification statement and not a substitute for a certification body's audit.", + "mapping_pack_published": "2026-08-22", "controls": { "AZ-STOR-001": { "control_id": "A.9.4.1", "control_name": "Information access restriction", - "description": "Public blob access allows unrestricted access to information stored in Azure Storage. Access to information and application system functions should be restricted in accordance with the access control policy." + "description": "Public blob access allows unrestricted access to information stored in Azure Storage. Access to information and application system functions should be restricted in accordance with the access control policy.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.4.1 ('Information access restriction') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-STOR-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-002": { "control_id": "A.10.1.1", "control_name": "Policy on the use of cryptographic controls", - "description": "Requiring secure transfer ensures cryptographic controls are applied to data in transit. A policy on the use of cryptographic controls for protection of information should be developed and implemented." + "description": "Requiring secure transfer ensures cryptographic controls are applied to data in transit. A policy on the use of cryptographic controls for protection of information should be developed and implemented.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.10.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.10.1.1 ('Policy on the use of cryptographic controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-STOR-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-001": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Unrestricted SSH access from the internet violates network access controls. Networks should be managed and controlled to protect information in systems and applications." + "description": "Unrestricted SSH access from the internet violates network access controls. Networks should be managed and controlled to protect information in systems and applications.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-002": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Unrestricted RDP access from the internet violates network access controls. Networks should be managed and controlled to protect information in systems and applications." + "description": "Unrestricted RDP access from the internet violates network access controls. Networks should be managed and controlled to protect information in systems and applications.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-003": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Unrestricted inbound access on port 443 from the internet increases exposure. Networks should be managed and controlled with appropriate restrictions on inbound traffic to protect information systems." + "description": "Unrestricted inbound access on port 443 from the internet increases exposure. Networks should be managed and controlled with appropriate restrictions on inbound traffic to protect information systems.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-004": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "NSGs with no rules provide no network controls. Networks should be managed and controlled with explicit rules that restrict traffic to what is required for the workload." + "description": "NSGs with no rules provide no network controls. Networks should be managed and controlled with explicit rules that restrict traffic to what is required for the workload.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-005": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Virtual networks without DDoS protection are vulnerable to availability attacks. Network controls should include protection against denial of service attacks to maintain availability of information systems." + "description": "Virtual networks without DDoS protection are vulnerable to availability attacks. Network controls should include protection against denial of service attacks to maintain availability of information systems.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-006": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Unassociated public IP addresses represent unnecessary network exposure. Network resources that are no longer required should be removed to minimise the attack surface." + "description": "Unassociated public IP addresses represent unnecessary network exposure. Network resources that are no longer required should be removed to minimise the attack surface.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-007": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Application Gateways without WAF provide no protection against web application attacks. Network controls should include application layer filtering to protect against common web exploits." + "description": "Application Gateways without WAF provide no protection against web application attacks. Network controls should include application layer filtering to protect against common web exploits.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-007 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-008": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Load balancers with no backend pool are unused resources. Unused network resources should be removed as part of regular network hygiene to maintain an accurate and minimal network topology." + "description": "Load balancers with no backend pool are unused resources. Unused network resources should be removed as part of regular network hygiene to maintain an accurate and minimal network topology.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-008 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-009": { "control_id": "A.13.2.1", "control_name": "Information transfer policies and procedures", - "description": "VPN connections using IKEv1 use an outdated protocol. Information transfer policies should require the use of current secure protocols to protect data in transit between networks." + "description": "VPN connections using IKEv1 use an outdated protocol. Information transfer policies should require the use of current secure protocols to protect data in transit between networks.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.2.1 ('Information transfer policies and procedures') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-009 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-010": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Subnets without NSGs have no network layer access controls. All subnets should have NSGs attached with explicit rules to enforce network controls at the subnet boundary." + "description": "Subnets without NSGs have no network layer access controls. All subnets should have NSGs attached with explicit rules to enforce network controls at the subnet boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-010 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-001": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "Service principals with overly broad permissions violate privileged access management. The allocation and use of privileged access rights should be restricted and controlled." + "description": "Service principals with overly broad permissions violate privileged access management. The allocation and use of privileged access rights should be restricted and controlled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-002": { "control_id": "A.9.4.2", "control_name": "Secure log-on procedures", - "description": "MFA enforces secure log-on for privileged accounts. Where required by the access control policy, access to systems and applications should be controlled by a secure log-on procedure." + "description": "MFA enforces secure log-on for privileged accounts. Where required by the access control policy, access to systems and applications should be controlled by a secure log-on procedure.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.4.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.4.2 ('Secure log-on procedures') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-003": { "control_id": "A.9.2.1", "control_name": "User registration and de-registration", - "description": "Unrestricted guest user invitations allow any organisation member to register external identities into the tenant without centralised review or approval. A.9.2.1 requires that users and external parties should be registered before access." + "description": "Unrestricted guest user invitations allow any organisation member to register external identities into the tenant without centralised review or approval. A.9.2.1 requires that users and external parties should be registered before access.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.1 ('User registration and de-registration') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-005": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "The allocation and use of privileged access rights must be restricted and controlled. Guest accounts in Entra ID with high privilege roles represent uncontrolled privileged access by external identities. A.9.2.3 requires that the allocation of privileged access rights is controlled through a formal authorisation process and that privileged roles are assigned only to internal accounts with a verified business need." + "description": "The allocation and use of privileged access rights must be restricted and controlled. Guest accounts in Entra ID with high privilege roles represent uncontrolled privileged access by external identities. A.9.2.3 requires that the allocation of privileged access rights is controlled through a formal authorisation process and that privileged roles are assigned only to internal accounts with a verified business need.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-006": { "control_id": "A.9.4.3", "control_name": "Password management system", - "description": "Service principal client secrets with no expiry or older than 90 days violate password management controls. A.9.4.3 requires that password management systems enforce quality and lifecycle requirements including regular rotation. Non-expiring secrets must have an expiry date set and secrets older than 90 days must be rotated immediately." + "description": "Service principal client secrets with no expiry or older than 90 days violate password management controls. A.9.4.3 requires that password management systems enforce quality and lifecycle requirements including regular rotation. Non-expiring secrets must have an expiry date set and secrets older than 90 days must be rotated immediately.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.4.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.4.3 ('Password management system') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-007": { "control_id": "A.9.4.2", "control_name": "Secure log-on procedures", - "description": "Users without MFA registered in Entra ID authenticate with a single factor, which does not meet secure log-on requirements. A.9.4.2 requires that access to systems and applications is controlled by a secure log-on procedure. Multi-factor authentication must be required for all active user accounts to prevent unauthorised access through compromised passwords." + "description": "Users without MFA registered in Entra ID authenticate with a single factor, which does not meet secure log-on requirements. A.9.4.2 requires that access to systems and applications is controlled by a secure log-on procedure. Multi-factor authentication must be required for all active user accounts to prevent unauthorised access through compromised passwords.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.4.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.4.2 ('Secure log-on procedures') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-007 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-008": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "Custom RBAC roles with wildcard permissions at subscription scope are a form of uncontrolled privileged access that is harder to audit than built-in roles. A.9.2.3 requires that privileged access rights are allocated only through a formal authorisation process and are regularly reviewed. Custom roles with wildcard actions must be narrowed to specific required permissions or removed if unused." + "description": "Custom RBAC roles with wildcard permissions at subscription scope are a form of uncontrolled privileged access that is harder to audit than built-in roles. A.9.2.3 requires that privileged access rights are allocated only through a formal authorisation process and are regularly reviewed. Custom roles with wildcard actions must be narrowed to specific required permissions or removed if unused.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-008 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-009": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "Subscriptions without an activity log alert for role assignment changes fail to generate actionable security events when privileged access is granted. A.12.4.1 requires that event logs recording user activities and security-relevant events are produced and maintained. An activity log alert for Microsoft.Authorization/roleAssignments/write must be configured and routed to a monitored channel." + "description": "Subscriptions without an activity log alert for role assignment changes fail to generate actionable security events when privileged access is granted. A.12.4.1 requires that event logs recording user activities and security-relevant events are produced and maintained. An activity log alert for Microsoft.Authorization/roleAssignments/write must be configured and routed to a monitored channel.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-009 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-001": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Public network access to PostgreSQL servers should be disabled. Database servers should only be accessible via private network connections with appropriate network controls in place." + "description": "Public network access to PostgreSQL servers should be disabled. Database servers should only be accessible via private network connections with appropriate network controls in place.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-DB-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-002": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "SQL Server auditing must be enabled to provide event logs. Event logs recording user activities, exceptions, faults and information security events should be produced and kept available." + "description": "SQL Server auditing must be enabled to provide event logs. Event logs recording user activities, exceptions, faults and information security events should be produced and kept available.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-DB-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-001": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Virtual machines with public IPs and no NSG have unrestricted network access. Network controls should be applied to all compute resources accessible from the internet." + "description": "Virtual machines with public IPs and no NSG have unrestricted network access. Network controls should be applied to all compute resources accessible from the internet.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-CMP-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-002": { "control_id": "A.10.1.1", "control_name": "Policy on the use of cryptographic controls", - "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). A.10.1.1 requires that a policy on the use of cryptographic controls is developed and implemented." + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). A.10.1.1 requires that a policy on the use of cryptographic controls is developed and implemented.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.10.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.10.1.1 ('Policy on the use of cryptographic controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-CMP-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-004": { "control_id": "A.12.6.1", "control_name": "Management of technical vulnerabilities", - "description": "The virtual machine does not have automatic OS patching enabled. A.12.6.1 requires that information about technical vulnerabilities is obtained and the organisation's exposure evaluated. Without automatic patching, known OS vulnerabilities remain unmitigated." + "description": "The virtual machine does not have automatic OS patching enabled. A.12.6.1 requires that information about technical vulnerabilities is obtained and the organisation's exposure evaluated. Without automatic patching, known OS vulnerabilities remain unmitigated.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.6.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.6.1 ('Management of technical vulnerabilities') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-CMP-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-007": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "A VM has management ports (SSH/RDP) open to the internet with no Just-In-Time VM access policy covering them. A.13.1.1 requires network controls that manage and protect access to systems. JIT limits management-port exposure to approved, time-boxed windows." + "description": "A VM has management ports (SSH/RDP) open to the internet with no Just-In-Time VM access policy covering them. A.13.1.1 requires network controls that manage and protect access to systems. JIT limits management-port exposure to approved, time-boxed windows.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-CMP-007 evaluates one Azure technical setting (Just-In-Time VM access coverage for open management ports) that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-003": { "control_id": "A.12.2.1", "control_name": "Controls against malware", - "description": "The virtual machine does not have a recognised endpoint protection extension installed. A.12.2.1 requires that detection, prevention and recovery controls are implemented to protect against malware. Without endpoint protection, malware executing on the VM will not be detected or prevented." + "description": "The virtual machine does not have a recognised endpoint protection extension installed. A.12.2.1 requires that detection, prevention and recovery controls are implemented to protect against malware. Without endpoint protection, malware executing on the VM will not be detected or prevented.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.2.1 ('Controls against malware') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-CMP-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-001": { "control_id": "A.17.2.1", "control_name": "Availability of information processing facilities", - "description": "Key Vault soft delete protects against loss of secrets, keys and certificates. Without soft delete, deleted vault objects cannot be recovered, reducing availability and recoverability of cryptographic material." + "description": "Key Vault soft delete protects against loss of secrets, keys and certificates. Without soft delete, deleted vault objects cannot be recovered, reducing availability and recoverability of cryptographic material.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.17.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.17.2.1 ('Availability of information processing facilities') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-KV-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-003": { "control_id": "A.8.3.1", "control_name": "Management of removable media", - "description": "Storage accounts without lifecycle policies retain data indefinitely with no automated disposal mechanism. Lifecycle management supports formal retention, tiering, and disposal procedures." + "description": "Storage accounts without lifecycle policies retain data indefinitely with no automated disposal mechanism. Lifecycle management supports formal retention, tiering, and disposal procedures.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.8.3.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.8.3.1 ('Management of removable media') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-STOR-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-004": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "Diagnostic logging must be enabled on Azure Storage blob, queue, and table services to produce event logs for read, write, and delete operations. Event logs recording user activities should be kept available." + "description": "Diagnostic logging must be enabled on Azure Storage blob, queue, and table services to produce event logs for read, write, and delete operations. Event logs recording user activities should be kept available.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-STOR-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-005": { "control_id": "A.17.2.1", "control_name": "Availability of information processing facilities", - "description": "Storage accounts using LRS or ZRS replication retain data only within a single region, providing no protection against regional outages or disasters. A regional disaster could result in complete data loss." + "description": "Storage accounts using LRS or ZRS replication retain data only within a single region, providing no protection against regional outages or disasters. A regional disaster could result in complete data loss.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.17.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.17.2.1 ('Availability of information processing facilities') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-STOR-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-002": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Networks should be managed and controlled to protect information systems and applications. Allowing public network access to Azure Key Vault increases exposure of sensitive cryptographic material." + "description": "Networks should be managed and controlled to protect information systems and applications. Allowing public network access to Azure Key Vault increases exposure of sensitive cryptographic material.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-KV-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-003": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "Azure Key Vault diagnostic logging records access to secrets, keys, and certificates. Event logs recording security-relevant activities should be produced, kept, and reviewed to support monitoring and investigation." + "description": "Azure Key Vault diagnostic logging records access to secrets, keys, and certificates. Event logs recording security-relevant activities should be produced, kept, and reviewed to support monitoring and investigation.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-KV-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-011": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "Network Watcher must be enabled in all regions where resources are deployed to ensure network events are logged and available for investigation. Event logs recording network activities should be produced and kept available." + "description": "Network Watcher must be enabled in all regions where resources are deployed to ensure network events are logged and available for investigation. Event logs recording network activities should be produced and kept available.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-011 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-012": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "A VNet flow log (or an existing legacy NSG flow log) records network traffic activity for investigation and monitoring. New NSG flow log creation is blocked as of 2025-06-30, so VNet flow logs are the current mechanism. Without either, event records needed to reconstruct suspicious network activity are not produced." + "description": "A VNet flow log (or an existing legacy NSG flow log) records network traffic activity for investigation and monitoring. New NSG flow log creation is blocked as of 2025-06-30, so VNet flow logs are the current mechanism. Without either, event records needed to reconstruct suspicious network activity are not produced.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-012 evaluates one Azure technical setting (VNet flow logs, with the legacy NSG flow log mechanism Microsoft is retiring accepted as a fallback) that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-003": { "control_id": "A.10.1.1", "control_name": "Policy on the use of cryptographic controls", - "description": "SSL enforcement on PostgreSQL Flexible Server applies cryptographic controls to data in transit. A policy on the use of cryptographic controls for protection of information should be developed and implemented." + "description": "SSL enforcement on PostgreSQL Flexible Server applies cryptographic controls to data in transit. A policy on the use of cryptographic controls for protection of information should be developed and implemented.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.10.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.10.1.1 ('Policy on the use of cryptographic controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-DB-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-004": { "control_id": "A.17.2.1", "control_name": "Availability of information processing facilities", - "description": "Purge protection prevents permanent deletion of Azure Key Vault secrets, keys, and certificates during the soft-delete retention period. Without it, cryptographic material can be irrecoverably destroyed, threatening the availability of information processing facilities that depend on those keys and secrets." + "description": "Purge protection prevents permanent deletion of Azure Key Vault secrets, keys, and certificates during the soft-delete retention period. Without it, cryptographic material can be irrecoverably destroyed, threatening the availability of information processing facilities that depend on those keys and secrets.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.17.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.17.2.1 ('Availability of information processing facilities') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-KV-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-005": { "control_id": "A.10.1.2", "control_name": "Key management", - "description": "A certificate stored in Azure Key Vault is expiring within 30 days with no auto-renewal configured. A.10.1.2 requires that a policy on the use, protection, and lifetime of cryptographic keys is developed and implemented. Certificates approaching expiry without renewal represent a failure in cryptographic key lifecycle management." + "description": "A certificate stored in Azure Key Vault is expiring within 30 days with no auto-renewal configured. A.10.1.2 requires that a policy on the use, protection, and lifetime of cryptographic keys is developed and implemented. Certificates approaching expiry without renewal represent a failure in cryptographic key lifecycle management.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.10.1.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.10.1.2 ('Key management') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-KV-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-006": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "Key Vaults authorizing access through legacy vault access policies instead of Azure RBAC lack scoped, reviewable privileged-access management. A.9.2.3 requires that the allocation of privileged access rights is restricted and controlled. Access policies do not provide the granular, role-based control needed to enforce least privilege on secrets, keys, and certificates." + "description": "Key Vaults authorizing access through legacy vault access policies instead of Azure RBAC lack scoped, reviewable privileged-access management. A.9.2.3 requires that the allocation of privileged access rights is restricted and controlled. Access policies do not provide the granular, role-based control needed to enforce least privilege on secrets, keys, and certificates.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-KV-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-004": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall bypasses network controls by permitting any Azure-hosted resource to connect to the database server. Networks should be managed and controlled with explicit rules that restrict access to known and trusted sources only." + "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall bypasses network controls by permitting any Azure-hosted resource to connect to the database server. Networks should be managed and controlled with explicit rules that restrict access to known and trusted sources only.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-DB-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-004": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "The allocation and use of privileged access rights should be restricted and controlled. PIM enforces just-in-time access with time limits and approval workflows, ensuring privileged access rights are tightly managed and not permanently assigned." + "description": "The allocation and use of privileged access rights should be restricted and controlled. PIM enforces just-in-time access with time limits and approval workflows, ensuring privileged access rights are tightly managed and not permanently assigned.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-013": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "A virtual network without an Azure Firewall relies on NSGs alone and has no centralized perimeter inspection or logging. A.13.1.1 requires that networks be managed and controlled to protect information in systems and applications. Deploying an Azure Firewall provides stateful inspection, filtering, and logging at the network boundary." + "description": "A virtual network without an Azure Firewall relies on NSGs alone and has no centralized perimeter inspection or logging. A.13.1.1 requires that networks be managed and controlled to protect information in systems and applications. Deploying an Azure Firewall provides stateful inspection, filtering, and logging at the network boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-013 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-014": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "VNet peering connections with gateway transit enabled allow traffic to flow between network segments through shared gateways, potentially bypassing network controls. Networks should be managed and controlled to protect information in systems and applications. Gateway transit on peering connections should be disabled unless explicitly required." + "description": "VNet peering connections with gateway transit enabled allow traffic to flow between network segments through shared gateways, potentially bypassing network controls. Networks should be managed and controlled to protect information in systems and applications. Gateway transit on peering connections should be disabled unless explicitly required.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-014 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-015": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Public DNS zones containing A records that reference RFC1918 private IP addresses or record names that suggest internal services expose the organisation's internal network layout. A.13.1.1 requires that networks are managed and controlled to protect information in systems and applications. Private infrastructure references must be removed from public DNS and served only through Azure Private DNS zones to prevent information leakage." + "description": "Public DNS zones containing A records that reference RFC1918 private IP addresses or record names that suggest internal services expose the organisation's internal network layout. A.13.1.1 requires that networks are managed and controlled to protect information in systems and applications. Private infrastructure references must be removed from public DNS and served only through Azure Private DNS zones to prevent information leakage.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-015 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-001": { "control_id": "A.10.1.1", "control_name": "Policy on the use of cryptographic controls", - "description": "TLS configurations using classical key exchange algorithms do not align with a forward-looking cryptographic controls policy. A.10.1.1 requires that the organisation defines rules for effective use of cryptography. The policy must address post-quantum threats and mandate migration to quantum-safe cipher suites when supported." + "description": "TLS configurations using classical key exchange algorithms do not align with a forward-looking cryptographic controls policy. A.10.1.1 requires that the organisation defines rules for effective use of cryptography. The policy must address post-quantum threats and mandate migration to quantum-safe cipher suites when supported.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "ISO/IEC 27001:2013:2013 (no post-quantum control defined)", + "rationale": "ISO/IEC 27001:2013 predates post-quantum cryptography migration guidance and Annex A defines no control for quantum-safe algorithm readiness. Mapping rule AZ-PQC-001 to A.10.1.1 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-002": { "control_id": "A.10.1.1", "control_name": "Policy on the use of cryptographic controls", - "description": "Key Vault keys using RSA or ECC do not meet the requirements of a cryptographic controls policy that accounts for quantum threats. A.10.1.1 requires that cryptographic controls are appropriate to the level of risk. Post-quantum safe algorithms must be adopted as part of the cryptographic policy when supported." + "description": "Key Vault keys using RSA or ECC do not meet the requirements of a cryptographic controls policy that accounts for quantum threats. A.10.1.1 requires that cryptographic controls are appropriate to the level of risk. Post-quantum safe algorithms must be adopted as part of the cryptographic policy when supported.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "ISO/IEC 27001:2013:2013 (no post-quantum control defined)", + "rationale": "ISO/IEC 27001:2013 predates post-quantum cryptography migration guidance and Annex A defines no control for quantum-safe algorithm readiness. Mapping rule AZ-PQC-002 to A.10.1.1 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-003": { "control_id": "A.10.1.1", "control_name": "Policy on the use of cryptographic controls", - "description": "Certificates using classical signature algorithms expose the organisation to quantum-enabled signature forgery. A.10.1.1 requires that the cryptographic controls policy covers all cryptographic assets including certificates. Migration planning to post-quantum safe signature algorithms is required." + "description": "Certificates using classical signature algorithms expose the organisation to quantum-enabled signature forgery. A.10.1.1 requires that the cryptographic controls policy covers all cryptographic assets including certificates. Migration planning to post-quantum safe signature algorithms is required.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "ISO/IEC 27001:2013:2013 (no post-quantum control defined)", + "rationale": "ISO/IEC 27001:2013 predates post-quantum cryptography migration guidance and Annex A defines no control for quantum-safe algorithm readiness. Mapping rule AZ-PQC-003 to A.10.1.1 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-001": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Private AKS API access restricts the control plane to approved network paths and reduces exposure to internet-originated attacks." + "description": "Private AKS API access restricts the control plane to approved network paths and reduces exposure to internet-originated attacks.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-AKS-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-002": { "control_id": "A.9.2.1", "control_name": "User registration and de-registration", - "description": "Disabling local accounts ensures AKS administrator access follows the centralized Microsoft Entra identity lifecycle." + "description": "Disabling local accounts ensures AKS administrator access follows the centralized Microsoft Entra identity lifecycle.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.1 ('User registration and de-registration') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-AKS-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-003": { "control_id": "A.9.2.1", "control_name": "User registration and de-registration", - "description": "Managed identity removes separately managed service-principal credentials from the AKS control plane." + "description": "Managed identity removes separately managed service-principal credentials from the AKS control plane.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.1 ('User registration and de-registration') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-AKS-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-004": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "Workload Identity allows Azure permissions to be scoped and lifecycle-managed for individual Kubernetes workloads." + "description": "Workload Identity allows Azure permissions to be scoped and lifecycle-managed for individual Kubernetes workloads.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-AKS-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-005": { "control_id": "A.12.1.2", "control_name": "Change management", - "description": "Azure Policy provides controlled and repeatable governance for Kubernetes resource admission and configuration changes." + "description": "Azure Policy provides controlled and repeatable governance for Kubernetes resource admission and configuration changes.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.1.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.1.2 ('Change management') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-AKS-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-006": { "control_id": "A.12.6.1", "control_name": "Management of technical vulnerabilities", - "description": "Automatic AKS node OS upgrades help deploy tested security patches within a managed maintenance process." + "description": "Automatic AKS node OS upgrades help deploy tested security patches within a managed maintenance process.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.6.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.6.1 ('Management of technical vulnerabilities') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-AKS-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-010": { "control_id": "A.9.2.1", "control_name": "User registration and de-registration", - "description": "App Registration ownership supports accountable identity lifecycle administration." + "description": "App Registration ownership supports accountable identity lifecycle administration.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.1 ('User registration and de-registration') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-010 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-011": { "control_id": "A.14.1.2", "control_name": "Securing application services on public networks", - "description": "Secure redirect URIs protect identity protocol responses traversing public networks." + "description": "Secure redirect URIs protect identity protocol responses traversing public networks.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.14.1.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.14.1.2 ('Securing application services on public networks') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-011 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-012": { "control_id": "A.9.4.2", "control_name": "Secure log-on procedures", - "description": "Modern authorization code flow with PKCE provides stronger token handling than implicit grant." + "description": "Modern authorization code flow with PKCE provides stronger token handling than implicit grant.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.4.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.4.2 ('Secure log-on procedures') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-012 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-013": { "control_id": "A.9.4.3", "control_name": "Password management system", - "description": "Avoiding client secrets reduces password-style application credential exposure." + "description": "Avoiding client secrets reduces password-style application credential exposure.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.4.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.4.3 ('Password management system') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-013 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-014": { "control_id": "A.12.1.2", "control_name": "Change management", - "description": "Property lock prevents unauthorized changes to sensitive service-principal instance configuration." + "description": "Property lock prevents unauthorized changes to sensitive service-principal instance configuration.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.1.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.1.2 ('Change management') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-014 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-015": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "Subscription Owner and Contributor assignments to managed identities require least-privilege reduction." + "description": "Subscription Owner and Contributor assignments to managed identities require least-privilege reduction.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-IDN-015 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-001": { "control_id": "A.12.3.1", "control_name": "Information backup", - "description": "The Recovery Services vault lacks the approved soft-delete recovery window, risking permanent loss of backup data before it can be restored." + "description": "The Recovery Services vault lacks the approved soft-delete recovery window, risking permanent loss of backup data before it can be restored.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.3.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.3.1 ('Information backup') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-BAK-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-002": { "control_id": "A.12.3.1", "control_name": "Information backup", - "description": "Vault immutability is disabled, allowing destructive changes to protected recovery points and undermining the integrity of backup copies." + "description": "Vault immutability is disabled, allowing destructive changes to protected recovery points and undermining the integrity of backup copies.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.3.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.3.1 ('Information backup') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-BAK-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-004": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "The vault does not enable Resource Guard multiuser authorization, allowing a single compromised or malicious identity to disable backup protections unilaterally." + "description": "The vault does not enable Resource Guard multiuser authorization, allowing a single compromised or malicious identity to disable backup protections unilaterally.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-BAK-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-006": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "The Recovery Services vault does not enable built-in monitoring for backup job failures, so a failed or tampered backup could go undetected." + "description": "The Recovery Services vault does not enable built-in monitoring for backup job failures, so a failed or tampered backup could go undetected.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-BAK-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-001": { "control_id": "A.13.2.1", "control_name": "Information transfer policies and procedures", - "description": "The Function App accepts unencrypted HTTP traffic, so requests and responses can cross the network without encryption in transit." + "description": "The Function App accepts unencrypted HTTP traffic, so requests and responses can cross the network without encryption in transit.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.2.1 ('Information transfer policies and procedures') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-FUNC-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-002": { "control_id": "A.13.2.1", "control_name": "Information transfer policies and procedures", - "description": "The Function App permits TLS older than 1.2, weakening the encryption protecting traffic in transit." + "description": "The Function App permits TLS older than 1.2, weakening the encryption protecting traffic in transit.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.2.1 ('Information transfer policies and procedures') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-FUNC-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-003": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "The Function App exposes an FTP or FTPS deployment channel, widening the network attack surface beyond the primary HTTPS endpoint." + "description": "The Function App exposes an FTP or FTPS deployment channel, widening the network attack surface beyond the primary HTTPS endpoint.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-FUNC-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-004": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Remote debugging expands the Function App management attack surface by opening an additional network-reachable control channel." + "description": "Remote debugging expands the Function App management attack surface by opening an additional network-reachable control channel.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-FUNC-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-005": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "The Function App has no Azure managed identity for secretless resource access, pushing workloads toward long-lived credentials that cross network and service boundaries." + "description": "The Function App has no Azure managed identity for secretless resource access, pushing workloads toward long-lived credentials that cross network and service boundaries.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-FUNC-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-001": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "A Storage Account remains publicly reachable; an approved private endpoint alone does not disable its public endpoint, leaving the network boundary uncontrolled." + "description": "A Storage Account remains publicly reachable; an approved private endpoint alone does not disable its public endpoint, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-PE-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-002": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "An Azure SQL logical server remains publicly reachable, regardless of whether a private endpoint also exists, leaving the network boundary uncontrolled." + "description": "An Azure SQL logical server remains publicly reachable, regardless of whether a private endpoint also exists, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-PE-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-003": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "A PostgreSQL Flexible Server remains publicly reachable instead of using private networking only, leaving the network boundary uncontrolled." + "description": "A PostgreSQL Flexible Server remains publicly reachable instead of using private networking only, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-PE-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-004": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "An App Service workload remains publicly reachable without a default-deny access policy, leaving the network boundary uncontrolled." + "description": "An App Service workload remains publicly reachable without a default-deny access policy, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-PE-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-005": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "A Recovery Services vault permits public access, even if a private endpoint also exists, leaving the network boundary uncontrolled." + "description": "A Recovery Services vault permits public access, even if a private endpoint also exists, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-PE-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-006": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "A private endpoint connection is pending, rejected, or disconnected and does not provide an active private path, leaving traffic to traverse the public network boundary instead." + "description": "A private endpoint connection is pending, rejected, or disconnected and does not provide an active private path, leaving traffic to traverse the public network boundary instead.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-PE-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-001": { "control_id": "A.9.2.1", "control_name": "User registration and de-registration", - "description": "The Container Registry admin user is enabled, providing a shared credential that bypasses individual identity management and cannot be attributed to a single user." + "description": "The Container Registry admin user is enabled, providing a shared credential that bypasses individual identity management and cannot be attributed to a single user.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.1 ('User registration and de-registration') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-002": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "The Container Registry is reachable from the public internet, leaving the network boundary that protects the organization's built container images uncontrolled." + "description": "The Container Registry is reachable from the public internet, leaving the network boundary that protects the organization's built container images uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-003": { "control_id": "A.9.2.1", "control_name": "User registration and de-registration", - "description": "The Container Registry allows anonymous pull, letting any client access every image without an authenticated, individually attributable identity." + "description": "The Container Registry allows anonymous pull, letting any client access every image without an authenticated, individually attributable identity.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.1 ('User registration and de-registration') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-004": { "control_id": "A.12.1.2", "control_name": "Change management", - "description": "The Container Registry has no retention or quarantine policy, so stale images accumulate and newly pushed images are deployable before any vulnerability scan evaluates them." + "description": "The Container Registry has no retention or quarantine policy, so stale images accumulate and newly pushed images are deployable before any vulnerability scan evaluates them.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.1.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.1.2 ('Change management') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-005": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "A Terraform remote state container is publicly readable, leaving the network boundary around infrastructure layout and captured secrets uncontrolled." + "description": "A Terraform remote state container is publicly readable, leaving the network boundary around infrastructure layout and captured secrets uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-006": { "control_id": "A.12.3.1", "control_name": "Information backup", - "description": "A storage account holding Terraform remote state has neither versioning nor soft delete enabled, so an overwritten or deleted state file cannot be recovered." + "description": "A storage account holding Terraform remote state has neither versioning nor soft delete enabled, so an overwritten or deleted state file cannot be recovered.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.3.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.3.1 ('Information backup') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-007": { "control_id": "A.9.2.3", "control_name": "Management of privileged access rights", - "description": "A pipeline service connection is scoped to the entire subscription rather than a single resource group, so every pipeline that uses it inherits subscription-wide access beyond what it needs." + "description": "A pipeline service connection is scoped to the entire subscription rather than a single resource group, so every pipeline that uses it inherits subscription-wide access beyond what it needs.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.2.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.2.3 ('Management of privileged access rights') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-007 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-008": { "control_id": "A.9.4.3", "control_name": "Password management system", - "description": "A pipeline service connection authenticates with a stored service principal secret instead of a federated credential, leaving a static credential to rotate and potentially leak." + "description": "A pipeline service connection authenticates with a stored service principal secret instead of a federated credential, leaving a static credential to rotate and potentially leak.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.9.4.3", + "rationale": "ISO/IEC 27001:2013 Annex A control A.9.4.3 ('Password management system') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SC-008 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-001": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "MACsec protects traffic on the customer-visible ExpressRoute Direct Ethernet boundary." + "description": "MACsec protects traffic on the customer-visible ExpressRoute Direct Ethernet boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-DL-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-002": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "XPN MACsec provides appropriate packet-number capacity for high-speed ExpressRoute Direct links." + "description": "XPN MACsec provides appropriate packet-number capacity for high-speed ExpressRoute Direct links.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-DL-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-016": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "NIC IP forwarding must be restricted to approved routing functions." + "description": "NIC IP forwarding must be restricted to approved routing functions.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-016 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-017": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Default routes must preserve the approved controlled egress boundary." + "description": "Default routes must preserve the approved controlled egress boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-017 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-018": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "PaaS resources using Private Link should not retain unnecessary public network exposure." + "description": "PaaS resources using Private Link should not retain unnecessary public network exposure.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-018 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-019": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Private Endpoint connections must be approved and operational." + "description": "Private Endpoint connections must be approved and operational.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-019 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-020": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Private Endpoints require an associated service-appropriate Private DNS zone." + "description": "Private Endpoints require an associated service-appropriate Private DNS zone.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-020 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-021": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Private Endpoint ARM DNS configuration must associate service names with private addresses; effective resolver-path validation remains separate evidence." + "description": "Private Endpoint FQDNs must resolve to private addresses through the controlled network path.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-021 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-022": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Critical PaaS resources restrict public exposure unless an approved exception exists." + "description": "Critical PaaS resources restrict public exposure unless an approved exception exists.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-022 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-023": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Azure Firewall denies traffic identified by Microsoft threat intelligence." + "description": "Azure Firewall denies traffic identified by Microsoft threat intelligence.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-023 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-024": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Application Gateway WAF operates in Prevention mode at the application boundary." + "description": "Application Gateway WAF operates in Prevention mode at the application boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-024 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-025": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "Application Gateway WAF diagnostic categories supported by its SKU are exported to an approved monitoring destination." + "description": "Application Gateway WAF diagnostic categories are exported to an approved monitoring destination.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-025 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-026": { "control_id": "A.14.2.5", "control_name": "Secure system engineering principles", - "description": "Current managed application and bot rules are maintained at the web perimeter." + "description": "Current managed application and bot rules are maintained at the web perimeter.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.14.2.5", + "rationale": "ISO/IEC 27001:2013 Annex A control A.14.2.5 ('Secure system engineering principles') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-026 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-027": { "control_id": "A.13.1.1", "control_name": "Network controls", - "description": "Rate limiting protects internet-facing application entry points." + "description": "Rate limiting protects internet-facing application entry points.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.13.1.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.13.1.1 ('Network controls') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-NET-027 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-001": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "The subscription's Activity Log is not exported to an approved central destination. A.12.4.1 requires event logs recording user activities, exceptions, faults, and information security events to be produced, kept, and regularly reviewed; a log that is never centrally exported cannot be reviewed or retained beyond the platform default." + "description": "The subscription's Activity Log is not exported to an approved central destination. A.12.4.1 requires event logs recording user activities, exceptions, faults, and information security events to be produced, kept, and regularly reviewed; a log that is never centrally exported cannot be reviewed or retained beyond the platform default.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-001 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-002": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "The Activity Log export omits organisation-required categories (Administrative, Security, Policy, ServiceHealth). A.12.4.1 requires event logging to capture the events relevant to information security; a partial category export leaves gaps in the recorded evidence base." + "description": "The Activity Log export omits organisation-required categories (Administrative, Security, Policy, ServiceHealth). A.12.4.1 requires event logging to capture the events relevant to information security; a partial category export leaves gaps in the recorded evidence base.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-002 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-003": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "A critical resource has no diagnostic setting exporting to an approved destination. A.12.4.1 requires event logs to be produced for systems, and resource-level activity that is never logged cannot support later review, investigation, or evidence of misuse." + "description": "A critical resource has no diagnostic setting exporting to an approved destination. A.12.4.1 requires event logs to be produced for systems, and resource-level activity that is never logged cannot support later review, investigation, or evidence of misuse.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-003 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-004": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "A security-relevant log export's retention is below the organisation's minimum. A.12.4.1 requires logs to be kept for an agreed period; retention that expires before an incident is discovered defeats the control's purpose of supporting later investigation." + "description": "A security-relevant log export's retention is below the organisation's minimum. A.12.4.1 requires logs to be kept for an agreed period; retention that expires before an incident is discovered defeats the control's purpose of supporting later investigation.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-004 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-005": { "control_id": "A.12.4.2", "control_name": "Protection of log information", - "description": "A critical resource's only log export sits in a destination the workload's own administrators can modify. A.12.4.2 requires logging facilities and log information to be protected against tampering and unauthorised access, including by administrators of the systems being logged, which this single-destination, same-resource-group export does not achieve." + "description": "A critical resource's only log export sits in a destination the workload's own administrators can modify. A.12.4.2 requires logging facilities and log information to be protected against tampering and unauthorised access, including by administrators of the systems being logged, which this single-destination, same-resource-group export does not achieve.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.2 ('Protection of log information') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-005 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-006": { "control_id": "A.12.6.1", "control_name": "Management of technical vulnerabilities", - "description": "A required Microsoft Defender for Cloud plan is not enabled for a critical workload type. A.12.6.1 requires timely information about technical vulnerabilities to be obtained and the organisation's exposure evaluated; Defender for Cloud is the Azure-native control providing that vulnerability and threat information, and an unlicensed workload type receives none of it." + "description": "A required Microsoft Defender for Cloud plan is not enabled for a critical workload type. A.12.6.1 requires timely information about technical vulnerabilities to be obtained and the organisation's exposure evaluated; Defender for Cloud is the Azure-native control providing that vulnerability and threat information, and an unlicensed workload type receives none of it.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.6.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.6.1 ('Management of technical vulnerabilities') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-006 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-007": { "control_id": "A.12.6.1", "control_name": "Management of technical vulnerabilities", - "description": "A High-severity Defender recommendation remains unresolved beyond the organisation's SLA. A.12.6.1 requires timely action to address identified technical vulnerabilities according to the organisation's associated risk; an SLA breach on a High-severity item is direct evidence that this control's timeliness requirement was not met." + "description": "A High-severity Defender recommendation remains unresolved beyond the organisation's SLA. A.12.6.1 requires timely action to address identified technical vulnerabilities according to the organisation's associated risk; an SLA breach on a High-severity item is direct evidence that this control's timeliness requirement was not met.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.6.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.6.1 ('Management of technical vulnerabilities') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-007 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-008": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "A required Sentinel data connector is missing or unhealthy on an onboarded workspace. A.12.4.1 requires the systems that generate security-relevant events to have their logs actually collected; a disconnected connector means the corresponding event source produces no logs for the SIEM to review." + "description": "A required Sentinel data connector is missing or unhealthy on an onboarded workspace. A.12.4.1 requires the systems that generate security-relevant events to have their logs actually collected; a disconnected connector means the corresponding event source produces no logs for the SIEM to review.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-008 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-009": { "control_id": "A.12.4.1", "control_name": "Event logging", - "description": "Sentinel lacks enabled High-severity analytics coverage for a required detection use case. A.12.4.1's objective of recording and reviewing security-relevant events is not met when the events are ingested but no analytics rule evaluates them for the specific threat pattern the organisation has identified as high-risk." + "description": "Sentinel lacks enabled High-severity analytics coverage for a required detection use case. A.12.4.1's objective of recording and reviewing security-relevant events is not met when the events are ingested but no analytics rule evaluates them for the specific threat pattern the organisation has identified as high-risk.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.12.4.1", + "rationale": "ISO/IEC 27001:2013 Annex A control A.12.4.1 ('Event logging') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-009 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-010": { "control_id": "A.16.1.2", "control_name": "Reporting information security events", - "description": "No monitored destination exists for security alerts or Sentinel incidents. A.16.1.2 requires information security events to be reported through appropriate management channels as quickly as possible; an alert with no notified recipient cannot be reported or acted on." - }, - "AZ-NET-018": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "PaaS resources using Private Link should not retain unnecessary public network exposure." - }, - "AZ-NET-019": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "Private Endpoint connections must be approved and operational." - }, - "AZ-NET-020": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "Private Endpoints require an associated service-appropriate Private DNS zone." - }, - "AZ-NET-021": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "Private Endpoint FQDNs must resolve to private addresses through the controlled network path." - }, - "AZ-NET-022": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "Critical PaaS resources restrict public exposure unless an approved exception exists." - }, - "AZ-NET-023": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "Azure Firewall denies traffic identified by Microsoft threat intelligence." - }, - "AZ-NET-024": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "Application Gateway WAF operates in Prevention mode at the application boundary." - }, - "AZ-NET-025": { - "control_id": "A.12.4.1", - "control_name": "Event logging", - "description": "Application Gateway WAF diagnostic categories are exported to an approved monitoring destination." - }, - "AZ-NET-026": { - "control_id": "A.14.2.5", - "control_name": "Secure system engineering principles", - "description": "Current managed application and bot rules are maintained at the web perimeter." - }, - "AZ-NET-027": { - "control_id": "A.13.1.1", - "control_name": "Network controls", - "description": "Rate limiting protects internet-facing application entry points." + "description": "No monitored destination exists for security alerts or Sentinel incidents. A.16.1.2 requires information security events to be reported through appropriate management channels as quickly as possible; an alert with no notified recipient cannot be reported or acted on.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "ISO/IEC 27001:2013:2013, Annex A control A.16.1.2", + "rationale": "ISO/IEC 27001:2013 Annex A control A.16.1.2 ('Reporting information security events') requires a documented ISMS control, not solely a technical configuration state. OpenShield rule AZ-SECOPS-010 evaluates one Azure technical setting that provides supporting automated evidence toward this control; full conformance also requires the organizational policy and process elements ISO 27001 mandates.", + "owner": null, + "review_status": "pending_review", + "review_date": null } } } diff --git a/compliance/frameworks/ncsc_pqc.json b/compliance/frameworks/ncsc_pqc.json index 2b07d9d1..15ec8ae5 100644 --- a/compliance/frameworks/ncsc_pqc.json +++ b/compliance/frameworks/ncsc_pqc.json @@ -2,27 +2,52 @@ "framework": "NCSC UK PQC Migration Guidance", "version": "2025", "published": "2025-03", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "OpenShield compliance mapping pack, authored against NCSC UK PQC migration guidance (2025). Technical-evidence mapping only.", + "mapping_pack_published": "2026-08-22", "controls": { "AZ-PQC-001": { "control_id": "NCSC-PQC-DISCOVERY", "control_name": "Discover quantum-vulnerable network cryptography", "description": "Identify internet-facing services that depend on classical public-key cryptography, assess the lifetime of protected data, and include their TLS configurations in the organisation's PQC migration plan.", "framework": "NCSC UK PQC Migration Guidance", - "url": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines" + "url": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines", + "rationale": "NCSC UK PQC Migration Guidance control NCSC-PQC-DISCOVERY ('Discover quantum-vulnerable network cryptography') directly specifies the quantum-safe migration practice that OpenShield rule AZ-PQC-001 evaluates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-002": { "control_id": "NCSC-PQC-PRIORITY", "control_name": "Prioritise migration of critical cryptographic keys", "description": "Inventory RSA and elliptic-curve keys, identify their system and supplier dependencies, and migrate keys protecting critical or long-lived data as a highest-priority activity.", "framework": "NCSC UK PQC Migration Guidance", - "url": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines" + "url": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines", + "rationale": "NCSC UK PQC Migration Guidance control NCSC-PQC-PRIORITY ('Prioritise migration of critical cryptographic keys') directly specifies the quantum-safe migration practice that OpenShield rule AZ-PQC-002 evaluates.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-003": { "control_id": "NCSC-PQC-PKI", "control_name": "Plan migration of public key infrastructure", "description": "Discover certificates and trust dependencies that rely on quantum-vulnerable signatures, then plan a staged migration that supports cryptographic agility and ecosystem readiness.", "framework": "NCSC UK PQC Migration Guidance", - "url": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines" + "url": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "https://www.ncsc.gov.uk/guidance/pqc-migration-timelines", + "rationale": "NCSC UK PQC Migration Guidance control NCSC-PQC-PKI ('Plan migration of public key infrastructure') directly specifies the quantum-safe migration practice that OpenShield rule AZ-PQC-003 evaluates.", + "owner": null, + "review_status": "pending_review", + "review_date": null } } } diff --git a/compliance/frameworks/nist_csf.json b/compliance/frameworks/nist_csf.json index 8fa9992b..6bcb0feb 100644 --- a/compliance/frameworks/nist_csf.json +++ b/compliance/frameworks/nist_csf.json @@ -2,586 +2,1282 @@ "framework": "NIST Cybersecurity Framework", "version": "1.1", "published": "2018-04", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "OpenShield compliance mapping pack, authored against NIST Cybersecurity Framework v1.1 subcategory text and the NIST CSF 1.1 Appendix A informative references crosswalk to SP 800-53 Rev 4. Technical-evidence mapping only; not a certification statement.", + "mapping_pack_published": "2026-08-22", "controls": { "AZ-STOR-001": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Public blob access enables unauthenticated remote access to storage resources. Disabling public access ensures remote access to storage is managed and authenticated." + "description": "Public blob access enables unauthenticated remote access to storage resources. Disabling public access ensures remote access to storage is managed and authenticated.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-STOR-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-002": { "control_id": "PR.DS-2", "control_name": "Data-in-transit is protected", - "description": "Requiring secure transfer ensures data in transit between clients and Azure Storage is encrypted using HTTPS, protecting against interception and tampering." + "description": "Requiring secure transfer ensures data in transit between clients and Azure Storage is encrypted using HTTPS, protecting against interception and tampering.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-STOR-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-001": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Unrestricted SSH access from the internet allows unmanaged remote access. NSG rules should restrict SSH to known IP ranges to ensure remote access is controlled and monitored." + "description": "Unrestricted SSH access from the internet allows unmanaged remote access. NSG rules should restrict SSH to known IP ranges to ensure remote access is controlled and monitored.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-002": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Unrestricted RDP access from the internet allows unmanaged remote access. NSG rules should restrict RDP to known IP ranges or use Azure Bastion to ensure remote access is controlled." + "description": "Unrestricted RDP access from the internet allows unmanaged remote access. NSG rules should restrict RDP to known IP ranges or use Azure Bastion to ensure remote access is controlled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-003": { - "control_id": "SC-7", - "control_name": "Boundary Protection", - "description": "Unrestricted inbound access on port 443 from the internet increases the attack surface. Public-facing HTTPS services should be fronted by a WAF-enabled Application Gateway rather than exposed directly via NSG rules." + "control_id": "PR.AC-5", + "control_name": "Network integrity is protected", + "description": "Unrestricted inbound access on port 443 from the internet increases the attack surface. Public-facing HTTPS services should be fronted by a WAF-enabled Application Gateway rather than exposed directly via NSG rules.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-004": { - "control_id": "SC-7", - "control_name": "Boundary Protection", - "description": "NSGs with no custom rules provide no meaningful boundary protection. Explicit least-privilege rules should be defined to control inbound and outbound traffic at the network perimeter." + "control_id": "PR.AC-5", + "control_name": "Network integrity is protected", + "description": "NSGs with no custom rules provide no meaningful boundary protection. Explicit least-privilege rules should be defined to control inbound and outbound traffic at the network perimeter.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-005": { - "control_id": "SC-5", - "control_name": "Denial of Service Protection", - "description": "Virtual networks without DDoS Protection Standard are vulnerable to volumetric denial of service attacks. DDoS Protection Standard provides enhanced mitigation for production workloads." + "control_id": "PR.DS-4", + "control_name": "Adequate capacity to ensure availability is maintained", + "description": "Virtual networks without DDoS Protection Standard are vulnerable to volumetric denial of service attacks. DDoS Protection Standard provides enhanced mitigation for production workloads.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-4", + "rationale": "NIST CSF 1.1 subcategory PR.DS-4 ('Adequate capacity to ensure availability is maintained') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-006": { - "control_id": "CM-7", - "control_name": "Least Functionality", - "description": "Unassociated public IP addresses represent unnecessary functionality and attack surface. Resources that are no longer in use should be removed to maintain least functionality." + "control_id": "PR.IP-1", + "control_name": "A baseline configuration is created and maintained", + "description": "Unassociated public IP addresses represent unnecessary functionality and attack surface. Resources that are no longer in use should be removed to maintain least functionality.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-1", + "rationale": "NIST CSF 1.1 subcategory PR.IP-1 ('A baseline configuration is created and maintained') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-007": { - "control_id": "SI-3", - "control_name": "Malicious Code Protection", - "description": "Application Gateways without WAF enabled provide no protection against web application attacks including OWASP Top 10 vulnerabilities. WAF in Prevention mode should be enabled on all public-facing Application Gateways." + "control_id": "DE.CM-4", + "control_name": "Malicious code is detected", + "description": "Application Gateways without WAF enabled provide no protection against web application attacks including OWASP Top 10 vulnerabilities. WAF in Prevention mode should be enabled on all public-facing Application Gateways.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-4", + "rationale": "NIST CSF 1.1 subcategory DE.CM-4 ('Malicious code is detected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-007 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-008": { - "control_id": "CM-7", - "control_name": "Least Functionality", - "description": "Load balancers with no backend pool configured serve no function and represent unnecessary resources. Unused resources should be removed to maintain least functionality and reduce cost." + "control_id": "PR.IP-1", + "control_name": "A baseline configuration is created and maintained", + "description": "Load balancers with no backend pool configured serve no function and represent unnecessary resources. Unused resources should be removed to maintain least functionality and reduce cost.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-1", + "rationale": "NIST CSF 1.1 subcategory PR.IP-1 ('A baseline configuration is created and maintained') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-008 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-009": { - "control_id": "SC-8", - "control_name": "Transmission Confidentiality and Integrity", - "description": "VPN connections using IKEv1 use an outdated protocol with known vulnerabilities. IKEv2 should be used for all VPN gateway connections to ensure transmission confidentiality and integrity." + "control_id": "PR.DS-2", + "control_name": "Data-in-transit is protected", + "description": "VPN connections using IKEv1 use an outdated protocol with known vulnerabilities. IKEv2 should be used for all VPN gateway connections to ensure transmission confidentiality and integrity.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-009 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-010": { - "control_id": "SC-7", - "control_name": "Boundary Protection", - "description": "Subnets without NSGs attached have no network layer access control. All production subnets should have NSGs with explicit rules to enforce boundary protection at the subnet level." + "control_id": "PR.AC-5", + "control_name": "Network integrity is protected", + "description": "Subnets without NSGs attached have no network layer access control. All production subnets should have NSGs with explicit rules to enforce boundary protection at the subnet level.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-010 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-001": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "Service principals with overly broad permissions violate least privilege. Access permissions should be scoped to the minimum required for the workload to function." + "description": "Service principals with overly broad permissions violate least privilege. Access permissions should be scoped to the minimum required for the workload to function.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-002": { "control_id": "PR.AC-7", "control_name": "Users, devices, and other assets are authenticated", - "description": "MFA ensures privileged users are strongly authenticated before accessing Azure resources. Without MFA, a compromised password is sufficient for full administrative access." + "description": "MFA ensures privileged users are strongly authenticated before accessing Azure resources. Without MFA, a compromised password is sufficient for full administrative access.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-7", + "rationale": "NIST CSF 1.1 subcategory PR.AC-7 ('Users, devices, and other assets are authenticated') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-003": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited", - "description": "Unrestricted guest user invitations allow any organisation member to introduce external identities into the tenant without centralised review. PR.AC-1 requires that identities and credentials are managed and verified. Restricting guest invitations to administrators ensures external identity provisioning is controlled and audited." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "Unrestricted guest user invitations allow any organisation member to introduce external identities into the tenant without centralised review. PR.AC-1 requires that identities and credentials are managed and verified. Restricting guest invitations to administrators ensures external identity provisioning is controlled and audited.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-005": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "Guest users with high privilege roles in Entra ID violate the principle of least privilege and separation of duties. PR.AC-4 requires that access permissions and authorisations are managed, incorporating the principles of least privilege and separation of duties. External guest accounts must not hold privileged directory roles." + "description": "Guest users with high privilege roles in Entra ID violate the principle of least privilege and separation of duties. PR.AC-4 requires that access permissions and authorisations are managed, incorporating the principles of least privilege and separation of duties. External guest accounts must not hold privileged directory roles.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-006": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are managed for authorised devices and users", - "description": "Client secrets on service principals that are older than 90 days or have no expiry violate credential lifecycle management requirements. PR.AC-1 requires that identities and credentials are issued, managed, verified, revoked, and audited for authorised devices, users, and processes. Long-lived secrets must be rotated or replaced with certificate-based or managed identity authentication." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "Client secrets on service principals that are older than 90 days or have no expiry violate credential lifecycle management requirements. PR.AC-1 requires that identities and credentials are issued, managed, verified, revoked, and audited for authorised devices, users, and processes. Long-lived secrets must be rotated or replaced with certificate-based or managed identity authentication.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-007": { "control_id": "PR.AC-7", "control_name": "Users, devices, and other assets are authenticated", - "description": "Active Entra ID users without MFA registered rely solely on a password for authentication, which is insufficient against modern credential attacks. PR.AC-7 requires that users, devices, and other assets are authenticated commensurate with the risk of the transaction. MFA must be enforced for all active user accounts via Conditional Access policy." + "description": "Active Entra ID users without MFA registered rely solely on a password for authentication, which is insufficient against modern credential attacks. PR.AC-7 requires that users, devices, and other assets are authenticated commensurate with the risk of the transaction. MFA must be enforced for all active user accounts via Conditional Access policy.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-7", + "rationale": "NIST CSF 1.1 subcategory PR.AC-7 ('Users, devices, and other assets are authenticated') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-007 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-008": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "Custom RBAC roles containing wildcard action patterns grant unrestricted resource permissions equivalent to the Owner built-in role. PR.AC-4 requires that access permissions and authorisations are managed incorporating the principle of least privilege. Wildcard actions in custom role definitions must be replaced with the minimum specific actions required." + "description": "Custom RBAC roles containing wildcard action patterns grant unrestricted resource permissions equivalent to the Owner built-in role. PR.AC-4 requires that access permissions and authorisations are managed incorporating the principle of least privilege. Wildcard actions in custom role definitions must be replaced with the minimum specific actions required.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-008 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-009": { "control_id": "DE.CM-3", "control_name": "Personnel activity is monitored to detect potential cybersecurity events", - "description": "The absence of an activity log alert for Microsoft.Authorization/roleAssignments/write means that privilege escalation events in the subscription are not detected in real time. DE.CM-3 requires that personnel activity is monitored to detect potential cybersecurity events. An alert must be configured to notify security personnel whenever a role assignment is created or modified." + "description": "The absence of an activity log alert for Microsoft.Authorization/roleAssignments/write means that privilege escalation events in the subscription are not detected in real time. DE.CM-3 requires that personnel activity is monitored to detect potential cybersecurity events. An alert must be configured to notify security personnel whenever a role assignment is created or modified.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-3", + "rationale": "NIST CSF 1.1 subcategory DE.CM-3 ('Personnel activity is monitored to detect potential cybersecurity events') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-009 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-001": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Public network access to PostgreSQL servers should be disabled. Database access should be restricted to private networks to ensure remote access is managed and controlled." + "description": "Public network access to PostgreSQL servers should be disabled. Database access should be restricted to private networks to ensure remote access is managed and controlled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-DB-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-002": { "control_id": "DE.AE-3", - "control_name": "Event data are aggregated and correlated", - "description": "SQL Server auditing must be enabled with sufficient retention to support threat detection and incident investigation. Audit logs provide the event data needed to detect and respond to anomalous database activity." + "control_name": "Event data are collected and correlated from multiple sources and sensors", + "description": "SQL Server auditing must be enabled with sufficient retention to support threat detection and incident investigation. Audit logs provide the event data needed to detect and respond to anomalous database activity.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.AE-3", + "rationale": "NIST CSF 1.1 subcategory DE.AE-3 ('Event data are collected and correlated from multiple sources and sensors') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-DB-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-001": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Virtual machines with public IPs and no NSG have unrestricted network access. NSGs should be attached to control inbound and outbound traffic and manage remote access to compute resources." + "description": "Virtual machines with public IPs and no NSG have unrestricted network access. NSGs should be attached to control inbound and outbound traffic and manage remote access to compute resources.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-CMP-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-002": { "control_id": "PR.DS-1", "control_name": "Data-at-rest is protected", - "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). PR.DS-1 requires that data at rest is protected using appropriate controls. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control." + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). PR.DS-1 requires that data at rest is protected using appropriate controls. Platform-managed encryption does not give the organisation control over the encryption keys. Customer-managed keys or Azure Disk Encryption are required to satisfy this control.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-1", + "rationale": "NIST CSF 1.1 subcategory PR.DS-1 ('Data-at-rest is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-CMP-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-003": { "control_id": "DE.CM-4", "control_name": "Malicious code is detected", - "description": "The virtual machine does not have a recognised endpoint protection extension installed. DE.CM-4 requires that malicious code is detected on organisational systems. Without endpoint protection, malware and ransomware executing on the VM will not be detected or blocked." + "description": "The virtual machine does not have a recognised endpoint protection extension installed. DE.CM-4 requires that malicious code is detected on organisational systems. Without endpoint protection, malware and ransomware executing on the VM will not be detected or blocked.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-4", + "rationale": "NIST CSF 1.1 subcategory DE.CM-4 ('Malicious code is detected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-CMP-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-004": { "control_id": "PR.IP-12", "control_name": "A vulnerability management plan is developed and implemented", - "description": "The virtual machine does not have automatic OS patching enabled. PR.IP-12 requires that a vulnerability management plan is developed and implemented. Without automatic patching, known OS vulnerabilities remain unmitigated and exploitable." + "description": "The virtual machine does not have automatic OS patching enabled. PR.IP-12 requires that a vulnerability management plan is developed and implemented. Without automatic patching, known OS vulnerabilities remain unmitigated and exploitable.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-12", + "rationale": "NIST CSF 1.1 subcategory PR.IP-12 ('A vulnerability management plan is developed and implemented') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-CMP-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-007": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "A VM has management ports (SSH/RDP) open to the internet with no Just-In-Time VM access policy covering them. PR.AC-3 requires that remote access is managed. JIT restricts management-port access to approved, time-boxed requests instead of leaving the ports standing open." + "description": "A VM has management ports (SSH/RDP) open to the internet with no Just-In-Time VM access policy covering them. PR.AC-3 requires that remote access is managed. JIT restricts management-port access to approved, time-boxed requests instead of leaving the ports standing open.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-CMP-007 evaluates one Azure technical control (whether Just-In-Time VM access covers open management ports) that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-001": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", - "description": "Key material in Azure Key Vault must be recoverable after accidental or malicious deletion. Soft delete provides a recoverable state for secrets, keys, and certificates, supporting backup and recovery requirements for critical cryptographic material." + "description": "Key material in Azure Key Vault must be recoverable after accidental or malicious deletion. Soft delete provides a recoverable state for secrets, keys, and certificates, supporting backup and recovery requirements for critical cryptographic material.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-4", + "rationale": "NIST CSF 1.1 subcategory PR.IP-4 ('Backups of information are conducted, maintained, and tested') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-KV-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-002": { - "control_id": "AC-17", - "control_name": "Remote access", - "description": "Key Vaults that allow public network access expose sensitive secrets, keys, and certificates to remote access attempts from outside trusted networks. Restricting access through private endpoints or trusted networks helps manage remote access paths." + "control_id": "PR.AC-3", + "control_name": "Remote access is managed", + "description": "Key Vaults that allow public network access expose sensitive secrets, keys, and certificates to remote access attempts from outside trusted networks. Restricting access through private endpoints or trusted networks helps manage remote access paths.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-KV-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-003": { "control_id": "DE.CM-7", "control_name": "Monitoring for unauthorized personnel, connections, devices, and software is performed", - "description": "Key Vault diagnostic logs provide the audit trail needed to monitor access to secrets, keys, and certificates. Without logging, unauthorized access and destructive changes cannot be detected or investigated." + "description": "Key Vault diagnostic logs provide the audit trail needed to monitor access to secrets, keys, and certificates. Without logging, unauthorized access and destructive changes cannot be detected or investigated.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-7", + "rationale": "NIST CSF 1.1 subcategory DE.CM-7 ('Monitoring for unauthorized personnel, connections, devices, and software is performed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-KV-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-003": { "control_id": "PR.DS-3", "control_name": "Assets are formally managed throughout removal, transfers, and disposition", - "description": "NIST CSF PR.DS-3 requires that data assets are managed through their full lifecycle including secure disposal. Storage accounts without a lifecycle management policy have no automated mechanism for expiring or deleting aged data, meaning data subject to disposal requirements persists indefinitely and is never formally retired from the asset inventory." + "description": "NIST CSF PR.DS-3 requires that data assets are managed through their full lifecycle including secure disposal. Storage accounts without a lifecycle management policy have no automated mechanism for expiring or deleting aged data, meaning data subject to disposal requirements persists indefinitely and is never formally retired from the asset inventory.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-3", + "rationale": "NIST CSF 1.1 subcategory PR.DS-3 ('Assets are formally managed throughout removal, transfers, and disposition') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-STOR-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-004": { "control_id": "DE.CM-7", "control_name": "Monitoring for unauthorized personnel, connections, devices, and software is performed", - "description": "Diagnostic logging on Azure Storage services provides the audit trail needed to monitor for unauthorized or anomalous read, write, and delete operations. Without logging, detection of data exfiltration or unauthorized access to blob, queue, or table services is not possible." + "description": "Diagnostic logging on Azure Storage services provides the audit trail needed to monitor for unauthorized or anomalous read, write, and delete operations. Without logging, detection of data exfiltration or unauthorized access to blob, queue, or table services is not possible.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-7", + "rationale": "NIST CSF 1.1 subcategory DE.CM-7 ('Monitoring for unauthorized personnel, connections, devices, and software is performed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-STOR-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-005": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", - "description": "Storage accounts configured with LRS or ZRS replicate data only within a single region. A regional outage or disaster could result in data unavailability or data loss. PR.IP-4 requires that backups and redundant copies of information are maintained. Geo-redundant replication (GRS or GZRS) ensures a secondary copy of data is maintained in a separate Azure region, satisfying backup and recovery requirements." + "description": "Storage accounts configured with LRS or ZRS replicate data only within a single region. A regional outage or disaster could result in data unavailability or data loss. PR.IP-4 requires that backups and redundant copies of information are maintained. Geo-redundant replication (GRS or GZRS) ensures a secondary copy of data is maintained in a separate Azure region, satisfying backup and recovery requirements.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-4", + "rationale": "NIST CSF 1.1 subcategory PR.IP-4 ('Backups of information are conducted, maintained, and tested') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-STOR-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-011": { "control_id": "DE.CM-7", "control_name": "Monitoring for unauthorized personnel, connections, devices, and software is performed", - "description": "Network Watcher must be enabled in all active regions to support continuous monitoring of network activity. Without it, unauthorized connections and anomalous network behaviour cannot be detected or investigated." + "description": "Network Watcher must be enabled in all active regions to support continuous monitoring of network activity. Without it, unauthorized connections and anomalous network behaviour cannot be detected or investigated.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-7", + "rationale": "NIST CSF 1.1 subcategory DE.CM-7 ('Monitoring for unauthorized personnel, connections, devices, and software is performed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-011 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-012": { "control_id": "DE.CM-1", "control_name": "The network is monitored to detect potential cybersecurity events", - "description": "A VNet flow log (or an existing legacy NSG flow log) provides visibility into network traffic patterns and blocked or allowed flows. New NSG flow log creation is blocked as of 2025-06-30, so VNet flow logs are the current mechanism. Without either, potential cybersecurity events in network traffic cannot be detected or reconstructed." + "description": "A VNet flow log (or an existing legacy NSG flow log) provides visibility into network traffic patterns and blocked or allowed flows. New NSG flow log creation is blocked as of 2025-06-30, so VNet flow logs are the current mechanism. Without either, potential cybersecurity events in network traffic cannot be detected or reconstructed.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-1", + "rationale": "NIST CSF 1.1 subcategory DE.CM-1 ('The network is monitored to detect potential cybersecurity events') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-012 evaluates one Azure technical control (VNet flow logs, with the legacy NSG flow log mechanism Microsoft is retiring accepted as a fallback) that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-003": { "control_id": "PR.DS-2", "control_name": "Data-in-transit is protected", - "description": "SSL enforcement on PostgreSQL Flexible Server ensures data in transit between applications and the database is encrypted. Disabling SSL exposes database traffic to interception and tampering." + "description": "SSL enforcement on PostgreSQL Flexible Server ensures data in transit between applications and the database is encrypted. Disabling SSL exposes database traffic to interception and tampering.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-DB-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-004": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", - "description": "Purge protection ensures that deleted Key Vault objects can be recovered within the retention period and cannot be permanently destroyed before it expires. Without purge protection, backups of cryptographic material may be rendered unrecoverable if an insider or compromised account issues a purge operation during the soft-delete window." + "description": "Purge protection ensures that deleted Key Vault objects can be recovered within the retention period and cannot be permanently destroyed before it expires. Without purge protection, backups of cryptographic material may be rendered unrecoverable if an insider or compromised account issues a purge operation during the soft-delete window.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-4", + "rationale": "NIST CSF 1.1 subcategory PR.IP-4 ('Backups of information are conducted, maintained, and tested') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-KV-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-005": { "control_id": "PR.MA-1", "control_name": "Maintenance and repair of organisational assets is performed", - "description": "A certificate stored in Azure Key Vault is expiring within 30 days with no auto-renewal configured. PR.MA-1 requires that maintenance of organisational assets is performed and logged. Certificate renewal is a critical maintenance task and failure to renew before expiry causes immediate service disruption." + "description": "A certificate stored in Azure Key Vault is expiring within 30 days with no auto-renewal configured. PR.MA-1 requires that maintenance of organisational assets is performed and logged. Certificate renewal is a critical maintenance task and failure to renew before expiry causes immediate service disruption.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.MA-1", + "rationale": "NIST CSF 1.1 subcategory PR.MA-1 ('Maintenance and repair of organisational assets is performed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-KV-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-006": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "Key Vaults authorizing access through legacy vault access policies instead of Azure RBAC lack centrally managed, auditable access permissions. PR.AC-4 requires that access permissions are managed incorporating the principles of least privilege and separation of duties. Access policies cannot express fine-grained, role-scoped permissions the way Azure RBAC role assignments can." + "description": "Key Vaults authorizing access through legacy vault access policies instead of Azure RBAC lack centrally managed, auditable access permissions. PR.AC-4 requires that access permissions are managed incorporating the principles of least privilege and separation of duties. Access policies cannot express fine-grained, role-scoped permissions the way Azure RBAC role assignments can.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-KV-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-004": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall permits any Azure-hosted resource to connect to the database remotely without restriction. PR.AC-3 requires that remote access is managed and controlled. Access should be restricted to specific trusted IP ranges or private endpoints to ensure only authorised systems can reach the database." + "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall permits any Azure-hosted resource to connect to the database remotely without restriction. PR.AC-3 requires that remote access is managed and controlled. Access should be restricted to specific trusted IP ranges or private endpoints to ensure only authorised systems can reach the database.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-DB-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-004": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "PIM ensures privileged access permissions are managed with time-bound activation and approval workflows. Without PIM, permanently assigned admin roles violate the principle of least privilege and increase the blast radius of compromised accounts." + "description": "PIM ensures privileged access permissions are managed with time-bound activation and approval workflows. Without PIM, permanently assigned admin roles violate the principle of least privilege and increase the blast radius of compromised accounts.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-013": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "A virtual network with no Azure Firewall relies on NSGs alone and lacks a centralized perimeter inspection and logging layer. PR.AC-5 requires that network integrity is protected through segregation. Deploying an Azure Firewall enforces inspected, logged traffic flow at the network boundary and strengthens segmentation." + "description": "A virtual network with no Azure Firewall relies on NSGs alone and lacks a centralized perimeter inspection and logging layer. PR.AC-5 requires that network integrity is protected through segregation. Deploying an Azure Firewall enforces inspected, logged traffic flow at the network boundary and strengthens segmentation.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-013 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-014": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "VNet peering with gateway transit enabled allows traffic to cross network boundaries through shared gateways, undermining network segmentation. PR.AC-5 requires that network integrity is protected. Disabling gateway transit on peering connections enforces boundary integrity between network zones." + "description": "VNet peering with gateway transit enabled allows traffic to cross network boundaries through shared gateways, undermining network segmentation. PR.AC-5 requires that network integrity is protected. Disabling gateway transit on peering connections enforces boundary integrity between network zones.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-014 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-015": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "Public DNS zones containing RFC1918 IP addresses or internal service hostnames in record names expose the internal network layout to external parties and assist attackers in identifying targets. PR.AC-5 requires that network integrity is protected through appropriate boundary controls. Private infrastructure references must be removed from public DNS and hosted in Azure Private DNS zones to prevent external reconnaissance." + "description": "Public DNS zones containing RFC1918 IP addresses or internal service hostnames in record names expose the internal network layout to external parties and assist attackers in identifying targets. PR.AC-5 requires that network integrity is protected through appropriate boundary controls. Private infrastructure references must be removed from public DNS and hosted in Azure Private DNS zones to prevent external reconnaissance.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-015 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-001": { "control_id": "PR.DS-2", - "control_name": "Data in transit is protected", - "description": "TLS configurations using classical key exchange algorithms expose data in transit to Harvest Now Decrypt Later attacks. PR.DS-2 requires that data in transit is protected. Migrating to TLS 1.3 and post-quantum safe cipher suites when supported helps data remain protected against quantum-enabled adversaries." + "control_name": "Data-in-transit is protected", + "description": "TLS configurations using classical key exchange algorithms expose data in transit to Harvest Now Decrypt Later attacks. PR.DS-2 requires that data in transit is protected. Migrating to TLS 1.3 and post-quantum safe cipher suites when supported helps data remain protected against quantum-enabled adversaries.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "NIST Cybersecurity Framework 1.1 (no post-quantum subcategory defined)", + "rationale": "NIST CSF 1.1 predates post-quantum cryptography migration guidance and defines no subcategory for quantum-safe algorithm readiness. Mapping rule AZ-PQC-001 to PR.DS-2 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-002": { "control_id": "PR.DS-2", - "control_name": "Data in transit is protected", - "description": "Key Vault keys using RSA or ECC can be broken by Shor's algorithm on quantum computers, compromising protected data and signatures. PR.DS-2 requires that data protection mechanisms are maintained. Post-quantum safe key encapsulation algorithms such as ML-KEM should replace classical alternatives when supported." + "control_name": "Data-in-transit is protected", + "description": "Key Vault keys using RSA or ECC can be broken by Shor's algorithm on quantum computers, compromising protected data and signatures. PR.DS-2 requires that data protection mechanisms are maintained. Post-quantum safe key encapsulation algorithms such as ML-KEM should replace classical alternatives when supported.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "NIST Cybersecurity Framework 1.1 (no post-quantum subcategory defined)", + "rationale": "NIST CSF 1.1 predates post-quantum cryptography migration guidance and defines no subcategory for quantum-safe algorithm readiness. Mapping rule AZ-PQC-002 to PR.DS-2 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-003": { "control_id": "PR.DS-2", - "control_name": "Data in transit is protected", - "description": "Certificates using classical signature algorithms are vulnerable to quantum attacks, undermining authentication and integrity guarantees. PR.DS-2 requires that data protection includes integrity mechanisms. Migration to ML-DSA or SLH-DSA signature algorithms should be planned." + "control_name": "Data-in-transit is protected", + "description": "Certificates using classical signature algorithms are vulnerable to quantum attacks, undermining authentication and integrity guarantees. PR.DS-2 requires that data protection includes integrity mechanisms. Migration to ML-DSA or SLH-DSA signature algorithms should be planned.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "NIST Cybersecurity Framework 1.1 (no post-quantum subcategory defined)", + "rationale": "NIST CSF 1.1 predates post-quantum cryptography migration guidance and defines no subcategory for quantum-safe algorithm readiness. Mapping rule AZ-PQC-003 to PR.DS-2 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-001": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "A private AKS API endpoint reduces public control-plane exposure and ensures administrative access is mediated through approved private network paths." + "description": "A private AKS API endpoint reduces public control-plane exposure and ensures administrative access is mediated through approved private network paths.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-AKS-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-002": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited", - "description": "Disabling local AKS accounts ensures cluster access uses centrally governed Microsoft Entra identities instead of unmanaged static credentials." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "Disabling local AKS accounts ensures cluster access uses centrally governed Microsoft Entra identities instead of unmanaged static credentials.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-AKS-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-003": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited", - "description": "Managed identities remove manually rotated service-principal credentials from AKS control-plane access to Azure resources." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "Managed identities remove manually rotated service-principal credentials from AKS control-plane access to Azure resources.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-AKS-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-004": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "Workload Identity supports workload-specific, least-privilege authorization to Azure resources without shared application secrets." + "description": "Workload Identity supports workload-specific, least-privilege authorization to Azure resources without shared application secrets.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-AKS-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-005": { "control_id": "PR.IP-1", "control_name": "A baseline configuration is created and maintained", - "description": "The Azure Policy add-on enables centrally defined Kubernetes security baselines to be audited and enforced consistently." + "description": "The Azure Policy add-on enables centrally defined Kubernetes security baselines to be audited and enforced consistently.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-1", + "rationale": "NIST CSF 1.1 subcategory PR.IP-1 ('A baseline configuration is created and maintained') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-AKS-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-006": { "control_id": "PR.IP-12", "control_name": "A vulnerability management plan is developed and implemented", - "description": "Managed node OS upgrade channels apply tested security updates to reduce exposure to known operating-system vulnerabilities." + "description": "Managed node OS upgrade channels apply tested security updates to reduce exposure to known operating-system vulnerabilities.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-12", + "rationale": "NIST CSF 1.1 subcategory PR.IP-12 ('A vulnerability management plan is developed and implemented') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-AKS-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-010": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "Assigned owners establish accountability for reviewing and maintaining application access." + "description": "Assigned owners establish accountability for reviewing and maintaining application access.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-010 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-011": { "control_id": "PR.DS-2", - "control_name": "Data in transit is protected", - "description": "HTTPS redirect URIs protect authorization responses from interception and modification in transit." + "control_name": "Data-in-transit is protected", + "description": "HTTPS redirect URIs protect authorization responses from interception and modification in transit.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-011 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-012": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Disabling implicit grant reduces exposure of front-channel tokens used for remote application access." + "description": "Disabling implicit grant reduces exposure of front-channel tokens used for remote application access.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST CSF 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-012 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-013": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are managed", - "description": "Replacing client secrets with managed credentials reduces credential leakage and rotation risk." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "Replacing client secrets with managed credentials reduces credential leakage and rotation risk.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-013 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-014": { "control_id": "PR.IP-1", "control_name": "A baseline configuration is created and maintained", - "description": "Application-instance property lock preserves the approved sensitive-property baseline across tenants." + "description": "Application-instance property lock preserves the approved sensitive-property baseline across tenants.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-1", + "rationale": "NIST CSF 1.1 subcategory PR.IP-1 ('A baseline configuration is created and maintained') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-014 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-015": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "Managed identities should receive only the minimum role and scope required by their workloads." + "description": "Managed identities should receive only the minimum role and scope required by their workloads.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-IDN-015 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-001": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", - "description": "The Recovery Services vault lacks the approved soft-delete recovery window, risking permanent loss of backup data before it can be restored." + "description": "The Recovery Services vault lacks the approved soft-delete recovery window, risking permanent loss of backup data before it can be restored.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-4", + "rationale": "NIST CSF 1.1 subcategory PR.IP-4 ('Backups of information are conducted, maintained, and tested') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-BAK-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-002": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", - "description": "Vault immutability is disabled, allowing destructive changes to protected recovery points and undermining the integrity of backup copies." + "description": "Vault immutability is disabled, allowing destructive changes to protected recovery points and undermining the integrity of backup copies.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-4", + "rationale": "NIST CSF 1.1 subcategory PR.IP-4 ('Backups of information are conducted, maintained, and tested') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-BAK-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-004": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "The vault does not enable Resource Guard multiuser authorization, allowing a single compromised or malicious identity to disable backup protections unilaterally." + "description": "The vault does not enable Resource Guard multiuser authorization, allowing a single compromised or malicious identity to disable backup protections unilaterally.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-BAK-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-006": { "control_id": "DE.CM-1", "control_name": "The network is monitored to detect potential cybersecurity events", - "description": "The Recovery Services vault does not enable built-in monitoring for backup job failures, so a failed or tampered backup could go undetected." + "description": "The Recovery Services vault does not enable built-in monitoring for backup job failures, so a failed or tampered backup could go undetected.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-1", + "rationale": "NIST CSF 1.1 subcategory DE.CM-1 ('The network is monitored to detect potential cybersecurity events') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-BAK-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-001": { "control_id": "PR.DS-2", "control_name": "Data-in-transit is protected", - "description": "The Function App accepts unencrypted HTTP traffic, so requests and responses can cross the network without encryption in transit." + "description": "The Function App accepts unencrypted HTTP traffic, so requests and responses can cross the network without encryption in transit.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-FUNC-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-002": { "control_id": "PR.DS-2", "control_name": "Data-in-transit is protected", - "description": "The Function App permits TLS older than 1.2, weakening the encryption protecting traffic in transit." + "description": "The Function App permits TLS older than 1.2, weakening the encryption protecting traffic in transit.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-FUNC-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-003": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "The Function App exposes an FTP or FTPS deployment channel, widening the network attack surface beyond the primary HTTPS endpoint." + "description": "The Function App exposes an FTP or FTPS deployment channel, widening the network attack surface beyond the primary HTTPS endpoint.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-FUNC-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-004": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "Remote debugging expands the Function App management attack surface by opening an additional network-reachable control channel." + "description": "Remote debugging expands the Function App management attack surface by opening an additional network-reachable control channel.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-FUNC-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-005": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "The Function App has no Azure managed identity for secretless resource access, pushing workloads toward long-lived credentials that cross network and service boundaries." + "description": "The Function App has no Azure managed identity for secretless resource access, pushing workloads toward long-lived credentials that cross network and service boundaries.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-FUNC-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-001": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "A Storage Account remains publicly reachable; an approved private endpoint alone does not disable its public endpoint, leaving the network boundary uncontrolled." + "description": "A Storage Account remains publicly reachable; an approved private endpoint alone does not disable its public endpoint, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-PE-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-002": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "An Azure SQL logical server remains publicly reachable, regardless of whether a private endpoint also exists, leaving the network boundary uncontrolled." + "description": "An Azure SQL logical server remains publicly reachable, regardless of whether a private endpoint also exists, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-PE-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-003": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "A PostgreSQL Flexible Server remains publicly reachable instead of using private networking only, leaving the network boundary uncontrolled." + "description": "A PostgreSQL Flexible Server remains publicly reachable instead of using private networking only, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-PE-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-004": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "An App Service workload remains publicly reachable without a default-deny access policy, leaving the network boundary uncontrolled." + "description": "An App Service workload remains publicly reachable without a default-deny access policy, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-PE-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-005": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "A Recovery Services vault permits public access, even if a private endpoint also exists, leaving the network boundary uncontrolled." + "description": "A Recovery Services vault permits public access, even if a private endpoint also exists, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-PE-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-006": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "A private endpoint connection is pending, rejected, or disconnected and does not provide an active private path, leaving traffic to traverse the public network boundary instead." + "description": "A private endpoint connection is pending, rejected, or disconnected and does not provide an active private path, leaving traffic to traverse the public network boundary instead.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-PE-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-001": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited", - "description": "The Container Registry admin user is enabled, providing a shared credential that bypasses individual identity management and cannot be attributed to a single user." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "The Container Registry admin user is enabled, providing a shared credential that bypasses individual identity management and cannot be attributed to a single user.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-002": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "The Container Registry is reachable from the public internet, leaving the network boundary that protects the organization's built container images uncontrolled." + "description": "The Container Registry is reachable from the public internet, leaving the network boundary that protects the organization's built container images uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-003": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited", - "description": "The Container Registry allows anonymous pull, letting any client access every image without an authenticated, individually attributable identity." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "The Container Registry allows anonymous pull, letting any client access every image without an authenticated, individually attributable identity.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-004": { "control_id": "PR.IP-1", "control_name": "A baseline configuration is created and maintained", - "description": "The Container Registry has no retention or quarantine policy, so stale images accumulate and newly pushed images are deployable before any vulnerability scan evaluates them." + "description": "The Container Registry has no retention or quarantine policy, so stale images accumulate and newly pushed images are deployable before any vulnerability scan evaluates them.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-1", + "rationale": "NIST CSF 1.1 subcategory PR.IP-1 ('A baseline configuration is created and maintained') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-005": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "A Terraform remote state container is publicly readable, leaving the network boundary around infrastructure layout and captured secrets uncontrolled." + "description": "A Terraform remote state container is publicly readable, leaving the network boundary around infrastructure layout and captured secrets uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-006": { "control_id": "PR.IP-4", "control_name": "Backups of information are conducted, maintained, and tested", - "description": "A storage account holding Terraform remote state has neither versioning nor soft delete enabled, so an overwritten or deleted state file cannot be recovered." + "description": "A storage account holding Terraform remote state has neither versioning nor soft delete enabled, so an overwritten or deleted state file cannot be recovered.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.IP-4", + "rationale": "NIST CSF 1.1 subcategory PR.IP-4 ('Backups of information are conducted, maintained, and tested') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-007": { "control_id": "PR.AC-4", "control_name": "Access permissions and authorizations are managed", - "description": "A pipeline service connection is scoped to the entire subscription rather than a single resource group, so every pipeline that uses it inherits subscription-wide access beyond what it needs." + "description": "A pipeline service connection is scoped to the entire subscription rather than a single resource group, so every pipeline that uses it inherits subscription-wide access beyond what it needs.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-4", + "rationale": "NIST CSF 1.1 subcategory PR.AC-4 ('Access permissions and authorizations are managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-007 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-008": { "control_id": "PR.AC-1", - "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited", - "description": "A pipeline service connection authenticates with a stored service principal secret instead of a federated credential, leaving a static credential to rotate and potentially leak." + "control_name": "Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes", + "description": "A pipeline service connection authenticates with a stored service principal secret instead of a federated credential, leaving a static credential to rotate and potentially leak.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-1", + "rationale": "NIST CSF 1.1 subcategory PR.AC-1 ('Identities and credentials are issued, managed, verified, revoked, and audited for authorized devices, users and processes') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SC-008 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-001": { "control_id": "PR.DS-2", - "control_name": "Data in transit is protected", - "description": "MACsec protects traffic on the customer-visible ExpressRoute Direct Ethernet boundary." + "control_name": "Data-in-transit is protected", + "description": "MACsec protects traffic on the customer-visible ExpressRoute Direct Ethernet boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-DL-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-002": { "control_id": "PR.DS-2", - "control_name": "Data in transit is protected", - "description": "XPN MACsec avoids packet-number exhaustion risk on high-speed ExpressRoute Direct links." + "control_name": "Data-in-transit is protected", + "description": "XPN MACsec avoids packet-number exhaustion risk on high-speed ExpressRoute Direct links.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-2", + "rationale": "NIST CSF 1.1 subcategory PR.DS-2 ('Data-in-transit is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-DL-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-016": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "Unnecessary NIC IP forwarding weakens Azure source and destination validation and can create an unintended transit path." + "description": "Unnecessary NIC IP forwarding weakens Azure source and destination validation and can create an unintended transit path.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-016 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-017": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "An explicit default Internet UDR can bypass the approved inspected egress path." + "description": "An explicit default Internet UDR can bypass the approved inspected egress path.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST CSF 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-017 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-018": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Disabling unnecessary public access ensures the Private Endpoint is the managed remote access path." + "description": "Disabling unnecessary public access ensures the Private Endpoint is the managed remote access path.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-018 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-019": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "Approved Private Endpoint connections preserve the intended private network boundary." + "description": "Approved Private Endpoint connections preserve the intended private network boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-019 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-020": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "Private DNS zone association directs service names through the intended private endpoint path." + "description": "Private DNS zone association directs service names through the intended private endpoint path.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-020 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-021": { "control_id": "PR.AC-5", "control_name": "Network integrity is protected", - "description": "Private Endpoint ARM DNS configuration associates service names with private addresses; effective resolver-path validation remains separate evidence." + "description": "Private address resolution provides evidence that service traffic follows the private network boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-5", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.AC-5 ('Network integrity is protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-021 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-022": { "control_id": "PR.AC-3", "control_name": "Remote access is managed", - "description": "Critical PaaS public access is disabled unless an explicit approved exception exists." + "description": "Critical PaaS public access is disabled unless an explicit approved exception exists.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.AC-3", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.AC-3 ('Remote access is managed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-022 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-023": { "control_id": "DE.CM-1", "control_name": "The network is monitored", - "description": "Azure Firewall threat intelligence alerts on and denies traffic involving known malicious infrastructure." + "description": "Azure Firewall threat intelligence alerts on and denies traffic involving known malicious infrastructure.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-1", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory DE.CM-1 ('The network is monitored') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-023 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-024": { "control_id": "PR.PT-4", "control_name": "Communications and control networks are protected", - "description": "Application Gateway WAF Prevention mode actively blocks matching application attacks." + "description": "Application Gateway WAF Prevention mode actively blocks matching application attacks.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.PT-4", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.PT-4 ('Communications and control networks are protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-024 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-025": { "control_id": "DE.CM-1", "control_name": "The network is monitored", - "description": "Application Gateway SKU-supported diagnostic logs provide perimeter monitoring evidence; v2 performance telemetry is supplied through metrics." + "description": "Application Gateway access, performance, and firewall logs provide perimeter monitoring evidence.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-1", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory DE.CM-1 ('The network is monitored') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-025 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-026": { "control_id": "PR.PT-4", "control_name": "Communications and control networks are protected", - "description": "Current base and bot managed rules protect the web application perimeter." + "description": "Current base and bot managed rules protect the web application perimeter.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.PT-4", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.PT-4 ('Communications and control networks are protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-026 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-027": { "control_id": "PR.PT-4", "control_name": "Communications and control networks are protected", - "description": "Rate-limit rules protect internet-facing applications from abusive request volume." + "description": "Rate-limit rules protect internet-facing applications from abusive request volume.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.PT-4", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory PR.PT-4 ('Communications and control networks are protected') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-NET-027 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-001": { "control_id": "PR.PT-1", "control_name": "Audit/log records are determined, documented, implemented, and reviewed in accordance with policy", - "description": "The subscription's Activity Log is not exported to an approved central destination. PR.PT-1 requires audit/log records to be implemented in accordance with policy; an unexported Activity Log is not available to the review process the policy requires." + "description": "The subscription's Activity Log is not exported to an approved central destination. PR.PT-1 requires audit/log records to be implemented in accordance with policy; an unexported Activity Log is not available to the review process the policy requires.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.PT-1", + "rationale": "NIST CSF 1.1 subcategory PR.PT-1 ('Audit/log records are determined, documented, implemented, and reviewed in accordance with policy') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-001 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-002": { "control_id": "PR.PT-1", "control_name": "Audit/log records are determined, documented, implemented, and reviewed in accordance with policy", - "description": "Required Activity Log categories are missing from the central export. PR.PT-1 requires audit/log records to be determined and implemented per policy; an export missing organisation-required categories does not implement the full policy-defined log scope." + "description": "Required Activity Log categories are missing from the central export. PR.PT-1 requires audit/log records to be determined and implemented per policy; an export missing organisation-required categories does not implement the full policy-defined log scope.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.PT-1", + "rationale": "NIST CSF 1.1 subcategory PR.PT-1 ('Audit/log records are determined, documented, implemented, and reviewed in accordance with policy') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-002 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-003": { "control_id": "DE.AE-3", "control_name": "Event data are collected and correlated from multiple sources and sensors", - "description": "A critical resource lacks diagnostic settings exporting to an approved destination. DE.AE-3 requires event data to be collected and correlated from multiple sources; a critical resource with no export is a source contributing no data to that correlation." + "description": "A critical resource lacks diagnostic settings exporting to an approved destination. DE.AE-3 requires event data to be collected and correlated from multiple sources; a critical resource with no export is a source contributing no data to that correlation.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.AE-3", + "rationale": "NIST CSF 1.1 subcategory DE.AE-3 ('Event data are collected and correlated from multiple sources and sensors') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-003 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-004": { "control_id": "PR.PT-1", "control_name": "Audit/log records are determined, documented, implemented, and reviewed in accordance with policy", - "description": "A security-relevant log export's retention is below the organisation's minimum. PR.PT-1 requires audit/log records to be reviewed in accordance with policy, which presumes the records still exist at review time; retention shorter than the policy's minimum breaks that assumption." + "description": "A security-relevant log export's retention is below the organisation's minimum. PR.PT-1 requires audit/log records to be reviewed in accordance with policy, which presumes the records still exist at review time; retention shorter than the policy's minimum breaks that assumption.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.PT-1", + "rationale": "NIST CSF 1.1 subcategory PR.PT-1 ('Audit/log records are determined, documented, implemented, and reviewed in accordance with policy') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-004 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-005": { "control_id": "PR.DS-6", "control_name": "Integrity checking mechanisms are used to verify software, firmware, and information integrity", - "description": "A critical resource's only log export sits in a destination its own workload administrators can modify. PR.DS-6 requires integrity-checking mechanisms to verify information integrity; a single, workload-owned destination provides no independent verification that the exported logs have not been altered or deleted by the resource's own administrators." + "description": "A critical resource's only log export sits in a destination its own workload administrators can modify. PR.DS-6 requires integrity-checking mechanisms to verify information integrity; a single, workload-owned destination provides no independent verification that the exported logs have not been altered or deleted by the resource's own administrators.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory PR.DS-6", + "rationale": "NIST CSF 1.1 subcategory PR.DS-6 ('Integrity checking mechanisms are used to verify software, firmware, and information integrity') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-005 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-006": { "control_id": "DE.CM-8", "control_name": "Vulnerability scans are performed", - "description": "A required Microsoft Defender for Cloud plan is not enabled for a critical workload type. DE.CM-8 requires vulnerability scans to be performed; Defender for Cloud performs this scanning for the workload types it protects, and an unlicensed type receives no such scanning." + "description": "A required Microsoft Defender for Cloud plan is not enabled for a critical workload type. DE.CM-8 requires vulnerability scans to be performed; Defender for Cloud performs this scanning for the workload types it protects, and an unlicensed type receives no such scanning.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-8", + "rationale": "NIST CSF 1.1 subcategory DE.CM-8 ('Vulnerability scans are performed') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-006 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-007": { "control_id": "RS.MI-3", "control_name": "Newly identified vulnerabilities are mitigated or documented as accepted risks", - "description": "A High-severity Defender recommendation remains unresolved beyond the organisation's SLA. RS.MI-3 requires newly identified vulnerabilities to be mitigated or documented as accepted risk; an SLA breach with no recorded exception means neither has happened." + "description": "A High-severity Defender recommendation remains unresolved beyond the organisation's SLA. RS.MI-3 requires newly identified vulnerabilities to be mitigated or documented as accepted risk; an SLA breach with no recorded exception means neither has happened.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory RS.MI-3", + "rationale": "NIST CSF 1.1 subcategory RS.MI-3 ('Newly identified vulnerabilities are mitigated or documented as accepted risks') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-007 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-008": { "control_id": "DE.AE-3", "control_name": "Event data are collected and correlated from multiple sources and sensors", - "description": "A required Sentinel data connector is missing or unhealthy. DE.AE-3 requires event data to be collected and correlated from multiple sources and sensors; a disconnected connector is a required sensor that is not contributing data." + "description": "A required Sentinel data connector is missing or unhealthy. DE.AE-3 requires event data to be collected and correlated from multiple sources and sensors; a disconnected connector is a required sensor that is not contributing data.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.AE-3", + "rationale": "NIST CSF 1.1 subcategory DE.AE-3 ('Event data are collected and correlated from multiple sources and sensors') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-008 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-009": { "control_id": "DE.CM-1", "control_name": "The network is monitored to detect potential cybersecurity events", - "description": "Sentinel lacks enabled High-severity analytics coverage for a required detection use case. DE.CM-1 requires the network to be monitored to detect potential cybersecurity events; ingested logs with no analytics rule evaluating them for a known high-risk pattern do not achieve that monitoring outcome for that use case." + "description": "Sentinel lacks enabled High-severity analytics coverage for a required detection use case. DE.CM-1 requires the network to be monitored to detect potential cybersecurity events; ingested logs with no analytics rule evaluating them for a known high-risk pattern do not achieve that monitoring outcome for that use case.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory DE.CM-1", + "rationale": "NIST CSF 1.1 subcategory DE.CM-1 ('The network is monitored to detect potential cybersecurity events') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-009 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-010": { "control_id": "RS.CO-2", "control_name": "Incidents are reported consistent with established criteria", - "description": "No monitored destination exists for security alerts or Sentinel incidents. RS.CO-2 requires incidents to be reported consistent with established criteria; an alert with no notified recipient is never reported to anyone who can act on it." - }, - "AZ-NET-018": { - "control_id": "PR.AC-3", - "control_name": "Remote access is managed", - "description": "Disabling unnecessary public access ensures the Private Endpoint is the managed remote access path." - }, - "AZ-NET-019": { - "control_id": "PR.AC-5", - "control_name": "Network integrity is protected", - "description": "Approved Private Endpoint connections preserve the intended private network boundary." - }, - "AZ-NET-020": { - "control_id": "PR.AC-5", - "control_name": "Network integrity is protected", - "description": "Private DNS zone association directs service names through the intended private endpoint path." - }, - "AZ-NET-021": { - "control_id": "PR.AC-5", - "control_name": "Network integrity is protected", - "description": "Private address resolution provides evidence that service traffic follows the private network boundary." - }, - "AZ-NET-022": { - "control_id": "PR.AC-3", - "control_name": "Remote access is managed", - "description": "Critical PaaS public access is disabled unless an explicit approved exception exists." - }, - "AZ-NET-023": { - "control_id": "DE.CM-1", - "control_name": "The network is monitored", - "description": "Azure Firewall threat intelligence alerts on and denies traffic involving known malicious infrastructure." - }, - "AZ-NET-024": { - "control_id": "PR.PT-4", - "control_name": "Communications and control networks are protected", - "description": "Application Gateway WAF Prevention mode actively blocks matching application attacks." - }, - "AZ-NET-025": { - "control_id": "DE.CM-1", - "control_name": "The network is monitored", - "description": "Application Gateway access, performance, and firewall logs provide perimeter monitoring evidence." - }, - "AZ-NET-026": { - "control_id": "PR.PT-4", - "control_name": "Communications and control networks are protected", - "description": "Current base and bot managed rules protect the web application perimeter." - }, - "AZ-NET-027": { - "control_id": "PR.PT-4", - "control_name": "Communications and control networks are protected", - "description": "Rate-limit rules protect internet-facing applications from abusive request volume." + "description": "No monitored destination exists for security alerts or Sentinel incidents. RS.CO-2 requires incidents to be reported consistent with established criteria; an alert with no notified recipient is never reported to anyone who can act on it.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "NIST Cybersecurity Framework 1.1, subcategory RS.CO-2", + "rationale": "NIST Cybersecurity Framework 1.1 subcategory RS.CO-2 ('Incidents are reported consistent with established criteria') describes a broader security outcome that requires organizational process in addition to technical configuration. OpenShield rule AZ-SECOPS-010 evaluates one Azure technical control that provides supporting automated evidence toward this outcome; it does not by itself fully satisfy the subcategory.", + "owner": null, + "review_status": "pending_review", + "review_date": null } } } diff --git a/compliance/frameworks/soc2.json b/compliance/frameworks/soc2.json index 4e312355..8eb8ff27 100644 --- a/compliance/frameworks/soc2.json +++ b/compliance/frameworks/soc2.json @@ -2,586 +2,1282 @@ "framework": "SOC 2 Type II", "version": "2017", "published": "2017-04", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "OpenShield compliance mapping pack, authored against the AICPA 2017 Trust Services Criteria (SOC 2 Type II) common criteria and additional criteria text. Technical-evidence mapping only; not a substitute for an independent auditor's SOC 2 examination.", + "mapping_pack_published": "2026-08-22", "controls": { "AZ-STOR-001": { "control_id": "CC6.6", - "control_name": "Restricts Access to Information Assets", - "description": "Public blob access allows unauthenticated users from outside the network boundary to read storage data without credentials. CC6.6 requires that access from outside the network perimeter is restricted and controlled. Disabling public access enforces this boundary by requiring authentication for all storage operations." + "control_name": "Restricts Access from Outside the Network Boundary", + "description": "Public blob access allows unauthenticated users from outside the network boundary to read storage data without credentials. CC6.6 requires that access from outside the network perimeter is restricted and controlled. Disabling public access enforces this boundary by requiring authentication for all storage operations.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-STOR-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-002": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit", - "description": "Allowing unencrypted HTTP traffic to a storage account exposes data in transit to interception and tampering. CC6.7 requires that data transmitted over networks is protected using encryption. Enforcing HTTPS-only ensures all storage traffic is encrypted in transit." + "control_name": "Restricts Transmission and Movement of Information", + "description": "Allowing unencrypted HTTP traffic to a storage account exposes data in transit to interception and tampering. CC6.7 requires that data transmitted over networks is protected using encryption. Enforcing HTTPS-only ensures all storage traffic is encrypted in transit.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.7", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.7 ('Restricts Transmission and Movement of Information') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-STOR-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-003": { "control_id": "CC8.1", "control_name": "Change Management", - "description": "A storage account with no lifecycle management policy allows data to accumulate indefinitely with no automatic expiry or tiering. CC8.1 requires that infrastructure and data are managed through formal processes. Implementing a lifecycle policy ensures data retention is controlled and old data is automatically moved or deleted according to organisational policy." + "description": "A storage account with no lifecycle management policy allows data to accumulate indefinitely with no automatic expiry or tiering. CC8.1 requires that infrastructure and data are managed through formal processes. Implementing a lifecycle policy ensures data retention is controlled and old data is automatically moved or deleted according to organisational policy.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC8.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC8.1 ('Change Management') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-STOR-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-004": { "control_id": "CC7.2", - "control_name": "System monitoring", - "description": "Azure Monitor diagnostic logging must be enabled for all storage account services (blob, queue, table) to ensure that security-relevant events are recorded. CC7.2 requires that the entity monitors the system and takes action to maintain compliance. Without full logging, unauthorized access or data exfiltration attempts may go undetected." + "control_name": "System Monitoring", + "description": "Azure Monitor diagnostic logging must be enabled for all storage account services (blob, queue, table) to ensure that security-relevant events are recorded. CC7.2 requires that the entity monitors the system and takes action to maintain compliance. Without full logging, unauthorized access or data exfiltration attempts may go undetected.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-STOR-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-STOR-005": { "control_id": "A1.2", "control_name": "Environmental Threats and Recovery", - "description": "Storage accounts configured with LRS or ZRS replication do not protect against environmental threats at the regional level. A regional outage or disaster could result in data loss and service unavailability. Geo-redundant replication is needed to ensure business continuity." + "description": "Storage accounts configured with LRS or ZRS replication do not protect against environmental threats at the regional level. A regional outage or disaster could result in data loss and service unavailability. Geo-redundant replication is needed to ensure business continuity.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion A1.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion A1.2 ('Environmental Threats and Recovery') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-STOR-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-001": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "An NSG allowing unrestricted RDP access from the internet permits any external party to attempt remote access to virtual machines. CC6.6 requires that logical access from outside the network boundary is restricted. Limiting RDP to known IP ranges enforces this boundary and eliminates unauthorised remote access attempts." + "description": "An NSG allowing unrestricted RDP access from the internet permits any external party to attempt remote access to virtual machines. CC6.6 requires that logical access from outside the network boundary is restricted. Limiting RDP to known IP ranges enforces this boundary and eliminates unauthorised remote access attempts.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-002": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "An NSG allowing unrestricted SSH access from the internet exposes virtual machines to brute force and credential attacks from any external party. CC6.6 requires that access from outside the network perimeter is restricted and controlled. Restricting SSH to known IP ranges or removing it in favour of Azure Bastion enforces this boundary." + "description": "An NSG allowing unrestricted SSH access from the internet exposes virtual machines to brute force and credential attacks from any external party. CC6.6 requires that access from outside the network perimeter is restricted and controlled. Restricting SSH to known IP ranges or removing it in favour of Azure Bastion enforces this boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-003": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "An NSG permitting unrestricted inbound access on port 443 from the internet exposes web services to automated scanning and exploitation attempts from any external source. CC6.6 requires that access from outside the network boundary is restricted to authorised sources. Public-facing services should be fronted by a WAF-enabled Application Gateway rather than exposed directly." + "description": "An NSG permitting unrestricted inbound access on port 443 from the internet exposes web services to automated scanning and exploitation attempts from any external source. CC6.6 requires that access from outside the network boundary is restricted to authorised sources. Public-facing services should be fronted by a WAF-enabled Application Gateway rather than exposed directly.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-004": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A Network Security Group with no custom rules provides no meaningful boundary control and relies entirely on Azure defaults. CC6.6 requires that logical access from outside the network perimeter is explicitly restricted. Explicit least-privilege rules must be defined to enforce the network boundary." + "description": "A Network Security Group with no custom rules provides no meaningful boundary control and relies entirely on Azure defaults. CC6.6 requires that logical access from outside the network perimeter is explicitly restricted. Explicit least-privilege rules must be defined to enforce the network boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-005": { "control_id": "A1.1", "control_name": "Capacity and Performance Monitoring", - "description": "Virtual networks without DDoS Protection Standard are vulnerable to volumetric attacks that can exhaust capacity and cause service outages. A1.1 requires that current processes and procedures are performed to manage capacity and performance." + "description": "Virtual networks without DDoS Protection Standard are vulnerable to volumetric attacks that can exhaust capacity and cause service outages. A1.1 requires that current processes and procedures are performed to manage capacity and performance.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion A1.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion A1.1 ('Capacity and Performance Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-006": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "Unassociated public IP addresses represent unnecessary exposure on the internet and may indicate leftover resources from decommissioned workloads. CC6.6 requires that the network boundary is managed to restrict logical access from outside sources. Orphaned public IPs should be removed." + "description": "Unassociated public IP addresses represent unnecessary exposure on the internet and may indicate leftover resources from decommissioned workloads. CC6.6 requires that the network boundary is managed to restrict logical access from outside sources. Orphaned public IPs should be removed.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-007": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "An Application Gateway without WAF enabled provides no protection against web application attacks from external sources including OWASP Top 10 vulnerabilities. CC6.6 requires that access from outside the network boundary is restricted through logical access controls including WAF." + "description": "An Application Gateway without WAF enabled provides no protection against web application attacks from external sources including OWASP Top 10 vulnerabilities. CC6.6 requires that access from outside the network boundary is restricted through logical access controls including WAF.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-007 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-008": { "control_id": "CC8.1", "control_name": "Change Management", - "description": "A load balancer with no backend pool configured is either misconfigured or a leftover resource from a decommissioned workload that was not properly cleaned up. CC8.1 requires that infrastructure is managed through formal change management and resource lifecycle procedures." + "description": "A load balancer with no backend pool configured is either misconfigured or a leftover resource from a decommissioned workload that was not properly cleaned up. CC8.1 requires that infrastructure is managed through formal change management and resource lifecycle procedures.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC8.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC8.1 ('Change Management') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-008 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-009": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit", - "description": "VPN gateway connections using IKEv1 use an outdated protocol with known vulnerabilities that weaken the confidentiality and integrity of data transmitted between networks. CC6.7 requires that data in transit is protected through encryption using current, secure protocols." + "control_name": "Restricts Transmission and Movement of Information", + "description": "VPN gateway connections using IKEv1 use an outdated protocol with known vulnerabilities that weaken the confidentiality and integrity of data transmitted between networks. CC6.7 requires that data in transit is protected through encryption using current, secure protocols.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.7", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.7 ('Restricts Transmission and Movement of Information') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-009 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-010": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A subnet without an NSG attached has no network layer access controls leaving all resources in that subnet reachable from other subnets or the internet with no filtering. CC6.6 requires that access is controlled through network-level restrictions." + "description": "A subnet without an NSG attached has no network layer access controls leaving all resources in that subnet reachable from other subnets or the internet with no filtering. CC6.6 requires that access is controlled through network-level restrictions.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-010 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-001": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "A service principal with Contributor role at subscription scope has unrestricted ability to create, modify and delete any resource in the environment. CC6.1 requires that logical access controls restrict authorizations to authenticated and verified users and processes." + "description": "A service principal with Contributor role at subscription scope has unrestricted ability to create, modify and delete any resource in the environment. CC6.1 requires that logical access controls restrict authorizations to authenticated and verified users and processes.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-002": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "Without MFA enforced on privileged accounts, a single compromised password grants full administrative access to the Azure environment. CC6.1 requires that logical access controls are implemented to authenticate and authorise users and processes." + "description": "Without MFA enforced on privileged accounts, a single compromised password grants full administrative access to the Azure environment. CC6.1 requires that logical access controls are implemented to authenticate and authorise users and processes.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-003": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "Unrestricted guest user invitations allow any organisation member to introduce unreviewed external identities into the tenant. CC6.1 requires that logical access to information assets is controlled and verified through authentication procedures." + "description": "Unrestricted guest user invitations allow any organisation member to introduce unreviewed external identities into the tenant. CC6.1 requires that logical access to information assets is controlled and verified through authentication procedures.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-005": { "control_id": "CC6.3", - "control_name": "Role-based access control", - "description": "Guest users assigned high privilege roles in Entra ID give external parties administrative control over the Azure tenant. CC6.3 requires that role-based access controls restrict access to authorised internal users based on their responsibilities. Privileged roles must be removed from all guest accounts." + "control_name": "Role-Based Access Control", + "description": "Guest users assigned high privilege roles in Entra ID give external parties administrative control over the Azure tenant. CC6.3 requires that role-based access controls restrict access to authorised internal users based on their responsibilities. Privileged roles must be removed from all guest accounts.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.3", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.3 ('Role-Based Access Control') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-006": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "Service principal client secrets older than 90 days or with no expiry date represent unmanaged credentials that persist beyond their useful life. CC6.1 requires that logical access controls implement authentication measures to prevent unauthorised access. Stale or non-expiring secrets must be rotated and replaced with time-bound credentials or managed identities." + "description": "Service principal client secrets older than 90 days or with no expiry date represent unmanaged credentials that persist beyond their useful life. CC6.1 requires that logical access controls implement authentication measures to prevent unauthorised access. Stale or non-expiring secrets must be rotated and replaced with time-bound credentials or managed identities.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-007": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "Active Entra ID users with no MFA registered can access Azure resources with a single compromised password. CC6.1 requires that logical access controls implement multi-factor authentication to protect against unauthorised access. Conditional Access policies must enforce MFA registration and usage for all active user accounts." + "description": "Active Entra ID users with no MFA registered can access Azure resources with a single compromised password. CC6.1 requires that logical access controls implement multi-factor authentication to protect against unauthorised access. Conditional Access policies must enforce MFA registration and usage for all active user accounts.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-007 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-008": { "control_id": "CC6.3", - "control_name": "Role-based access control", - "description": "Custom RBAC roles with wildcard permissions grant unconstrained access to subscription resources and undermine role-based access controls. CC6.3 requires that role-based access controls restrict access based on defined job responsibilities. Wildcard actions in custom roles must be replaced with explicit, minimal permission sets." + "control_name": "Role-Based Access Control", + "description": "Custom RBAC roles with wildcard permissions grant unconstrained access to subscription resources and undermine role-based access controls. CC6.3 requires that role-based access controls restrict access based on defined job responsibilities. Wildcard actions in custom roles must be replaced with explicit, minimal permission sets.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.3", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.3 ('Role-Based Access Control') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-008 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-009": { "control_id": "CC7.2", - "control_name": "System monitoring", - "description": "Without an activity log alert for role assignment changes, privilege escalation events in the subscription are not detected or investigated. CC7.2 requires that the entity monitors system components and the operation of controls to detect anomalies. An alert for Microsoft.Authorization/roleAssignments/write must be created and linked to an active action group." + "control_name": "System Monitoring", + "description": "Without an activity log alert for role assignment changes, privilege escalation events in the subscription are not detected or investigated. CC7.2 requires that the entity monitors system components and the operation of controls to detect anomalies. An alert for Microsoft.Authorization/roleAssignments/write must be created and linked to an active action group.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-009 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-001": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit and At Rest", - "description": "SQL Server without Transparent Data Encryption stores database files in plain text on disk. CC6.7 requires that data is protected using encryption both in transit and at rest against interception and tampering." + "control_name": "Restricts Transmission and Movement of Information", + "description": "SQL Server without Transparent Data Encryption stores database files in plain text on disk. CC6.7 requires that data is protected using encryption both in transit and at rest against interception and tampering.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.7", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.7 ('Restricts Transmission and Movement of Information') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-DB-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-002": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A SQL Server firewall rule allowing all IP addresses makes the database reachable from anywhere on the internet. CC6.6 requires that access from outside the network boundary is restricted to authorised sources through explicit firewall rules or private endpoints." + "description": "A SQL Server firewall rule allowing all IP addresses makes the database reachable from anywhere on the internet. CC6.6 requires that access from outside the network boundary is restricted to authorised sources through explicit firewall rules or private endpoints.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-DB-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-001": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A virtual machine with a public IP and no NSG has unrestricted inbound network access from the internet with no filtering in place. CC6.6 requires that logical access from outside the network boundary is restricted and controlled." + "description": "A virtual machine with a public IP and no NSG has unrestricted inbound network access from the internet with no filtering in place. CC6.6 requires that logical access from outside the network boundary is restricted and controlled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-CMP-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-002": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit and At Rest", - "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CC6.7 requires that data is protected using encryption. Platform-managed keys lack customer control and audit capabilities needed for compliance." + "control_name": "Restricts Transmission and Movement of Information", + "description": "Virtual machine OS and data disks are using platform-managed encryption only (EncryptionAtRestWithPlatformKey). CC6.7 requires that data is protected using encryption. Platform-managed keys lack customer control and audit capabilities needed for compliance.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.7", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.7 ('Restricts Transmission and Movement of Information') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-CMP-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-003": { "control_id": "CC6.8", "control_name": "Prevents or Detects Unauthorized Software", - "description": "Virtual machines without recognized endpoint protection lack controls to prevent, detect, and act upon malicious software. CC6.8 requires controls that address the introduction of unauthorized or malicious software on systems." + "description": "Virtual machines without recognized endpoint protection lack controls to prevent, detect, and act upon malicious software. CC6.8 requires controls that address the introduction of unauthorized or malicious software on systems.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.8", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.8 ('Prevents or Detects Unauthorized Software') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-CMP-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-004": { "control_id": "CC7.1", - "control_name": "System Vulnerabilities are Identified and Managed", - "description": "The virtual machine does not have automatic OS patching enabled. CC7.1 requires that vulnerabilities in system components are identified and managed through a defined process. Without automatic patching, known OS vulnerabilities are left unmitigated and exploitable." + "control_name": "Detection and Monitoring of New Vulnerabilities", + "description": "The virtual machine does not have automatic OS patching enabled. CC7.1 requires that vulnerabilities in system components are identified and managed through a defined process. Without automatic patching, known OS vulnerabilities are left unmitigated and exploitable.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.1 ('Detection and Monitoring of New Vulnerabilities') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-CMP-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-CMP-007": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A VM has management ports (SSH/RDP) open to the internet with no Just-In-Time VM access policy covering them. CC6.6 requires that access from outside the network boundary is restricted. JIT opens management ports only for approved, time-boxed requests instead of continuously." + "description": "A VM has management ports (SSH/RDP) open to the internet with no Just-In-Time VM access policy covering them. CC6.6 requires that access from outside the network boundary is restricted. JIT opens management ports only for approved, time-boxed requests instead of continuously.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-CMP-007 evaluates one Azure technical control (Just-In-Time VM access coverage for open management ports) that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-001": { "control_id": "A1.2", "control_name": "Environmental Threats and Recovery", - "description": "Key Vault without soft delete enabled allows permanent deletion of secrets, keys and certificates with no recovery possible. A1.2 requires that environmental threats to availability of information systems are addressed through recovery procedures." + "description": "Key Vault without soft delete enabled allows permanent deletion of secrets, keys and certificates with no recovery possible. A1.2 requires that environmental threats to availability of information systems are addressed through recovery procedures.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion A1.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion A1.2 ('Environmental Threats and Recovery') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-KV-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-002": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A Key Vault accessible from the public internet allows any external party to attempt access to secrets, keys and certificates. CC6.6 requires that access from outside the network boundary is restricted. Network rules should deny public access." + "description": "A Key Vault accessible from the public internet allows any external party to attempt access to secrets, keys and certificates. CC6.6 requires that access from outside the network boundary is restricted. Network rules should deny public access.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-KV-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-003": { "control_id": "CC7.2", - "control_name": "System monitoring", - "description": "Key Vault diagnostic logging supports monitoring of access to secrets, keys, and certificates. Without diagnostic logs, unauthorized activity cannot be detected, investigated, or escalated through monitoring procedures." + "control_name": "System Monitoring", + "description": "Key Vault diagnostic logging supports monitoring of access to secrets, keys, and certificates. Without diagnostic logs, unauthorized activity cannot be detected, investigated, or escalated through monitoring procedures.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-KV-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-011": { "control_id": "CC7.2", - "control_name": "System monitoring", - "description": "Network Watcher must be enabled in all regions where resources are deployed to support continuous system monitoring. Without it, network-level events cannot be detected or investigated, preventing incident response." + "control_name": "System Monitoring", + "description": "Network Watcher must be enabled in all regions where resources are deployed to support continuous system monitoring. Without it, network-level events cannot be detected or investigated, preventing incident response.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-011 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-012": { "control_id": "CC7.2", - "control_name": "System monitoring", - "description": "A VNet flow log (or an existing legacy NSG flow log) supports continuous monitoring of network traffic and investigation of anomalous connections. New NSG flow log creation is blocked as of 2025-06-30, so VNet flow logs are the current mechanism. Without either, network-level security events may not be detected or reconstructed." + "control_name": "System Monitoring", + "description": "A VNet flow log (or an existing legacy NSG flow log) supports continuous monitoring of network traffic and investigation of anomalous connections. New NSG flow log creation is blocked as of 2025-06-30, so VNet flow logs are the current mechanism. Without either, network-level security events may not be detected or reconstructed.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-012 evaluates one Azure technical control (VNet flow logs, with the legacy NSG flow log mechanism Microsoft is retiring accepted as a fallback) that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-003": { "control_id": "CC6.1", - "control_name": "Logical and physical access controls", - "description": "SSL enforcement ensures database connections are encrypted, protecting data in transit from unauthorised access. Disabling SSL undermines logical access controls by exposing credentials and sensitive data to interception." + "control_name": "Logical Access Security Measures", + "description": "SSL enforcement ensures database connections are encrypted, protecting data in transit from unauthorised access. Disabling SSL undermines logical access controls by exposing credentials and sensitive data to interception.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-DB-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-004": { "control_id": "CC9.1", "control_name": "Risk Mitigation", - "description": "Azure Key Vaults without purge protection enabled allow permanent deletion of secrets, keys, and certificates during the soft-delete retention period. CC9.1 requires that identified risks are mitigated through controls that reduce the likelihood or impact of risk events. Enabling purge protection mitigates the risk of irrecoverable loss of cryptographic material." + "description": "Azure Key Vaults without purge protection enabled allow permanent deletion of secrets, keys, and certificates during the soft-delete retention period. CC9.1 requires that identified risks are mitigated through controls that reduce the likelihood or impact of risk events. Enabling purge protection mitigates the risk of irrecoverable loss of cryptographic material.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC9.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC9.1 ('Risk Mitigation') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-KV-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-005": { "control_id": "CC9.1", "control_name": "Risk Mitigation", - "description": "A certificate stored in Azure Key Vault is expiring within 30 days with no auto-renewal configured. CC9.1 requires that identified risks are mitigated through controls that reduce the likelihood or impact of risk events. An expiring certificate without auto-renewal represents an unmitigated operational risk that will cause service outages if not addressed." + "description": "A certificate stored in Azure Key Vault is expiring within 30 days with no auto-renewal configured. CC9.1 requires that identified risks are mitigated through controls that reduce the likelihood or impact of risk events. An expiring certificate without auto-renewal represents an unmitigated operational risk that will cause service outages if not addressed.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC9.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC9.1 ('Risk Mitigation') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-KV-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-KV-006": { "control_id": "CC6.1", - "control_name": "Logical Access Security", - "description": "Key Vaults authorizing access through legacy vault access policies instead of Azure RBAC lack the scoped, role-based logical access controls CC6.1 requires. Access policies grant broad, per-permission-type access rather than least-privilege role assignments, increasing the risk of unauthorized access to secrets, keys, and certificates." + "control_name": "Logical Access Security Measures", + "description": "Key Vaults authorizing access through legacy vault access policies instead of Azure RBAC lack the scoped, role-based logical access controls CC6.1 requires. Access policies grant broad, per-permission-type access rather than least-privilege role assignments, increasing the risk of unauthorized access to secrets, keys, and certificates.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-KV-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DB-004": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall creates a rule that permits any Azure-hosted resource — including services from other tenants — to connect to the database. CC6.6 requires that access from outside the network boundary is restricted to authorised sources. Disabling this setting and replacing it with explicit firewall rules or private endpoints enforces the network boundary and ensures only known and trusted systems can reach the SQL Server." + "description": "Enabling 'Allow access to Azure services' on a SQL Server firewall creates a rule that permits any Azure-hosted resource \u2014 including services from other tenants \u2014 to connect to the database. CC6.6 requires that access from outside the network boundary is restricted to authorised sources. Disabling this setting and replacing it with explicit firewall rules or private endpoints enforces the network boundary and ensures only known and trusted systems can reach the SQL Server.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-DB-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-004": { "control_id": "CC6.3", - "control_name": "Role-based access control", - "description": "PIM provides role-based access control with time-bound activation for privileged roles. Without PIM, admin roles are permanently assigned with no controls, violating the requirement for managed and restricted privileged access." + "control_name": "Role-Based Access Control", + "description": "PIM provides role-based access control with time-bound activation for privileged roles. Without PIM, admin roles are permanently assigned with no controls, violating the requirement for managed and restricted privileged access.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.3", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.3 ('Role-Based Access Control') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-013": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A virtual network without an Azure Firewall relies on NSGs alone and lacks a centralized point to inspect, filter, and log traffic crossing the network boundary. CC6.6 requires that logical access from outside the network boundary is restricted and controlled. Deploying an Azure Firewall enforces inspected, logged perimeter access for the network." + "description": "A virtual network without an Azure Firewall relies on NSGs alone and lacks a centralized point to inspect, filter, and log traffic crossing the network boundary. CC6.6 requires that logical access from outside the network boundary is restricted and controlled. Deploying an Azure Firewall enforces inspected, logged perimeter access for the network.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-013 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-014": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "VNet peering with allowGatewayTransit or useRemoteGateways enabled allows traffic to cross network boundaries through shared gateways, weakening the logical separation between network zones. CC6.6 requires that logical access from outside the network boundary is restricted and controlled. Gateway transit on peering connections should be disabled to enforce boundary separation." + "description": "VNet peering with allowGatewayTransit or useRemoteGateways enabled allows traffic to cross network boundaries through shared gateways, weakening the logical separation between network zones. CC6.6 requires that logical access from outside the network boundary is restricted and controlled. Gateway transit on peering connections should be disabled to enforce boundary separation.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-014 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-015": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "Public DNS zones that expose RFC1918 IP addresses or internal service hostnames provide attackers with reconnaissance data about the organisation's private network topology. CC6.6 requires that logical access from outside the network boundary is restricted and controlled. Records referencing private infrastructure must be removed from public DNS zones to prevent external enumeration of internal services." + "description": "Public DNS zones that expose RFC1918 IP addresses or internal service hostnames provide attackers with reconnaissance data about the organisation's private network topology. CC6.6 requires that logical access from outside the network boundary is restricted and controlled. Records referencing private infrastructure must be removed from public DNS zones to prevent external enumeration of internal services.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-015 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-001": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit", - "description": "TLS configurations using classical key exchange algorithms expose data in transit to Harvest Now Decrypt Later attacks where adversaries collect traffic today and decrypt it with future quantum computers. CC6.7 requires that data transmitted over networks is protected using encryption. Enforcing TLS 1.3 minimum reduces this risk." + "control_name": "Restricts Transmission and Movement of Information", + "description": "TLS configurations using classical key exchange algorithms expose data in transit to Harvest Now Decrypt Later attacks where adversaries collect traffic today and decrypt it with future quantum computers. CC6.7 requires that data transmitted over networks is protected using encryption. Enforcing TLS 1.3 minimum reduces this risk.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria) (no post-quantum criterion defined)", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) predates post-quantum cryptography migration guidance and defines no criterion for quantum-safe algorithm readiness. Mapping rule AZ-PQC-001 to CC6.7 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-002": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit", - "description": "Key Vault keys using RSA or ECC will be vulnerable to Shor's algorithm, compromising data encrypted or signed with these keys. CC6.7 requires that data is protected using encryption. Post-quantum safe key encapsulation algorithms should replace classical alternatives when supported to maintain this protection." + "control_name": "Restricts Transmission and Movement of Information", + "description": "Key Vault keys using RSA or ECC will be vulnerable to Shor's algorithm, compromising data encrypted or signed with these keys. CC6.7 requires that data is protected using encryption. Post-quantum safe key encapsulation algorithms should replace classical alternatives when supported to maintain this protection.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria) (no post-quantum criterion defined)", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) predates post-quantum cryptography migration guidance and defines no criterion for quantum-safe algorithm readiness. Mapping rule AZ-PQC-002 to CC6.7 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PQC-003": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit", - "description": "Certificates using classical signature algorithms will be vulnerable to quantum-enabled forgery, undermining authentication and data integrity. CC6.7 requires that data integrity is maintained through encryption and signing. Migration to post-quantum safe certificate algorithms should be planned." + "control_name": "Restricts Transmission and Movement of Information", + "description": "Certificates using classical signature algorithms will be vulnerable to quantum-enabled forgery, undermining authentication and data integrity. CC6.7 requires that data integrity is maintained through encryption and signing. Migration to post-quantum safe certificate algorithms should be planned.", + "mapping_type": "not_applicable", + "evidence_type": "not_applicable", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria) (no post-quantum criterion defined)", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) predates post-quantum cryptography migration guidance and defines no criterion for quantum-safe algorithm readiness. Mapping rule AZ-PQC-003 to CC6.7 would overstate this framework edition's coverage, so it is marked not applicable pending a framework edition that addresses PQC readiness.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-001": { "control_id": "CC6.6", - "control_name": "Restricts Access to Information Assets", - "description": "A private AKS API endpoint restricts control-plane access to approved private network paths." + "control_name": "Restricts Access from Outside the Network Boundary", + "description": "A private AKS API endpoint restricts control-plane access to approved private network paths.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-AKS-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-002": { "control_id": "CC6.1", - "control_name": "Logical and Physical Access Controls", - "description": "Disabling AKS local accounts makes centrally governed Microsoft Entra identities the required authentication path." + "control_name": "Logical Access Security Measures", + "description": "Disabling AKS local accounts makes centrally governed Microsoft Entra identities the required authentication path.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-AKS-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-003": { "control_id": "CC6.1", - "control_name": "Logical and Physical Access Controls", - "description": "Managed identities reduce reliance on long-lived service-principal credentials for AKS control-plane operations." + "control_name": "Logical Access Security Measures", + "description": "Managed identities reduce reliance on long-lived service-principal credentials for AKS control-plane operations.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-AKS-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-004": { "control_id": "CC6.3", - "control_name": "Role-Based Access", - "description": "Workload Identity enables permissions to be assigned to specific Kubernetes workloads according to least privilege." + "control_name": "Role-Based Access Control", + "description": "Workload Identity enables permissions to be assigned to specific Kubernetes workloads according to least privilege.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.3", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.3 ('Role-Based Access Control') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-AKS-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-005": { "control_id": "CC8.1", "control_name": "Change Management", - "description": "The Azure Policy add-on supports consistent audit and enforcement of approved Kubernetes configurations." + "description": "The Azure Policy add-on supports consistent audit and enforcement of approved Kubernetes configurations.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC8.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC8.1 ('Change Management') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-AKS-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-AKS-006": { "control_id": "CC7.1", - "control_name": "Detects and Monitors Configuration Changes", - "description": "Managed node OS upgrade channels maintain worker-node security patches through an observable Azure-controlled process." + "control_name": "Detection and Monitoring of New Vulnerabilities", + "description": "Managed node OS upgrade channels maintain worker-node security patches through an observable Azure-controlled process.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.1 ('Detection and Monitoring of New Vulnerabilities') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-AKS-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-010": { "control_id": "CC6.2", "control_name": "Registers and Authorizes Users", - "description": "Assigned application owners establish responsibility for authorization and lifecycle review." + "description": "Assigned application owners establish responsibility for authorization and lifecycle review.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.2 ('Registers and Authorizes Users') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-010 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-011": { "control_id": "CC6.7", - "control_name": "Protects Data in Transit", - "description": "HTTPS redirect URIs protect authorization responses transmitted between identity and application endpoints." + "control_name": "Restricts Transmission and Movement of Information", + "description": "HTTPS redirect URIs protect authorization responses transmitted between identity and application endpoints.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.7", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.7 ('Restricts Transmission and Movement of Information') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-011 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-012": { "control_id": "CC6.1", - "control_name": "Logical and Physical Access Controls", - "description": "Disabling implicit grant reduces exposure of browser-delivered access and identity tokens." + "control_name": "Logical Access Security Measures", + "description": "Disabling implicit grant reduces exposure of browser-delivered access and identity tokens.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-012 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-013": { "control_id": "CC6.1", - "control_name": "Logical and Physical Access Controls", - "description": "Secretless or certificate authentication reduces compromise of application access credentials." + "control_name": "Logical Access Security Measures", + "description": "Secretless or certificate authentication reduces compromise of application access credentials.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-013 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-014": { "control_id": "CC6.6", - "control_name": "Restricts Access to Information Assets", - "description": "Property lock prevents tenant service-principal instances from changing sensitive credentials and encryption settings." + "control_name": "Restricts Access from Outside the Network Boundary", + "description": "Property lock prevents tenant service-principal instances from changing sensitive credentials and encryption settings.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-014 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-IDN-015": { "control_id": "CC6.3", - "control_name": "Role-Based Access", - "description": "Managed identities should not receive broad subscription roles beyond workload requirements." + "control_name": "Role-Based Access Control", + "description": "Managed identities should not receive broad subscription roles beyond workload requirements.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.3", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.3 ('Role-Based Access Control') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-IDN-015 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-001": { "control_id": "A1.2", "control_name": "Environmental Threats and Recovery", - "description": "The Recovery Services vault lacks the approved soft-delete recovery window, risking permanent loss of backup data before it can be restored." + "description": "The Recovery Services vault lacks the approved soft-delete recovery window, risking permanent loss of backup data before it can be restored.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion A1.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion A1.2 ('Environmental Threats and Recovery') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-BAK-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-002": { "control_id": "A1.2", "control_name": "Environmental Threats and Recovery", - "description": "Vault immutability is disabled, allowing destructive changes to protected recovery points and undermining the integrity of backup copies." + "description": "Vault immutability is disabled, allowing destructive changes to protected recovery points and undermining the integrity of backup copies.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion A1.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion A1.2 ('Environmental Threats and Recovery') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-BAK-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-004": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "The vault does not enable Resource Guard multiuser authorization, allowing a single compromised or malicious identity to disable backup protections unilaterally." + "description": "The vault does not enable Resource Guard multiuser authorization, allowing a single compromised or malicious identity to disable backup protections unilaterally.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-BAK-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-BAK-006": { "control_id": "CC7.2", - "control_name": "System monitoring", - "description": "The Recovery Services vault does not enable built-in monitoring for backup job failures, so a failed or tampered backup could go undetected." + "control_name": "System Monitoring", + "description": "The Recovery Services vault does not enable built-in monitoring for backup job failures, so a failed or tampered backup could go undetected.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-BAK-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-001": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "The Function App accepts unencrypted HTTP traffic, allowing requests and responses to cross the network boundary without encryption in transit." + "description": "The Function App accepts unencrypted HTTP traffic, allowing requests and responses to cross the network boundary without encryption in transit.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-FUNC-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-002": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "The Function App permits TLS older than 1.2, weakening the network controls that protect traffic crossing the network boundary." + "description": "The Function App permits TLS older than 1.2, weakening the network controls that protect traffic crossing the network boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-FUNC-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-003": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "The Function App exposes an FTP or FTPS deployment channel, widening the network attack surface beyond the primary HTTPS endpoint." + "description": "The Function App exposes an FTP or FTPS deployment channel, widening the network attack surface beyond the primary HTTPS endpoint.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-FUNC-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-004": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "Remote debugging expands the Function App management attack surface by opening an additional network-reachable control channel." + "description": "Remote debugging expands the Function App management attack surface by opening an additional network-reachable control channel.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-FUNC-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-FUNC-005": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "The Function App has no Azure managed identity for secretless resource access, pushing workloads toward long-lived credentials that cross network and service boundaries." + "description": "The Function App has no Azure managed identity for secretless resource access, pushing workloads toward long-lived credentials that cross network and service boundaries.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-FUNC-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-001": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A Storage Account remains publicly reachable; an approved private endpoint alone does not disable its public endpoint, leaving the network boundary uncontrolled." + "description": "A Storage Account remains publicly reachable; an approved private endpoint alone does not disable its public endpoint, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-PE-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-002": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "An Azure SQL logical server remains publicly reachable, regardless of whether a private endpoint also exists, leaving the network boundary uncontrolled." + "description": "An Azure SQL logical server remains publicly reachable, regardless of whether a private endpoint also exists, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-PE-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-003": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A PostgreSQL Flexible Server remains publicly reachable instead of using private networking only, leaving the network boundary uncontrolled." + "description": "A PostgreSQL Flexible Server remains publicly reachable instead of using private networking only, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-PE-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-004": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "An App Service workload remains publicly reachable without a default-deny access policy, leaving the network boundary uncontrolled." + "description": "An App Service workload remains publicly reachable without a default-deny access policy, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-PE-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-005": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A Recovery Services vault permits public access, even if a private endpoint also exists, leaving the network boundary uncontrolled." + "description": "A Recovery Services vault permits public access, even if a private endpoint also exists, leaving the network boundary uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-PE-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-PE-006": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A private endpoint connection is pending, rejected, or disconnected and does not provide an active private path, leaving traffic to traverse the public network boundary instead." + "description": "A private endpoint connection is pending, rejected, or disconnected and does not provide an active private path, leaving traffic to traverse the public network boundary instead.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-PE-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-001": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "The Container Registry admin user is enabled, providing a shared credential that bypasses individual identity management and cannot be attributed to a single user." + "description": "The Container Registry admin user is enabled, providing a shared credential that bypasses individual identity management and cannot be attributed to a single user.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-002": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "The Container Registry is reachable from the public internet, leaving the network boundary that protects the organization's built container images uncontrolled." + "description": "The Container Registry is reachable from the public internet, leaving the network boundary that protects the organization's built container images uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-003": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "The Container Registry allows anonymous pull, letting any client access every image without an authenticated, individually attributable identity." + "description": "The Container Registry allows anonymous pull, letting any client access every image without an authenticated, individually attributable identity.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-004": { "control_id": "CC7.1", - "control_name": "System Vulnerabilities are Identified and Managed", - "description": "The Container Registry has no retention or quarantine policy, so stale images accumulate and newly pushed images are deployable before any vulnerability scan evaluates them." + "control_name": "Detection and Monitoring of New Vulnerabilities", + "description": "The Container Registry has no retention or quarantine policy, so stale images accumulate and newly pushed images are deployable before any vulnerability scan evaluates them.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.1 ('Detection and Monitoring of New Vulnerabilities') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-005": { "control_id": "CC6.6", "control_name": "Restricts Access from Outside the Network Boundary", - "description": "A Terraform remote state container is publicly readable, leaving the network boundary around infrastructure layout and captured secrets uncontrolled." + "description": "A Terraform remote state container is publicly readable, leaving the network boundary around infrastructure layout and captured secrets uncontrolled.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-006": { "control_id": "A1.2", "control_name": "Environmental Threats and Recovery", - "description": "A storage account holding Terraform remote state has neither versioning nor soft delete enabled, so an overwritten or deleted state file cannot be recovered." + "description": "A storage account holding Terraform remote state has neither versioning nor soft delete enabled, so an overwritten or deleted state file cannot be recovered.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion A1.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion A1.2 ('Environmental Threats and Recovery') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-007": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "A pipeline service connection is scoped to the entire subscription rather than a single resource group, so every pipeline that uses it inherits subscription-wide access beyond what it needs." + "description": "A pipeline service connection is scoped to the entire subscription rather than a single resource group, so every pipeline that uses it inherits subscription-wide access beyond what it needs.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-007 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SC-008": { "control_id": "CC6.1", "control_name": "Logical Access Security Measures", - "description": "A pipeline service connection authenticates with a stored service principal secret instead of a federated credential, leaving a static credential to rotate and potentially leak." + "description": "A pipeline service connection authenticates with a stored service principal secret instead of a federated credential, leaving a static credential to rotate and potentially leak.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.1 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SC-008 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-001": { "control_id": "CC6.7", "control_name": "Restricts Transmission and Movement of Information", - "description": "MACsec protects traffic crossing the customer-visible ExpressRoute Direct Ethernet boundary." + "description": "MACsec protects traffic crossing the customer-visible ExpressRoute Direct Ethernet boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.7", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.7 ('Restricts Transmission and Movement of Information') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-DL-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-DL-002": { "control_id": "CC6.7", "control_name": "Restricts Transmission and Movement of Information", - "description": "XPN MACsec provides suitable packet-number capacity for high-speed protected links." + "description": "XPN MACsec provides suitable packet-number capacity for high-speed protected links.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.7", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.7 ('Restricts Transmission and Movement of Information') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-DL-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-016": { "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "NIC IP forwarding is restricted to reviewed network virtual appliances and routing functions." + "control_name": "Restricts Access from Outside the Network Boundary", + "description": "NIC IP forwarding is restricted to reviewed network virtual appliances and routing functions.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-016 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-017": { "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "User-defined default routes preserve approved inspected egress paths." + "control_name": "Restricts Access from Outside the Network Boundary", + "description": "User-defined default routes preserve approved inspected egress paths.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Restricts Access from Outside the Network Boundary') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-017 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-018": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Private Link targets restrict unnecessary public network access." + "description": "Private Link targets restrict unnecessary public network access.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-018 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-019": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Private Endpoint connections are approved and operational before they are relied upon as an access boundary." + "description": "Private Endpoint connections are approved and operational before they are relied upon as an access boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-019 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-020": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Private DNS association preserves the approved private access path." + "description": "Private DNS association preserves the approved private access path.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-020 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-021": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Private Endpoint ARM DNS configuration associates service names with private addresses; effective resolver-path validation remains separate evidence." + "description": "Private Endpoint service names resolve to private addresses within the approved access boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-021 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-022": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Critical PaaS resources restrict public access unless an approved exception exists." + "description": "Critical PaaS resources restrict public access unless an approved exception exists.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-022 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-023": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Azure Firewall denies traffic involving infrastructure identified by threat intelligence." + "description": "Azure Firewall denies traffic involving infrastructure identified by threat intelligence.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-023 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-024": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Application Gateway WAF Prevention mode blocks matching malicious requests." + "description": "Application Gateway WAF Prevention mode blocks matching malicious requests.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-024 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-025": { "control_id": "CC7.2", "control_name": "System monitoring", - "description": "Application Gateway SKU-supported diagnostic logs support anomaly monitoring; v2 performance telemetry is supplied through metrics." + "description": "Application Gateway access, performance, and firewall logs support anomaly monitoring.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-025 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-026": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Current application and bot managed rules protect the logical access boundary." + "description": "Current application and bot managed rules protect the logical access boundary.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-026 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-NET-027": { "control_id": "CC6.6", "control_name": "Logical Access Security Measures", - "description": "Rate-limit rules protect public application access from abusive request volume." + "description": "Rate-limit rules protect public application access from abusive request volume.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC6.6", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC6.6 ('Logical Access Security Measures') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-NET-027 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-001": { "control_id": "CC7.2", "control_name": "System Monitoring", - "description": "The subscription's Activity Log is not exported to an approved central destination. CC7.2 requires the entity to monitor system components for anomalies; an unexported Activity Log removes the raw evidence that monitoring depends on." + "description": "The subscription's Activity Log is not exported to an approved central destination. CC7.2 requires the entity to monitor system components for anomalies; an unexported Activity Log removes the raw evidence that monitoring depends on.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-001 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-002": { "control_id": "CC7.2", "control_name": "System Monitoring", - "description": "Required Activity Log categories are missing from the central export. CC7.2 requires monitoring to cover the events relevant to detecting security anomalies; a partial category export leaves gaps in what can be monitored." + "description": "Required Activity Log categories are missing from the central export. CC7.2 requires monitoring to cover the events relevant to detecting security anomalies; a partial category export leaves gaps in what can be monitored.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-002 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-003": { "control_id": "CC7.2", "control_name": "System Monitoring", - "description": "A critical resource lacks diagnostic settings exporting to an approved destination. CC7.2 requires monitoring of infrastructure and software for anomalies; a critical resource with no export is not being monitored at all." + "description": "A critical resource lacks diagnostic settings exporting to an approved destination. CC7.2 requires monitoring of infrastructure and software for anomalies; a critical resource with no export is not being monitored at all.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-003 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-004": { "control_id": "CC7.2", "control_name": "System Monitoring", - "description": "A security-relevant log export's retention is below the organisation's minimum. CC7.2's monitoring objective depends on evidence remaining available long enough to detect and investigate anomalies; retention below the organisation's minimum shortens that window." + "description": "A security-relevant log export's retention is below the organisation's minimum. CC7.2's monitoring objective depends on evidence remaining available long enough to detect and investigate anomalies; retention below the organisation's minimum shortens that window.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-004 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-005": { "control_id": "CC7.2", "control_name": "System Monitoring", - "description": "A critical resource's only log export sits in a destination its own workload administrators can modify. CC7.2 requires monitoring information to be reliable; a destination the monitored workload's own administrators can alter undermines that reliability." + "description": "A critical resource's only log export sits in a destination its own workload administrators can modify. CC7.2 requires monitoring information to be reliable; a destination the monitored workload's own administrators can alter undermines that reliability.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-005 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-006": { "control_id": "CC7.1", "control_name": "Detection and Monitoring of New Vulnerabilities", - "description": "A required Microsoft Defender for Cloud plan is not enabled for a critical workload type. CC7.1 requires the entity to use detection and monitoring procedures to identify changes and vulnerabilities; Defender for Cloud is the mechanism providing that detection for the affected workload type." + "description": "A required Microsoft Defender for Cloud plan is not enabled for a critical workload type. CC7.1 requires the entity to use detection and monitoring procedures to identify changes and vulnerabilities; Defender for Cloud is the mechanism providing that detection for the affected workload type.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.1 ('Detection and Monitoring of New Vulnerabilities') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-006 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-007": { "control_id": "CC7.1", "control_name": "Detection and Monitoring of New Vulnerabilities", - "description": "A High-severity Defender recommendation remains unresolved beyond the organisation's SLA. CC7.1 requires identified vulnerabilities to be evaluated and addressed; an SLA breach indicates the vulnerability-management process required by CC7.1 is not operating effectively." + "description": "A High-severity Defender recommendation remains unresolved beyond the organisation's SLA. CC7.1 requires identified vulnerabilities to be evaluated and addressed; an SLA breach indicates the vulnerability-management process required by CC7.1 is not operating effectively.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.1", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.1 ('Detection and Monitoring of New Vulnerabilities') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-007 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-008": { "control_id": "CC7.2", "control_name": "System Monitoring", - "description": "A required Sentinel data connector is missing or unhealthy. CC7.2 requires monitoring of system components for anomalies; a disconnected connector is a monitored source that has stopped contributing data without detection." + "description": "A required Sentinel data connector is missing or unhealthy. CC7.2 requires monitoring of system components for anomalies; a disconnected connector is a monitored source that has stopped contributing data without detection.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-008 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-009": { "control_id": "CC7.2", "control_name": "System Monitoring", - "description": "Sentinel lacks enabled High-severity analytics coverage for a required detection use case. CC7.2 requires monitoring to actually evaluate collected data for anomalies; ingested logs with no analytics rule evaluating a known high-risk pattern do not fulfil that requirement for that use case." + "description": "Sentinel lacks enabled High-severity analytics coverage for a required detection use case. CC7.2 requires monitoring to actually evaluate collected data for anomalies; ingested logs with no analytics rule evaluating a known high-risk pattern do not fulfil that requirement for that use case.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.2", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.2 ('System Monitoring') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-009 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null }, "AZ-SECOPS-010": { "control_id": "CC7.4", "control_name": "Incident Response", - "description": "No monitored destination exists for security alerts or Sentinel incidents. CC7.4 requires the entity to respond to identified security incidents; an alert nobody is notified of cannot trigger the incident-response process CC7.4 requires." - }, - "AZ-NET-018": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Private Link targets restrict unnecessary public network access." - }, - "AZ-NET-019": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Private Endpoint connections are approved and operational before they are relied upon as an access boundary." - }, - "AZ-NET-020": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Private DNS association preserves the approved private access path." - }, - "AZ-NET-021": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Private Endpoint service names resolve to private addresses within the approved access boundary." - }, - "AZ-NET-022": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Critical PaaS resources restrict public access unless an approved exception exists." - }, - "AZ-NET-023": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Azure Firewall denies traffic involving infrastructure identified by threat intelligence." - }, - "AZ-NET-024": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Application Gateway WAF Prevention mode blocks matching malicious requests." - }, - "AZ-NET-025": { - "control_id": "CC7.2", - "control_name": "System monitoring", - "description": "Application Gateway access, performance, and firewall logs support anomaly monitoring." - }, - "AZ-NET-026": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Current application and bot managed rules protect the logical access boundary." - }, - "AZ-NET-027": { - "control_id": "CC6.6", - "control_name": "Logical Access Security Measures", - "description": "Rate-limit rules protect public application access from abusive request volume." + "description": "No monitored destination exists for security alerts or Sentinel incidents. CC7.4 requires the entity to respond to identified security incidents; an alert nobody is notified of cannot trigger the incident-response process CC7.4 requires.", + "mapping_type": "supporting", + "evidence_type": "automated_configuration_scan", + "primary_source": "SOC 2 Type II (2017 Trust Services Criteria), criterion CC7.4", + "rationale": "AICPA SOC 2 (2017 Trust Services Criteria) criterion CC7.4 ('Incident Response') is evaluated by an independent auditor across technical, procedural and organizational evidence. OpenShield rule AZ-SECOPS-010 evaluates one Azure technical control that provides supporting automated evidence toward this criterion; it is not a substitute for an auditor's evaluation.", + "owner": null, + "review_status": "pending_review", + "review_date": null } } } diff --git a/docs/adding-a-rule.md b/docs/adding-a-rule.md index b93ab33e..f1025194 100644 --- a/docs/adding-a-rule.md +++ b/docs/adding-a-rule.md @@ -216,25 +216,46 @@ print(json.dumps(result, indent=2)) ## Update the Compliance Framework Files -If your rule maps to controls not yet in the compliance JSON files, add entries to the relevant file(s) in `compliance/frameworks/`: +Add an entry for your rule to each file in `compliance/frameworks/`: - `cis_azure_benchmark.json` - `nist_csf.json` - `iso27001.json` - `soc2.json` +Every control entry is a versioned evidence claim, not just a label — CI's +"Compliance mapping semantics validation" check rejects entries missing any +of the fields below. See `docs/compliance-mapping-pack.md` for the full +schema and the meaning of each `mapping_type`. + ```json { "controls": { "AZ-XXXX-000": { "control_id": "3.7", "control_name": "CIS control name here", - "description": "Why this control is relevant to your finding." + "description": "Why this control is relevant to your finding.", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.7", + "rationale": "Why this rule's PASS/FAIL result is (or is not) direct technical evidence for this specific control.", + "owner": null, + "review_status": "pending_review", + "review_date": null } } } ``` +Use `mapping_type: "not_applicable"` instead of forcing a weak mapping when +the framework edition genuinely does not define a relevant control (for +example, a framework edition published before the practice your rule checks +existed). `not_applicable` and `organizational` mappings are excluded from +the framework's pass-rate denominator rather than counted as an automatic +PASS or removed from the file. Leave `owner` and `review_date` as `null` and +`review_status` as `"pending_review"` — these are set by a maintainer during +independent mapping review, not by the contributor opening the rule PR. + --- ## Submit a Pull Request @@ -248,7 +269,7 @@ git push origin rule/az-xxxx-000-short-description Then open a PR. Use the PR template — it will ask you for the rule ID, severity, and which frameworks you mapped. A maintainer will review within 48 hours. -Before requesting review, make sure all seven CI checks pass: +Before requesting review, make sure all eight rule-validation checks pass: - Python syntax on rule files - Rule structure validation @@ -257,6 +278,7 @@ Before requesting review, make sure all seven CI checks pass: - Compliance JSON validation - API syntax check - Compliance rule cross-reference +- Compliance mapping-pack semantics validation --- diff --git a/docs/api-reference.md b/docs/api-reference.md index 0ddbf8fd..7bdd7c4a 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -232,24 +232,38 @@ Missing subscription response: ## GET /api/score -Returns the overall security posture score from 0 to 100. Under [severity contract v1](severity-contract.md), the score starts at 100 and deducts 20 per CRITICAL finding, 10 per HIGH finding, 5 per MEDIUM finding, and 2 per LOW finding. INFO findings deduct zero. +Returns the overall security posture score from 0 to 100. Under [severity contract v1](severity-contract.md), the score starts at 100 and deducts 20 per CRITICAL finding, 10 per HIGH finding, 5 per MEDIUM finding, and 2 per LOW finding; INFO findings deduct zero. Scoped to the most recent **completed** scan — if no completed scan exists yet, this returns `status: "NO_SCAN_DATA"` with `score: null` rather than a misleading 100 (a scan with no findings and no evidence at all would otherwise be indistinguishable). Query parameters: none -Example response: +Example response (a completed scan exists): ```json { + "status": "OK", "score": 82, "max_score": 100 } ``` +Example response (no completed scan exists yet): + +```json +{ + "status": "NO_SCAN_DATA", + "score": null, + "max_score": 100, + "message": "No completed scan is available yet, so there is no security posture to score." +} +``` + +Consumers must check `status` and treat a `null` `score` as "not assessed" — never coerce it to `0`, which would misrepresent absence of evidence as a confirmed worst-case score. + --- ## GET /api/compliance/<framework> -Returns a pass/fail control breakdown for a supported compliance framework. +Returns technical-evidence coverage against a compliance framework mapping pack, scoped to the most recent **completed** scan. This is coverage, not a certification or a claim of full framework compliance — see `docs/compliance-mapping-pack.md` for the full mapping-pack schema and `evaluation_basis` semantics. Supported frameworks: @@ -259,36 +273,77 @@ Supported frameworks: | `nist` | `nist_csf.json` | | `iso27001` | `iso27001.json` | | `soc2` | `soc2.json` | +| `ncsc_pqc` | `ncsc_pqc.json` | +| `enisa_pqc` | `enisa_pqc.json` | Query parameters: none -Example response: +`status` is one of: +- `OK` — a completed scan exists and at least one mapped control is in scope; `score_percent` is a real evaluated percentage. +- `NO_SCAN_DATA` — no completed scan exists yet, so there is no evidence to report; `score_percent` is `null`. +- `NO_IN_SCOPE_CONTROLS` — a completed scan exists, but every mapped control for this framework is `not_applicable`/`organizational` and excluded from the denominator; `score_percent` is `null`. + +Consumers must check `status` and never treat a `null` `score_percent` as `0` — a missing/excluded score is a different fact from a real, evaluated 0%. + +Example response (`OK`): ```json { "framework": "CIS Microsoft Azure Foundations Benchmark", "version": "2.0.0", - "total_controls": 20, - "passed": 19, - "failed": 1, - "score_percent": 95, + "status": "OK", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "OpenShield compliance mapping pack, authored against CIS Microsoft Azure Foundations Benchmark v2.0.0 official control text. Technical-evidence mapping only; not a certification statement.", + "mapping_pack_published": "2026-08-22", + "scan_id": "scan-1", + "evaluation_basis": "PASS reflects the absence of findings for this rule in the most recent completed scan. ...", + "total_controls": 95, + "in_scope_controls": 49, + "excluded_controls": 46, + "passed": 47, + "failed": 2, + "score_percent": 96, "controls": [ { "rule_id": "AZ-STOR-001", "control_id": "3.5", "control_name": "Ensure that 'Public access level' is set to Private for blob containers", - "status": "FAIL" + "status": "FAIL", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.5", + "rationale": "...", + "owner": null, + "review_status": "pending_review", + "review_date": null } ] } ``` -Unknown framework response: +Example response (`NO_SCAN_DATA`, HTTP 200 — never 500): + +```json +{ + "status": "NO_SCAN_DATA", + "message": "No completed scan is available yet, so no technical evidence exists to report against this framework.", + "total_controls": 95, + "in_scope_controls": 0, + "excluded_controls": 0, + "passed": 0, + "failed": 0, + "score_percent": null, + "controls": [] +} +``` + +Unknown framework response (HTTP 400): ```json { - "error": "Unknown framework 'pci'", - "supported": ["cis", "nist", "iso27001", "soc2"] + "error": "Invalid request parameters", + "supported": ["cis", "nist", "iso27001", "soc2", "ncsc_pqc", "enisa_pqc"] } ``` diff --git a/docs/api-render-deploy.md b/docs/api-render-deploy.md index 6585660d..d755cb76 100644 --- a/docs/api-render-deploy.md +++ b/docs/api-render-deploy.md @@ -178,8 +178,8 @@ API_URL=https://openshield-api.onrender.com JWT_SECRET= \ #### Score Endpoint * **TC-09:** GET `/api/score` returns HTTP 200. -* **TC-10:** GET `/api/score` returns a numeric score. -* **TC-11:** GET `/api/score` ensures the score is mathematically between 0 and 100. +* **TC-10:** GET `/api/score` returns a numeric score when `status` is `"OK"` (a numeric score is not required when `status` is `"NO_SCAN_DATA"` — `score` is legitimately `null` then). +* **TC-11:** GET `/api/score` ensures the score is mathematically between 0 and 100, or `null` with a non-`"OK"` status. #### Scans Endpoint * **TC-12:** GET `/api/scans` returns HTTP 200. diff --git a/docs/architecture.md b/docs/architecture.md index 85dc4ef4..1ca9a194 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -199,7 +199,9 @@ GET /api/findings GET /api/score → db.get_score() # contract v1: CRITICAL -20, HIGH -10, MEDIUM -5, LOW -2 - → returns plain integer (e.g. 18) + → returns { status, score, max_score } — status is "OK" (score: 0-100) or + "NO_SCAN_DATA" (score: null) when no completed scan exists yet, never a + false 100 GET /api/resources → aggregates unique resources from latest scan's findings diff --git a/docs/compliance-mapping-pack.md b/docs/compliance-mapping-pack.md new file mode 100644 index 00000000..1cd353dd --- /dev/null +++ b/docs/compliance-mapping-pack.md @@ -0,0 +1,112 @@ +# Compliance Mapping Pack + +OpenShield's compliance reports are versioned technical evidence coverage +against a specific edition of a named framework, produced by an internal +OpenShield mapping pack. They are not a certification, an audit opinion, or a +claim of full framework compliance. See "Security limitations" in +`docs/security-requirements.md` for the project-wide disclaimer this section +implements for compliance reporting specifically. + +## Supported framework editions + +| Framework key | Framework | Edition currently mapped | Source file | +|---|---|---|---| +| `cis` | CIS Microsoft Azure Foundations Benchmark | 2.0.0 (2023-02) | `compliance/frameworks/cis_azure_benchmark.json` | +| `nist` | NIST Cybersecurity Framework | 1.1 | `compliance/frameworks/nist_csf.json` | +| `iso27001` | ISO/IEC 27001 | 2013 | `compliance/frameworks/iso27001.json` | +| `soc2` | AICPA SOC 2 Type II (Trust Services Criteria) | 2017 | `compliance/frameworks/soc2.json` | +| `ncsc_pqc` | NCSC UK PQC Migration Guidance | 2025 | `compliance/frameworks/ncsc_pqc.json` | +| `enisa_pqc` | ENISA Post-Quantum Cryptography Recommendations | 2021 | `compliance/frameworks/enisa_pqc.json` | + +These are the only editions OpenShield currently maps. Newer editions (for +example CIS Azure Benchmark 3.x, NIST CSF 2.0, or ISO/IEC 27001:2022) are not +mapped yet — do not present a report generated against an older edition as +coverage of a newer one. When a newer edition is added, the older mapping +pack must be kept and explicitly marked `"mapping_pack_status": "legacy"` +rather than overwritten, so a report generated under it stays interpretable. + +## The mapping-pack schema + +Each framework JSON file in `compliance/frameworks/` carries pack-level +metadata plus per-control evidence metadata: + +```json +{ + "framework": "CIS Microsoft Azure Foundations Benchmark", + "version": "2.0.0", + "published": "2023-02", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "...", + "mapping_pack_published": "2026-08-22", + "controls": { + "AZ-STOR-001": { + "control_id": "3.5", + "control_name": "...", + "description": "...", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "CIS Microsoft Azure Foundations Benchmark v2.0.0, control 3.5", + "rationale": "...", + "owner": null, + "review_status": "pending_review", + "review_date": null + } + } +} +``` + +| Field | Meaning | +|---|---| +| `mapping_pack_version` | Semantic version of OpenShield's mapping pack for this framework file, independent of the framework's own edition/version. | +| `mapping_pack_status` | `"current"` or `"legacy"`. Exactly one mapping pack per framework should be `"current"` at a time. | +| `mapping_pack_source` | Free text describing what the mapping pack was authored against. | +| `mapping_pack_published` | Date this mapping pack revision was published. | +| `mapping_type` | `"direct"` — the rule's PASS/FAIL result is itself the control's evidence. `"supporting"` — the rule provides partial automated evidence toward a broader control that also requires organizational or procedural evidence. `"organizational"` — the control is in scope for the framework but cannot be evaluated by a technical scan at all. `"not_applicable"` — this framework edition does not define a control the rule's subject matter belongs to. | +| `evidence_type` | How the evidence was produced, e.g. `"automated_configuration_scan"`. `"not_applicable"` for `not_applicable`/`organizational` controls. | +| `primary_source` | The specific framework document and control identifier this mapping is authored against. | +| `rationale` | Why this `mapping_type` was chosen, grounded in the actual control text and what the rule technically evaluates. | +| `owner` | The person who has independently reviewed this mapping, or `null` if unreviewed. | +| `review_status` | `"pending_review"` or `"reviewed"`. A control cannot be `"reviewed"` without both `owner` and `review_date` set — CI enforces this. | +| `review_date` | ISO date of the last independent review, or `null` if unreviewed. | + +## Scoring: what is excluded from the denominator + +`mapping_type: "not_applicable"` and `mapping_type: "organizational"` +controls are listed in a compliance report but excluded from +`score_percent`'s denominator — they contribute to neither `passed` nor +`failed`. A report's `total_controls` count includes them; +`in_scope_controls` is the denominator actually used for the score. + +## Historical accuracy + +`api/models/finding.py::save_scan()` snapshots each framework's pack-level +metadata (`framework`, `version`, `mapping_pack_version`, +`mapping_pack_status`, `mapping_pack_source`, `mapping_pack_published`) into +the `scans.compliance_mapping_snapshot` column at scan-completion time. +`get_compliance_score()` prefers that snapshot over the live file when +reporting on a specific scan, so a report for an old scan continues to show +the mapping-pack identity that was actually in effect when it ran, even +after the mapping pack on disk is later revised. + +## Independent review + +`review_status` starts as `"pending_review"` for every mapping in this pack. +None of the mappings shipped in the initial 302 mapping-pack revision have +undergone an independent security/compliance review — see the "Acceptance +criteria" evidence in the PR that introduced this file for the current +review status. A maintainer completing that review should set `owner` and +`review_date` and flip `review_status` to `"reviewed"` per entry; CI rejects +a `"reviewed"` entry missing either field. + +## What this does not do + +- It does not implement per-resource evaluation tracking. `PASS` currently + means "no findings for this rule in the most recent completed scan," not + "this rule was confirmed to run successfully against every applicable + resource." An errored or skipped rule cannot yet be distinguished from a + clean pass — that requires the persisted rule-evaluation contract tracked + in issue #263. `get_compliance_score()`'s `evaluation_basis` field states + this limitation on every response. +- It does not replace an auditor, a certification body, or a formal + assessment. See `docs/security-requirements.md`. diff --git a/docs/security-requirements.md b/docs/security-requirements.md index 6dd4792d..87f6846f 100644 --- a/docs/security-requirements.md +++ b/docs/security-requirements.md @@ -38,8 +38,12 @@ permissions, service tiers, Azure API behavior and organizational context. Remediation playbooks can affect availability and require operator review. OpenShield does not claim that its framework mappings constitute certification -or complete benchmark coverage. Unsupported versions receive no guaranteed -security fixes. +or complete benchmark coverage. Compliance reports are versioned technical +evidence coverage against a specific mapping-pack revision, not an audit +opinion; see `docs/compliance-mapping-pack.md` for supported framework +editions, mapping-pack versioning, and what is excluded from each framework's +pass-rate denominator. Unsupported versions receive no guaranteed security +fixes. ## Verification evidence diff --git a/docs/validation/FRONTEND_API_TESTING.md b/docs/validation/FRONTEND_API_TESTING.md index 09f98b4f..e7d9a700 100644 --- a/docs/validation/FRONTEND_API_TESTING.md +++ b/docs/validation/FRONTEND_API_TESTING.md @@ -97,11 +97,14 @@ This guide validates the **frontend/API/database integration** of OpenShield. It ### Score (`GET /api/score`) -Raw backend response — source of truth: `api/models/finding.py` (`get_score()` is typed `-> int`). The endpoint returns a **bare integer** (0–100), not an object: +Raw backend response — source of truth: `api/models/finding.py` (`get_score()` is typed `-> Dict[str, Any]`). The endpoint returns an object, not a bare integer, and `score` is `null` (not `0`) when no completed scan exists yet: ```json -68 +{ "status": "OK", "score": 68, "max_score": 100 } ``` -> `normalizeScore()` in `frontend/src/utils/api.js` wraps the number into `{ "score": 68, "max_score": 100 }`. That object shape is frontend-only — the backend never emits `score`/`max_score` keys for this endpoint. +```json +{ "status": "NO_SCAN_DATA", "score": null, "max_score": 100, "message": "No completed scan is available yet, so there is no security posture to score." } +``` +> `normalizeScore()` in `frontend/src/utils/api.js` also accepts a bare legacy integer for backward compatibility (treated as `{ status: "OK", score, max_score: 100 }`), but the backend itself has emitted the object shape since issue #302. Consumers must check `status` and never coerce a `null` `score` to `0`. ### Findings List (`GET /api/findings`) ```json diff --git a/frontend/API_ENDPOINTS.txt b/frontend/API_ENDPOINTS.txt index a88052ed..45d74165 100644 --- a/frontend/API_ENDPOINTS.txt +++ b/frontend/API_ENDPOINTS.txt @@ -110,10 +110,24 @@ SCORE AND CVE SUMMARY GET /api/score -Returns a JSON integer from 0 to 100. The frontend normalizes this number to -{ score, max_score: 100 } for its components. +Response (a completed scan exists) +──────── + { + "status": "OK", + "score": 68, + "max_score": 100 + } + +Response (no completed scan yet — never a false 100) +──────── + { + "status": "NO_SCAN_DATA", + "score": null, + "max_score": 100, + "message": "No completed scan is available yet, so there is no security posture to score." + } - 82 +A null score must be rendered as "not assessed", never coerced to 0. GET /api/score/cve-summary diff --git a/frontend/src/components/compliance/FrameworkCards.jsx b/frontend/src/components/compliance/FrameworkCards.jsx index 18195c52..f6f07bf0 100644 --- a/frontend/src/components/compliance/FrameworkCards.jsx +++ b/frontend/src/components/compliance/FrameworkCards.jsx @@ -4,7 +4,13 @@ export default function FrameworkCards({ frameworks, selected, onSelect }) { return (
{frameworks.map((fw) => { - const pct = fw.score; + // A null score means no evidence to report - either no completed + // scan exists yet, or every mapped control is excluded from the + // denominator. Both are distinct facts from a real, evaluated 0%, + // and must never render as one. + const hasScore = typeof fw.score === 'number'; + const pct = hasScore ? fw.score : 0; + const notAssessedLabel = fw.status === 'NO_IN_SCOPE_CONTROLS' ? 'No in-scope controls' : 'Not assessed'; const isSelected = selected?.id === fw.id; return (
- {pct}% + + {hasScore ? `${pct}%` : notAssessedLabel} +

{fw.name}

{fw.version}

@@ -28,7 +36,7 @@ export default function FrameworkCards({ frameworks, selected, onSelect }) {
diff --git a/frontend/src/components/monitoring/ScoreGauge.jsx b/frontend/src/components/monitoring/ScoreGauge.jsx index 0e95816b..c4f78d03 100644 --- a/frontend/src/components/monitoring/ScoreGauge.jsx +++ b/frontend/src/components/monitoring/ScoreGauge.jsx @@ -13,6 +13,24 @@ function getScoreLabel(score) { } export default function ScoreGauge({ score, maxScore = 100 }) { + // A null score (no completed scan yet) is a distinct fact from a real, + // evaluated 0 - it must render as "no data", never as a gauge, a + // percentage, or the "Poor" label a confirmed worst-case score would get. + if (score === null || score === undefined) { + return ( +
+
+
+ + Not assessed +
+
+

Security Score

+

No completed scan yet

+
+ ); + } + const pct = Math.round((score / maxScore) * 100); const color = getScoreColor(pct); const remaining = 100 - pct; diff --git a/frontend/src/pages/Monitoring.jsx b/frontend/src/pages/Monitoring.jsx index bb8f4a06..7450a715 100644 --- a/frontend/src/pages/Monitoring.jsx +++ b/frontend/src/pages/Monitoring.jsx @@ -29,8 +29,13 @@ export default function Monitoring() { const counts = countBySeverity(findings); return { - score: scoreData.score ?? scoreData, - maxScore: scoreData.max_score ?? 100, + // scoreData is always normalizeScore()'s output ({status, score, + // max_score}) - score is preserved as-is (including null for + // NO_SCAN_DATA) rather than falling back to a truthy-looking + // default, so ScoreGauge can render "not assessed" correctly. + score: scoreData.score, + scoreStatus: scoreData.status, + maxScore: scoreData.max_score ?? 100, stats: { totalFindings: findings.length, criticalIssues: counts.CRITICAL, diff --git a/frontend/src/utils/api.js b/frontend/src/utils/api.js index af52ad6b..2e0427fd 100644 --- a/frontend/src/utils/api.js +++ b/frontend/src/utils/api.js @@ -33,8 +33,17 @@ async function apiFetch(path, options = {}) { // ───────────────────────────────────────────────────────────────────────────── function normalizeScore(raw) { - if (typeof raw === 'number') return { score: raw, max_score: 100 }; - return { score: raw.score ?? raw.score_percent ?? 0, max_score: raw.max_score ?? 100 }; + // score stays null (never coerced to 0) when the backend reports + // NO_SCAN_DATA - a missing score and a genuinely evaluated 0 are different + // facts, and collapsing them would render "no evidence yet" as "confirmed + // worst possible posture", the same false-negative gap fixed on the + // backend for get_score()/get_compliance_score() (issue #302). + if (typeof raw === 'number') return { status: 'OK', score: raw, max_score: 100 }; + return { + status: raw.status ?? 'OK', + score: raw.score ?? null, + max_score: raw.max_score ?? 100, + }; } function normalizeFinding(f) { @@ -185,9 +194,16 @@ function normalizePlaybook(p) { function normalizeComplianceFramework(data, id, color) { return { id, - name: data.framework, - version: data.version, - score: data.score_percent, + name: data.framework, + version: data.version, + // status distinguishes why score can be null: NO_SCAN_DATA (no + // completed scan exists yet - no evidence at all) vs + // NO_IN_SCOPE_CONTROLS (a scan exists, but every mapped control is + // excluded from the denominator, so there's nothing to score) vs OK + // (a genuinely evaluated percentage). Never coerced to 0 - that would + // render "no evidence" as a confirmed 0% failing score. + status: data.status ?? 'OK', + score: data.score_percent ?? null, totalControls: data.total_controls, passing: data.passed, failing: data.failed, diff --git a/frontend/src/utils/api.test.mjs b/frontend/src/utils/api.test.mjs new file mode 100644 index 00000000..3e6ad1da --- /dev/null +++ b/frontend/src/utils/api.test.mjs @@ -0,0 +1,191 @@ +// Tests that a null/NO_SCAN_DATA score from the backend is preserved as +// "no data", never coerced into a real-looking 0 (issue #302). Covers the +// three states get_score()/get_compliance_score() can return: NO_SCAN_DATA +// (no completed scan exists), NO_IN_SCOPE_CONTROLS (a scan exists but every +// mapped control is excluded from the denominator), and a genuinely +// evaluated OK score. +// +// frontend/ has no test runner configured (only eslint + vite). This loads +// the real source (no duplication of the logic under test), neutralizes the +// one Vite-only construct (import.meta.env), and evaluates it with a +// stubbed fetch/localStorage — matching the pattern in aiApi.test.mjs. +// +// Run with: node frontend/src/utils/api.test.mjs + +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +function loadApiModule(fetchImpl) { + let source = readFileSync(path.join(__dirname, 'api.js'), 'utf8'); + + source = source.replace( + /import\.meta\.env\.VITE_API_URL\s*\|\|\s*\(import\.meta\.env\.DEV \? '[^']*' : '[^']*'\)/, + "'http://localhost:5000'", + ); + assert.ok(!source.includes('import.meta'), 'failed to neutralize import.meta usage — test harness is stale'); + + // normalizeScore()/normalizeComplianceFramework() (what this file actually + // tests) never call normalizeRisk()/normalizeSeverity() themselves - those + // belong to severity.js and have their own dedicated tests + // (npm run test:severity). Stubbed here (not inlined) so this file stays + // scoped to what it's actually testing, rather than re-executing a second + // module's already-tested logic; the stub only needs to satisfy the + // functions in this file that reference the names at module scope. + assert.ok( + source.includes("import { normalizeRisk, normalizeSeverity } from './severity.js';"), + 'expected severity.js import — test harness is stale', + ); + source = source.replace( + "import { normalizeRisk, normalizeSeverity } from './severity.js';", + 'const normalizeRisk = (value) => value; const normalizeSeverity = (value) => value;', + ); + + source = source.replace(/^export const /gm, 'const '); + source = source.replace(/^export default api;\s*$/m, ''); + source += '\nreturn { api, normalizeScore, normalizeComplianceFramework };'; + + const localStorageStub = { + getItem: () => null, + setItem: () => {}, + removeItem: () => {}, + }; + + const load = new Function('localStorage', 'fetch', source); + return load(localStorageStub, fetchImpl); +} + +function jsonResponse(body) { + return Promise.resolve({ ok: true, status: 200, statusText: 'OK', json: () => Promise.resolve(body) }); +} + +let failures = 0; +function check(description, fn) { + try { + fn(); + console.log(`PASS: ${description}`); + } catch (err) { + failures += 1; + console.error(`FAIL: ${description}`); + console.error(` ${err.message}`); + } +} + +async function checkAsync(description, fn) { + try { + await fn(); + console.log(`PASS: ${description}`); + } catch (err) { + failures += 1; + console.error(`FAIL: ${description}`); + console.error(` ${err.message}`); + } +} + +// ── normalizeScore ─────────────────────────────────────────────────────── + +{ + const { normalizeScore } = loadApiModule(() => Promise.reject(new Error('fetch should not be called'))); + + check('normalizeScore preserves null score and NO_SCAN_DATA status, never coerces to 0', () => { + const result = normalizeScore({ status: 'NO_SCAN_DATA', score: null, message: 'no completed scan' }); + assert.equal(result.status, 'NO_SCAN_DATA'); + assert.equal(result.score, null); + assert.equal(result.max_score, 100); + }); + + check('normalizeScore passes through a genuinely evaluated OK score', () => { + const result = normalizeScore({ status: 'OK', score: 82 }); + assert.equal(result.status, 'OK'); + assert.equal(result.score, 82); + }); + + check('normalizeScore treats a bare legacy number as OK', () => { + const result = normalizeScore(75); + assert.equal(result.status, 'OK'); + assert.equal(result.score, 75); + assert.equal(result.max_score, 100); + }); +} + +// ── normalizeComplianceFramework ───────────────────────────────────────── + +{ + const { normalizeComplianceFramework } = loadApiModule(() => + Promise.reject(new Error('fetch should not be called'))); + + check('normalizeComplianceFramework preserves null score for NO_SCAN_DATA', () => { + const result = normalizeComplianceFramework( + { status: 'NO_SCAN_DATA', score_percent: null, framework: 'CIS Azure', version: '2.0', total_controls: 95 }, + 'cis', + '#3b82f6', + ); + assert.equal(result.status, 'NO_SCAN_DATA'); + assert.equal(result.score, null); + }); + + check('normalizeComplianceFramework preserves null score for NO_IN_SCOPE_CONTROLS', () => { + const result = normalizeComplianceFramework( + { + status: 'NO_IN_SCOPE_CONTROLS', + score_percent: null, + framework: 'CIS Azure', + version: '2.0', + total_controls: 95, + passed: 0, + failed: 0, + }, + 'cis', + '#3b82f6', + ); + assert.equal(result.status, 'NO_IN_SCOPE_CONTROLS'); + assert.equal(result.score, null); + }); + + check('normalizeComplianceFramework passes through a genuinely evaluated score', () => { + const result = normalizeComplianceFramework( + { status: 'OK', score_percent: 91, framework: 'CIS Azure', version: '2.0', total_controls: 95 }, + 'cis', + '#3b82f6', + ); + assert.equal(result.status, 'OK'); + assert.equal(result.score, 91); + }); + + check('normalizeComplianceFramework defaults status to OK when the backend omits it (back-compat)', () => { + const result = normalizeComplianceFramework( + { score_percent: 50, framework: 'CIS Azure', version: '2.0', total_controls: 95 }, + 'cis', + '#3b82f6', + ); + assert.equal(result.status, 'OK'); + assert.equal(result.score, 50); + }); +} + +// ── end-to-end through api.getScore() with a stubbed fetch ────────────── + +await checkAsync('api.getScore() surfaces NO_SCAN_DATA from the real response shape without coercion', async () => { + const { api } = loadApiModule(() => + jsonResponse({ status: 'NO_SCAN_DATA', score: null, message: 'no completed scan' })); + const result = await api.getScore(); + assert.equal(result.status, 'NO_SCAN_DATA'); + assert.equal(result.score, null); +}); + +await checkAsync('api.getScore() surfaces a real evaluated score unchanged', async () => { + const { api } = loadApiModule(() => jsonResponse({ status: 'OK', score: 63 })); + const result = await api.getScore(); + assert.equal(result.status, 'OK'); + assert.equal(result.score, 63); +}); + +if (failures > 0) { + console.error(`\n${failures} test(s) failed.`); + process.exit(1); +} else { + console.log('\nAll api.js score-normalization tests passed.'); +} diff --git a/scanner/engine.py b/scanner/engine.py index f7af9aa2..54aacaee 100644 --- a/scanner/engine.py +++ b/scanner/engine.py @@ -117,12 +117,22 @@ def run_scan(self, scan_id: Optional[str] = None) -> Dict[str, Any]: len(self.rules), ) + # A rule that raises or returns malformed data is not silently + # equivalent to "the rule ran and found nothing" - a caller scoring + # PASS/FAIL from absence of findings (get_compliance_score()) must be + # able to tell the two apart, or a crashed rule reads as a clean + # pass. Full per-resource evaluation persistence is issue #263; + # tracking which rules failed to complete at all is the minimum this + # scan result can honestly report without it. + failed_rule_ids: List[str] = [] + for rule in self.rules: rule_id = getattr(rule, "RULE_ID", "UNKNOWN") try: rule_findings = rule.scan(self.client, self.subscription_id) if not isinstance(rule_findings, list): logger.warning("Rule %s returned %s instead of list — skipped", rule_id, type(rule_findings)) + failed_rule_ids.append(rule_id) continue validated_findings = [] @@ -145,6 +155,7 @@ def run_scan(self, scan_id: Optional[str] = None) -> Dict[str, Any]: except Exception as exc: RULE_ERRORS_TOTAL.labels(rule_id=rule_id).inc() logger.error("Rule %s raised an exception: %s", rule_id, exc, exc_info=True) + failed_rule_ids.append(rule_id) completed_at = datetime.now(timezone.utc).isoformat() @@ -161,6 +172,7 @@ def run_scan(self, scan_id: Optional[str] = None) -> Dict[str, Any]: "score": score, "severity_contract_version": CONTRACT_VERSION, "findings": findings, + "failed_rule_ids": failed_rule_ids, } logger.info("Scan %s complete — %d total finding(s). Normalising results...", scan_id, len(findings)) diff --git a/tests/smoke_test.py b/tests/smoke_test.py index 2cba3834..cec46aa5 100755 --- a/tests/smoke_test.py +++ b/tests/smoke_test.py @@ -207,16 +207,34 @@ def skip(name, reason): lambda s, b: s == 200, ) test( - "TC-10 GET /api/score returns numeric score", + # score is legitimately null when status is NO_SCAN_DATA (no completed + # scan exists yet) - that is a valid response, not a failure, so this + # only requires a numeric score when status says one was computed. + "TC-10 GET /api/score returns numeric score when status is OK", "GET", "/api/score", - lambda s, b: isinstance(b, (int, float)) or (isinstance(b, dict) and isinstance(b.get("score"), (int, float))), + lambda s, b: ( + isinstance(b, (int, float)) + or (isinstance(b, dict) and (b.get("status") != "OK" or isinstance(b.get("score"), (int, float)))) + ), ) test( - "TC-11 GET /api/score is between 0 and 100", + # b.get("score", -1) is not null-safe: a present-but-None value is + # returned as-is, not replaced by the default, so a naive bounds check + # here would TypeError on a real NO_SCAN_DATA response instead of + # accepting it as a legitimate, non-failing result. + "TC-11 GET /api/score is between 0 and 100 (or null with a non-OK status)", "GET", "/api/score", - lambda s, b: (0 <= b <= 100) if isinstance(b, (int, float)) else (0 <= b.get("score", -1) <= 100), + lambda s, b: ( + (0 <= b <= 100) + if isinstance(b, (int, float)) + else ( + (0 <= b.get("score") <= 100) + if isinstance(b, dict) and isinstance(b.get("score"), (int, float)) + else isinstance(b, dict) and b.get("score") is None and b.get("status") != "OK" + ) + ), ) # ── TC-12 to TC-14: Scans endpoint ──────────────────────────────────────── diff --git a/tests/test_clean_scan.py b/tests/test_clean_scan.py index 55bbfbf5..4b846e0f 100644 --- a/tests/test_clean_scan.py +++ b/tests/test_clean_scan.py @@ -61,11 +61,25 @@ def test_get_findings_clean_scan_returns_empty_list(): # ── get_score ───────────────────────────────────────────────────────────────── +def _mock_score_cursor(scan_row, severity_rows): + """get_score() now issues two sequential queries on one cursor: a scan- + existence check (fetchone) and, only if a scan was found, the severity + breakdown (fetchall). A single rows list can no longer stand in for both, + since a real completed scan with zero findings and no completed scan at + all must be distinguishable.""" + cur = MagicMock() + cur.__enter__ = lambda s: s + cur.__exit__ = MagicMock(return_value=False) + cur.fetchone.return_value = scan_row + cur.fetchall.return_value = severity_rows + return cur + + def test_get_score_uses_completed_status(): """get_score() must scope to status='completed', not total_findings > 0.""" db = _db() conn = MagicMock() - cur = _mock_cursor([]) + cur = _mock_score_cursor(None, []) conn.cursor.return_value = cur with patch.object(db, "_get_conn", return_value=conn): @@ -80,26 +94,45 @@ def test_get_score_is_100_after_clean_scan(): """A clean scan (no findings) must yield a perfect score of 100.""" db = _db() conn = MagicMock() - cur = _mock_cursor([]) + cur = _mock_score_cursor((1,), []) conn.cursor.return_value = cur with patch.object(db, "_get_conn", return_value=conn): score = db.get_score() - assert score == 100 + assert score == {"status": "OK", "score": 100, "max_score": 100} def test_get_score_does_not_include_old_scan_findings(): """After a clean scan, old HIGH findings must not deduct points.""" db = _db() conn = MagicMock() - cur = _mock_cursor([]) + cur = _mock_score_cursor((1,), []) conn.cursor.return_value = cur with patch.object(db, "_get_conn", return_value=conn): score = db.get_score() - assert score == 100 + assert score == {"status": "OK", "score": 100, "max_score": 100} + + +def test_get_score_no_completed_scan_returns_no_scan_data_not_a_pass(): + """No completed scan at all must never be reported as a perfect (or any) + score - that would present the absence of evidence as a clean pass, the + same class of bug fixed in get_compliance_score() for issue #302.""" + db = _db() + conn = MagicMock() + cur = _mock_score_cursor(None, []) + conn.cursor.return_value = cur + + with patch.object(db, "_get_conn", return_value=conn): + score = db.get_score() + + assert score["status"] == "NO_SCAN_DATA" + assert score["score"] is None + # Only the scan-existence check should have run - a NO_SCAN_DATA result + # must not also execute (and discard) the findings/severity query. + assert conn.cursor.return_value.execute.call_count == 1 # ── get_compliance_score ────────────────────────────────────────────────────── @@ -111,6 +144,7 @@ def test_get_compliance_score_scopes_to_latest_scan(): db = _db() conn = MagicMock() cur = _mock_cursor([]) + cur.fetchone.return_value = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} conn.cursor.return_value = cur with patch.object(db, "_get_conn", return_value=conn): @@ -131,9 +165,16 @@ def test_get_compliance_score_scopes_to_latest_scan(): with patch.object(Path, "exists", return_value=True): db.get_compliance_score("cis") - executed_sql = conn.cursor.return_value.execute.call_args[0][0] - assert "status = 'completed'" in executed_sql - assert "total_findings" not in executed_sql + # get_compliance_score() issues two queries: first it resolves the latest + # completed scan, then it looks up findings scoped to that resolved + # scan_id — so "status = 'completed'" and the findings lookup are on + # different statements, not one combined query. + executed_statements = [call[0][0] for call in conn.cursor.return_value.execute.call_args_list] + assert any("status = 'completed'" in sql for sql in executed_statements) + findings_sql = executed_statements[-1] + assert "FROM findings" in findings_sql + assert "scan_id = %s" in findings_sql + assert "total_findings" not in findings_sql def test_get_compliance_score_all_pass_after_clean_scan(): @@ -141,6 +182,7 @@ def test_get_compliance_score_all_pass_after_clean_scan(): db = _db() conn = MagicMock() cur = _mock_cursor([]) + cur.fetchone.return_value = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} conn.cursor.return_value = cur import json @@ -176,6 +218,7 @@ def test_get_compliance_score_remediated_rule_shows_pass(): db = _db() conn = MagicMock() cur = _mock_cursor([]) + cur.fetchone.return_value = {"scan_id": "scan-2", "compliance_mapping_snapshot": None} conn.cursor.return_value = cur import json @@ -203,12 +246,20 @@ def test_get_compliance_score_remediated_rule_shows_pass(): def test_get_compliance_score_reports_worst_critical_failure_without_inventing_pass_severity(): db = _db() conn = MagicMock() + # get_compliance_score() issues two queries on this connection: a + # scan-existence check (RealDictCursor, fetchone) and, only once a scan + # is confirmed to exist, the severity/category grouping below (a plain + # cursor, fetchall - see the comment on that query for why it isn't + # RealDictCursor too). conn.cursor(...) returns the same mock either way, + # so fetchone must be configured with a real scan row, independently of + # the grouped rows fetchall returns. cur = _mock_cursor( [ ("AZ-STOR-001", "HIGH", "Storage", 1), ("AZ-STOR-001", "CRITICAL", "Storage", 2), ] ) + cur.fetchone.return_value = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} conn.cursor.return_value = cur import io @@ -240,6 +291,15 @@ def test_get_compliance_score_reports_worst_critical_failure_without_inventing_p "severity": "CRITICAL", "category": "Storage", "resources": 3, + # fake_framework's controls carry no evidence-schema fields, so + # these all fall back to their defaults. + "mapping_type": "supporting", + "evidence_type": None, + "primary_source": None, + "rationale": None, + "owner": None, + "review_status": None, + "review_date": None, } assert controls["AZ-NET-001"]["status"] == "PASS" assert controls["AZ-NET-001"]["severity"] is None diff --git a/tests/test_compliance_scoring.py b/tests/test_compliance_scoring.py new file mode 100644 index 00000000..d5f61567 --- /dev/null +++ b/tests/test_compliance_scoring.py @@ -0,0 +1,669 @@ +"""Tests for the compliance mapping-pack scoring in DatabaseManager.get_compliance_score() +and the mapping-pack snapshot persisted by save_scan() (issue #302).""" + +import json +from unittest.mock import MagicMock, patch + +import api.models.finding as finding_module +import api.routes.compliance as compliance_route + + +def _db(dsn="postgresql://mock/mock"): + db = finding_module.DatabaseManager.__new__(finding_module.DatabaseManager) + db.dsn = dsn + db.conn = None + return db + + +def _mock_cursor(fetchone_return=None, fetchall_return=None): + cur = MagicMock() + cur.__enter__ = lambda s: s + cur.__exit__ = MagicMock(return_value=False) + cur.fetchone.return_value = fetchone_return + cur.fetchall.return_value = fetchall_return or [] + return cur + + +def _write_framework(tmp_path, filename, controls, **pack_overrides): + data = { + "framework": "Test Framework", + "version": "1.0", + "published": "2026-01", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "test fixture", + "mapping_pack_published": "2026-08-22", + "controls": controls, + } + data.update(pack_overrides) + path = tmp_path / filename + with open(path, "w") as fh: + json.dump(data, fh) + return path + + +def _control(control_id, mapping_type="direct"): + return { + "control_id": control_id, + "control_name": f"Control {control_id}", + "description": "test", + "mapping_type": mapping_type, + "evidence_type": "not_applicable" + if mapping_type in ("not_applicable", "organizational") + else "automated_configuration_scan", + "primary_source": "test source", + "rationale": "test rationale", + "owner": None, + "review_status": "pending_review", + "review_date": None, + } + + +# ── No completed scan: must never report a passing score from absent data ── + + +def test_no_completed_scan_returns_no_scan_data_not_a_pass(): + db = _db() + conn = MagicMock() + conn.cursor.return_value = _mock_cursor(fetchone_return=None) + with ( + patch.object(db, "_get_conn", return_value=conn), + patch.object(finding_module, "FRAMEWORKS_DIR", finding_module.FRAMEWORKS_DIR), + ): + result = db.get_compliance_score("cis") + + assert result["status"] == "NO_SCAN_DATA" + assert result["score_percent"] is None + # None, not 0 - a literal 0 would read as "this pack has zero in-scope + # controls" (the distinct NO_IN_SCOPE_CONTROLS case), when nothing has + # actually been evaluated yet. + assert result["passed"] is None + assert result["failed"] is None + assert result["in_scope_controls"] is None + assert result["excluded_controls"] is None + assert "error" not in result # route must return 200, not 500, for this normal state + assert result["controls"] == [] + assert "evaluation_basis" in result + + +# ── Unknown framework / missing file ──────────────────────────────────────── + + +def test_unknown_framework_returns_error(): + db = _db() + result = db.get_compliance_score("not-a-real-framework") + assert "error" in result + + +# ── PASS / FAIL / exclusion semantics, using a synthetic framework file ──── + + +def _patched_db_with_framework(tmp_path, controls, scan_row, finding_rows): + db = _db() + conn = MagicMock() + cur = _mock_cursor(fetchone_return=scan_row, fetchall_return=finding_rows) + conn.cursor.return_value = cur + + framework_file = "test_fw.json" + _write_framework(tmp_path, framework_file, controls) + + return db, conn, framework_file + + +def test_direct_control_with_no_findings_is_pass(tmp_path, monkeypatch): + controls = {"AZ-TEST-001": _control("1.1", "direct")} + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["controls"][0]["status"] == "PASS" + assert result["passed"] == 1 + assert result["failed"] == 0 + assert result["score_percent"] == 100 + + +def test_control_with_finding_is_fail(tmp_path, monkeypatch): + controls = {"AZ-TEST-001": _control("1.1", "direct")} + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} + finding_rows = [("AZ-TEST-001", "HIGH", "Storage", 1)] + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, finding_rows) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["controls"][0]["status"] == "FAIL" + assert result["passed"] == 0 + assert result["failed"] == 1 + assert result["score_percent"] == 0 + + +def test_not_applicable_and_organizational_excluded_from_denominator(tmp_path, monkeypatch): + controls = { + "AZ-TEST-001": _control("1.1", "direct"), # PASS + "AZ-TEST-002": _control("1.2", "direct"), # FAIL + "AZ-TEST-003": _control("1.3", "not_applicable"), + "AZ-TEST-004": _control("1.4", "organizational"), + } + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} + finding_rows = [("AZ-TEST-002", "HIGH", "Storage", 1)] + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, finding_rows) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + statuses = {c["rule_id"]: c["status"] for c in result["controls"]} + assert statuses["AZ-TEST-001"] == "PASS" + assert statuses["AZ-TEST-002"] == "FAIL" + assert statuses["AZ-TEST-003"] == "NOT_APPLICABLE" + assert statuses["AZ-TEST-004"] == "ORGANIZATIONAL" + + assert result["total_controls"] == 4 + assert result["excluded_controls"] == 2 + assert result["in_scope_controls"] == 2 + assert result["passed"] == 1 + assert result["failed"] == 1 + # Score is 1/2, not 1/4 — excluded controls must not dilute the denominator. + assert result["score_percent"] == 50 + + +def test_rule_that_did_not_complete_is_not_evaluated_not_pass(tmp_path, monkeypatch): + """A rule the scan engine recorded as failed (raised, or returned + malformed data - scanner/engine.py's failed_rule_ids) must not be read + as a PASS just because it produced no findings. It's excluded from the + denominator as NOT_EVALUATED instead, the same way not_applicable/ + organizational controls are, but for a different reason: this is + missing evidence, not a control the mapping pack says a scan can't + establish (issue #302 item 4).""" + controls = { + "AZ-TEST-001": _control("1.1", "direct"), # ran clean -> PASS + "AZ-TEST-002": _control("1.2", "direct"), # ran, found a finding -> FAIL + "AZ-TEST-003": _control("1.3", "direct"), # never completed -> NOT_EVALUATED + } + scan_row = { + "scan_id": "scan-1", + "compliance_mapping_snapshot": {"_scan_rule_outcomes": {"failed_rule_ids": ["AZ-TEST-003"]}}, + } + finding_rows = [("AZ-TEST-002", "HIGH", "Storage", 1)] + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, finding_rows) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + statuses = {c["rule_id"]: c["status"] for c in result["controls"]} + assert statuses["AZ-TEST-001"] == "PASS" + assert statuses["AZ-TEST-002"] == "FAIL" + assert statuses["AZ-TEST-003"] == "NOT_EVALUATED" + + assert result["total_controls"] == 3 + # AZ-TEST-003 is excluded from the denominator like not_applicable/ + # organizational controls, so in_scope is 2 (AZ-TEST-001, AZ-TEST-002). + assert result["excluded_controls"] == 1 + assert result["in_scope_controls"] == 2 + assert result["passed"] == 1 + assert result["failed"] == 1 + assert result["score_percent"] == 50 + + +def test_failed_rule_ids_from_an_older_scan_do_not_leak_into_a_later_ones_scoring(tmp_path, monkeypatch): + """_scan_rule_outcomes is read from the latest scan's own snapshot only - + a rule that failed on a previous scan but completed cleanly on the + latest one must score PASS, not get stuck as NOT_EVALUATED forever.""" + controls = {"AZ-TEST-001": _control("1.1", "direct")} + # The latest scan's snapshot has no _scan_rule_outcomes at all (it + # completed with no rule failures), even though an earlier scan might + # have recorded AZ-TEST-001 as failed. + scan_row = {"scan_id": "scan-2", "compliance_mapping_snapshot": {}} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["controls"][0]["status"] == "PASS" + + +def test_ok_status_and_score_present_when_controls_are_in_scope(tmp_path, monkeypatch): + """A genuinely evaluated result must be explicitly distinguishable from + NO_SCAN_DATA/NO_IN_SCOPE_CONTROLS by status, not just by score_percent + happening to be non-null.""" + controls = {"AZ-TEST-001": _control("1.1", "direct")} + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["status"] == "OK" + assert result["score_percent"] == 100 + + +def test_no_in_scope_controls_status_when_everything_is_excluded(tmp_path, monkeypatch): + """A scan exists and every mapped control resolved, but all of them are + not_applicable/organizational - this must be distinguishable from both + NO_SCAN_DATA (no evidence exists at all) and a real evaluated score, not + collapsed into the same null score_percent as either.""" + controls = { + "AZ-TEST-001": _control("1.1", "not_applicable"), + "AZ-TEST-002": _control("1.2", "organizational"), + } + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["status"] == "NO_IN_SCOPE_CONTROLS" + assert result["score_percent"] is None + assert result["in_scope_controls"] == 0 + assert result["total_controls"] == 2 + + +def test_mapping_pack_snapshot_preferred_over_live_file(tmp_path, monkeypatch): + """A full historical snapshot (controls + hash, not just metadata) wins + over whatever is on disk now.""" + controls = {"AZ-TEST-001": _control("1.1", "direct")} + historical_snapshot = { + "testfw": { + "framework": "Test Framework (historical)", + "version": "0.9", + "mapping_pack_version": "0.1.0", + "mapping_pack_status": "legacy", + "mapping_pack_source": "historical fixture", + "mapping_pack_published": "2025-01-01", + "controls": controls, + finding_module._CONTENT_HASH_KEY: finding_module._compute_mapping_pack_content_hash(controls), + } + } + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": historical_snapshot} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + # Report shows what was true when the scan ran, not the current file on disk. + assert result["mapping_pack_version"] == "0.1.0" + assert result["mapping_pack_status"] == "legacy" + assert result["framework"] == "Test Framework (historical)" + assert result["mapping_provenance"] == "snapshot" + + +def test_legacy_metadata_only_snapshot_is_not_labelled_snapshot(tmp_path, monkeypatch): + """A snapshot saved before the full-controls capture existed (pack + metadata only, no "controls" key) cannot reproduce the historical + mapping - denominator/classification still has to come from the live + file, so it must be labelled a live fallback, not "snapshot". Claiming + "snapshot" here would be exactly the bug flagged in issue #302 item 3: + presenting a live-data read as if it were historically accurate.""" + controls = {"AZ-TEST-001": _control("1.1", "direct")} + historical_snapshot = { + "testfw": { + "framework": "Test Framework (historical)", + "version": "0.9", + "mapping_pack_version": "0.1.0", + "mapping_pack_status": "legacy", + "mapping_pack_source": "historical fixture", + "mapping_pack_published": "2025-01-01", + } + } + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": historical_snapshot} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["mapping_pack_version"] == "0.1.0" # metadata still honored + assert result["mapping_provenance"] == "live_fallback_legacy_snapshot" + + +def test_snapshot_hash_mismatch_is_flagged_not_silently_trusted(tmp_path, monkeypatch): + """If a stored snapshot's controls no longer match its own recorded + hash (corruption, partial write), that must be surfaced, not silently + presented as a clean, verified "snapshot".""" + controls = {"AZ-TEST-001": _control("1.1", "direct")} + historical_snapshot = { + "testfw": { + "framework": "Test Framework", + "version": "1.0", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "historical fixture", + "mapping_pack_published": "2025-01-01", + "controls": controls, + finding_module._CONTENT_HASH_KEY: "0" * 64, # deliberately wrong + } + } + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": historical_snapshot} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["mapping_provenance"] == "snapshot_hash_mismatch" + # Still the best available historical data, so still used rather than + # silently substituting the live file. + assert result["controls"][0]["rule_id"] == "AZ-TEST-001" + + +def test_mapping_update_after_scan_does_not_change_that_scans_reported_mapping(tmp_path, monkeypatch): + """The exact acceptance test item 3 asked for: save a scan under a v1 + mapping pack, change the live mapping to v2, then query that same scan + again and prove its controls, classification, denominator, hash, and + metadata all remain v1 - not silently re-evaluated under v2.""" + v1_controls = {"AZ-TEST-001": _control("1.1", "direct")} + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + framework_file = "test_fw.json" + _write_framework(tmp_path, framework_file, v1_controls, mapping_pack_version="1.0.0") + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + # Simulate what save_scan() captured at v1 scan time. + v1_snapshot = finding_module._build_compliance_mapping_snapshot() + v1_hash = v1_snapshot["testfw"][finding_module._CONTENT_HASH_KEY] + + # The mapping pack is revised: AZ-TEST-001 becomes not_applicable and a + # new control is added. This must never retroactively change how the v1 + # scan is reported. + v2_controls = { + "AZ-TEST-001": _control("1.1", "not_applicable"), + "AZ-TEST-002": _control("1.2", "direct"), + } + _write_framework(tmp_path, framework_file, v2_controls, mapping_pack_version="2.0.0") + + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": v1_snapshot} + db, conn, _ = _patched_db_with_framework(tmp_path, v2_controls, scan_row, []) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["mapping_provenance"] == "snapshot" + assert result["mapping_pack_version"] == "1.0.0" + assert result[finding_module._CONTENT_HASH_KEY] == v1_hash + assert list(result["controls"][0].keys()) # sanity: shape unchanged + assert len(result["controls"]) == 1 # v1 had one control, not v2's two + assert result["controls"][0]["rule_id"] == "AZ-TEST-001" + assert result["controls"][0]["mapping_type"] == "direct" # still v1's classification + assert result["controls"][0]["status"] == "PASS" + assert result["total_controls"] == 1 + assert result["in_scope_controls"] == 1 + + +def test_mapping_provenance_flags_capture_failure_instead_of_silently_using_live_data(tmp_path, monkeypatch): + """When this exact scan's snapshot attempt failed for this framework + (recorded under _capture_errors at save time), falling back to the live + file on disk is the only option, but the response must say so explicitly + rather than presenting live data as if it were historically accurate.""" + controls = {"AZ-TEST-001": _control("1.1", "direct")} + scan_row = { + "scan_id": "scan-1", + "compliance_mapping_snapshot": {"_capture_errors": {"testfw": "OSError: disk read failed"}}, + } + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["mapping_provenance"] == "live_fallback_capture_failed" + + +def test_mapping_provenance_is_benign_fallback_when_scan_predates_snapshot_feature(tmp_path, monkeypatch): + """An old scan saved before the snapshot feature existed (or before this + framework was added) has neither a snapshot entry nor a recorded capture + error for it - a real, benign fallback, distinct from a genuine failure.""" + controls = {"AZ-TEST-001": _control("1.1", "direct")} + scan_row = {"scan_id": "scan-1", "compliance_mapping_snapshot": None} + db, conn, framework_file = _patched_db_with_framework(tmp_path, controls, scan_row, []) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + monkeypatch.setitem(finding_module.FRAMEWORK_FILE_MAP, "testfw", framework_file) + + with patch.object(db, "_get_conn", return_value=conn): + result = db.get_compliance_score("testfw") + + assert result["mapping_provenance"] == "live_fallback_no_snapshot" + + +# ── compliance_mapping_snapshot construction for save_scan() ─────────────── + + +def test_build_compliance_mapping_snapshot_reads_all_frameworks(tmp_path, monkeypatch): + for key, filename in finding_module.FRAMEWORK_FILE_MAP.items(): + _write_framework(tmp_path, filename, {}) + + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + snapshot = finding_module._build_compliance_mapping_snapshot() + + assert set(snapshot.keys()) == set(finding_module.FRAMEWORK_FILE_MAP.keys()) + for entry in snapshot.values(): + assert entry["mapping_pack_version"] == "1.0.0" + assert entry["mapping_pack_status"] == "current" + + +def test_build_compliance_mapping_snapshot_records_missing_file_not_silently(tmp_path, monkeypatch): + """A missing framework file must never be silently omitted — it's + recorded under "_capture_errors" so a later consumer of this exact + snapshot can tell "never captured" apart from "nothing went wrong".""" + # No framework files written at all — every FRAMEWORKS_DIR / filename lookup misses. + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + snapshot = finding_module._build_compliance_mapping_snapshot() + assert set(snapshot.keys()) == {"_capture_errors"} + assert set(snapshot["_capture_errors"].keys()) == set(finding_module.FRAMEWORK_FILE_MAP.keys()) + assert all("FileNotFoundError" in msg for msg in snapshot["_capture_errors"].values()) + + +def test_build_compliance_mapping_snapshot_records_malformed_file_not_silently(tmp_path, monkeypatch): + for key, filename in finding_module.FRAMEWORK_FILE_MAP.items(): + (tmp_path / filename).write_text("{not valid json") + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + + snapshot = finding_module._build_compliance_mapping_snapshot() + + assert set(snapshot.keys()) == {"_capture_errors"} + assert all("JSONDecodeError" in msg for msg in snapshot["_capture_errors"].values()) + + +def test_build_compliance_mapping_snapshot_partial_failure_keeps_successful_frameworks(tmp_path, monkeypatch): + """One framework failing to capture must not discard frameworks that + captured successfully.""" + good_filename = next(iter(finding_module.FRAMEWORK_FILE_MAP.values())) + _write_framework(tmp_path, good_filename, {}) + # Every other framework's file is left unwritten (missing). + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + + snapshot = finding_module._build_compliance_mapping_snapshot() + + good_key = next(k for k, v in finding_module.FRAMEWORK_FILE_MAP.items() if v == good_filename) + assert good_key in snapshot + assert snapshot[good_key]["mapping_pack_version"] == "1.0.0" + assert "_capture_errors" in snapshot + assert good_key not in snapshot["_capture_errors"] + assert len(snapshot["_capture_errors"]) == len(finding_module.FRAMEWORK_FILE_MAP) - 1 + + +def test_save_scan_persists_compliance_mapping_snapshot(tmp_path, monkeypatch): + for key, filename in finding_module.FRAMEWORK_FILE_MAP.items(): + _write_framework(tmp_path, filename, {}) + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + + db = _db() + conn = MagicMock() + conn.cursor.return_value = _mock_cursor() + with patch.object(db, "_get_conn", return_value=conn): + db.save_scan( + { + "scan_id": "scan-1", + "subscription_id": "sub-1", + "started_at": "2026-08-22T00:00:00Z", + "completed_at": "2026-08-22T00:05:00Z", + "total_findings": 0, + "findings": [], + } + ) + + executed_sql, params = conn.cursor.return_value.execute.call_args_list[0][0] + assert "compliance_mapping_snapshot" in executed_sql + snapshot_param = params[-1] + snapshot = json.loads(snapshot_param) + assert set(snapshot.keys()) == set(finding_module.FRAMEWORK_FILE_MAP.keys()) + + +def test_save_scan_records_failed_rule_ids_into_snapshot(tmp_path, monkeypatch): + """scanner/engine.py's failed_rule_ids must reach the persisted snapshot + under _scan_rule_outcomes, so get_compliance_score() can later exclude + those rules as NOT_EVALUATED instead of reading them as PASS.""" + for key, filename in finding_module.FRAMEWORK_FILE_MAP.items(): + _write_framework(tmp_path, filename, {}) + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + + db = _db() + conn = MagicMock() + conn.cursor.return_value = _mock_cursor() + with patch.object(db, "_get_conn", return_value=conn): + db.save_scan( + { + "scan_id": "scan-1", + "subscription_id": "sub-1", + "started_at": "2026-08-22T00:00:00Z", + "completed_at": "2026-08-22T00:05:00Z", + "total_findings": 0, + "findings": [], + # Duplicates and unsorted input must not leak through verbatim. + "failed_rule_ids": ["AZ-TEST-002", "AZ-TEST-001", "AZ-TEST-002"], + } + ) + + executed_sql, params = conn.cursor.return_value.execute.call_args_list[0][0] + snapshot = json.loads(params[-1]) + assert snapshot["_scan_rule_outcomes"] == {"failed_rule_ids": ["AZ-TEST-001", "AZ-TEST-002"]} + + +def test_save_scan_omits_scan_rule_outcomes_when_nothing_failed(tmp_path, monkeypatch): + """A clean scan must not carry an empty _scan_rule_outcomes key - its + absence is exactly what lets a later get_compliance_score() call treat + every rule's silence as eligible for PASS.""" + for key, filename in finding_module.FRAMEWORK_FILE_MAP.items(): + _write_framework(tmp_path, filename, {}) + monkeypatch.setattr(finding_module, "FRAMEWORKS_DIR", tmp_path) + + db = _db() + conn = MagicMock() + conn.cursor.return_value = _mock_cursor() + with patch.object(db, "_get_conn", return_value=conn): + db.save_scan( + { + "scan_id": "scan-1", + "subscription_id": "sub-1", + "started_at": "2026-08-22T00:00:00Z", + "completed_at": "2026-08-22T00:05:00Z", + "total_findings": 0, + "findings": [], + "failed_rule_ids": [], + } + ) + + executed_sql, params = conn.cursor.return_value.execute.call_args_list[0][0] + snapshot = json.loads(params[-1]) + assert "_scan_rule_outcomes" not in snapshot + + +# ── Route-level: /api/compliance/ must degrade to 200, not 500, +# when there is genuinely no scan evidence yet ────────────────────────── + + +def test_route_returns_200_for_no_scan_data(client, auth_headers): + db = MagicMock() + db.get_compliance_score.return_value = { + "framework": "Test Framework", + "version": "1.0", + "status": "NO_SCAN_DATA", + "message": "No completed scan is available yet.", + "total_controls": 3, + "in_scope_controls": 0, + "excluded_controls": 0, + "passed": 0, + "failed": 0, + "score_percent": None, + "controls": [], + } + with patch.object(compliance_route, "_get_db", return_value=db): + resp = client.get("/api/compliance/cis", headers=auth_headers) + + assert resp.status_code == 200 + body = resp.get_json() + assert body["status"] == "NO_SCAN_DATA" + assert body["score_percent"] is None + + +def test_route_reports_mapping_metadata_fields(client, auth_headers): + db = MagicMock() + db.get_compliance_score.return_value = { + "framework": "Test Framework", + "version": "1.0", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "test", + "mapping_pack_published": "2026-08-22", + "scan_id": "scan-1", + "evaluation_basis": "...", + "total_controls": 1, + "in_scope_controls": 1, + "excluded_controls": 0, + "passed": 1, + "failed": 0, + "score_percent": 100, + "controls": [ + { + "rule_id": "AZ-TEST-001", + "control_id": "1.1", + "control_name": "Control 1.1", + "status": "PASS", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "test source", + "rationale": "test rationale", + "owner": None, + "review_status": "pending_review", + "review_date": None, + } + ], + } + with patch.object(compliance_route, "_get_db", return_value=db): + resp = client.get("/api/compliance/cis", headers=auth_headers) + + assert resp.status_code == 200 + body = resp.get_json() + assert body["mapping_pack_version"] == "1.0.0" + assert body["controls"][0]["mapping_type"] == "direct" + assert body["controls"][0]["rationale"] == "test rationale" diff --git a/tests/test_database_manager_reliability.py b/tests/test_database_manager_reliability.py index 06249280..288f408d 100644 --- a/tests/test_database_manager_reliability.py +++ b/tests/test_database_manager_reliability.py @@ -26,10 +26,22 @@ def _mock_cursor(rows=None, rowcount=0): # ── REL-001: get_score must issue valid SQL (single GROUP BY) ────────────── +def _mock_score_cursor(scan_row, severity_rows): + """get_score() issues two sequential queries on one cursor: a scan-existence + check (fetchone), then - only once a scan is found - the severity breakdown + (fetchall).""" + cur = MagicMock() + cur.__enter__ = lambda s: s + cur.__exit__ = MagicMock(return_value=False) + cur.fetchone.return_value = scan_row + cur.fetchall.return_value = severity_rows + return cur + + def test_get_score_sql_has_single_group_by(): db = _db() conn = MagicMock() - conn.cursor.return_value = _mock_cursor([]) + conn.cursor.return_value = _mock_score_cursor((1,), []) with patch.object(db, "_get_conn", return_value=conn): db.get_score() executed_sql = conn.cursor.return_value.execute.call_args[0][0] @@ -39,11 +51,11 @@ def test_get_score_sql_has_single_group_by(): def test_get_score_deducts_points_for_findings(): db = _db() conn = MagicMock() - conn.cursor.return_value = _mock_cursor([("HIGH", 2), ("MEDIUM", 1)]) + conn.cursor.return_value = _mock_score_cursor((1,), [("HIGH", 2), ("MEDIUM", 1)]) with patch.object(db, "_get_conn", return_value=conn): score = db.get_score() # 100 - (10 * 2 + 5 * 1) = 75 - assert score == 75 + assert score == {"status": "OK", "score": 75, "max_score": 100} # REL-002 (recover_stale_scans's interval handling) is now covered by diff --git a/tests/test_engine_integration.py b/tests/test_engine_integration.py index e7006d5c..1e4e80e1 100644 --- a/tests/test_engine_integration.py +++ b/tests/test_engine_integration.py @@ -150,17 +150,17 @@ def test_engine_empty_subscription_is_consistent(monkeypatch): def test_engine_isolates_a_failing_rule(monkeypatch): - """One rule raising inside scan() must not abort the whole scan. - - Demonstrates the OBSERVABILITY GAP: the failed rule is swallowed and the - result dict has no field recording which rules errored, so a partial scan - is indistinguishable from a fully clean one. - """ + """One rule raising inside scan() must not abort the whole scan, and the + failure must be recorded in the result (issue #302: a rule that crashed + is not the same as a rule that ran and found nothing - get_compliance_score() + needs failed_rule_ids to avoid reading the crash as a clean PASS).""" _patch_engine_client(monkeypatch, _offline_mock()) eng = ScanEngine(_SUB) assert len(eng.rules) >= 45 # Force the first loaded rule to raise when scanned. + failing_rule_id = eng.rules[0].RULE_ID + def _boom(*args, **kwargs): raise RuntimeError("simulated rule failure") @@ -168,9 +168,51 @@ def _boom(*args, **kwargs): result = eng.run_scan() # must not raise assert result["status"] == "completed" - # The other rules still ran (empty mock -> no findings) and the scan - # completed. Crucially, there is NO field in the result naming the failed - # rule -- this is the observability gap flagged in the validation report. - assert "errored_rules" not in result - assert "rules_failed" not in result - assert "errors" not in result + # The other rules still ran and the scan completed, but the crashed rule + # is explicitly named so its absence from findings is never mistaken for + # a clean pass. (Not asserting the list is exactly [failing_rule_id]: a + # handful of resilience/backup rules already error against the offline + # mock for an unrelated, pre-existing reason - MockAzureClient predates + # them and is missing methods like get_recovery_vault_security_posture. + # That gap is real but out of scope here; this test only cares that the + # rule we deliberately broke shows up.) + assert failing_rule_id in result["failed_rule_ids"] + + +def test_engine_records_a_rule_that_returns_malformed_data_as_failed(monkeypatch): + """A rule returning something other than a list is not silently treated + as clean either - it's the same "did not actually run to completion" + case as a raised exception.""" + _patch_engine_client(monkeypatch, _offline_mock()) + eng = ScanEngine(_SUB) + + malformed_rule_id = eng.rules[0].RULE_ID + monkeypatch.setattr(eng.rules[0], "scan", lambda *a, **k: {"not": "a list"}) + + result = eng.run_scan() + assert result["status"] == "completed" + assert malformed_rule_id in result["failed_rule_ids"] + + +def test_engine_run_scan_always_reports_failed_rule_ids_as_a_list(monkeypatch): + """failed_rule_ids must always be a list, never an absent key, so + get_compliance_score() can read it unconditionally.""" + _patch_engine_client(monkeypatch, _offline_mock()) + eng = ScanEngine(_SUB) + + result = eng.run_scan() + assert isinstance(result["failed_rule_ids"], list) + + +def test_engine_a_rule_that_completes_cleanly_is_never_recorded_as_failed(monkeypatch): + """Rules that ran successfully - even producing zero findings - must not + appear in failed_rule_ids. Only rules that actually raised or returned + malformed data belong there.""" + _patch_engine_client(monkeypatch, _offline_mock()) + eng = ScanEngine(_SUB) + + healthy_rule_id = eng.rules[0].RULE_ID + monkeypatch.setattr(eng.rules[0], "scan", lambda *a, **k: []) + + result = eng.run_scan() + assert healthy_rule_id not in result["failed_rule_ids"] diff --git a/tests/test_mapping_pack_validation.py b/tests/test_mapping_pack_validation.py new file mode 100644 index 00000000..51e57a86 --- /dev/null +++ b/tests/test_mapping_pack_validation.py @@ -0,0 +1,180 @@ +"""Unit tests for .github/scripts/validate_mapping_pack.py against fixture +directories, so the mapping-pack semantics rules are exercised directly +rather than only implicitly via CI running against the real framework files. +""" + +import importlib.util +import json +from pathlib import Path + +SCRIPT_PATH = Path(__file__).resolve().parents[1] / ".github" / "scripts" / "validate_mapping_pack.py" +_spec = importlib.util.spec_from_file_location("validate_mapping_pack", SCRIPT_PATH) +validate_mapping_pack = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(validate_mapping_pack) + +validate_framework_dir = validate_mapping_pack.validate_framework_dir + + +def _control(**overrides): + base = { + "control_id": "1.1", + "control_name": "Example control", + "description": "Example description", + "mapping_type": "direct", + "evidence_type": "automated_configuration_scan", + "primary_source": "Example Framework v1.0, control 1.1", + "rationale": "This rule evaluates exactly the setting this control requires.", + "owner": None, + "review_status": "pending_review", + "review_date": None, + } + base.update(overrides) + return base + + +def _pack(controls, **overrides): + base = { + "framework": "Example Framework", + "version": "1.0", + "mapping_pack_version": "1.0.0", + "mapping_pack_status": "current", + "mapping_pack_source": "Test fixture", + "mapping_pack_published": "2026-08-22", + "controls": controls, + } + base.update(overrides) + return base + + +def _write(tmp_path, name, pack): + path = tmp_path / name + with open(path, "w") as fh: + json.dump(pack, fh) + return path + + +def test_valid_pack_produces_no_failures(tmp_path): + _write(tmp_path, "example.json", _pack({"AZ-EX-001": _control()})) + assert validate_framework_dir(tmp_path) == [] + + +def test_na_control_id_classified_direct_fails(tmp_path): + """The exact bug this check exists to catch: a synthetic N/A-* control ID + (this repository's own convention for 'no real framework control exists') + still marked as direct technical evidence.""" + control = _control( + control_id="N/A-EX-001", + control_name="Not mapped in Example Framework v1.0", + mapping_type="direct", + ) + _write(tmp_path, "example.json", _pack({"AZ-EX-001": control})) + failures = validate_framework_dir(tmp_path) + assert any("must be 'not_applicable'" in f for f in failures) + + +def test_na_control_id_classified_not_applicable_passes(tmp_path): + control = _control( + control_id="N/A-EX-001", + control_name="Not mapped in Example Framework v1.0", + mapping_type="not_applicable", + evidence_type="not_applicable", + ) + _write(tmp_path, "example.json", _pack({"AZ-EX-001": control})) + assert validate_framework_dir(tmp_path) == [] + + +def test_prose_disclaimer_classified_direct_fails(tmp_path): + """Even without an N/A- prefixed ID, text that explicitly disclaims a + real mapping ('not directly mapped', etc.) cannot be paired with direct.""" + control = _control( + control_id="9.9", + description="This control is not directly mapped to any Example Framework requirement.", + mapping_type="direct", + ) + _write(tmp_path, "example.json", _pack({"AZ-EX-001": control})) + failures = validate_framework_dir(tmp_path) + assert any("must be 'not_applicable'" in f for f in failures) + + +def test_invalid_mapping_type_fails(tmp_path): + _write(tmp_path, "example.json", _pack({"AZ-EX-001": _control(mapping_type="mostly_direct")})) + failures = validate_framework_dir(tmp_path) + assert any("mapping_type 'mostly_direct'" in f for f in failures) + + +def test_not_applicable_with_automated_scan_evidence_type_fails(tmp_path): + control = _control(mapping_type="not_applicable", evidence_type="automated_configuration_scan") + _write(tmp_path, "example.json", _pack({"AZ-EX-001": control})) + failures = validate_framework_dir(tmp_path) + assert any("cannot have evidence_type" in f for f in failures) + + +def test_reviewed_without_owner_or_date_fails(tmp_path): + control = _control(review_status="reviewed", owner=None, review_date=None) + _write(tmp_path, "example.json", _pack({"AZ-EX-001": control})) + failures = validate_framework_dir(tmp_path) + assert any("owner and/or review_date is missing" in f for f in failures) + + +def test_reviewed_with_owner_and_date_passes(tmp_path): + control = _control(review_status="reviewed", owner="security-team", review_date="2026-08-22") + _write(tmp_path, "example.json", _pack({"AZ-EX-001": control})) + assert validate_framework_dir(tmp_path) == [] + + +def test_missing_rationale_fails(tmp_path): + control = _control(rationale="") + _write(tmp_path, "example.json", _pack({"AZ-EX-001": control})) + failures = validate_framework_dir(tmp_path) + assert any("'rationale' must be a non-empty string" in f for f in failures) + + +def test_invalid_semantic_version_fails(tmp_path): + _write(tmp_path, "example.json", _pack({"AZ-EX-001": _control()}, mapping_pack_version="v1.0")) + failures = validate_framework_dir(tmp_path) + assert any("not a valid semantic version" in f for f in failures) + + +def test_valid_semantic_version_passes(tmp_path): + _write(tmp_path, "example.json", _pack({"AZ-EX-001": _control()}, mapping_pack_version="2.3.10")) + assert validate_framework_dir(tmp_path) == [] + + +def test_invalid_iso_date_fails(tmp_path): + _write(tmp_path, "example.json", _pack({"AZ-EX-001": _control()}, mapping_pack_published="08/22/2026")) + failures = validate_framework_dir(tmp_path) + assert any("not a valid ISO date" in f for f in failures) + + +def test_invalid_pack_status_fails(tmp_path): + _write(tmp_path, "example.json", _pack({"AZ-EX-001": _control()}, mapping_pack_status="draft")) + failures = validate_framework_dir(tmp_path) + assert any("mapping_pack_status 'draft'" in f for f in failures) + + +def test_legacy_pack_status_passes(tmp_path): + _write(tmp_path, "example.json", _pack({"AZ-EX-001": _control()}, mapping_pack_status="legacy")) + assert validate_framework_dir(tmp_path) == [] + + +def test_missing_top_level_field_fails(tmp_path): + pack = _pack({"AZ-EX-001": _control()}) + del pack["mapping_pack_source"] + _write(tmp_path, "example.json", pack) + failures = validate_framework_dir(tmp_path) + assert any("missing or empty top-level 'mapping_pack_source'" in f for f in failures) + + +def test_malformed_json_is_reported_not_raised(tmp_path): + path = tmp_path / "broken.json" + path.write_text("{not valid json") + failures = validate_framework_dir(tmp_path) + assert any("could not parse" in f for f in failures) + + +def test_real_repository_framework_files_pass(): + """The actual shipped framework files must always satisfy this validator - + this is the same check CI runs, exercised here so a regression is caught + by the unit-test suite too, not only a full CI run.""" + real_dir = Path(__file__).resolve().parents[1] / "compliance" / "frameworks" + assert validate_framework_dir(real_dir) == [] diff --git a/tests/test_score_route_contract.py b/tests/test_score_route_contract.py new file mode 100644 index 00000000..5bd54097 --- /dev/null +++ b/tests/test_score_route_contract.py @@ -0,0 +1,44 @@ +"""Route-level contract tests for GET /api/score. + +get_score() moved from a bare integer to {status, score, max_score} so +NO_SCAN_DATA can be reported explicitly instead of a false 100 (issue #302). +These tests pin the actual HTTP response shape for both states, since the +frontend, API reference docs, and any external consumer all depend on it. +""" + +from unittest.mock import MagicMock, patch + +import api.routes.score as score_route + + +def test_route_returns_ok_status_and_max_score_for_a_real_score(client, auth_headers): + db = MagicMock() + db.get_score.return_value = {"status": "OK", "score": 82, "max_score": 100} + with patch.object(score_route, "_get_db", return_value=db): + resp = client.get("/api/score", headers=auth_headers) + + assert resp.status_code == 200 + body = resp.get_json() + assert body == {"status": "OK", "score": 82, "max_score": 100} + + +def test_route_returns_200_with_null_score_for_no_scan_data(client, auth_headers): + """A missing scan must surface as a normal 200 with an explicit + NO_SCAN_DATA status and a null score - never a 500, and never a score + value that looks like a real evaluated result.""" + db = MagicMock() + db.get_score.return_value = { + "status": "NO_SCAN_DATA", + "score": None, + "max_score": 100, + "message": "No completed scan is available yet, so there is no security posture to score.", + } + with patch.object(score_route, "_get_db", return_value=db): + resp = client.get("/api/score", headers=auth_headers) + + assert resp.status_code == 200 + body = resp.get_json() + assert body["status"] == "NO_SCAN_DATA" + assert body["score"] is None + assert body["max_score"] == 100 + assert "error" not in body diff --git a/tests/test_severity_contract.py b/tests/test_severity_contract.py index 097ce33b..3c402c43 100644 --- a/tests/test_severity_contract.py +++ b/tests/test_severity_contract.py @@ -125,7 +125,7 @@ def test_database_score_uses_the_same_critical_weight_as_engine(): conn = MagicMock() conn.cursor.return_value = _cursor([("CRITICAL", 1)]) with patch.object(db, "_get_conn", return_value=conn): - assert db.get_score() == 80 + assert db.get_score() == {"status": "OK", "score": 80, "max_score": 100} def test_persistence_rejects_invalid_severity_before_opening_connection():