Skip to content

feat(catalog): topology layer — image layer, box templates, subnet layouts, network policies#180

Open
t0kubetsu wants to merge 18 commits into
devfrom
feat/topology-layer-templates
Open

feat(catalog): topology layer — image layer, box templates, subnet layouts, network policies#180
t0kubetsu wants to merge 18 commits into
devfrom
feat/topology-layer-templates

Conversation

@t0kubetsu
Copy link
Copy Markdown
Contributor

Closes #179

Context

range42-playbooks (feat/r42playbooks-generator) introduces the r42playbooks scenario generator, which reads structured descriptors from the catalog to allocate VMs, assign IPs, and resolve Ansible roles and attachments. This PR provides the catalog-side additions required to make that generator work end-to-end.

Merge dependency: must be reviewed and merged in coordination with range42-playbooks PR for feat/r42playbooks-generator — the generator expects the exact catalog shape defined here.

What this adds

01_image_layer/

Cloud image descriptors for the two supported distros:

  • ubuntu_noble/v1.0.0/ — 12 proxmox_templates, cloud_image download spec
  • debian_trixie/v1.0.0/ — 2 proxmox_templates, cloud_image download spec

VM names follow the template-vm-{distro}-{codename}-* convention for global uniqueness across a Proxmox node.

05_topology_layer/

Structured YAML descriptors consumed directly by r42playbooks:

  • box_templatesadmin-wazuh, debian-jump, deployer, student-box, vuln-box: each carries template_vm, image, firewall_rules, and attachments (docker stacks, ansible roles)
  • subnet_layoutsdefault-3zone, dual-lan: define subnets with name, cidr, bridge, section/label metadata, and a template_subnet for image-layer VMs
  • network_policiesdual-lan-isolate: deny-by-default inter-subnet policy with explicit egress rules, rendered as iptables R42-FORWARD chain rules (torn down by range42 PR #207)

Roles

  • 02_ansible_layer/linux/debian-based/ — renamed from ubuntu/; when conditions and Docker repo URLs updated to cover both Ubuntu and Debian

Test plan

  • r42playbooks new generates a scenario using default-3zone layout and a box template — allocates correctly
  • r42playbooks new with dual-lan layout and dual-lan-isolate policy — generates iptables rules in the scenario
  • r42playbooks catalog load finds all box_templates, subnet_layouts, network_policies with no validation errors
  • Debian-based role applies correctly on a debian_trixie VM

w1ld3r and others added 18 commits June 3, 2026 13:09
New symbolic, parametric templates consumed by the r42topo compiler
(range42-playbooks) to author + compile topology.json into deployable
scenarios. Directory-per-version layout: <id>/v<MAJOR.MINOR.PATCH>/template.yml.

- subnet_layouts/default-3zone — admin/student/ctf bridge plan
- box_templates/{admin-wazuh,deployer,vuln-box,student-box} — VM archetypes
  (role, inventory group, spec, default catalog role attachments)
- network_policies/air-gap-ctf — symbolic generalization of demo_lab_network's
  hardcoded 05_network_isolation (zones + services + allow/deny matrix + air-gap)
- network_policies/flat-open — no-isolation baseline
- manifest.json: register the topology layer + categories
Box templates can now declare their base OS, so a box's clone image is chosen at
authoring time while the warmup roles keep self-detecting the OS at runtime via
ansible_facts.distribution (feat/local-apt-mirror).

- os: ubuntu added explicitly to admin-wazuh, deployer, student-box, vuln-box
  (optional, defaults to ubuntu in the loader — no behaviour change).
- New debian-jump box: os: debian, Debian 13 (trixie), 2cpu/4gb/32gb student
  jump box — the reference example of a non-ubuntu box.

Values match ansible_facts.distribution lower-cased (ubuntu/debian/fedora). See
the generator's docs/box-template-os-field.md for the full rationale + the
template-image gate (debian images exist as trixie; fedora not yet).
…ename>)

