Compare commits

...
7 Commits
Author SHA1 Message Date
thesabear 8ceadab38a netbird-zero-trust.md: new doc for the zero-trust mesh overlay
New file covering NetBird - a self-hosted WireGuard mesh giving every
fleet host and personal device a stable overlay identity, with a
genuinely-implemented zero-trust policy layer (deny-by-default, groups,
scoped setup keys, peer approval, posture checks).

- Why a mesh over a classic VPN concentrator, illustrated with a real
  topology diagram (control plane handles coordination only; actual
  data flows peer-to-peer, bypassing it entirely - the literal
  distinction from a concentrator, drawn not just asserted)
- Ties back to today's iac-pipeline.md update: this LXC is the first
  host ever built through the new Terraform LXC-native path, start to
  finish, no manual provisioning step
- Real bring-up incident: gRPC/h2c requirements broke through a naive
  proxy chain, and a proxying CDN 403s the agent outright - both root
  causes documented, not just the fixes
- Evidence: 3 real command blocks (docker ps, live Caddyfile splitter
  config, netbird status --detail from an enrolled peer), 2 real
  screenshots (dashboard Peers list, Access Control Policies - port
  counts in the screenshot match the real policy detail in the text)
- Second diagram (edge routing chain) for the specific gRPC/h2c/path
  split detail, kept separate from the topology diagram since they show
  genuinely different shapes of information
- Honest, non-rounded-up rollout status table - several phases still
  explicitly open
- Sanitize-checked: no internal IPs/domains/personal email

Also: fixes iac-pipeline.md's forward-reference to this doc to use the
repo's actual link convention ([docs/x.md](x.md)), not descriptive
prose link text.
2026-09-01 00:21:06 +03:00
thesabear 2d6be37271 iac-pipeline.md: update for new Terraform LXC support
Terraform gained a second provider (bpg/proxmox) alongside the existing
telmate/proxmox, via a new containers.tf / proxmox_virtual_environment_container
resource - real, live-verified against the actual repo files. Corrects
the doc's previous "Terraform only manages virtual machines... cannot
create or manage LXC containers" claim, which is no longer true.

- Terraform section: VM/LXC comparison table, real containers.tf
  excerpt, explains why LXCs need an extra pct-exec bootstrap step
  (stock template has no sshd, since it never went through Packer)
- WARNING section: new paragraph noting the LXC-provisioning gap is
  closed for new hosts going forward (the three existing exceptions
  stay as preserved history, not retroactively fixed) - forward-links
  to docs/netbird-zero-trust.md (next commit)
- Fixed now-stale section heading ("one resource type" -> "two
  resource types")
- Sanitize-checked: no internal IPs/domains
2026-08-31 23:59:36 +03:00
thesabear 6519a90db4 orchestration-flow-patterns.svg: pick up latest drawio edit, re-apply strip fix
New export reflecting the user's latest diagram edit. Same white-line
strip as aae1ff2 applied fresh to this export (variant this time: flat
#1C1D1E plus inverted light-dark(#1C1D1E, #d3d4d5)) - verified 0 broken
patterns remain, valid XML, all 8 correct span backgrounds preserved.
2026-08-30 07:52:54 +03:00
thesabear 5e409d5510 assets: fix edge-label white-line rendering artifact in remaining 7 diagrams
Same fix as orchestration-flow-patterns.svg (8772564), applied after a
comprehensive re-check that found the bug wasn't limited to the 6 files
originally caught by a narrower pattern match - architecture-overview.svg
and firewall-and-network-docker-bypass.svg were also affected.

Confirmed via a control test on orchestration-flow-patterns.svg that the
.drawio source's labelBackgroundColor property was never the actual
cause (reverted it, re-exported, still broken, still fixed cleanly by
the same strip) - this is a draw.io export-time quirk, not a content or
convention problem, so no CLAUDE.md changes needed.

Each file: stripped the same broken wrapper-div background-color
declarations (flat #1C1D1E / #ffffff, or the equivalent light-dark()/
var(--ge-adaptive-bg) variants - not consistent across exports of the
same file), verified 0 remain, valid XML, and the correct adaptive span
background count unchanged before/after in every file.

Files: architecture-overview.svg, firewall-and-network-docker-bypass.svg,
iac-pipeline-tools-flow.svg, observability-pipeline.svg,
readme-trust-boundaries-blast-radius.svg, secret-distribution-flows.svg,
secrets-and-pki-lifecycle.svg
2026-08-29 19:08:50 +03:00
thesabear 0d7c97ab37 orchestration-flow-patterns.svg: fix edge-label white-line rendering artifact
The exported SVG's 4 edge labels (no/yes/approve/decline) had two extra,
non-adaptive background-color declarations stamped onto their wrapper
divs by the draw.io exporter (flat #ffffff, and an undefined
var(--ge-adaptive-bg) CSS variable that falls back to #ffffff) -
independent of both the .drawio source content and the export dialog's
Appearance setting (tested Automatic and Light, both showed it).
Surgically stripped just those two declarations from the exported SVG,
verified count (4+4 removed, 0 remaining), confirmed the correct
adaptive span background (light-dark(white, #1C1D1E)) and every other
color in the diagram were untouched, confirmed still valid XML.
2026-08-29 09:27:13 +03:00
thesabear 6aa9117ad2 iac-pipeline.md: full 7-step audit
- Replaced both mermaid diagrams with real Nextcloud diagrams; the
  Ansible-stages rebuild caught a real omission - the old diagram showed
  only 2 stages (init/compliance) when there are genuinely 3
  (provisioning.yml exists too, currently just clamav/rocky-docker)
- Live-verified against the real iac repo: roles_metadata.yml (9
  cis_hardening + 6 other compliance roles, 1 provisioning role),
  kickstart partitioning/packages/SSH config, both Packer bootstrap
  scripts, terraform.tfvars, pct list on both hypervisors, a real
  rendered host_tags.yml
- KB fix: LXC Strategy note's PBS row was wrong, not just stale - PBS
  genuinely has a populated vm_tags list and live compliance roles
  (confirmed via real artifacts on the host itself), not 'never
  Ansible-managed' as it said; corrected and re-verified via re-fetch
- Added real content not previously in the doc: the deliberately
  permissive build-time SSH window closed by ssh_hardening, the
  admin/ansible identity split baked into the image at build time, and a
  third pipeline exception (PBS) that's genuinely different in kind from
  the other two, including a real Rocky-vs-Debian PAM ordering bug found
  onboarding it
- Considered two screenshot candidates (Proxmox template list, VM/LXC
  mix) - declined as low-value; command evidence covers this
  source-driven topic well on its own
- Sanitize-checked: no internal IPs/MACs/domains/personal info/forbidden
  app names
2026-08-29 08:21:38 +03:00
thesabear 57c494e354 notifications.md: full 7-step audit
- Replaced mermaid diagram with real Nextcloud diagram; rebuild caught a
  real bug in the old one (showed Kopia/Bazarr flowing through the App
  Router, which flows.json disproves - they bypass it entirely)
- Live-verified Mosquitto broker config/ACL, Node-RED flow routing (16
  switch rules = 15 apps + unknown fallback, 2 dedicated endpoints),
  mqtt-monitor.sh check count against the real script
- Named NetBox and Kestra directly (previously generic) after the real
  Node-RED screenshot made them visible anyway; Postiz/nocodb-content
  stay generic per standing instruction
- Added real evidence: routing-table command output, the real
  topic-agnostic Inventory Parse function source, real Mosquitto
  ACL/config, real check-count grep, a real Node-RED flow canvas
  screenshot, and a real Mosquitto connection log screenshot (the
  kestra-notify client is live proof of the MQTT-not-HTTP claim)
- KB fix: Ansible mqtt_client Role note was missing a 23rd real check
  (crash-looping systemd units, distinct from the failed-units check,
  added to the script after a real vault-agent crash-loop incident)
- Sanitize-checked: no internal IPs/domains/personal info/forbidden app
  names
2026-08-29 07:49:33 +03:00
19 changed files with 381 additions and 45 deletions

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io --> <!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1782px" height="632px" viewBox="0 0 1782 632" id="ge-svg-vzNy4PLln0NM0pvYZeNF" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Architecture Overview&quot; id=&quot;architecture-overview&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1664&quot; dy=&quot;931&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1900&quot; pageHeight=&quot;900&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;internet&quot; parent=&quot;1&quot; style=&quot;ellipse;whiteSpace=wrap;html=1;fillColor=light-dark(#FFFFFF,#292929);strokeColor=#333333;fontColor=light-dark(#333333,#FFFFFF);fontSize=14;&quot; value=&quot;Internet&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;140&quot; x=&quot;40&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;edge&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;&quot; value=&quot;Edge Firewall&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;280&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;lan&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;LAN&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;140&quot; x=&quot;560&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;dns&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;Internal DNS&amp;#xa;two zones&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;800&quot; y=&quot;140&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vault&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;Vault&amp;#xa;PKI + secrets&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;800&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fileserver&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;File Server&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;800&quot; y=&quot;700&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;edgeproxy&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;User-Facing Proxy&amp;#xa;mTLS&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1080&quot; y=&quot;140&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;automation&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;Automation VM&amp;#xa;Git + orchestration&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1080&quot; y=&quot;560&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;apphost&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;App Host&amp;#xa;41 stacks&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1360&quot; y=&quot;330&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;monitoring&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;&quot; value=&quot;Monitoring&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1360&quot; y=&quot;560&quot; as=&quot;geometry&quot; /&gt;&#10; Line truncated <svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1782px" height="632px" viewBox="0 0 1782 632" id="ge-svg-vzNy4PLln0NM0pvYZeNF" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Architecture Overview&quot; id=&quot;architecture-overview&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1664&quot; dy=&quot;931&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1900&quot; pageHeight=&quot;900&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;internet&quot; parent=&quot;1&quot; style=&quot;ellipse;whiteSpace=wrap;html=1;fillColor=light-dark(#FFFFFF,#292929);strokeColor=#333333;fontColor=light-dark(#333333,#FFFFFF);fontSize=14;&quot; value=&quot;Internet&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;140&quot; x=&quot;40&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;edge&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontSize=14;&quot; value=&quot;Edge Firewall&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;280&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;lan&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;LAN&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;140&quot; x=&quot;560&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;dns&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;Internal DNS&amp;#xa;two zones&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;800&quot; y=&quot;140&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vault&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;Vault&amp;#xa;PKI + secrets&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;800&quot; y=&quot;420&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fileserver&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;File Server&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;800&quot; y=&quot;700&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;edgeproxy&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;User-Facing Proxy&amp;#xa;mTLS&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1080&quot; y=&quot;140&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;automation&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;Automation VM&amp;#xa;Git + orchestration&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1080&quot; y=&quot;560&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;apphost&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=14;&quot; value=&quot;App Host&amp;#xa;41 stacks&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1360&quot; y=&quot;330&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;monitoring&quot; parent=&quot;1&quot; style=&quot;rounded=0;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontSize=14;&quot; value=&quot;Monitoring&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;1360&quot; y=&quot;560&quot; as=&quot;geometry&quot; /&gt;&#10; Line truncated

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 230 KiB

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io --> <!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="937px" height="699px" viewBox="0 0 937 699" id="ge-svg-_YH1L1cVkdBsB7NmxaGf" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Docker Firewalld Bypass&quot; id=&quot;docker-bypass-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1100&quot; pageHeight=&quot;740&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;traffic&quot; parent=&quot;1&quot; style=&quot;shape=cloud;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Incoming Traffic&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;440&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;pfsense&quot; parent=&quot;1&quot; style=&quot;shape=mxgraph.basic.shield;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;pfSense&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;Layer 1 — always applies&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;120&quot; width=&quot;120&quot; x=&quot;480&quot; y=&quot;170&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;bgfill_host&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=none;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;300&quot; width=&quot;820&quot; x=&quot;140&quot; y=&quot;360&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;host&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#666666;dashed=1;fontSize=12;fontStyle=1;fontColor=#333333;align=center;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;TARGET HOST — everything below this line is decided by what&amp;#39;s running on it&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;300&quot; width=&quot;820&quot; x=&quot;140&quot; y=&quot;360&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;firewalld&quot; parent=&quot;host&quot; style=&quot;shape=mxgraph.basic.shield;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;firewalld&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;Layer 2 — native services only&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;110&quot; width=&quot;110&quot; x=&quot;80&quot; y=&quot;70&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;native&quot; parent=&quot;host&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Native Service&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;e.g. Alloy, Wazuh agent&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;190&quot; x=&quot;40&quot; y=&quot;210&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;docker&quot; parent=&quot;host&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Docker-published port&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;dozens of containerized apps&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;550&quot; y=&quot;210&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e3&quot; edge=&quot;1&quot; parent=&quot;host&quot; source=&quot;firewalld&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;native&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;1&quot; Line truncated <svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="937px" height="699px" viewBox="0 0 937 699" id="ge-svg-_YH1L1cVkdBsB7NmxaGf" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Docker Firewalld Bypass&quot; id=&quot;docker-bypass-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1100&quot; pageHeight=&quot;740&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;traffic&quot; parent=&quot;1&quot; style=&quot;shape=cloud;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Incoming Traffic&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;440&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;pfsense&quot; parent=&quot;1&quot; style=&quot;shape=mxgraph.basic.shield;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;pfSense&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;Layer 1 — always applies&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;120&quot; width=&quot;120&quot; x=&quot;480&quot; y=&quot;170&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;bgfill_host&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=none;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;300&quot; width=&quot;820&quot; x=&quot;140&quot; y=&quot;360&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;host&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#666666;dashed=1;fontSize=12;fontStyle=1;fontColor=#333333;align=center;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;TARGET HOST — everything below this line is decided by what&amp;#39;s running on it&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;300&quot; width=&quot;820&quot; x=&quot;140&quot; y=&quot;360&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;firewalld&quot; parent=&quot;host&quot; style=&quot;shape=mxgraph.basic.shield;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;firewalld&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;Layer 2 — native services only&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;110&quot; width=&quot;110&quot; x=&quot;80&quot; y=&quot;70&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;native&quot; parent=&quot;host&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Native Service&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;e.g. Alloy, Wazuh agent&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;190&quot; x=&quot;40&quot; y=&quot;210&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;docker&quot; parent=&quot;host&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Docker-published port&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;dozens of containerized apps&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;550&quot; y=&quot;210&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e3&quot; edge=&quot;1&quot; parent=&quot;host&quot; source=&quot;firewalld&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;native&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;1&quot; Line truncated

Before

Width:  |  Height:  |  Size: 363 KiB

After

Width:  |  Height:  |  Size: 363 KiB

+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="932px" height="318px" viewBox="0 0 932 318" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Ansible Stages&quot; id=&quot;iac-ansiblestages-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1080&quot; pageHeight=&quot;360&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;tags&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Per-host tag list&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;from Terraform&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;200&quot; x=&quot;20&quot; y=&quot;140&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;init&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Initialization stage&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;runs once, at creation&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;360&quot; y=&quot;20&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;prov&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Provisioning stage&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;every run — 1 role today, one host&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;360&quot; y=&quot;140&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;comp&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Compliance stage&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;re-applied every run&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;360&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;sub&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;9 independently-tagged&amp;lt;br&amp;gt;hardening sub-roles&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;720&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;tags&quot; style=&quot;html=1;endArrow=block;strokeColor=#d6b656;strokeWidth=2;rounded=1;exitX=1;exitY=0.5;entryX=0;entryY=0.5;&quot; target=&quot;init&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e2&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;tags&quot; style=&quot;html=1;endArrow=block;strokeColor=#d6b656;strokeWidth=2;rounded=1;exitX=1;exitY=0.5;entryX=0;entryY=0.5;&quot; target=&quot;prov&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e3&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;tags&quot; style=&quot;html=1;endArrow=block;strokeColor=#d6b656;strokeWidth=2;rounded=1;exitX=1;exitY=0.5;entryX=0;entryY=0.5;&quot; target=&quot;comp&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e4&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;comp&quot; style=&quot;html=1;endArrow=block;strokeColor=#82b366;strokeWidth=2;rounded=1;&quot; target=&quot;sub&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quoLine truncated

After

Width:  |  Height:  |  Size: 153 KiB

+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1052px" height="132px" viewBox="0 0 1052 132" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Tools Flow&quot; id=&quot;iac-toolsflow-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1080&quot; pageHeight=&quot;240&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;packer&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Packer&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;builds the base image&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;200&quot; x=&quot;20&quot; y=&quot;80&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;terraform&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Terraform&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;provisions the VM&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;200&quot; x=&quot;300&quot; y=&quot;80&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;tags&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;host_tags.yml&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;the tag list&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;200&quot; x=&quot;580&quot; y=&quot;80&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;ansible&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Ansible&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;configures &amp;amp;amp; hardens&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;200&quot; x=&quot;860&quot; y=&quot;80&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;packer&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;terraform&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e2&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;terraform&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#d79b00;fontColor=#d79b00;strokeWidth=2;rounded=1;fontSize=11;&quot; target=&quot;tags&quot; value=&quot;&amp;lt;span style=&amp;quot;background-color: light-dark(rgb(255, 255, 255), rgb(28, 29, 30));&amp;quot;&amp;gt;generates&amp;lt;/span&amp;gt;&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; y=&quot;15&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e3&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;tags&quot; style=&quot;html=1;endArrow=block;strokeColor=#d6b656;strokeWidth=2;rounded=1;&quot; target=&quot;ansible&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;loop&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;ansible&quot; style=&quot;html=1;endArrow=block;strokeColor=#82b366;strokeWidth=2;rounded=1;curved=1;labelBackgroundColor=#1C1D1E;fontColor=#82b366;fontSize=11;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;&quot; target=&quot;ansible&quot; value=&quot;&amp;lt;span style=&amp;quot;background-color: light-dark(rgb(255, 255, 255), rgb(28, 29, 30));&amp;quot;&amp;gt;&amp;lt;font style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;re-applied every run&amp;lt;/font&amp;gt;&amp;lt;/span&amp;gt;&quot;&gt;&#10; &lt;mxGeometry Line truncated

After

Width:  |  Height:  |  Size: 125 KiB

+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1062px" height="248px" viewBox="0 0 1062 248" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Edge Path&quot; id=&quot;netbird-edgepath-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1080&quot; pageHeight=&quot;320&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;client&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Client&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;gRPC agent&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;110&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;edge&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Edge firewall&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;HTTPS termination&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;200&quot; x=&quot;280&quot; y=&quot;110&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;proxy&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;In-stack proxy&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;content-type / path split&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;220&quot; x=&quot;560&quot; y=&quot;110&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;server&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Management / Signal&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;h2c end-to-end&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;850&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;dash&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Dashboard SPA&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;220&quot; x=&quot;850&quot; y=&quot;200&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;client&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;edge&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e2&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;edge&quot; style=&quot;html=1;endArrow=block;strokeColor=#d79b00;strokeWidth=2;rounded=1;&quot; target=&quot;proxy&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e3&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;proxy&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#82b366;fontColor=#82b366;strokeWidth=2;rounded=1;fontSize=11;exitX=1;exitY=0.3;entryX=0;entryY=0.5;&quot; target=&quot;server&quot; value=&quot;&amp;lt;span style=&amp;quot;background-color: light-dark(rgb(255, 255, 255), rgb(28, 29, 30));&amp;quot;&amp;gt;gRPC / API / relay&amp;lt;/span&amp;gt;&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; x=&quot;0.3028&quot; y=&quot;51&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint as=&quot;offset&quot; /&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e4&quot; edge=&quot;1&quot; parent=&quot;1&quotLine truncated

After

Width:  |  Height:  |  Size: 147 KiB

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1045px" height="548px" viewBox="0 0 1045 548" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Mesh Topology&quot; id=&quot;netbird-mesh-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1178&quot; dy=&quot;659&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1080&quot; pageHeight=&quot;620&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;cp&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;NetBird control plane&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;Management + Signal + Relay + IdP&amp;lt;br&amp;gt;coordination only — not in the data path&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;280&quot; x=&quot;400&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;p1&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Fleet host&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;e.g. Vault&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;190&quot; x=&quot;60&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;p2&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Fleet host&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;e.g. Automation&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;190&quot; x=&quot;60&quot; y=&quot;500&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;p3&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Fleet host&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;9 more, same pattern&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;190&quot; x=&quot;830&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;laptop&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Laptop&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;roaming, off-LAN&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;190&quot; x=&quot;830&quot; y=&quot;500&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;c1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;cp&quot; style=&quot;html=1;endArrow=none;dashed=1;strokeColor=#d6b656;strokeWidth=1.5;rounded=1;&quot; target=&quot;p1&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;c2&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;cp&quot; style=&quot;html=1;endArrow=none;dashed=1;strokeColor=#d6b656;strokeWidth=1.5;rounded=1;&quot; target=&quot;p2&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;c3&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;cp&quot; style=&quot;html=1;endArrow=none;dashed=1;strokeColor=#d6b656;strokeWidth=1.5;rounded=1;&quot; target=&quot;p3&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;c4&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;cp&quot; style=&quot;html=1;endArrow=none;dashed=1;strokeColor=#d6b656;strokeWidth=1.5;rounded=1;&quot; target=&quot;laptop&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geoLine truncated

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1098px" height="362px" viewBox="0 0 1098 362" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Fan-in Fan-out&quot; id=&quot;notif-faninfanout-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1120&quot; pageHeight=&quot;420&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;fangroup&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;startSize=30;swimlane;fillColor=none;strokeColor=#666666;dashed=1;fontSize=13;fontStyle=1;fontColor=#333333;align=center;&quot; value=&quot;FAN-IN&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;360&quot; width=&quot;220&quot; x=&quot;20&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s1&quot; parent=&quot;fangroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;15 apps&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;HTTP webhook, /app-webhook&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;190&quot; x=&quot;15&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s2&quot; parent=&quot;fangroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Kopia / Bazarr&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;dedicated endpoints, non-JSON&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;190&quot; x=&quot;15&quot; y=&quot;140&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s3&quot; parent=&quot;fangroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Every host&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;MQTT publish, homelab/#&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;190&quot; x=&quot;15&quot; y=&quot;250&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;p1&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;App Router → Switch&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;payload-shape detection, per-app mapper&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;240&quot; x=&quot;340&quot; y=&quot;45&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;p2&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Own mapper&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;bypasses the router entirely&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;240&quot; x=&quot;340&quot; y=&quot;155&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;p3&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Inventory Parse Function&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;topic-agnostic: any homelab/&amp;amp;lt;id&amp;amp;gt;/notify&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;240&quot; x=&quot;340&quot; y=&quot;265&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;fmt&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;ShLine truncated

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io --> <!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="838px" height="324px" viewBox="0 0 838 324" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Pipeline&quot; id=&quot;obs-pipeline-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1178&quot; dy=&quot;659&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1000&quot; pageHeight=&quot;420&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;srcgroup&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;startSize=30;swimlane;fillColor=none;strokeColor=#666666;dashed=1;fontSize=13;fontStyle=1;fontColor=#333333;align=center;&quot; value=&quot;PER-HOST SOURCES&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;320&quot; width=&quot;220&quot; x=&quot;30&quot; y=&quot;40&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s1&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;journald&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;persistent, 14-day retention&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s2&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Docker container&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;stdout/stderr, docker_hosts only&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;105&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s3&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Node metrics&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;CPU / mem / disk / net&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s4&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Native app metrics&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;5 apps expose endpoints&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;255&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;agent&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Grafana Alloy&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;native systemd service&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;360&quot; y=&quot;160&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;loki&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Loki&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;160&quot; x=&quot;700&quot; y=&quot;70&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;prom&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Prometheus&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;160&quot; x=&quot;700&quot; y=&quot;270&quot; as=&quot;geometry&quot; /&gt;&#10; Line truncated <svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="838px" height="324px" viewBox="0 0 838 324" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Pipeline&quot; id=&quot;obs-pipeline-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1178&quot; dy=&quot;659&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1000&quot; pageHeight=&quot;420&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;srcgroup&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;startSize=30;swimlane;fillColor=none;strokeColor=#666666;dashed=1;fontSize=13;fontStyle=1;fontColor=#333333;align=center;&quot; value=&quot;PER-HOST SOURCES&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;320&quot; width=&quot;220&quot; x=&quot;30&quot; y=&quot;40&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s1&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;journald&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;persistent, 14-day retention&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s2&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Docker container&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;stdout/stderr, docker_hosts only&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;105&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s3&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Node metrics&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;CPU / mem / disk / net&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s4&quot; parent=&quot;srcgroup&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Native app metrics&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;5 apps expose endpoints&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;20&quot; y=&quot;255&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;agent&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Grafana Alloy&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;native systemd service&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;360&quot; y=&quot;160&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;loki&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Loki&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;160&quot; x=&quot;700&quot; y=&quot;70&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;prom&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Prometheus&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;160&quot; x=&quot;700&quot; y=&quot;270&quot; as=&quot;geometry&quot; /&gt;&#10; Line truncated

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 211 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io --> <!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1142px" height="642px" viewBox="0 0 1142 642" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Flow Patterns&quot; id=&quot;orch-patterns-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1200&quot; pageHeight=&quot;640&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;lane1&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#6c8ebf;dashed=1;fontSize=13;fontStyle=1;fontColor=#333333;align=left;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;12 OF 13 FLOWS — no human gate&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;140&quot; width=&quot;1140&quot; x=&quot;30&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l1s&quot; parent=&quot;lane1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Weekly / scheduled trigger&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;220&quot; x=&quot;40&quot; y=&quot;50&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l1r&quot; parent=&quot;lane1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Runs the playbook directly&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;os-update-vms, container-update, disk-cleanup, os-update-pbs, dashy-fleet-audit, and 7 more&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;420&quot; x=&quot;360&quot; y=&quot;45&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l1n&quot; parent=&quot;lane1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Notify: succeeded / failed&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;220&quot; x=&quot;880&quot; y=&quot;50&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;lane1&quot; source=&quot;l1s&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;l1r&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e2&quot; edge=&quot;1&quot; parent=&quot;lane1&quot; source=&quot;l1r&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;l1n&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;lane2&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#d79b00;dashed=1;fontSize=13;fontStyle=1;fontColor=#333333;align=left;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;1 OF 13 FLOWS (app-update) — check → pause → human approval → apply&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;480&quot; width=&quot;1140&quot; x=&quot;30&quot; y=&quot;190&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l2s&quot; parent=&quot;lane2&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Weekly schedule&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;40&quot; y=&quot;40&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l2c&quot; parent=&quot;lane2&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Check mode run&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;detect pending Vault/Technitium/Alloy updates&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10Line truncated <svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1142px" height="642px" viewBox="0 0 1142 642" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Flow Patterns&quot; id=&quot;orch-patterns-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1200&quot; pageHeight=&quot;640&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;lane1&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#6c8ebf;dashed=1;fontSize=13;fontStyle=1;fontColor=#333333;align=left;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;12 OF 13 FLOWS — no human gate&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;140&quot; width=&quot;1140&quot; x=&quot;30&quot; y=&quot;30&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l1s&quot; parent=&quot;lane1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Weekly / scheduled trigger&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;220&quot; x=&quot;40&quot; y=&quot;50&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l1r&quot; parent=&quot;lane1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Runs the playbook directly&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;os-update-vms, container-update, disk-cleanup, os-update-pbs, dashy-fleet-audit, and 7 more&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;70&quot; width=&quot;470&quot; x=&quot;340&quot; y=&quot;45&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l1n&quot; parent=&quot;lane1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Notify: succeeded / failed&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;220&quot; x=&quot;880&quot; y=&quot;50&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;lane1&quot; source=&quot;l1s&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;l1r&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e2&quot; edge=&quot;1&quot; parent=&quot;lane1&quot; source=&quot;l1r&quot; style=&quot;html=1;endArrow=block;strokeColor=#6c8ebf;strokeWidth=2;rounded=1;&quot; target=&quot;l1n&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;lane2&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#d79b00;dashed=1;fontSize=13;fontStyle=1;fontColor=#333333;align=left;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;1 OF 13 FLOWS (app-update) — check → pause → human approval → apply&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;480&quot; width=&quot;1140&quot; x=&quot;30&quot; y=&quot;190&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l2s&quot; parent=&quot;lane2&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Weekly schedule&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;180&quot; x=&quot;40&quot; y=&quot;40&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;l2c&quot; parent=&quot;lane2&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Check mode run&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 10px;&amp;quot;&amp;gt;detect pending Vault/Technitium/Alloy updates&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10Line truncated

Before

Width:  |  Height:  |  Size: 400 KiB

After

Width:  |  Height:  |  Size: 403 KiB

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io --> <!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1022px" height="659px" viewBox="0 0 1022 659" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Trust Boundaries and Blast Radius&quot; id=&quot;trust-boundaries-2&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1100&quot; pageHeight=&quot;700&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;pfsense&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=15;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;pfSense&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;Edge Firewall + Public HAProxy&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;100&quot; width=&quot;170&quot; x=&quot;465&quot; y=&quot;20&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;nodeA&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;dashed=1;verticalAlign=top;fontSize=13;fontStyle=1;spacingTop=8;fontColor=#333333;&quot; value=&quot;PROXMOX NODE A — day-to-day applications&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;370&quot; width=&quot;460&quot; x=&quot;40&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;internalCaddy&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=14;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Internal Caddy&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 11px;&amp;quot;&amp;gt;app-to-app zone&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;100&quot; width=&quot;170&quot; x=&quot;115&quot; y=&quot;220&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;apps&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=15;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Docker Apps&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;LXC host, most of the fleet&amp;#39;s stacks&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;380&quot; x=&quot;80&quot; y=&quot;440&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;nodeB&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;dashed=1;verticalAlign=top;fontSize=13;fontStyle=1;spacingTop=8;fontColor=#333333;&quot; value=&quot;PROXMOX NODE B — trust &amp;amp;amp; sensitive infrastructure&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;370&quot; width=&quot;460&quot; x=&quot;600&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;caddyVM&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=14;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Caddy VM&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 11px;&amp;quot;&amp;gt;browser zone, mTLS&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;100&quot; width=&quot;170&quot; x=&quot;815&quot; y=&quot;220&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vaultDns&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=15;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Vault + Technitium DNS&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;trust backbone&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;380&quot; x=&quot;640&quot; y=&quot;440&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;pfsense&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#d79b00;fontColor=#d79b00;fontSize=13;rounded=1;edgeStyle=orthogonalEdgeStyle;entryLine truncated <svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1022px" height="659px" viewBox="0 0 1022 659" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Trust Boundaries and Blast Radius&quot; id=&quot;trust-boundaries-2&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1100&quot; pageHeight=&quot;700&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;pfsense&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=15;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;pfSense&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;Edge Firewall + Public HAProxy&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;100&quot; width=&quot;170&quot; x=&quot;465&quot; y=&quot;20&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;nodeA&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;dashed=1;verticalAlign=top;fontSize=13;fontStyle=1;spacingTop=8;fontColor=#333333;&quot; value=&quot;PROXMOX NODE A — day-to-day applications&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;370&quot; width=&quot;460&quot; x=&quot;40&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;internalCaddy&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=14;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Internal Caddy&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 11px;&amp;quot;&amp;gt;app-to-app zone&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;100&quot; width=&quot;170&quot; x=&quot;115&quot; y=&quot;220&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;apps&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontSize=15;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Docker Apps&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;LXC host, most of the fleet&amp;#39;s stacks&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;380&quot; x=&quot;80&quot; y=&quot;440&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;nodeB&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;dashed=1;verticalAlign=top;fontSize=13;fontStyle=1;spacingTop=8;fontColor=#333333;&quot; value=&quot;PROXMOX NODE B — trust &amp;amp;amp; sensitive infrastructure&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;370&quot; width=&quot;460&quot; x=&quot;600&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;caddyVM&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontSize=14;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Caddy VM&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 11px;&amp;quot;&amp;gt;browser zone, mTLS&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;100&quot; width=&quot;170&quot; x=&quot;815&quot; y=&quot;220&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vaultDns&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontSize=15;fontStyle=1;fontColor=#333333;shadow=1;&quot; value=&quot;Vault + Technitium DNS&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;trust backbone&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;380&quot; x=&quot;640&quot; y=&quot;440&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;e1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;pfsense&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#d79b00;fontColor=#d79b00;fontSize=13;rounded=1;edgeStyle=orthogonalEdgeStyle;entryLine truncated

Before

Width:  |  Height:  |  Size: 415 KiB

After

Width:  |  Height:  |  Size: 414 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io --> <!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1179px" height="545px" viewBox="0 0 1179 545" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Secret Distribution Flows&quot; id=&quot;secret-dist-flows-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1200&quot; pageHeight=&quot;620&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;repo&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Provisioning Repo&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;template inventory&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;40&quot; y=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;agentconfig&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Vault Agent Config&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;on the target host&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;410&quot; y=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;bgfill_dataplane&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=none;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;290&quot; width=&quot;440&quot; x=&quot;380&quot; y=&quot;230&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;dataplane&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#9673a6;dashed=1;fontSize=12;fontStyle=1;fontColor=#333333;align=center;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;DATA PLANE — what Vault Agent actually renders&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;290&quot; width=&quot;440&quot; x=&quot;380&quot; y=&quot;230&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vaultagent&quot; parent=&quot;dataplane&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Vault Agent&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;140&quot; x=&quot;150&quot; y=&quot;40&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;certflow&quot; parent=&quot;dataplane&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=light-dark(#FFFFFF,#392F3F);strokeColor=#9673a6;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Certificate Flow&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;PKI engine, short-lived&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;170&quot; x=&quot;30&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;secflow&quot; parent=&quot;dataplane&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=light-dark(#FFFFFF,#392F3F);strokeColor=#9673a6;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;App Secret Flow&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;KV, rendered 0600&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;170&quot; x=&quot;240&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;container&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Container&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;reads local disk only&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;900&quotLine truncated <svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1179px" height="545px" viewBox="0 0 1179 545" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Secret Distribution Flows&quot; id=&quot;secret-dist-flows-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1200&quot; pageHeight=&quot;620&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;repo&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Provisioning Repo&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;template inventory&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;40&quot; y=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;agentconfig&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#ffe6cc;strokeColor=#d79b00;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Vault Agent Config&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;on the target host&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;410&quot; y=&quot;60&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;bgfill_dataplane&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=none;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;290&quot; width=&quot;440&quot; x=&quot;380&quot; y=&quot;230&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;dataplane&quot; parent=&quot;1&quot; style=&quot;swimlane;whiteSpace=wrap;html=1;startSize=30;fillColor=none;strokeColor=#9673a6;dashed=1;fontSize=12;fontStyle=1;fontColor=#333333;align=center;spacingLeft=8;verticalAlign=middle;&quot; value=&quot;DATA PLANE — what Vault Agent actually renders&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;290&quot; width=&quot;440&quot; x=&quot;380&quot; y=&quot;230&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vaultagent&quot; parent=&quot;dataplane&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontColor=#333333;fontSize=13;fontStyle=1;shadow=1;&quot; value=&quot;Vault Agent&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;60&quot; width=&quot;140&quot; x=&quot;150&quot; y=&quot;40&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;certflow&quot; parent=&quot;dataplane&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=light-dark(#FFFFFF,#392F3F);strokeColor=#9673a6;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;Certificate Flow&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;PKI engine, short-lived&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;170&quot; x=&quot;30&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;secflow&quot; parent=&quot;dataplane&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=light-dark(#FFFFFF,#392F3F);strokeColor=#9673a6;fontColor=#333333;fontSize=12;fontStyle=1;shadow=1;&quot; value=&quot;App Secret Flow&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;KV, rendered 0600&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;65&quot; width=&quot;170&quot; x=&quot;240&quot; y=&quot;180&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;container&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Container&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;reads local disk only&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;80&quot; width=&quot;200&quot; x=&quot;900&quotLine truncated

Before

Width:  |  Height:  |  Size: 422 KiB

After

Width:  |  Height:  |  Size: 422 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Do not edit this file with editors other than draw.io --> <!-- Do not edit this file with editors other than draw.io -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1312px" height="420px" viewBox="0 0 1312 420" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Secret Lifecycle&quot; id=&quot;secret-lifecycle-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1340&quot; pageHeight=&quot;620&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;agent&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Vault Agent&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;runs on the consuming host&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;40&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vault&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Vault&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;server&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;380&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;disk&quot; parent=&quot;1&quot; style=&quot;shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;boundedLbl=1;&quot; value=&quot;Local Disk&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;rendered file&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;110&quot; width=&quot;160&quot; x=&quot;620&quot; y=&quot;250&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;app&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Application&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;1140&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;agent&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#9673a6;fontColor=#9673a6;fontSize=11;rounded=1;edgeStyle=orthogonalEdgeStyle;exitX=0.3;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&quot; target=&quot;vault&quot; value=&quot;&amp;lt;font style=&amp;quot;font-size: 13px; background-color: light-dark(rgb(255, 255, 255), rgb(28, 29, 30));&amp;quot;&amp;gt;① authenticate — AppRole (role_id + secret_id)&amp;lt;/font&amp;gt;&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; y=&quot;20&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint as=&quot;offset&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;100&quot; y=&quot;200&quot; /&gt;&#10; &lt;mxPoint x=&quot;480&quot; y=&quot;200&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s2&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;vault&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#9673a6;fontColor=#9673a6;fontSize=11;rounded=1;edgeStyle=orthogonalEdgeStyle;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.603;entryY=0.996;entryDx=0;entryDy=0;entryPerimeter=0;&quot; target=&quot;agent&quot; value=&quot;&amp;lt;font style=&amp;quot;font-size: 13px; background-color: light-dark(rgb(255, 255, 255), rgb(28, 29, 30));&amp;quot;&amp;gt;② short-lived token issued, cached, auto-renewed&amp;lt;/font&amp;gt;&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; x=&quot;0.0547&quot; y=&quot;15&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint as=&quot;offset&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;480&quot; y=&quot;375&quot; /&gt;&#10; &lt;mxPoint x=&quot;160&quot; y=&quot;375&quot; Line truncated <svg xmlns="http://www.w3.org/2000/svg" style="background: transparent; background-color: transparent; color-scheme: light dark;" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1312px" height="420px" viewBox="0 0 1312 420" content="&lt;mxfile host=&quot;embed.diagrams.net&quot; scale=&quot;1&quot; border=&quot;0&quot;&gt;&#10; &lt;diagram name=&quot;Secret Lifecycle&quot; id=&quot;secret-lifecycle-1&quot;&gt;&#10; &lt;mxGraphModel dx=&quot;1414&quot; dy=&quot;791&quot; grid=&quot;1&quot; gridSize=&quot;10&quot; guides=&quot;1&quot; tooltips=&quot;1&quot; connect=&quot;1&quot; arrows=&quot;1&quot; fold=&quot;1&quot; page=&quot;1&quot; pageScale=&quot;1&quot; pageWidth=&quot;1340&quot; pageHeight=&quot;620&quot; math=&quot;0&quot; shadow=&quot;0&quot;&gt;&#10; &lt;root&gt;&#10; &lt;mxCell id=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;1&quot; parent=&quot;0&quot; /&gt;&#10; &lt;mxCell id=&quot;agent&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Vault Agent&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;runs on the consuming host&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;40&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;vault&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#e1d5e7;strokeColor=#9673a6;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Vault&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;server&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;380&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;disk&quot; parent=&quot;1&quot; style=&quot;shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#666666;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;boundedLbl=1;&quot; value=&quot;Local Disk&amp;lt;br&amp;gt;&amp;lt;font style=&amp;quot;font-size:11px&amp;quot;&amp;gt;rendered file&amp;lt;/font&amp;gt;&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;110&quot; width=&quot;160&quot; x=&quot;620&quot; y=&quot;250&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;app&quot; parent=&quot;1&quot; style=&quot;rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333;fontSize=14;fontStyle=1;shadow=1;&quot; value=&quot;Application&quot; vertex=&quot;1&quot;&gt;&#10; &lt;mxGeometry height=&quot;90&quot; width=&quot;200&quot; x=&quot;1140&quot; y=&quot;260&quot; as=&quot;geometry&quot; /&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s1&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;agent&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#9673a6;fontColor=#9673a6;fontSize=11;rounded=1;edgeStyle=orthogonalEdgeStyle;exitX=0.3;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;&quot; target=&quot;vault&quot; value=&quot;&amp;lt;font style=&amp;quot;font-size: 13px; background-color: light-dark(rgb(255, 255, 255), rgb(28, 29, 30));&amp;quot;&amp;gt;① authenticate — AppRole (role_id + secret_id)&amp;lt;/font&amp;gt;&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; y=&quot;20&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint as=&quot;offset&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;100&quot; y=&quot;200&quot; /&gt;&#10; &lt;mxPoint x=&quot;480&quot; y=&quot;200&quot; /&gt;&#10; &lt;/Array&gt;&#10; &lt;/mxGeometry&gt;&#10; &lt;/mxCell&gt;&#10; &lt;mxCell id=&quot;s2&quot; edge=&quot;1&quot; parent=&quot;1&quot; source=&quot;vault&quot; style=&quot;html=1;labelBackgroundColor=#1C1D1E;endArrow=block;strokeColor=#9673a6;fontColor=#9673a6;fontSize=11;rounded=1;edgeStyle=orthogonalEdgeStyle;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.603;entryY=0.996;entryDx=0;entryDy=0;entryPerimeter=0;&quot; target=&quot;agent&quot; value=&quot;&amp;lt;font style=&amp;quot;font-size: 13px; background-color: light-dark(rgb(255, 255, 255), rgb(28, 29, 30));&amp;quot;&amp;gt;② short-lived token issued, cached, auto-renewed&amp;lt;/font&amp;gt;&quot;&gt;&#10; &lt;mxGeometry relative=&quot;1&quot; x=&quot;0.0547&quot; y=&quot;15&quot; as=&quot;geometry&quot;&gt;&#10; &lt;mxPoint as=&quot;offset&quot; /&gt;&#10; &lt;Array as=&quot;points&quot;&gt;&#10; &lt;mxPoint x=&quot;480&quot; y=&quot;375&quot; /&gt;&#10; &lt;mxPoint x=&quot;160&quot; y=&quot;375&quot; Line truncated

Before

Width:  |  Height:  |  Size: 346 KiB

After

Width:  |  Height:  |  Size: 346 KiB

+144 -17
View File
@@ -5,13 +5,7 @@
## The pipeline ## The pipeline
```mermaid ![Packer builds the base image, Terraform provisions the VM and generates host_tags.yml, which Ansible consumes to configure and harden the host, re-applying its compliance stage on every run](../assets/iac-pipeline-tools-flow.svg)
flowchart LR
Packer["Packer<br/>builds the base image"] --> Terraform["Terraform<br/>provisions the VM"]
Terraform -->|generates| Tags["host_tags.yml<br/>the tag list"]
Tags --> Ansible["Ansible<br/>configures & hardens"]
Ansible -->|re-applied every run| Compliance["Compliance stage<br/>not just once at creation"]
```
## Why three separate tools instead of one ## Why three separate tools instead of one
@@ -19,30 +13,163 @@ A single tool covering image-build-through-configuration was a real option — s
## Packer: hardening baked in at install time, not bolted on after ## Packer: hardening baked in at install time, not bolted on after
A single base image (`rocky10-cis`) is built from a minimal Rocky Linux 10 install with CIS-oriented hardening baked into the kickstart itself — disk partitioning (mount options like `nodev`/`nosuid`/`noexec` on specific partitions) and package selection decided at install time, not patched in afterward by Ansible. This was a deliberate split with the compliance work in [`docs/security-monitoring.md`](security-monitoring.md): some controls are genuinely easier and more reliable to get right once, at image-build time, than to retrofit repeatedly with a configuration tool after the fact — partition layout in particular can't be changed after boot without real risk, so it has to be correct in the image, not corrected later. A single base image (`rocky10-cis`) is built from a minimal Rocky Linux 10 install with CIS-oriented hardening baked into the kickstart itself — disk partitioning (mount options like `nodev`/`nosuid`/`noexec` on specific partitions) and package selection decided at install time, not patched in afterward by Ansible. This was a deliberate split with the compliance work in [`docs/security-monitoring.md`](security-monitoring.md): some controls are genuinely easier and more reliable to get right once, at image-build time, than to retrofit repeatedly with a configuration tool after the fact — partition layout in particular can't be changed after boot without real risk, so it has to be correct in the image, not corrected later. This is the real kickstart partitioning, not a paraphrase of the intent:
## Terraform: one resource type, tag generation as the real output ```
$ grep -A8 'Logical volumes' http/ks.cfg
logvol /tmp --fstype=xfs --size=2048 --name=lv_tmp --vgname=rocky --fsoptions="defaults,nodev,nosuid"
logvol /home --fstype=xfs --size=2048 --name=lv_home --vgname=rocky --fsoptions="defaults,nodev"
logvol /var --fstype=xfs --size=4096 --name=lv_var --vgname=rocky --fsoptions="defaults,nodev"
logvol /var/tmp --fstype=xfs --size=1024 --name=lv_vartmp --vgname=rocky --fsoptions="defaults,nodev,nosuid,noexec"
logvol /var/log --fstype=xfs --size=2048 --name=lv_varlog --vgname=rocky --fsoptions="defaults,nodev,noexec,nosuid"
logvol /var/log/audit --fstype=xfs --size=2048 --name=lv_audit --vgname=rocky --fsoptions="defaults,nodev,noexec,nosuid"
logvol / --fstype=xfs --name=lv_root --vgname=rocky --grow --size=512 --fsoptions="defaults"
```
`/var/tmp` and `/var/log` both get the full `nodev,nosuid,noexec` treatment; `/home` and `/var` only get `nodev` — a reader can see exactly which mount points earned the stricter posture and which didn't, rather than one blanket policy applied everywhere.
> [!TIP]
> Two things happen at image-build time that aren't part of the pipeline's "steady state" and are easy to miss reading only the diagram above. First, the kickstart deliberately leaves SSH in a **permissive** state during the build — `PermitRootLogin yes` and `PasswordAuthentication yes` — because the build environment isn't reachable from anywhere except the hypervisor doing the build, and that window closes for good once the compliance stage's `ssh_hardening` role runs on a provisioned host. Second, Packer's own post-install provisioners create both fleet identities right there in the image — a personal admin account, and the dedicated `ansible` service account used for all automation — and the admin account's setup script ends by writing a sudoers rule that explicitly **denies it permission to run `ansible`/`ansible-playbook` at all**. Automation only ever runs as the service account; that's not a convention someone has to remember, it's baked into every host from before it's even provisioned.
## Terraform: two resource types, tag generation as the real output
> [!TIP] > [!TIP]
> Every VM is one entry in a single map — VM ID, target node, template, resources, network, disk, and its own tag list. Two supporting pieces do the real connective work: a wait step that blocks completion until the new VM actually answers SSH as the automation identity (so nothing downstream races a host that isn't up yet), and a template render that writes that VM's tag list directly into Ansible's own host-variable tree. **This tag file is the actual link between provisioning and configuration** — the tags Terraform assigns to a VM are the exact same tags every later Ansible stage (including the security hardening in [`docs/security-monitoring.md`](security-monitoring.md) and the observability rollout in [`docs/observability.md`](observability.md)) matches against. Get this file wrong and every downstream stage silently configures the wrong thing for that host — which is why it's generated, not hand-written. > Every VM is one entry in a single map — VM ID, target node, template, resources, network, disk, and its own tag list. Two supporting pieces do the real connective work: a wait step that blocks completion until the new VM actually answers SSH as the automation identity (so nothing downstream races a host that isn't up yet), and a template render that writes that VM's tag list directly into Ansible's own host-variable tree. **This tag file is the actual link between provisioning and configuration** — the tags Terraform assigns to a VM are the exact same tags every later Ansible stage (including the security hardening in [`docs/security-monitoring.md`](security-monitoring.md) and the observability rollout in [`docs/observability.md`](observability.md)) matches against. Get this file wrong and every downstream stage silently configures the wrong thing for that host — which is why it's generated, not hand-written.
Terraform only manages virtual machines, deliberately — containers are handled differently (below), a scope boundary that avoids fighting Terraform's own resource model for something it wasn't built to represent well. Terraform manages both VMs and LXCs now — two separate resource types, one per guest kind, coexisting in one config with no shared state between them:
| | VMs | LXCs |
|---|---|---|
| Provider | `telmate/proxmox` | `bpg/proxmox` |
| Resource | `proxmox_vm_qemu` | `proxmox_virtual_environment_container` |
| Source image | the `rocky10-cis` Packer template — hardening, `sshd`, both fleet identities pre-baked | stock Rocky 10 template — root-only, no `sshd` |
| Ansible group | `rocky_vm` | `rocky_lxc` |
The LXC path is genuinely newer and mirrors the VM flow step-for-step, but has to close a gap the VM path never has: the stock container template has no `sshd` and no fleet users at all, since it never went through Packer. A `pct exec` bootstrap step runs first — installing `sshd` and creating both fleet identities with their keys, the same baseline Packer bakes into the VM image at build time instead of at provision time — before the same wait-for-SSH and tag-file-render steps every VM already gets. This is the real resource definition, not a paraphrase:
```
$ head -20 containers.tf
resource "proxmox_virtual_environment_container" "ct" {
provider = proxmox-bpg
for_each = var.containers
node_name = each.value.target_node
vm_id = each.value.vmid
unprivileged = each.value.unprivileged
start_on_boot = each.value.onboot
started = true
tags = each.value.tags
cpu {
cores = each.value.cores
}
memory {
dedicated = each.value.memory
swap = each.value.swap
}
```
An empty `var.containers` makes this file completely inert — nothing created, no effect — the same "opt-in, not a parallel system that has to be kept in sync" pattern as every other tag-driven piece of this pipeline.
This is the actual template that renders into every host's tag file — the literal source, not a description of its fields:
```
$ cat host_tags.yml.tpl
vmid: ${vmid}
vm_name: ${name}
target_node: ${target_node}
template: ${template}
cores: ${cores}
sockets: ${sockets}
memory: ${memory}
balloon: ${balloon}
bridge: ${bridge}
macaddr: ${macaddr}
disk_size: ${disk_size}GB
disk_storage: ${disk_storage}
ip: ${ip}
vlan: ${vlan}
vm_tags:
%{ for tag in tags ~}
- ${tag}
%{ endfor ~}
```
Every field in this file traces back to one map entry in Terraform's own VM definitions — nothing here is hand-maintained separately from the VM it describes. And this is a real rendered instance of it, not a hypothetical fill-in — one fleet host's actual generated tag file, `ip`/`macaddr` redacted:
```
$ cat host_vars/technitium/host_tags.yml
vmid: 118
vm_name: technitium
target_node: hyper2
template: rocky10-cis
cores: 2
sockets: 1
memory: 3072
balloon: 1536
bridge: vmbr0
macaddr: [technitium's MAC]
disk_size: 50GB
disk_storage: local
ip: [technitium's IP]
vlan: 0
vm_tags:
- packages
- hostname_network
- root_password
- disk_resize
- base_users
- firewall_ssh
- zsh_custom
- vault_agent
- technitium
- ssh_hardening
- password_policy
- banners
- file_permissions
- service_disable
- kernel_hardening
- filesystem_hardening
- chrony_hardening
- auditd_hardening
- observability_agent
- mqtt_client
- wazuh_agent_tuning
```
21 tags on this one host alone, spanning both the initialization roles (`packages`, `firewall_ssh`, …) and every one of the 9 compliance sub-roles — the same file Terraform generated is the exact input every Ansible stage after it reads.
## Ansible: tag-driven, re-applied continuously ## Ansible: tag-driven, re-applied continuously
```mermaid ![The per-host tag list from Terraform drives three independent Ansible stages: initialization (runs once, at creation), provisioning (every run, one role today on one host), and compliance (re-applied every run), which fans out into 9 independently-tagged hardening sub-roles](../assets/iac-pipeline-ansible-stages.svg)
flowchart TD
Tags["Per-host tag list<br/>from Terraform"] --> Init["Initialization stage<br/>runs once, at creation"] There are genuinely three stages, not two — the third one is easy to miss because it's currently almost empty. `provisioning.yml` exists for roles that fit neither "once at init" nor "every compliance run," and as of this writing exactly one role is tagged for it:
Tags --> Compliance["Compliance stage<br/>re-applied every run"]
Compliance --> Sub["9 independently-tagged<br/>hardening sub-roles"] ```
$ python3 -c "
import yaml
d = yaml.safe_load(open('roles_metadata.yml'))['roles_metadata']
print('provisioning:', [k for k,v in d.items() if v.get('provisioning') is True])
print('compliance:', sorted(k for k,v in d.items() if v.get('compliance') is True))
"
provisioning: ['clamav']
compliance: ['auditd_hardening', 'banners', 'chrony_hardening', 'disk_resize', 'docker_bench', 'file_permissions', 'filesystem_hardening', 'kernel_hardening', 'mqtt_client', 'observability_agent', 'password_policy', 'service_disable', 'ssh_hardening', 'wazuh_agent_tuning', 'zsh_custom']
``` ```
Compliance hardening runs as a set of independently-tagged sub-roles, selected per host via that same tag list — which controls apply to a given host is explicit and auditable in that host's own config, not an implicit "all or nothing." All 9 current sub-roles are active fleet-wide; none are disabled or pending. This same tag-driven selection mechanism is what makes the deliberate CIS deviations in [`docs/security-monitoring.md`](security-monitoring.md) auditable rather than hidden — a reader can see exactly which controls a given host runs by reading its tags, not by reverse-engineering behavior. `clamav` is the only provisioning-stage role, and only one host carries it in its `vm_tags`. An under-used pipeline stage isn't the same as an unused one — it exists on purpose for exactly this shape of role, not as leftover scaffolding.
Compliance hardening runs as a set of independently-tagged sub-roles, selected per host via that same tag list — which controls apply to a given host is explicit and auditable in that host's own config, not an implicit "all or nothing." All 9 current sub-roles (of the 15 total compliance-stage roles above — the other 6 handle observability, notifications, and disk/shell setup, not CIS hardening specifically) are active fleet-wide; none are disabled or pending. This same tag-driven selection mechanism is what makes the deliberate CIS deviations in [`docs/security-monitoring.md`](security-monitoring.md) auditable rather than hidden — a reader can see exactly which controls a given host runs by reading its tags, not by reverse-engineering behavior.
## The honest exception: not everything fits the clean model ## The honest exception: not everything fits the clean model
> [!WARNING] > [!WARNING]
> Two hosts don't follow the pipeline above cleanly, and that history is preserved rather than erased. Both were originally provisioned as Terraform-managed virtual machines, then at some point converted directly into LXC containers outside Terraform's management — a resource-type mismatch that Terraform's VM-only tooling genuinely can't represent (LXCs aren't `proxmox_vm_qemu` resources). Rather than deleting their old Terraform entries when this happened, they were commented out, preserving the historical record of how these hosts actually came to exist rather than presenting a cleaner story than what's true. Ansible still configures both today through the same tag-driven mechanism as every VM — only the initial provisioning step is now manual instead of automated. This is the kind of real-world messiness that a from-scratch design document never mentions but that every infrastructure actually accumulates over time — worth showing, not hiding. > Two hosts don't follow the pipeline above cleanly, and that history is preserved rather than erased. Both were originally provisioned as Terraform-managed virtual machines, then at some point converted directly into LXC containers outside Terraform's management — a resource-type mismatch that Terraform's VM-only tooling genuinely can't represent (LXCs aren't `proxmox_vm_qemu` resources). Rather than deleting their old Terraform entries when this happened, they were commented out, preserving the historical record of how these hosts actually came to exist rather than presenting a cleaner story than what's true. Ansible still configures both today through the same tag-driven mechanism as every VM — only the initial provisioning step is now manual instead of automated. This is the kind of real-world messiness that a from-scratch design document never mentions but that every infrastructure actually accumulates over time — worth showing, not hiding.
>
> A third host breaks the model in a genuinely different way — not a variation on the same story, a different one entirely. Proxmox Backup Server runs as the vendor's own official Debian-based appliance image, deployed by hand and never a Terraform resource at all — there's no commented-out entry to preserve, because there was never a Terraform-managed version of it to convert away from. It still ended up on the tag-driven Ansible side of the pipeline: wired into its own inventory group and given a hand-written tag list after the fact, since compliance only ever checks whether a tag is present, not how a host arrived in the inventory. It's also the fleet's only non-Rocky host, which surfaced a real gap in one of the 9 hardening sub-roles above: `password_policy` configures PAM lockout behavior, and the ordering it assumes is Rocky's own — safe on every other host, but wrong on this one until it was fixed at the role level and explicitly re-validated.
>
> None of these three exceptions were retroactively fixed once the LXC-provider gap closed — the point of preserving history is that it stays history, not that it gets quietly cleaned up the moment it becomes possible to. But the gap itself is real and worth naming honestly too: for any *new* LXC going forward, this entire honest-exception story no longer applies. The mesh overlay in [`docs/netbird-zero-trust.md`](netbird-zero-trust.md) is the first host actually built through the LXC-native path above, start to finish, with no manual step anywhere in its provisioning.
--- ---
Related: [`docs/secrets-and-pki.md`](secrets-and-pki.md), [`docs/security-monitoring.md`](security-monitoring.md), [`docs/disaster-recovery.md`](disaster-recovery.md) Related: [`docs/secrets-and-pki.md`](secrets-and-pki.md), [`docs/security-monitoring.md`](security-monitoring.md), [`docs/disaster-recovery.md`](disaster-recovery.md), [`docs/netbird-zero-trust.md`](netbird-zero-trust.md)
+139
View File
@@ -0,0 +1,139 @@
# 🕸️ Zero-Trust Mesh Overlay
> [!NOTE]
> A self-hosted **NetBird** WireGuard mesh gives every fleet host — and every device that needs to reach it — its own stable overlay identity, independent of where that device physically sits. Access is granted per-identity through mesh policy, not inferred from LAN position. The mesh is **deny-by-default**: nothing crosses it unless an explicit policy allows it, the same instinct behind every other boundary in [`docs/architecture-overview.md`](architecture-overview.md), applied to remote and roaming access specifically.
## Why a mesh, not a classic VPN
A traditional VPN concentrator was the obvious alternative, and it was rejected for the same reason a flat LAN got rejected everywhere else in this fleet: it's one more device sitting in a path, and reaching it means punching a hole to a single choke point rather than establishing an identity-scoped connection to exactly the host that's actually needed. A mesh instead gives every peer — fleet host or personal device — its own stable identity (`<host>.netbird.selfhosted`, a `100.91.0.0/16` overlay address) and lets WireGuard tunnels form directly, peer-to-peer, falling back to a relay only when direct connectivity isn't possible. Policy is written once, per identity or group, and travels with the peer regardless of which network it's physically on.
This is the actual shape of it — the control plane coordinates, but it's deliberately not where the traffic goes:
![The NetBird control plane sends thin coordination-only signals to every peer, while real data flows over direct peer-to-peer WireGuard tunnels that bypass the control plane entirely, with relay fallback only when a direct path isn't possible](../assets/netbird-zero-trust-mesh-topology.svg)
That's the actual difference from a VPN concentrator, drawn rather than just asserted: a concentrator puts itself in every data path by design; here the control plane's spokes only ever carry coordination traffic, and every thick line is two peers talking directly to each other.
## Built on a capability that didn't exist yet
The mesh's own control plane is the first host in this fleet ever provisioned through a genuinely new capability: Terraform gaining native LXC support (a second provider, `bpg/proxmox`, alongside the existing VM-only one — full story in [`docs/iac-pipeline.md`](iac-pipeline.md)). Every other LXC in this fleet either predates Terraform entirely or was hand-converted after the fact; this one went through the pipeline start to finish with no manual provisioning step anywhere. That's not a coincidence — a lightweight mesh control-plane container was exactly the kind of workload that made closing the LXC gap worth doing.
## Control plane
One `netbirdio/netbird-server` container runs Management, Signal, the embedded relay, and NetBird's own embedded IdP together — combined-server mode, not four separate services. A digest-pinned `netbirdio/dashboard` container serves the admin SPA. This is the real container list, not a claimed one:
```
$ docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
NAMES IMAGE STATUS
netbird-proxy caddy:2-alpine Up 38 hours
netbird-server netbirdio/netbird-server:0.77.1 Up 38 hours
netbird-dashboard f3eb26c93ca9 Up 38 hours
```
Configuration is Vault-Agent-rendered, never committed — secrets live in Vault under a dedicated AppRole and policy scoped to this one host, the same pattern as every other secret in [`docs/secrets-and-pki.md`](secrets-and-pki.md). The identity provider is NetBird's own embedded one, not Authentik — Authentik is deliberately LAN-only in this fleet and publishing it wasn't in scope, so there's no OIDC migration path here; the first-login owner account is the permanent identity for this system specifically.
## The edge routing problem, and what actually broke
> [!WARNING]
> **Learned the hard way during bring-up, not designed in from the start.** NetBird's Management and Signal services need native gRPC over HTTP/2-cleartext (h2c) end-to-end — any downgrade to HTTP/1.1 anywhere in the chain kills the bidirectional stream with an `unexpected EOF`, and the client agent just wedges with no useful error. The edge firewall's own reverse proxy can carry h2c to a single plain-HTTP backend, but it can't perform NetBird's own content-type/path split between the management API, the relay, and the dashboard SPA — so a small in-stack proxy does exactly that split, one hop further in. A second, unrelated thing broke the same week: the public DNS record for this service has to stay **DNS-only**, not proxied through a CDN — a proxying CDN returns an outright 403 to the gRPC-speaking agent, no explanation given, and the fix was disabling that proxying entirely for this one record rather than trying to work around it.
The real path a request takes:
![A client's gRPC request passes through the edge firewall's HTTPS termination, into an in-stack proxy that splits traffic by content-type and path, then either to the management/signal server or the dashboard SPA depending on that split](../assets/netbird-zero-trust-edge-path.svg)
And this is the actual splitter doing that work — the real config, not a description of the logic:
```
$ cat Caddyfile
{
admin off
auto_https off
servers {
protocols h1 h2 h2c
}
}
:33000 {
# native gRPC + gRPC-web (any application/grpc* content-type) -> server over h2c
@grpc header Content-Type application/grpc*
handle @grpc {
reverse_proxy h2c://netbird-server:80
}
# REST, OAuth, relay/signal WebSockets, and the gRPC service paths -> server
@srv path /api/* /oauth2/* /relay* /ws-proxy/* /signalexchange* /management*
handle @srv {
reverse_proxy netbird-server:80
}
# everything else -> dashboard SPA
handle {
reverse_proxy netbird-dashboard:80
}
}
```
## Fleet enrolment
A dedicated Ansible role installs the mesh agent and enrols a host, opt-in per host via the same tag-driven mechanism as every other role in [`docs/iac-pipeline.md`](iac-pipeline.md) — nothing joins the mesh by default just because it exists. Enrolment uses a reusable, class-scoped setup key fetched live from the secrets platform at play time, never stored in the repo, and read only on a host's first join. Because peer approval is required, a brand-new peer pauses for an operator to approve it in the dashboard before it gets any mesh access at all — there's no silent auto-join path.
All fleet hosts are enrolled today, plus two personal devices (a laptop with full mesh access, a home device with none by default — being *on* the mesh and being *allowed* anywhere on it are two separate, independently-granted things). Fleet servers run with local DNS resolution disabled on the mesh interface deliberately — they're not roaming, and the fleet's own internal DNS already handles them; only the one roaming device gets split-DNS behavior, resolving the fleet's internal zones over the mesh specifically because it's the one peer that actually needs to.
This is the real, live peer roster, not a claimed enrolment count — every fleet host plus both personal devices, each with its own overlay identity:
![Real NetBird dashboard: 13 connected peers, a mix of fleet hosts and personal devices, each showing its own group membership, agent version, and OS](../assets/netbird-zero-trust-peers.png)
## Zero-trust policy: deny-by-default, not just present
The mesh ships with a built-in allow-everything default policy — the first real security decision here was turning it off. With it disabled, no traffic crosses the mesh interface at all unless a specific policy grants it; LAN traffic is completely untouched by this, since the policy only governs the overlay interface, not the physical network.
**Groups** carry the actual access model:
| Group | Role |
|---|---|
| Admin | Full fleet access — the policy source for everything below |
| Servers | Every fleet host — coarse policy destination |
| Endpoints | Personal devices with no fleet access by default — on the mesh for connectivity, not for reach |
| Functional sub-groups | Hypervisors / infra / Docker hosts / storage — each server is in exactly one, no policy on them yet, there so future rules can be scoped precisely instead of broadly |
**Policies**, all sourced from the admin group and one-directional: SSH and hypervisor-management ports to servers (an explicit port list — the platform's own API rejects ranges, so nothing here is a lazy wildcard), ICMP for diagnostics, and DNS specifically to the infra sub-group to support split-DNS for the roaming device. A posture check gates admin-level access behind a minimum agent version and kernel version — an out-of-date or unpatched peer simply doesn't qualify for the policy regardless of which group it's in. Login expiration applies only to the human-authenticated peer; the fleet's own service-key peers don't expire on a timer, since there's no human session behind them to expire.
This is the real policy list, not a description of the intent — the built-in allow-all sitting disabled at the top, every real rule beneath it scoped to a specific source, direction, and an explicit port list rather than "allow the group and hope":
![Real NetBird Access Control page: 5 policies, the built-in Default allow-all shown disabled, and four explicit admin-sourced rules each scoped to a specific protocol and port list](../assets/netbird-zero-trust-policies.png)
This is the mesh actually enforcing that model, not a claimed state — a real enrolled peer's own live status:
```
$ netbird status --detail
Peers detail:
[laptop]:
NetBird IP: [overlay address]
Status: Idle
-- detail --
Last WireGuard handshake: -
...
Events:
[INFO] SYSTEM
Message: Network map updated
Time: 5 minutes, 7 seconds ago
```
The network map updating on its own, unprompted, on a peer that isn't even the control plane, is the mesh's policy engine actually pushing live state to every connected peer — not a dashboard claiming a policy exists.
## Rollout, phased and honestly incomplete
Not everything is finished, and that's stated plainly rather than rounded up:
| Phase | Scope | State |
|---|---|---|
| Control plane + dashboard, embedded identity | Stand up the mesh itself | Done |
| First peers | Laptop + one fleet host, verified on-LAN | Done |
| Fleet enrolment | Every fleet host via the dedicated role | Done |
| Roaming | Split-DNS (done) + full-LAN route + off-LAN verification | Partly done |
| Zero-trust policy | Groups, keys, deny-by-default, approval, posture, login expiry | Done |
| Enforcement | Per-host firewall rejects non-mesh admin access | Planned |
The honest gaps: off-LAN connectivity (STUN/relay through NAT) hasn't been verified end-to-end yet, the full internal-network route for agent-less devices is still open, and per-host firewall enforcement — actually *requiring* the mesh for admin access rather than just offering it as one more path — is a deliberate later phase, not an oversight. A phased rollout that's honest about which phases aren't done yet is worth more than a status page that rounds every in-progress item up to "complete."
---
Related: [`docs/iac-pipeline.md`](iac-pipeline.md), [`docs/architecture-overview.md`](architecture-overview.md), [`docs/firewall-and-network.md`](firewall-and-network.md), [`docs/secrets-and-pki.md`](secrets-and-pki.md), [`docs/dns-naming.md`](dns-naming.md)
+71 -21
View File
@@ -5,30 +5,46 @@
## Fan-in, fan-out ## Fan-in, fan-out
```mermaid ![Three independent fan-in sources converging on one shared formatting subflow: 15 apps over HTTP webhook go through the App Router and Switch to a per-app mapper, Kopia/Bazarr post to their own dedicated endpoints and bypass the router entirely with their own mapper, and every host publishes over MQTT into a topic-agnostic Inventory Parse function — all three land on the same subflow before reaching Slack](../assets/notifications-fan-in-fan-out.svg)
flowchart LR
subgraph FanIn["Fan-in"]
Apps["15 apps<br/>HTTP webhook"]
Dedicated["2 apps<br/>dedicated endpoints<br/>non-JSON payloads"]
MQTT["Every host<br/>MQTT publish"]
end
Apps --> Router["Node-RED App Router<br/>payload-shape detection"]
Dedicated --> Router
Router --> Mapper["Per-app mapper"]
MQTT --> Parser["Inventory parser"]
Mapper --> Subflow["Shared formatting subflow"]
Parser --> Subflow
Subflow --> Slack["Slack"]
```
## Why one Node-RED instance instead of per-app scripts ## Why one Node-RED instance instead of per-app scripts
The alternative — each app posting directly to a per-app Slack webhook, or a small script per integration — was rejected because it would mean N different message formats, N different places to add a new integration's logic, and no single point to add fleet-wide behavior (like the OS-level checks below) without touching every app individually. One Node-RED instance with a shared router and a shared formatting subflow means a new app's alerts get the same visual treatment as every existing one automatically, and a fleet-wide change (say, adding a severity-based routing rule) happens in one place. The alternative — each app posting directly to a per-app Slack webhook, or a small script per integration — was rejected because it would mean N different message formats, N different places to add a new integration's logic, and no single point to add fleet-wide behavior (like the OS-level checks below) without touching every app individually. One Node-RED instance with a shared router and a shared formatting subflow means a new app's alerts get the same visual treatment as every existing one automatically, and a fleet-wide change (say, adding a severity-based routing rule) happens in one place.
> [!WARNING] > [!WARNING]
> **Real debt in the flow**: of the apps wired into the router, a couple no longer resolve to anything — one was fully decommissioned (see [`docs/registry-and-build.md`](registry-and-build.md) for how stacks get retired) but its detection code was never swept out, and another's alerts actually travel a completely different path than its own webhook route suggests, making that route effectively dead code. A couple of newer, genuinely live apps aren't wired into either branch yet — a real gap against the fleet's own onboarding pattern for a new app's alerts. > **Real debt in the flow**: of the apps wired into the router, two no longer resolve to anything — NetBox was fully decommissioned (see [`docs/registry-and-build.md`](registry-and-build.md) for how stacks get retired) but its detection code was never swept out, and Kestra's alerts actually travel a completely different path than its own webhook route suggests: Kestra publishes its own alerts over MQTT, not HTTP, which makes its dedicated webhook route effectively dead code. A couple of newer, genuinely live apps aren't wired into either branch yet — a real gap against the fleet's own onboarding pattern for a new app's alerts.
This is the real routing table, not a claimed count — counted directly from the flow export, not restated from memory:
```
$ python3 -c "
import json
flows = json.load(open('flows.json'))
switch = next(n for n in flows if n.get('type')=='switch')
print('Switch rules:', len(switch['rules']))
dedicated = [n for n in flows if n.get('type')=='http in' and n.get('url','').endswith('-webhook') and n.get('url') != '/app-webhook']
print('Dedicated non-router endpoints:', len(dedicated))
"
Switch rules: 16
Dedicated non-router endpoints: 2
```
16 rules = the 15 routed apps plus one `unknown` fallback that just drops the payload. And this is the real function behind the "completely different path" line above — the MQTT branch doesn't parse `msg.topic` looking for a known set of fleet hosts, it just takes whatever the second path segment is:
```
$ grep -A4 '"Inventory Parse Function' flows.json
const parts = msg.topic.split("/");
msg.inventory = parts[1];
msg.channel = `#${msg.inventory}`;
msg.slackData = msg.payload;
return msg;
```
Topic-agnostic by construction — so a publisher that isn't a fleet host at all gets handled identically to one that is, which is exactly the mechanism that makes an app's *own* MQTT-published alerts real and its dedicated webhook route genuinely dead, not just theoretically bypassable.
This is the real flow, not a redrawn version of it — the App Router feeding a 16-way Switch, NetBox's and Kestra's mapper functions still sitting there wired in and unreachable, Kopia and Bazarr's dedicated endpoints bypassing all of it entirely on their way to the same shared subflow:
![Real Node-RED canvas: HTTP-in webhook through App Router into a 16-rule Switch function feeding per-app mapper functions (including netbox mapper and kestra mapper, both still wired but dead), MQTT-in through the Inventory Parse Function, and Kopia/Bazarr's own dedicated HTTP-in nodes bypassing the router entirely — all converging on the shared MQTT → Slack subflow](../assets/notifications-node-red-flow.png)
## Message broker ## Message broker
@@ -39,23 +55,57 @@ The alternative — each app posting directly to a per-app Slack webhook, or a s
| **Topic structure** | One topic per host, wildcard-subscribed centrally | | **Topic structure** | One topic per host, wildcard-subscribed centrally |
| **Users** | Two — a publish identity used fleet-wide, and Node-RED's own read-only subscriber | | **Users** | Two — a publish identity used fleet-wide, and Node-RED's own read-only subscriber |
Both broker users are credential-managed through the same Vault-rendered pipeline as everything else in [`docs/secrets-and-pki.md`](secrets-and-pki.md) — not a bare manually-edited password file. Both broker users are credential-managed through the same Vault-rendered pipeline as everything else in [`docs/secrets-and-pki.md`](secrets-and-pki.md) — not a bare manually-edited password file. This is the real broker config and ACL, not a description of the intended setup:
```
$ cut -d: -f1 mosquitto/config/passwords
notifier
node-red
$ cat mosquitto/config/acl
user notifier
topic write homelab/+/notify
topic read #
user node-red
topic read #
$ grep -E 'listener|allow_anonymous|protocol' mosquitto/config/mosquitto.conf
listener 1883
protocol mqtt
allow_anonymous false
```
The ACL is the concrete version of "publish identity" and "read-only subscriber" above: `notifier` can write only to its own topic pattern (plus read access to the full wildcard, not write-only despite the name), `node-red` can only ever read.
And this is the broker actually being used, not just configured — real connection log, including Kestra's own `kestra-notify` client publishing under the `notifier` identity, the same live evidence behind the "Kestra's alerts travel over MQTT" claim above:
![Real Mosquitto container log: a kestra-notify client connecting and disconnecting under the notifier identity, alongside other short-lived notifier connections from fleet hosts, interleaved with periodic in-memory database saves](../assets/notifications-mosquitto-logs.png)
> [!IMPORTANT] > [!IMPORTANT]
> **A real, tracked fragility, worth naming precisely**: the publish identity's password has to stay in sync across three separate places — the Vault-rendered broker credential file, the source value used to render every host's own publish script (via the same tag-driven Ansible model in [`docs/iac-pipeline.md`](iac-pipeline.md)), and a hardcoded copy inside the orchestration engine's own alert-publishing flow definition (not sourced from Vault at all, unlike everything else in [`docs/secret-distribution.md`](secret-distribution.md)). Rotating it means updating all three by hand — a documented, real exception to the "one source of truth" rule that governs every other secret in this fleet, called out explicitly rather than left for someone to discover mid-rotation. > **A real, tracked fragility, worth naming precisely**: the publish identity's password has to stay in sync across three separate places — the Vault-rendered broker credential file, the source value used to render every host's own publish script (via the same tag-driven Ansible model in [`docs/iac-pipeline.md`](iac-pipeline.md)), and a hardcoded copy inside the orchestration engine's own alert-publishing flow definition (not sourced from Vault at all, unlike everything else in [`docs/secret-distribution.md`](secret-distribution.md)). Rotating it means updating all three by hand — a documented, real exception to the "one source of truth" rule that governs every other secret in this fleet, called out explicitly rather than left for someone to discover mid-rotation.
## Detection logic ## Detection logic
The Node-RED App Router figures out which app sent a webhook by inspecting the payload's shape — an explicit field for some apps, structural pattern-matching for others (one app, for instance, is identified purely by a nested field only that vendor's payload happens to include, since it never sends an explicit app identifier). Two apps skip the shared router entirely with their own dedicated endpoints, since they post plain text rather than JSON and the shared router's shape-detection logic simply doesn't apply to them. The Node-RED App Router figures out which app sent a webhook by inspecting the payload's shape — an explicit field for some apps, structural pattern-matching for others (Emby, for instance, is identified purely by a nested `data.Server` field only that vendor's payload happens to include, since it never sends an explicit app identifier). Kopia and Bazarr skip the shared router entirely with their own dedicated endpoints, since they post plain text rather than JSON and the shared router's shape-detection logic simply doesn't apply to them.
## Every host, not just apps ## Every host, not just apps
> [!TIP] > [!TIP]
> A dedicated Ansible role puts every fleet host onto this same pipeline for OS-level health, independent of any application-level alert — the same fleet-wide, tag-driven rollout pattern used for the observability agent in [`docs/observability.md`](observability.md) and the compliance hardening in [`docs/security-monitoring.md`](security-monitoring.md). It runs over 20 distinct checks per host — disk thresholds, password/certificate expiry, failed logins (both local and from outside the trusted network), cron/systemd failures, container health, pending reboots, time-sync drift, OOM events, read-only filesystem remounts, and several security-platform-specific checks (Vault audit log anomalies, Vault Agent authentication failures) — deliberately complementary to Wazuh in [`docs/security-monitoring.md`](security-monitoring.md), not duplicating its file-integrity or account monitoring. Splitting OS-health checks from the SOC's own detection engine keeps each system's role narrow enough to actually reason about, instead of one monolithic monitoring tool trying to do both jobs at once. > A dedicated Ansible role puts every fleet host onto this same pipeline for OS-level health, independent of any application-level alert — the same fleet-wide, tag-driven rollout pattern used for the observability agent in [`docs/observability.md`](observability.md) and the compliance hardening in [`docs/security-monitoring.md`](security-monitoring.md). It runs over 20 distinct checks per host — disk thresholds, password/certificate expiry, failed logins (both local and from outside the trusted network), cron/systemd failures, container health, pending reboots, time-sync drift, OOM events, read-only filesystem remounts, and several security-platform-specific checks (Vault audit log anomalies, Vault Agent authentication failures) — deliberately complementary to Wazuh in [`docs/security-monitoring.md`](security-monitoring.md), not duplicating its file-integrity or account monitoring. Splitting OS-health checks from the SOC's own detection engine keeps each system's role narrow enough to actually reason about, instead of one monolithic monitoring tool trying to do both jobs at once.
>
> This is a real count against the role's own script, not the doc's own claim restated:
>
> ```
> $ grep -oE '\$STATE_DIR/[a-zA-Z_]+' mqtt-monitor.sh.j2 | sed -E 's/(_alert|_last_count|_since|_report)$//' | sort -u | wc -l
> 22
> ```
>
> 22 from that count, plus disk-usage thresholds — which don't show up in that grep because its state key is built dynamically per mountpoint, not a fixed name — makes 23. One of those 22 was a genuine KB gap this doc caught mid-audit: crash-looping systemd units (`activating`/`auto-restart` stuck in a loop) never trips the plain failed-units check above it, because a unit that keeps getting restarted never actually reaches systemd's "failed" state. That distinction wasn't theoretical — it's in the script because of a real incident where exactly that happened and produced zero alerts.
## One formatter, every source ## One formatter, every source
Every branch — app webhooks, host-level alerts, and the two dedicated non-JSON endpoints — converges on one shared subflow before anything reaches Slack. This is the single point where message formatting is standardized, regardless of which of the dozen-plus sources triggered it — a reader in Slack never has to learn a different alert format depending on which system fired it. Every branch — app webhooks, host-level alerts, and Kopia/Bazarr's own dedicated non-JSON endpoints — converges on one shared subflow before anything reaches Slack. This is the single point where message formatting is standardized, regardless of which of the dozen-plus sources triggered it — a reader in Slack never has to learn a different alert format depending on which system fired it.
--- ---
Related: [`docs/secrets-and-pki.md`](secrets-and-pki.md), [`docs/security-monitoring.md`](security-monitoring.md), [`docs/observability.md`](observability.md), [`docs/dashy-soc-board.md`](dashy-soc-board.md) · Stacks: [`stacks/platform/mosquitto/`](../stacks/platform/mosquitto/), [`stacks/platform/node-red/`](../stacks/platform/node-red/) Related: [`docs/secrets-and-pki.md`](secrets-and-pki.md), [`docs/security-monitoring.md`](security-monitoring.md), [`docs/observability.md`](observability.md), [`docs/dashy-soc-board.md`](dashy-soc-board.md) · Stacks: [`stacks/platform/mosquitto/`](../stacks/platform/mosquitto/), [`stacks/platform/node-red/`](../stacks/platform/node-red/)