NetworkEdge¶
cloudg.schema.models.NetworkEdge, a Pydantic v2 model (extra="allow"). A directed edge between
two assets.
5.1 Fields¶
| Field | Type | Default | Meaning |
|---|---|---|---|
id |
str |
new UUID4 | Edge ID, regenerated each run. |
source_id |
str |
required | Source endpoint. For edges produced by the inventory linker and mapper this is always an asset id. See 5.3 for the exception. |
target_id |
str |
required | Target endpoint, same rules. |
edge_type |
EdgeType |
required | Coarse class; see section 6. |
relationship |
str \| None |
None |
Fine-grained relation, a RelationType name from the ontology (TRIGGERED_BY, RUNS_ON, CROSS_ACCOUNT_TRUST, ...). None when the edge class says it all. See the vocabulary. |
properties |
dict[str, Any] |
{} |
Relation-specific detail copied from the declaration (empty values dropped), plus linker annotations (below). |
description |
str \| None |
None |
Human-readable explanation ("event source mapping", "arn:aws:iam::999999999999:root can assume this role"). |
ports |
list[int] |
[] |
Network edges only. Capped at 100 ports per range, so a wide range lists only its first 100; use port_range. |
port_range |
str \| None |
None |
Network edges only, in the provider's notation: see 5.3. "443", "80-443", "0-65535", "22,3389,8000-8100", "*". |
protocol |
str \| None |
None |
Network edges only, with the provider's casing: TCP, UDP, ICMP, ALL from AWS and GCP, Tcp, Udp, Icmp, * from Azure. |
cidr |
str \| None |
None |
Network edges only: "0.0.0.0/0". |
direction |
str |
"ingress" |
ingress or egress for network rule edges. Relationship edges keep the default "ingress", which carries no meaning for them. |
5.2 properties keys added by the linker and mapper¶
| Key | Added by | Meaning |
|---|---|---|
external_reference |
linker | The edge points at an external account placeholder; this is the identifier that was referenced (the specific role ARN or bucket in the unmapped account). |
hierarchy |
add_account_hierarchy |
true on account → top-level resource CONTAINS edges. These edges are excluded from unlinked_assets, cross_account_edges and dependency walks. |
Every other key comes from the collector's declaration. Common ones: cross_account
(true when the grantee lives in another account), conditions (the IAM condition block of a
trust statement), external_id_required, actions, access_policies (EKS access entries),
role, privileged, principal_type, assignment_id (Azure role assignments), events
(S3 notification events), batch_size, state, network_rule, status, key_uri, via.
5.3 Collector network edges¶
The AWS collector's own collect_edges() adds two kinds of edges before linking:
SECURITY_GROUP_RULE, one per rule and IPv4 CIDR (IpRanges; IPv6 ranges and rules that name another security group are not turned into edges), between the CIDR string and the security group asset'sid: ingress edges gocidr → <sg asset id>, egress edges<sg asset id> → cidr. The native group ID stays in the asset'smetadata.group_idandarn.port_rangeis"from-to", or a single port when both are equal; protocol-1(all traffic) is written as protocolALLwith"0-65535", other protocols upper-case. For ICMP the two numbers are the ICMP type and code, so an echo-request rule reads"8--1".portsis filled on ingress edges only;cidranddirectionon both.CONTAINSfrom a VPC to every asset whosemetadata.vpc_idnames it (subnets, instances, security groups, load balancers and so on), between asset UUIDs, with norelationshipand the description"VPC <vpc_id> contains <name>".
The Azure collector's collect_edges() adds SECURITY_GROUP_RULE edges for NSG inbound allow
rules, from the rule's source address prefix (a CIDR, a service tag such as Internet, *, or
an application security group's resource ID when it was collected) to the NSG asset, and
CONTAINS / VPC_CONTAINS_SUBNET edges from each VNet to its subnets. port_range is the
rule's destination port ranges joined with commas ("22,3389,8000-8100") or "*" for every
port, protocol is Azure's own spelling (Tcp, Udp, Icmp, *), and description is
"NSG rule <name>".
The GCP collector adds one edge per internet ingress entry from 0.0.0.0/0 to the exposed asset:
INTERNET_EXPOSED for exposure found through IAM, external IPs or load balancers, and
SECURITY_GROUP_RULE for firewall rules. Every one of them has relationship:
"INTERNET_REACHABLE" and the way the exposure was found as its description. port_range is
the firewall's ports list joined with commas, or null when the rule lists no ports (which
for TCP, UDP and SCTP means every port), and protocol is upper-case, ALL for all.
Every consumer in cloudg (the graph builder, the reachability analysis, the ontology) reads
these strings through cloudg.graph.ports.parse_port_ranges() and edge_port_ranges(), which
turn all three notations into numeric ranges and treat ICMP and other port-less protocols as
opening no ports.
The security group / NSG side of a rule edge is always an asset id; the other side is
deliberately external. Consumers that join edges to assets must therefore expect a few endpoints
that are not asset IDs: CIDRs, Azure service tags and *, and the resource ID of an application
security group that was not collected. The graph exports turn them into nodes with is_external: true
(section 15), and DependencyGraph ignores edges whose endpoints
are not assets.
{
"id": "8cbfec40-e9a8-4546-bf1f-2f47d542b8b3",
"source_id": "0.0.0.0/0",
"target_id": "6f0d2c8e-3b1a-4f57-9c2e-8a41d7e5b903",
"edge_type": "SECURITY_GROUP_RULE",
"ports": [443],
"port_range": "443",
"protocol": "TCP",
"cidr": "0.0.0.0/0",
"direction": "ingress",
"description": null,
"relationship": null,
"properties": {}
}
5.4 Examples of linked edges¶
Cross-account trust, from the external vendor account to a role (the role's trust policy requires an external ID):
{
"id": "d9c70eec-a4c4-4144-ab2f-27f67e00b6c5",
"source_id": "277ef061-8a0c-4e1e-9451-a50aa57198f8",
"target_id": "1bd88609-88f3-46d7-868e-ac65ece6b65a",
"edge_type": "IAM_TRUST",
"ports": [], "port_range": null, "protocol": null, "cidr": null,
"direction": "ingress",
"description": "arn:aws:iam::999999999999:root can assume this role",
"relationship": "CROSS_ACCOUNT_TRUST",
"properties": {
"conditions": {"StringEquals": {"sts:ExternalId": "vendor-123"}},
"external_id_required": true,
"external_reference": "arn:aws:iam::999999999999:root"
}
}
The external ID value shown is the one in the trust policy of the test fixture. Trust policy
conditions are copied as written, so treat properties.conditions with the same care as the
policy itself.
S3 event notification invoking a function (arn:aws:s3:::orders-uploads →
…:function:orders-worker):
{
"source_id": "2028991c-a3b7-4c55-afde-01ccac602552",
"target_id": "60cac611-8a80-469e-bca6-ee3cf1cdc35b",
"edge_type": "INVOKES",
"description": "event notification",
"relationship": "INVOKES",
"properties": {"events": ["s3:ObjectCreated:*"]}
}
Account hierarchy:
{
"source_id": "95628cf7-805e-4b30-989c-189c6da80ef6",
"target_id": "8d7d700b-7f64-4821-97b2-45577d1faf7a",
"edge_type": "CONTAINS",
"description": "account 123456789012 contains FullAWSAccess",
"relationship": "ACCOUNT_CONTAINS_REGION",
"properties": {"hierarchy": true}
}