CloudAsset¶
cloudg.schema.models.CloudAsset, a Pydantic v2 model (extra="allow", populate_by_name=True).
One node of the map: a cloud resource, an identity, a security service (or its absence), an
account, an organization unit, a policy, or a Kubernetes object.
3.1 Fields¶
| Field | Type | Default | Meaning |
|---|---|---|---|
id |
str |
new UUID4 | Internal ID, unique within one map, regenerated each run. Edge endpoints reference it. |
arn |
str \| None |
None |
Stable native or synthetic identifier (formats). Deduplication key: two assets with the same arn are merged. Every inventory asset sets it. |
name |
str |
required | Display name: the Name tag, the resource name, or the identifier when the resource has no name. Not unique. |
asset_type |
AssetType |
required | One of 156 values; see INVENTORY_CATALOG.md. Unclassifiable resources are OTHER. |
provider |
CloudProvider |
required | AWS, AZURE or GCP (upper case). Kubernetes objects inside EKS are AWS, inside GKE GCP. |
region |
str |
"global" |
Region / location. "global" for account-wide resources (IAM, S3 buckets as listed, CloudFront, Route 53, organizations, accounts, Entra principals). Azure uses the ARM location (eastus), GCP the CAI location (us-central1, us-central1-a, global). |
account_id |
str \| None |
None |
AWS account ID, Azure subscription ID, or GCP project ID. None for tenant-wide identities (Entra principals) and GCP organization / folder level resources. |
tags |
dict[str, str] |
{} |
Tags / labels, values stringified. Kubernetes objects carry their labels here. |
metadata |
dict[str, Any] |
{} |
Normalised attributes. Contents depend on the type; see Common metadata keys and the per-type reference. Always JSON-serialisable. |
raw_data |
dict[str, Any] |
{} |
Raw API payload used during linking. Excluded from serialisation (exclude=True): never present in model_dump() or any file. |
collected_at |
datetime |
now (UTC) | When the asset object was built. |
is_internet_exposed |
bool |
False |
Reachable from the internet according to the collector (public IP with an open security group, internet-facing load balancer, public bucket / function URL / API, GCP firewall open to 0.0.0.0/0, allUsers bindings, Azure public network access without a deny ACL, Kubernetes LoadBalancer services and ingresses with a hostname, ...). |
display_id |
str (computed) |
arn or id |
Serialised by model_dump(); ignored by InventoryResult.load(). |
Because the model allows extra fields, a collector or plugin may attach additional top-level
fields; they survive model_dump() and load().
3.2 Example¶
A Lambda function from the example run (metadata abridged to the keys that matter here):
{
"id": "60cac611-8a80-469e-bca6-ee3cf1cdc35b",
"arn": "arn:aws:lambda:us-east-1:123456789012:function:orders-worker",
"name": "orders-worker",
"asset_type": "LAMBDA_FUNCTION",
"provider": "AWS",
"region": "us-east-1",
"account_id": "123456789012",
"tags": {},
"metadata": {
"runtime": "python3.12",
"handler": "h.h",
"package_type": "Zip",
"image_uri": null,
"memory_size": 128,
"timeout": 3,
"vpc_config": null,
"role_arn": "arn:aws:iam::123456789012:role/orders-worker",
"environment_keys": ["DB_PASSWORD", "QUEUE_URL"],
"event_sources": ["arn:aws:sqs:us-east-1:123456789012:orders"],
"function_url_auth": null,
"policy_allows_public": false,
"relations": [
{"target": "arn:aws:iam::123456789012:role/orders-worker",
"edge": "ASSUMES_ROLE", "relationship": "RUNS_ON", "description": "execution role"},
{"target": "https://sqs.us-east-1.amazonaws.com/123456789012/orders",
"edge": "REFERENCES", "relationship": "DEPENDS_ON", "description": "environment reference"},
{"target": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/orders-worker",
"edge": "LOGS_TO", "relationship": "LOGS_TO"},
{"target": "arn:aws:sqs:us-east-1:123456789012:orders",
"edge": "INVOKES", "relationship": "TRIGGERED_BY", "reverse": true,
"description": "event source mapping",
"properties": {"state": "Enabled", "batch_size": 10}}
],
"aliases": ["arn:aws:lambda:us-east-1:123456789012:function:orders-worker:$LATEST"]
},
"collected_at": "2026-10-04T15:34:54.643569",
"is_internet_exposed": false,
"display_id": "arn:aws:lambda:us-east-1:123456789012:function:orders-worker"
}
Things to notice:
environment_keyslists variable names. Values are never collected. The queue URL inQUEUE_URLreached the map only as a relation target, because identifier-shaped values (ARNs, SQS queue URLs judged by their parsed host) are extracted as references and everything else is dropped.- The relations are the collector's declarations. The linker turned four of them into edges
except the log group one, which did not resolve (the log group did not exist) and therefore
appears in
unresolved_references(section 11). reverse: trueon the event source mapping means the edge points from the queue to the function:SQS INVOKES Lambda (TRIGGERED_BY).
3.3 Placeholder assets¶
Some assets stand for something that was referenced rather than collected:
| Kind | arn |
asset_type |
Distinguishing metadata |
|---|---|---|---|
| Security service not enabled (AWS) | cloudg:aws:<service>:<region>:<account>:not-enabled |
the service's type (VULNERABILITY_SCANNER, THREAT_DETECTOR, ...) |
security_service, enabled: false, status: "not enabled", alias aws-security:<service>:<region>:<account> |
| Defender plan off (Azure) | the pricing resource ID | THREAT_DETECTOR |
security_service: "defender-<plan>", enabled: false |
| External account | arn:aws:iam::<id>:root, /subscriptions/<id>, //cloudresourcemanager.googleapis.com/projects/<id> |
CLOUD_ACCOUNT |
external: true, discovered_via: "cross-account reference" |
| Entra principal | entra:principal/<objectId> |
IDENTITY_USER, IDENTITY_GROUP or SERVICE_PRINCIPAL |
placeholder: true, principal_type, discovered_via: "entra-principal-reference" |
| GCP principal | gcp-principal:<member> or k8s-gke://… |
IDENTITY_USER, IDENTITY_GROUP, SERVICE_PRINCIPAL, K8S_SERVICE_ACCOUNT, ... |
discovered_via: "iam_policy" or "workload_reference" |
GCP parity placeholders:
| Kind | arn |
asset_type |
Distinguishing metadata |
|---|---|---|---|
| Security service not enabled (GCP) | cloudg:gcp:<service>:<parent>:not-enabled, where parent is projects/<id>, folders/<id> or organizations/<id> |
the service's type (SECURITY_HUB, THREAT_DETECTOR, CONFIG_RECORDER, VULNERABILITY_SCANNER, DATA_SECURITY_SCANNER, CLOUDTRAIL) |
security_service (scc, event-threat-detection, artifact-analysis, dlp-discovery, audit-logs, ...), enabled: false, status: "not enabled", alias gcp-security:<service>:<parent> |
| GCP principal named by a deny rule, PAM entitlement or group membership | gcp-principal:<member> |
as above | discovered_via: "relation_reference" |
Azure placeholders added with the parity work:
| Kind | arn |
asset_type |
Distinguishing metadata |
|---|---|---|---|
| Defender plan not listed (Azure) | cloudg:azure:defender-<plan>:<subscription>:not-enabled |
THREAT_DETECTOR |
security_service: "defender-<plan>", enabled: false, status: "not enabled", alias azure-security:defender-<plan>:<subscription>. Created for every plan of STANDARD_PLANS the pricings query did not return. |
| Sentinel not enabled (Azure) | cloudg:azure:sentinel:<subscription>:not-enabled |
THREAT_DETECTOR |
as above with security_service: "sentinel"; created when no Log Analytics workspace of the subscription is onboarded. |
| External source repository | repo:<url> (lower case, no .git, no credentials) |
SOURCE_CONNECTION |
external: true, repository_url, host, discovered_via: "repository-reference". The target of READS_FROM from web app source control, Flux, ACR tasks, Static Web Apps, Data Factory Git and dev center catalogs. |
| Entra principal from a directory role | entra:principal/<objectId> |
SERVICE_PRINCIPAL |
placeholder: true, discovered_via: "entra-principal-reference"; a role holder Microsoft Graph did not list. |
Example, Inspector not enabled:
{
"id": "07911321-f52d-438c-91b1-3be831c2451b",
"arn": "cloudg:aws:inspector2:us-east-1:123456789012:not-enabled",
"name": "Inspector (not enabled)",
"asset_type": "VULNERABILITY_SCANNER",
"provider": "AWS",
"region": "us-east-1",
"account_id": "123456789012",
"tags": {},
"metadata": {
"security_service": "inspector2",
"enabled": false,
"status": "not enabled",
"aliases": ["aws-security:inspector2:us-east-1:123456789012"]
},
"collected_at": "2026-10-04T15:34:07.879548",
"is_internet_exposed": false,
"display_id": "cloudg:aws:inspector2:us-east-1:123456789012:not-enabled"
}
Example, an external account created because a role trusts it:
{
"id": "277ef061-8a0c-4e1e-9451-a50aa57198f8",
"arn": "arn:aws:iam::999999999999:root",
"name": "external account 999999999999",
"asset_type": "CLOUD_ACCOUNT",
"provider": "AWS",
"region": "global",
"account_id": "999999999999",
"metadata": {
"account_id": "999999999999",
"external": true,
"discovered_via": "cross-account reference"
},
"is_internet_exposed": false
}