Skip to content

Configuration Reference

Cloud Security is configured entirely through three Hive types. Anything the console can configure, limacharlie hive set can configure — which makes tenant onboarding and fleet-wide policy a script, not a UI workflow (see Automation & IaC for recipes).

Hive Records Purpose
cloudsec_provider one per cloud / IdP / SaaS / AI connection what to collect and with which credential
cloudsec_policy many, discriminated by policy_type classification, coverage, emission, exclusions, suppression, compliance assignments
cloudsec_query one per saved query shared saved graph queries

Permissions

cloudsec_provider records are gated by the dedicated cloudsec_provider.get/set/del permissions; cloudsec_policy and cloudsec_query follow cloudsec.get/cloudsec.set.

cloudsec_provider

One record per provider connection. provider_type discriminates; each type reads its own scope fields. The full per-provider walkthrough — including the credential shape for each — is in Connecting Providers; this is the field reference.

Common fields (all provider types):

Field Meaning
provider_type gcp | aws | azure | okta | entra | google_workspace | 1password | auth0 | cloudflare | github | openai | anthropic | limacharlie
credentials A hive://secret/<name> reference. The credential itself lives in the secret Hive — it is not stored inline.
compliance_credentials Optional second hive://secret/<name> reference for providers with a second credential plane (today: Anthropic's compliance/analytics key).
internal_domains Your own email domains (bare domains, no @) beyond the discoverable primary — human identities outside this set are classified external.
sync_now Opaque nonce; change its value to trigger an on-demand sweep.
refresh Periodic re-enumeration cadence as a duration string (e.g. "6h"); empty uses the service default of 6h.
feed_subscription Optional fully-qualified Pub/Sub subscription carrying a cloud change feed, for event-driven freshness between full sweeps.

Per-provider scope fields:

provider_type Fields
gcp gcp_scope: projects/{id}, folders/{id}, or organizations/{id} (optional gcp_project)
aws aws_role_arn (the read-only role to assume), aws_external_id, optional aws_regions, optional aws_member_role_name — the role name assumed in each member account of an AWS Organization (defaults to the name in aws_role_arn)
azure azure_tenant_id, azure_client_id, azure_subscription_id (service-principal auth)
okta okta_org_url — the org base URL; the credential is an SSWS API token or an API Services app (client credentials)
entra entra_tenant_id, entra_client_id — a standalone Entra directory connection (no Azure subscription); service-principal auth
google_workspace workspace_customer_idmy_customer or an explicit customer id; the credential is a service-account key with domain-wide delegation plus the admin subject to impersonate
1password onepassword_scim_url — the SCIM bridge URL; the credential is the SCIM bearer token
auth0 auth0_domain — the canonical tenant domain (*.auth0.com); the credential is an M2M app authorized for the Management API
cloudflare cloudflare_account_id — the 32-hex account id
github github_org, github_app_id, github_installation_id — a GitHub App installed on the org; the App private key is the credential
openai optional openai_org_id (org-...); the credential is an Admin API key with api.management.read
anthropic optional anthropic_org_uuid (required when only the compliance plane is connected); Console Admin key in credentials, optional compliance key in compliance_credentials
limacharlie exactly one of limacharlie_oid (org key) or limacharlie_uid (user key — the MSSP fleet case)

Use limacharlie cloudsec provider test to preflight a record before saving it — see Getting Started.

cloudsec_policy

Each record declares exactly one policy_type and fills the matching sub-object.

Rule matchers — read this first

Several policy types scope over resources with rules, and every rule shares the same matcher grammar:

Matcher Matches
account_contains / account_glob the resource's account (substring / glob)
name_contains / name_glob the resource's name (substring / glob)
resource_type the normalized resource type (e.g. bucket, compute_instance, service_account)
provider the producing provider (gcp, aws, okta, …)
region the region (globs)
label a set of key: value label pairs — all must be present
label_key_present a set of label keys — all must be present
tag a set of tags (compute only) — all must be present
public tri-state exposure (true / false)
content_class detected sensitive-content classes on a data store (pii, pci, phi, financial) — accepted and validated, but see the caveat below

Matchers within a rule are ANDed

A rule matches a resource only when every populated dimension matches. Within a single-valued dimension the listed patterns are OR alternatives (account_glob: ["a-*", "b-*"] matches either); set-valued dimensions (label, tag) require all entries. A rule with no matcher matches nothing, and a populated dimension that cannot be evaluated for a given resource fails the rule rather than being ignored. Separate rules in a list compose with OR.

(This is a change from earlier behavior, where dimensions within a rule were ORed. The store_kind matcher has been folded into resource_type.)

content_class rules do not match anything yet

The content_class dimension is accepted and validated wherever it appears, but the content-detection pipeline that populates detected content classes on resources is not live in the current release. Until it ships, a rule matching on content_class saves cleanly and matches zero resources. Express sensitivity you need enforced today with the other dimensions (name_glob, label, tag, account_glob, …).

Glob syntax

Every glob dimension (account_glob, name_glob, region, and suppression account matchers) shares one dialect:

Pattern Matches
* any run of characters (not /)
? one character (not /)
[abc], [a-z] a character class; [^…] or [!…] negates the class
{a,b} alternation — proj-{prod,staging}-*
** any run including / (only differs from * on values containing /)
\c the literal character c

A pattern whose first character is ! is a negation: within one list the positive patterns OR together as before, and any matching negation vetoes the whole list. A list containing only negations matches everything it doesn't exclude — account_glob: ["!sandbox-*"] means "every account without the sandbox- prefix". \! matches a literal leading !. Case-insensitive dimensions stay case-insensitive under negation.

account_glob: ["*-prod", "!sandbox-*"]  # every -prod account except sandbox ones
region: ["!eu-*"]                        # everywhere outside the EU

Not every dimension is honored on every surface, and a dimension a surface does not accept is rejected when you save rather than silently ignored:

Dimension Where it is honored
tag compute resources only. Within classification that means the compute section; the dimension is also accepted on coverage and exclusions.
public data stores and compute.
content_class data stores only — and not yet populated, see the caveat above.
label / label_key_present resources carrying cloud labels. Not honored on classification.identities.
services / resource_types collection exclusions only.
account / name / provider matchers every surface, including the exclusions emission list — which honors only these.

The console's policy editors enforce this per surface and offer live value autocomplete from your actual estate, plus a Simulate preview that shows which resources a rule matches before you save (see Previewing policies).

Assign-side fields (not matchers): name carries provenance and is accepted anywhere, but the two that assign meaning are surface-bound and rejected at save elsewhere — classes (the classes a rule assigns) is accepted on classification data-store rules only, and tier (critical/high/medium/low) on classification rules only.

classification — crown jewels

Declares which resources are sensitive (nothing is sensitive by default). Rules match resources and assign classes and/or a criticality tier, in three sections — data_stores, compute, identities:

{
  "policy_type": "classification",
  "classification": {
    "data_stores": [
      {"name_contains": ["customer", "pii"], "classes": ["pii"]},
      {"content_class": ["pci"], "classes": ["pci"]}
    ],
    "compute": [
      {"label": {"tier": "crown-jewel"}, "tier": "critical"}
    ]
  }
}

Content-based sensitivity is expressed with content_class rules: detected content classes (pii, pci, phi, financial) become facts on a data store, and a content_class rule is what turns such a detection into a sensitivity claim. Your explicit policy always remains authoritative.

Content detection is not live yet

content_class rules are accepted and validated today, but the pipeline that populates detected content classes on resources has not shipped in the current release — so the second rule in the example above currently matches nothing. Classify by name, label, or tag for sensitivity you need enforced now, and treat content_class rules as forward-looking.

auto_classify has been removed

Earlier versions accepted an auto_classify: true boolean. It is gone, and a record that still carries it is now rejected at save with an unknown- field error rather than being ignored. Remove auto_classify from any existing record before updating it. Explicit content_class rules are the replacement: the same intent, but visible in the policy and testable with Simulate.

coverage — workload coverage expectations

Declares which cloud workloads are expected to run a LimaCharlie sensor, with required and exempt resource-rule lists — the "EDR on production VMs" expectation. An empty required means every compute resource is expected to be covered; exempt wins.

Accepted and validated, but not currently evaluated

A coverage-typed record saves and validates, but nothing evaluates it in the current release — it produces no findings. Use the CAASM coverage policy instead, which is the live expected-coverage surface:

limacharlie cloudsec caasm policy set --input-file coverage.json

It has a different shape ({expect: [{label, capability, kinds}]}) and is evaluated over the merged asset inventory, where a cloud_instance kind covers cloud workloads as well as third-party assets — so the "EDR expected on production VMs" expectation belongs there today. See CAASM. This coverage policy type is documented for records that already exist and for the shape it will take when evaluation lands; it is not synced with the CAASM policy.

emission — the event feed

Controls which Cloud Security events reach the organization's event stream:

Field Meaning Default
resource_events cloud_resource.* inventory change events off
finding_events cloud_finding.* lifecycle events on
ops_events operational events — cloudsec.sweep_failed off
severity_floor drop finding events below this severity (CRITICALINFO); the first-sync summary still counts the whole estate none
suppress_first_sync emit one summary instead of a per-finding flood on the first / rebuild sweep on

