# Dynu DNS Read-Only Inventory This repository includes a **read-only** Dynu DNS inventory workflow for `lan.ddnsgeek.com`. > This integration is intentionally read-only. No Dynu mutations are permitted in this repo at this stage. ## Scope - Fetch live DNS/domain data from Dynu using **GET requests only**. - Correlate Dynu hostnames with Traefik `Host(...)` rules found in compose files. - Generate local inventory artifacts for documentation. ## Safety Guard Rails - Scripts fail unless `DYNU_READ_ONLY=true`. - No Dynu write methods (`POST`, `PUT`, `PATCH`, `DELETE`) are implemented. - No Terraform Dynu provider/resources/modules are introduced. - No Ansible Dynu mutation tasks are introduced. - API secrets are read from environment variables and are never logged. ## Correlation logic `scripts/dynu/correlate_dynu_with_traefik.py` uses compose files as the source of truth and parses them as YAML. It supports both common label formats: - list style: ```yaml labels: - "traefik.http.routers.app.rule=Host(`app.lan.ddnsgeek.com`)" ``` - map style: ```yaml labels: traefik.http.routers.app.rule: "Host(`app.lan.ddnsgeek.com`)" ``` The parser extracts hostnames from router rules such as: - `Host(`a`)` - `Host("a")` - `Host('a')` - multi-host rules (comma-delimited) - combined expressions such as `Host(...) && PathPrefix(...)` ## Route metadata in inventory Each discovered hostname mapping includes: - fqdn - compose service name - compose file path - stack area (`apps`, `monitoring`, `core`) - router label key(s) - raw router rule - `uses_tls` - `tls_options` - `middlewares` - `uses_mtls` - `uses_authelia` mTLS is metadata only and **never blocks mapping**. ## Validation model The generated JSON/Markdown include a top-level `validation` section with: - `allowed_unmapped_hostnames` - `unexpected_unmapped_hostnames` - `duplicate_hostnames` - `ambiguous_hostnames` - `validation_ok` Current policy: - `edge.lan.ddnsgeek.com` is the only allowed unmapped DNS hostname. - every other `*.lan.ddnsgeek.com` DNS hostname should map to a compose/Traefik-discovered service. Optional strict mode: - Set `DYNU_ENFORCE_VALIDATION=true` to make the correlate script exit non-zero when unexpected unmapped hostnames exist. ## Required Environment Variables - `DYNU_API_KEY` (required for fetch) - `DYNU_BASE_URL` (optional, defaults to `https://api.dynu.com`) - `DYNU_READ_ONLY` (**must** be `true`) Recommended local secrets file (not committed): `secrets/dynu.env` ```bash DYNU_API_KEY=replace-with-real-api-key DYNU_READ_ONLY=true DYNU_BASE_URL=https://api.dynu.com ``` Notes: - Keep values unquoted unless required by your shell. - `scripts/dynu/build_dns_inventory.sh` will auto-load `secrets/dynu.env` when present. ## Commands Run directly: ```bash DYNU_READ_ONLY=true DYNU_API_KEY=... python3 scripts/dynu/fetch_dynu_dns.py DYNU_READ_ONLY=true python3 scripts/dynu/correlate_dynu_with_traefik.py ``` Or run the wrapper: ```bash scripts/dynu/build_dns_inventory.sh ``` ## Artifacts - `data/dns/dynu_live.json` (generated, untracked by default due to repo `data/` ignore) - `data/dns/dynu_traefik_inventory.json` (generated, untracked by default) - `docs/generated/dns-inventory.md` (generated documentation artifact) Because `data/` is gitignored in this repository, JSON outputs are intentionally local-only unless ignore behavior changes in the future. ## Ansible Wrapper (Read-Only) A syntax-safe wrapper playbook is provided at: - `infrastructure/ansible/playbooks/dns-inventory.yml` It only executes the local read-only scripts and does not call write-capable Dynu APIs. ## Not Managed Yet Dynu DNS records are **not** managed by Terraform or Ansible in this repository at this stage. No configuration in this repository sends Dynu mutation requests.