Compliance¶
Cloud Security evaluates compliance frameworks continuously against the live estate. Controls combine observed configuration, findings and, where required, scoped manual evidence. A finding can prove a violation even when collection is partial. A clean result receives credit only after the required collection and assessment finish against the current connection settings. A report is an assessment of that evidence, not certification of the entire framework.
The report¶
# Whole-estate assessment against a framework (default: cis-gcp).
limacharlie cloudsec compliance report --framework cis-gcp
# Which frameworks are available?
limacharlie cloudsec compliance frameworks
Fifteen frameworks ship today: cis-aws, cis-azure, cis-gcp (the
default), cis-gcp-v5, cis-m365, cis-m365-v7, soc2, pci-dss, hipaa,
iso-27001, nist-csf, nist-ai-rmf, owasp-llm, owasp-top10, and
cis-supply-chain. nist-ai-rmf
and owasp-llm are AI frameworks: they assess the OpenAI and Anthropic estate
connected through the AI providers.
owasp-top10 (OWASP Top 10:2021, mapped by CWE) and cis-supply-chain (the CIS
Software Supply Chain Security Guide's Source Code and Dependencies
sections) use Code Security, GitHub
configuration and manual evidence, and apply to connected GitHub organizations.
The Supply Chain dependency scanner checks combine observed settings across active
GitHub repositories with code-scan observations under your selected policy. They
do not certify complete software composition analysis across every repository.
OWASP A06/A08 and CIS Supply Chain 3.1.1 can FAIL from observed code findings;
their clean assessment currently remains unverified because the required code
evaluation completion evidence is unavailable.
The set grows over time, so limacharlie cloudsec compliance frameworks
(GET /compliance/frameworks) — which carries each framework's id, name,
version, and control counts — is the source of truth for valid
--framework values.
CIS benchmark versions¶
Two CIS benchmarks ship in two versions, side by side. Each version is its own framework id, so an assignment or report on the older id keeps working unchanged, and you move to the newer one when you are ready:
| Framework | Benchmark | Controls |
|---|---|---|
cis-gcp |
CIS Google Cloud Platform Foundation Benchmark (v2.0 subset) | 21 |
cis-gcp-v5 |
CIS Google Cloud Platform Foundation Benchmark v5.0.0 | 93: 76 automated, 8 partly automated, 9 manual |
cis-m365 |
CIS Microsoft 365 Foundations Benchmark (v4.0 subset) | 26 |
cis-m365-v7 |
CIS Microsoft 365 Foundations Benchmark v7.0.0 | 160: 143 automated, 17 manual |
The newer catalogs include every benchmark control; collection support and
manual requirements still determine which controls can be assessed. Each control
carries its CIS recommendation number (external_id, for example 5.1.2.3) with a title and a
description of what LimaCharlie checks, written by LimaCharlie. The benchmark
text itself is published by CIS at
cisecurity.org.
cis-gcp-v5reads project and organization configuration (IAM, logging and alerting, networking, compute, Cloud SQL, storage, BigQuery). Several of these reads need optional roles or APIs on the service account; without them, the controls they feed report NOT_ASSESSED and name the missing read. See Google Cloud provider setup. A partly automated control can FAIL from what LimaCharlie reads, but a PASS also needs your attestation, so without one it reports NOT_ASSESSED.cis-m365-v7covers Entra ID, Exchange Online, Defender for Office 365, Purview, SharePoint and OneDrive, Teams, Intune, Microsoft Forms and Power BI / Fabric. It applies to a tenant connected as anentraprovider. Its Microsoft Graph reads work with either credential type. Exchange Online, Defender for Office 365, Purview and the SharePoint advanced settings need the connection's certificate mode. The Entra half of anazureconnection reads the Microsoft Graph settings only; Exchange Online, Purview, Teams and Power BI / Fabric are read through anentraconnection.cis-m365(v4.0) covers a benchmark selection. Its Entra checks apply to anentraprovider or the Entra half of anazureconnection. Anentraconnection also supplies the named v7 reads reused by legacy checks: password expiration, common attachment filtering, unified audit logging, privileged-role access review definitions, SharePoint external sharing and Teams anonymous meetings. The non-Graph reads need certificate mode as described above. This reuse does not assess every control in those admin centers or change an assignment to the v7 benchmark.
Licence-gated Microsoft 365 controls
37 cis-m365-v7 controls grade a feature that exists only with a specific
Microsoft licence: Entra ID P1 or P2, Entra ID Governance, Intune, Defender for
Office 365 Plan 1 or 2, Safe Documents, Customer Lockbox, or Purview
Communications DLP. LimaCharlie reads the tenant's licences. When a tenant does
not hold the licence a control needs, that control reports NOT_ASSESSED and
its reason names the licence, for example no licence was observed for the
feature this control grades: Microsoft Entra ID P1. It never reports PASS
for a feature the tenant cannot turn on. It does not report FAIL either,
because the fix is a purchase, not a setting.
The report is per-control, and each control lands in one of four states:
- PASS — every required input was read, the relevant detectors completed, no open finding proves a violation, and any required manual evidence is valid for the assessed scope.
- FAIL — one or more open findings prove it; their
finding_ids are attached as evidence. - NOT_ASSESSED — evidence is missing or unverified. This includes unread,
denied, capped or stale collection; changed connection settings awaiting a
successful collection; incomplete assessment; and manual requirements without
valid scoped evidence. A partly automated control can FAIL from observed
counterevidence, but needs its manual requirements satisfied to PASS. A control
also lands here when the detection that would have decided it never ran —
including when a
rulespolicy has disabled every rule the control relies on and it has no other basis to be graded from. A zero-violation result from a detector that did not run is not evidence of compliance, so it is never reported as a PASS. - NOT_APPLICABLE — complete observation proves that the control has no eligible resources in this scope, or authoritative connection inventory proves its provider is absent. A newly connected, unread or failed provider is NOT_ASSESSED, even if no resources have been inventoried yet.
A framework scoped to a single cloud assesses only that cloud's findings —
cis-aws looks at AWS findings, cis-gcp at GCP. A framework with no
eligible resources comes back NOT_APPLICABLE only when absence is established,
so an unread estate never reads as compliant.
How the score is computed¶
The report's summary carries passed, failed, not_assessed,
not_applicable, total, score, and applicable. The score is the share of
assessable controls that pass:
Only PASS and FAIL are assessable. NOT_ASSESSED and NOT_APPLICABLE controls are excluded from the denominator entirely, so a manual control you have not attested does not drag the number down, and a framework you are only partly in scope for is not penalized for the parts that do not apply.
No assessable controls means applicable: false, not 100%
When nothing in the framework is assessable against your estate, the report
comes back with applicable: false and a score of 0 — never a
vacuous 100. Read applicable before reading score: a 0 with
applicable: false means "we could not assess this", not "you failed
everything".
FAIL evidence is capped per control
A failing control attaches at most 25 proving finding_ids in the JSON
report, while evidence_count reports the true total — so a control with
900 violations shows 25 examples and evidence_count: 900. The CSV export
raises the cap to 2,000 ids per control for auditors who need the fuller
list; use the findings API itself when you need all of them.
Auditor export¶
For auditors, the same report exports as CSV — one row per control including
the evidence finding ids — via the API's ?format=csv
(see Automation & IaC).
Scoped assignments¶
A whole-estate score is often the wrong altitude: production must meet the
bar, the sandbox does not. A compliance-typed cloudsec_policy record
creates a named, scoped assignment — a framework evaluated over a subset
of the estate:
cat > prod-cis.json <<EOF
{
"policy_type": "compliance",
"compliance": {
"framework_id": "cis-gcp",
"description": "Production accounts only",
"scope": [
{"account_glob": ["proj-prod-*"]}
]
}
}
EOF
limacharlie hive set --hive-name cloudsec_policy --key prod-cis \
--oid $OID --input-file prod-cis.json --enabled
Scope matchers support account_contains, account_glob, name_contains,
and name_glob (globs use the shared dialect, including leading-!
negation — see Glob syntax); an empty scope
means the whole estate.
List assignments (each with its own scoped score) and evaluate one:
limacharlie cloudsec compliance assignments
limacharlie cloudsec compliance report --assignment prod-cis
When --assignment is set, its framework is used and --framework is
ignored.
Permissions
Reading compliance requires cloudsec.get. Assignments are Hive policy
records, so creating them follows the cloudsec_policy hive
permissions.