See Findings are events too for the full event taxonomy.

exclusions — the escape hatch

The per-org escape hatch for whales and noise: the account with hundreds of thousands of buckets, the account whose events should never reach your stream. It has independent rule lists, one per surface, and a rule on one surface has no effect on the others. At least one list must be non-empty:

List Effect
collection Matching scopes are skipped by the collection sweep. Only this list may add the services and resource_types narrowers on top of the shared resource matchers — an account-only rule excludes the whole account, while adding services/resource_types narrows the exclusion to those collector services or resource types inside the matched scope.
emission Matching events are dropped before delivery to the event stream. Only account/name/provider matchers are honored here — an emission rule constrained on labels or tags can never be satisfied by a lean event and so never drops one.

A collection exclusion deletes the inventory it excludes

Collection exclusion is not just "stop collecting from here". On the next sweep the excluded scope is reported as covered with zero rows, so the authoritative diff deletes the scope's existing inventory rows (the resulting delete storm is kept out of the event feed). This is deliberate — an excluded scope disappears instead of lingering as stale rows — but it means excluding a scope you still want recorded loses that inventory until you remove the exclusion and let a sweep repopulate it.

Exclusions are captured when a sweep starts, so an edit lands on the next sweep. Change the provider's sync_now nonce to apply it immediately instead of waiting for the refresh cadence.

suppression — finding disposition policy

Auto-dispositions matching findings — see Automation & IaC for semantics and a worked example. Ordered rules; each rule's match accepts finding_class, rule, account, urn_prefix, max_severity; the effect is kind (accepted/false_positive), reason (required), ttl_days.

compliance — scoped assignments

A named framework assignment over a scoped subset of the estate — see Compliance. Fields: framework_id (required, lowercase slug), description, scope (the account/name matchers).

cloudsec_query

A saved graph query, shared org-wide:

{
  "version": 1,
  "name": "Exposed VMs reaching sensitive data",
  "description": "Weekly review lens",
  "query": {"text": "..."},
  "project": "rows",
  "tags": ["weekly"]
}

query takes exactly one of named (a query-pack reference), text, or ast (the raw DSL) — setting none or more than one is rejected. The other fields draw on closed sets: version accepts 0 (unset) or 1, both meaning the shape documented here; project is rows (table) or graph (canvas), defaulting to rows; the optional ui hint takes view (table or graph) and columns. The query appears in the Query console and as a pinnable lens on the Attack Surface page.

Scheduled queries — any saved query as a detection source

The schedule block turns a saved query into a live detection source, with no new rule syntax:

{
  "version": 1,
  "name": "Exposed VMs reaching sensitive data",
  "query": {"text": "..."},
  "schedule": {"scheduled": true, "interval": "1h"}
}
Field Meaning
scheduled Activates evaluation. The record must also be enabled — a disabled record is never a live detection source.
interval Cadence as a Go duration ("1h", "24h"); minimum 5m.
cron A 5-field cron expression, with optional timezone (IANA name).
emit_suppressed Emit matches for anchors your suppression policy suppressed. Default false (suppressed anchors stay silent). Only meaningful with scheduled: true.

Set at most one of interval or cron. With neither, the query is evaluated after each projection cycle — the default and usually the right choice, since it fires as soon as the estate actually changes.

Evaluation follows the same lifecycle symmetry as findings: cloud_query.match is emitted once per new anchor entering the match set, cloud_query.resolved once per anchor leaving it — so a re-evaluation that changed nothing emits nothing. These events flow through the same emission policy gate as every other Cloud Security event.

Two budgets protect the loop

An org runs at most 25 scheduled queries per pass (excess is skipped in deterministic query-name order, not silently dropped). A single query whose match set exceeds 1,000 anchors is over budget: it emits one cloud_query.overbudget instead of a match flood, and per-anchor tracking pauses until it comes back under the cap. Scope a scheduled query so its result set is a worklist, not a table dump.

The detection block is still reserved: it is validated for shape so infrastructure-as-code written today keeps working, but nothing consumes it yet.

Previewing policies

Two read-only, cloudsec.get-gated aids make policy authoring safe — both are in the console policy editors, on the API, and on the CLI (limacharlie cloudsec simulate / limacharlie cloudsec policy):

  • Simulate evaluates an in-progress matcher against your real data before you save. A resource matcher (classification / coverage / exclusions) is previewed against stored inventory; a suppression matcher is previewed against open findings. The result is a match count plus a bounded sample.
  • Vocabulary & autocomplete feed the editors the closed vocabularies (resource types, providers, tiers, content classes) and live value suggestions drawn from your estate's actual accounts and names.

See the API Reference for the underlying routes.