Diagram Data Validation

1. Overview

D2 diagrams contain hardcoded infrastructure data (IPs, hostnames, ports). This runbook ensures diagram accuracy by validating against live systems before committing.

Problem: D2 files cannot use Antora attributes - values are baked into SVG at render time.

Solution: Validate all infrastructure data against authoritative sources before creating or updating diagrams.

2. Validation Workflow

Diagram Validation Flow
Figure 1. Diagram Validation Process

3. Authoritative Sources

Data Type Primary Source Command

DNS Records

BIND (bind-01/bind-02)

dig @bind-01 inside.domusdigitalis.dev AXFR

Host IPs

DNS resolution

host <hostname>.inside.domusdigitalis.dev

Service Ports

Live port check

nc -zv <ip> <port>

Switch/WLC

Device query

netapi wlc show system / netapi ios run "show version"

ISE

ISE API

netapi ise deployment nodes

Vault

Vault API

vault status

k3s Services

kubectl

kubectl get svc -A -o wide

4. Phase 1: DNS Validation

4.1. 1.1 Get All DNS Records

# Query BIND directly for all A records
dig @bind-01 inside.domusdigitalis.dev AXFR | grep -E "IN\s+A\s+" | head -50

4.2. 1.2 Validate Specific Host

host <hostname>.inside.domusdigitalis.dev
Example
host ise-01.inside.domusdigitalis.dev

4.3. 1.3 Reverse Lookup

host <ip>
Example
host 10.50.1.20

4.4. 1.4 Bulk DNS Validation

for host in ise-01 ise-02 vault-01 vyos-01 nas-01 k3s-master-01; do
  echo -n "$host: "
  host $host.inside.domusdigitalis.dev | awk '{print $NF}'
done

5. Phase 2: Service Port Validation

5.1. 2.1 Single Port Check

nc -zv <ip> <port>
Example
nc -zv 10.50.1.20 443

5.2. 2.2 Multi-Port Check

for port in 443 8443 22 1812 1813; do
  nc -zv 10.50.1.20 $port 2>&1 | grep -E "succeeded|refused"
done

5.3. 2.3 Wazuh Ports

WAZUH_VIP=10.50.1.130
for port in 443 514 1514 1515 9200 55000; do
  echo -n "Port $port: "
  timeout 2 nc -zv $WAZUH_VIP $port 2>&1 | grep -oE "succeeded|refused|timed out" || echo "timeout"
done

5.4. 2.4 ISE Ports

ISE_IP=10.50.1.20
for port in 443 8443 9060 1812 1813; do
  echo -n "Port $port: "
  timeout 2 nc -zv $ISE_IP $port 2>&1 | grep -oE "succeeded|refused" || echo "timeout"
done

6. Phase 3: API Validation

6.1. 3.1 ISE Deployment

dsource d000 dev/network
netapi ise deployment nodes

6.2. 3.2 Vault Status

dsource d000 dev/vault
vault status

6.3. 3.3 VyOS System

ssh vyos-01 "show version"
ssh vyos-01 "show vrrp"

6.4. 3.4 k3s Services with VIPs

ssh k3s-master-01 "kubectl get svc -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,VIP:.status.loadBalancer.ingress[0].ip,PORTS:.spec.ports[*].port'" | grep -v "^NS"

6.5. 3.5 WLC System Info

dsource d000 dev/network
netapi wlc run "show version" | head -20

7. Phase 4: Diagram Audit

7.1. 4.1 Extract IPs from D2

grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' /path/to/diagram.d2 | sort -u

7.2. 4.2 Validate Extracted IPs

grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' /path/to/diagram.d2 | sort -u | while read ip; do
  echo -n "$ip: "
  host $ip 2>/dev/null | awk '{print $NF}' || echo "NO PTR"
done

7.3. 4.3 Compare D2 vs antora.yml

echo "=== IPs in D2 ==="
grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' diagram.d2 | sort -u

echo ""
echo "=== IPs in antora.yml ==="
grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' /home/evanusmodestus/atelier/_bibliotheca/domus-infra-ops/docs/asciidoc/antora.yml | sort -u

8. Phase 5: Advanced Validation Patterns

8.1. 5.1 Parallel DNS Resolution

grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' diagram.d2 | sort -u | \
  xargs -P4 -I{} sh -c 'printf "%-15s %s\n" "{}" "$(host {} 2>/dev/null | awk "{print \$NF}" | head -1)"'

8.2. 5.2 Full Infrastructure Audit (One-Liner)

dig @bind-01 inside.domusdigitalis.dev AXFR | awk '/IN\s+A\s+/ {print $1, $5}' | while read h ip; do printf "%-30s %-15s %s\n" "$h" "$ip" "$(timeout 1 nc -zv $ip 22 2>&1 | grep -oE 'succeeded|refused' || echo 'no-ssh')"; done