os: ubuntu/debian -> image: ubuntu_noble/debian_trixie. The field now carries the
version (image-set name = the 01_init_proxmox templates/<image>/ dir), so a box is
never ambiguous about which Debian. debian-jump -> image: debian_trixie.
The renderer now emits attachment params into stage_01, so the box catalog is the
parametric source of a VM's config: software.configure.firewalls carries its
firewall_rules (22/80/8080 tcp), and a container attachment (cve/crypto/openssl/
CVE-2014-0160) wires a docker-compose play. Replaces the concrete copy in the
create-vms-vuln bundle.
…ry box

All box templates now own their host firewall rules via the
software.configure.firewalls attachment params (emitted into stage_01 by the
generator), matching the demo_lab rules:

- admin-wazuh : 22, 443, 1514, 1515 (ssh, dashboard, wazuh agent events/enroll)
- deployer    : 22, 80, 443 (ssh, http, https)
- student-box : 22 (ssh)
- debian-jump : 22 (ssh)
- vuln-box    : 22, 80, 8080 + docker CTF stack (prior commit)

IP-dependent role config (wazuh indexer IPs, etc.) intentionally stays at the
role defaults / deploy time — not catalog-appropriate. The catalog box_template
is now the parametric source of a VM's host config, replacing the concrete copies
in the create-vms-* bundles.
… debian_trixie

Each image now carries the cloud_image.url + cloud_image.filename needed by the
generator to render stage_00-download_cloudinit_files/<image>.yml. Only the
image actually used by templates is listed (noble-minimal, not noble-server).
… debian_trixie (2 VMs)

Each image now carries the full Proxmox template VM specs (vm_id, vm_name,
spec, ip, bridge) needed by the generator to render stage_01-create_templates
without any hardcoded data in the playbooks repo.
… convention

- box_templates: replace spec/image with template_vm (direct ProxmoxTemplateSpec ref)
- proxmox_templates: replace ip/bridge with ip_octet; remove bridge (both now
  come from the subnet layout's template_subnet at generation time)
- vm_names renamed to template-vm-{distro}-{codename}-* for global uniqueness
  (ubuntu: template-vm-ubuntu-noble-*, debian: template-vm-debian-trixie-*)
- default-3zone: add template_subnet: {cidr, bridge} — keeps "3-zone" accurate
  (templates subnet is infrastructure, not a lab zone)
…sed/, update when conditions and docker repo URLs

- software.configure.firewalls: ubuntu/ → debian-based/, when includes Debian
- software.install.warmup.basic_packages: all ubuntu/ subdirs → debian-based/,
  all dispatcher _main.yaml when conditions updated, docker GPG/repo URLs
  now use ansible_facts.distribution | lower for Ubuntu and Debian
…ta to layout

Box templates no longer carry role. Subnet layouts gain base_octet, section,
and label per subnet so the generator derives placement purely from the layout.
Group is now derived from subnet name at generation time (r42_{subnet}_group).
…l-lan layout

Section directory names and Ansible task labels are now derived automatically
from each subnet's list index and name — no need to declare them explicitly in
template YAML. Also adds dual-lan layout (lan1/lan2, vmbr150/vmbr151).
Mutual DROP isolation between lan1 and lan2 for the dual-lan layout.
Zone names match subnet names so compile_network_policy_from_alloc
resolves concrete CIDRs (192.168.150.0/24 <-> 192.168.151.0/24).
default_action: drop was blocking all internet/NAT traffic from VMs
(cloud-init apt updates, internet reachability). The isolation intent
is only to block lan1<->lan2 cross traffic, not all forwarded packets.

Matrix DROP rules at w=500 fire before the default ACCEPT at w=900,
so the lan1/lan2 mutual block still holds.
Revert default_action to drop (deny-by-default posture).
Add explicit {src: lan1/lan2, dst: wan, action: accept} rows for
internet egress. These compile at W_EGRESS_ACCEPT=700, AFTER the
cross-LAN DROP rules (500), so isolation is preserved.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants