Model: node and edge kinds¶
The graph (vpcatlas-graph/1) has two layers. The network layer (VPCs, subnets, route tables, gateways, endpoints,
load balancers, Network Firewall, Resolver, RAM, prefix lists) is described in architecture.md. The service
layer sits on top of it: DNS, the edge, APIs, compute, data and the account services. This page documents the
kinds of the service layer, their edges and how the registry draws them.
Everything here is data. Which nodes a page draws, and where, is decided by exporters/layout.py and
exporters/graphview.py; the registry (exporters/registry.py) only says how a kind looks.
Rules every kind follows¶
- One class per kind in
model/resources.py, subclassingResource;RESOURCE_TYPESregisters it by itstype. The class is also exported frommodel/__init__.py.model.SERVICE_TYPESlists the types of the service layer. idis the AWS id, or a composed one that never changes between scans (the table says which).account_idis the owner.regionis"global"(GLOBAL_REGION) for the global services (model.GLOBAL_SERVICE_TYPES, and a web ACL of theCLOUDFRONTscope), else the region of the object. A CloudFront certificate or web ACL is collected inus-east-1, and a certificate keeps that region.- One
containsparent per node. A service attached to a VPC is contained by its VPC; a regional service with no VPC by its Region node; a global one by its Account node; an ECS service by its cluster. A subnet is never a parent: a service that runs in subnets lists their ids insubnet_idsand gets anattached_toedge (relation="subnet") to each, as a load balancer does. The diagram code draws the icon inside the subnet from those edges. - Relations between services are ids and ARNs in fields (
target_group_arns,web_acl_id,vpc_link_id...). The builder turns them into the edges below; the fixture adds the same edges by hand. - Lists are sorted and capped by the collector (instance ids, rule names, table names); the matching count field
keeps the real number.
Noneon a count or a flag means "not read" (the call was denied or unsupported), never zero or false; the collector also records the gap. - Instances that an
InstanceGrouplists are the same instances theeninodes of the subnet already show as workloads (NetworkInterface.instance_id); a page must not draw both.
Node kinds¶
type |
Class | id |
Region | Parent | Main fields |
|---|---|---|---|---|---|
hosted_zone |
HostedZone |
zone id without /hostedzone/ |
global | account | zone_name, private, vpc_ids, record_count, records (alias records and CNAMEs to known endpoints: name, record_type, alias, target, target_kind (cloudfront, elb, api_gateway, s3, s3_website, lambda_url, mediastore, accelerator, endpoint, other), routing (simple, weighted, latency, failover, geolocation, geoproximity, ip-based, multivalue)) |
cloudfront |
CloudFrontDistribution |
distribution id | global | account | domain_name, aliases, origins (id, domain, kind s3/elb/api_gateway/custom, path, access oac/oai, target), web_acl_id, certificate_arn, price_class, enabled |
web_acl |
WebAcl |
WAF id | global (CLOUDFRONT) or region (REGIONAL) |
account or region | scope, default_action, rule_count, rule_names, managed_rule_groups, associated_arns, logging |
certificate |
Certificate |
last part of the ARN | region of the certificate | account (us-east-1) or region |
domain_name, alt_names, cert_type, in_use_by, not_after, key_algorithm |
shield |
ShieldSubscription |
shield |
global | account | tier standard/advanced, subscribed, protections |
api_gateway |
ApiGatewayApi |
API id | region | region | api_type REST/HTTP/WEBSOCKET, endpoint_type, stages, custom_domains, certificate_arns, web_acl_arn, integrations (route, kind lambda/elb/vpc_link/http, target, vpc_link_id) |
api_vpc_link |
ApiVpcLink |
link id | region | VPC | link_kind, vpc_id, subnet_ids, security_group_ids, target_arns |
target_group |
TargetGroup |
targetgroup/{name}/{hash} |
region | VPC | target_type instance/ip/lambda/alb, protocol, port, load_balancer_arns, health_check_path, targets (id, port, zone, health), healthy_count, unhealthy_count |
ecs_cluster |
EcsCluster |
cluster name | region | region | service_count, running_tasks, capacity_providers |
ecs_service |
EcsService |
{cluster}/{service} |
region | cluster | launch_type, desired_count, running_count, vpc_id, subnet_ids, security_group_ids, assign_public_ip, target_group_arns |
eks_cluster |
EksCluster |
cluster name | region | VPC | version, vpc_id, subnet_ids, security_group_ids, endpoint_public, endpoint_private, public_access_cidrs, node_groups |
instance_group |
InstanceGroup |
asg:{name}, name:{Name tag} or subnet:{id} |
region | VPC | group_by asg/name/subnet, instance_count, instance_ids, instance_types, subnet_ids, security_group_ids, public_ips, min_size, max_size, desired_capacity, target_group_arns |
rds |
RdsDatabase |
identifier, or cluster:{identifier} |
region | VPC | db_kind instance/cluster, engine, engine_version, instance_class, multi_az, publicly_accessible, subnet_group, subnet_ids, security_group_ids, members; is_aurora |
elasticache |
ElastiCacheCluster |
replication group id, else cluster id | region | VPC | engine, node_type, node_count, multi_az, subnet_group, subnet_ids, security_group_ids |
efs |
EfsFileSystem |
fs-... |
region | VPC | performance_mode, throughput_mode, encrypted, size_bytes, mount_targets (id, subnet_id, zone, ip_address) |
lambda |
LambdaFunction |
function name | region | VPC (with a VPC config) or region | runtime, memory_mb, timeout_s, vpc_id, subnet_ids, security_group_ids, invoked_by |
s3_bucket |
S3Bucket |
bucket name | bucket region | region | website, versioning, public_access_blocked, encryption, used_as (only buckets some diagram needs) |
s3 |
S3Summary |
s3 |
global | account | bucket_count |
dynamodb |
DynamoDbSummary |
dynamodb |
region | region | table_count, table_names |
cloudtrail |
CloudTrailSummary |
cloudtrail |
global | account | trail_count, trails (name, home_region, multi_region, organization, logging) |
guardduty |
GuardDutySummary |
guardduty |
region | region | enabled, detector_id |
config_recorder |
ConfigRecorder |
config |
region | region | enabled, recording, all_resources |
cloudwatch |
CloudWatchSummary |
cloudwatch |
region | region | log_group_count, alarm_count |
kms |
KmsSummary |
kms |
region | region | key_count (customer managed keys) |
ecr |
EcrSummary |
ecr |
region | region | repository_count |
HostedZone uses the diagram kind hosted_zone that already exists; the other kinds got theirs in the registry
(next section). The summary kinds (s3, dynamodb, cloudtrail, guardduty, config_recorder, cloudwatch,
kms, ecr) are one node each so that a denied call leaves one unknown number, not a wrong zero for the others.
Edge kinds¶
The edge kind is a string; model.EdgeKind lists the values. Direction is source to destination.
| Kind | From | To | Attributes | Style (never by colour) |
|---|---|---|---|---|
serves |
hosted zone | CloudFront, API, load balancer, bucket | record, record_type |
2 px, dashed 6 3, block head |
origin |
CloudFront | load balancer, bucket, API | origin_id, origin_kind, path, access |
2 px solid, open head |
protects |
web ACL, Shield | CloudFront, load balancer, API | via web_acl/shield |
1 px, dotted 3 3, round head |
secures |
certificate | load balancer, CloudFront, API | use listener/distribution/domain, port |
1 px, dotted 1 3, no head |
integrates |
API; VPC link | Lambda, load balancer, VPC link; load balancer | route, integration (lambda, vpc_link, elb, http) |
2 px, dash-dot 6 2 1 2, block head |
targets |
load balancer; target group | target group; instance group, ECS service, Lambda, load balancer | port, health (healthy, degraded, unhealthy) |
1 px solid, block head |
attaches |
ECS service, Auto Scaling group | target group | port |
1 px, dashed 8 4, open block head |
mounts |
EFS | subnet | mount_target, ip_address |
1 px, dotted 2 2, round tail |
attaches is the registration (service side), targets the forwarding (target group side); both are kept
because the page draws the first inside the compute row and the second on the load balancer path. The network
edges (contains, attached_to, routes_to, peered_with, shared_from) are unchanged.
Registry¶
exporters/registry.py keeps the service layer in tables of its own, because the style guide
(diagram-style.md 2.5) has to list a shape before it can enter KINDS, and lucid_classes.json has to carry
its Lucid class. When the diagrams draw them, move the entries into KINDS, EDGE_KINDS and the JSON file and
add the shapes to the guide; ALL_KINDS, spec, drawio_style and edge_style already read both tables.
| Table | Content |
|---|---|
SERVICE_KINDS |
one KindSpec per diagram kind: draw.io resIcon, size, family colour, abbreviation (the caption of the Lucid fallback square) and title (the legend) |
SERVICE_TYPE_KINDS |
model type to the diagram kinds that can draw it (rds or aurora by engine, ecs_service or fargate_service by launch type, instance_group as asg or instance) |
service_lucid_classes() |
Lucid class of each kind (Arch...AWS2024, verified: false until the probe document confirms it) |
SERVICE_EDGE_KINDS, SERVICE_EDGE_TITLES, SERVICE_EDGE_TAIL |
the eight edges, their legend rows and their width, dash and heads |
SERVICE_FLOWS, SERVICE_FLOW_COLORS, service_badge_color |
the numbered flows of the service pages |
Colours follow the AWS categories: networking purple (the profile's), compute #ED7100, storage #7AA116,
database #C925D1, security #DD344C, management #E7157B.
| Diagram kind | draw.io icon | Category | Model type |
|---|---|---|---|
route53 |
route_53 |
networking | hosted_zone (service icon for the regional row) |
cloudfront |
cloudfront |
networking | cloudfront |
web_acl |
waf |
security | web_acl |
certificate |
certificate_manager |
security | certificate |
shield |
shield |
security | shield |
api_gateway |
api_gateway |
networking | api_gateway |
api_vpc_link |
endpoints |
networking | api_vpc_link |
target_group |
elastic_load_balancing |
networking | target_group |
ecs_cluster, ecs_service |
ecs |
compute | ecs_cluster, ecs_service |
fargate_service |
fargate |
compute | ecs_service with launch_type FARGATE |
eks_cluster |
eks |
compute | eks_cluster |
asg |
auto_scaling2 |
compute | instance_group with group_by asg |
rds, aurora |
rds, aurora |
database | rds (aurora when is_aurora) |
elasticache |
elasticache |
database | elasticache |
efs |
elastic_file_system |
storage | efs |
lambda |
lambda |
compute | lambda |
s3, s3_bucket |
s3 |
storage | s3, s3_bucket |
dynamodb |
dynamodb |
database | dynamodb |
cloudtrail |
cloudtrail |
management | cloudtrail |
guardduty |
guardduty |
security | guardduty |
config_recorder |
config |
management | config_recorder |
cloudwatch |
cloudwatch_2 |
management | cloudwatch |
kms |
key_management_service |
security | kms |
ecr |
ecr |
compute | ecr |
Flows of the service pages¶
The network flows (1 to 7, FLOW_COLORS) keep their numbers and colours. The service pages number their own
three flows from 1, with colours that no network flow uses:
| Flow | Number | Colour | Path |
|---|---|---|---|
ingress |
1 | #0E7490 |
users, Route 53, CloudFront, WAF, load balancer, target group |
api |
2 | #7C3AED |
users, Route 53, API Gateway, VPC link or Lambda |
database |
3 | #BE185D |
workload to RDS, ElastiCache or EFS |
The fixture¶
tests/fixtures/malz.py gives the Application account the services of one realistic application, so round 5b
can render it: the public zone app.example.com with alias records to a CloudFront distribution (origin
app-alb, a second origin on an S3 bucket through OAC, a CLOUDFRONT web ACL, a us-east-1 certificate) and
api.app.example.com to an HTTP API (a VPC link to app-internal, a Lambda integration, a regional
certificate); app-alb with a regional web ACL and two target groups, one for the Auto Scaling group
Application Instances (the six instances the subnets already draw) and one for an ECS Fargate service; Aurora
PostgreSQL, an ElastiCache replication group and an EFS with a mount target per private subnet; a Lambda in the
VPC and one without; Shield Standard; and the account services row. The network counts that
test_malz_fixture.py asserts did not change.
Adding a kind¶
- A class in
model/resources.py(type: Literal["x"] = "x"), exported inmodel/__init__.py, added toSERVICE_TYPES(and toGLOBAL_SERVICE_TYPESif it is global). - A row in the table above, and a row in
inventory/build.pyTYPE_LABELS. - A diagram kind in
SERVICE_KINDSandSERVICE_TYPE_KINDS, with its Lucid name in_LUCID_SERVICE_NAMES. - A collector in
collectors/that fills it, registered inDEFAULT_COLLECTORS, and an alias inexporters/graphview.py_ALIASso that the layout does not read the type asother. tests/test_model_services.pychecks 1 and 3 for every type ofSERVICE_TYPESby itself.