8.3. 5.3 Compare D2 IPs vs Live DNS

comm -23 \
  <(grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' diagram.d2 | sort -u) \
  <(netapi pfsense dns list 2>/dev/null | grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' | sort -u) \
  | while read ip; do echo "WARNING: $ip in D2 but not in DNS"; done

8.4. 5.4 Validate All Diagrams in Directory

for d2 in *.d2; do
  echo "=== $d2 ==="
  grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' "$d2" 2>/dev/null | sort -u | \
    xargs -I{} sh -c 'h=$(host {} 2>/dev/null | awk "{print \$NF}" | head -1); [ -z "$h" ] && echo "❌ {} NO PTR" || echo "✓ {} $h"'
done

8.5. 5.5 k3s Service VIP Extraction

ssh k3s-master-01 "kubectl get svc -A -o json" | \
  jq -r '.items[] | select(.status.loadBalancer.ingress) | "\(.metadata.namespace)/\(.metadata.name) \(.status.loadBalancer.ingress[0].ip) \(.spec.ports[].port)"' | \
  column -t

8.6. 5.6 Port Scan with Status Matrix

HOSTS="10.50.1.20 10.50.1.21 10.50.1.60 10.50.1.130"
PORTS="22 443 8443 1514 9200"

printf "%-15s" "IP"
for p in $PORTS; do printf "%-8s" "$p"; done
echo ""

for ip in $HOSTS; do
  printf "%-15s" "$ip"
  for port in $PORTS; do
    timeout 1 nc -z $ip $port 2>/dev/null && printf "%-8s" "✓" || printf "%-8s" "-"
  done
  echo ""
done

8.7. 5.7 ISE Node Validation with netapi

dsource d000 dev/network
netapi ise deployment nodes 2>/dev/null | awk '/│/ && !/─/ {gsub(/│/,""); if(NF>2) print $1, $2, $3}' | column -t

8.8. 5.8 Wazuh VIP Chain Validation

for vip in wazuh wazuh-api wazuh-indexer; do
  ip=$(host $vip.inside.domusdigitalis.dev 2>/dev/null | awk '{print $NF}')
  printf "%-20s %-15s " "$vip" "$ip"
  if [ -n "$ip" ] && [ "$ip" != "3(NXDOMAIN)" ]; then
    timeout 1 nc -z $ip 443 2>/dev/null && echo "✓ HTTPS" || echo "- no HTTPS"
  else
    echo "❌ NO DNS"
  fi
done

9. Phase 6: Validation Script

Save as ~/.local/bin/validate-diagram:

#!/usr/bin/env bash
# Validate D2 diagram IPs against live infrastructure

set -euo pipefail

D2_FILE="${1:?Usage: validate-diagram <file.d2>}"

echo "=== Extracting IPs from $D2_FILE ==="
IPS=$(grep -oE '10\.[0-9]+\.[0-9]+\.[0-9]+' "$D2_FILE" | sort -u)

echo ""
echo "=== Validating against DNS ==="
echo "$IPS" | while read -r ip; do
  printf "%-15s " "$ip"
  result=$(host "$ip" 2>/dev/null | awk '{print $NF}' | head -1)
  if [[ "$result" == *"NXDOMAIN"* ]] || [[ -z "$result" ]]; then
    echo "❌ NO PTR RECORD"
  else
    echo "✓ $result"
  fi
done

echo ""
echo "=== Port Checks ==="
echo "$IPS" | while read -r ip; do
  printf "%-15s " "$ip"
  if timeout 1 nc -z "$ip" 22 2>/dev/null; then
    echo "✓ SSH open"
  elif timeout 1 nc -z "$ip" 443 2>/dev/null; then
    echo "✓ HTTPS open"
  else
    echo "⚠ No common ports responding"
  fi
done

Make executable:

chmod +x ~/.local/bin/validate-diagram

Usage:

validate-diagram docs/asciidoc/modules/ROOT/images/diagrams/wazuh-monitoring-sources.d2

10. Quick Reference

Table 1. Validation Commands
Task Command

All DNS records

dig @bind-01 inside.domusdigitalis.dev AXFR

Forward lookup

host <name>.inside.domusdigitalis.dev

Reverse lookup

host <ip>

Port check

nc -zv <ip> <port>

ISE nodes

netapi ise deployment nodes

k3s services

kubectl get svc -A

Extract D2 IPs

grep -oE '10\.\.[0-9]\.[0-9]+' file.d2

11. Pre-Commit Checklist

Before committing any D2 diagram:

  • All IPs validated via DNS (host command)

  • All ports validated via netcat (nc -zv)

  • Hostnames match BIND DNS records

  • Service names match k3s kubectl get svc output

  • antora.yml attributes match (for documentation consistency)

  • D2 renders without errors (d2 --theme 200 file.d2 file.svg)