156 lines
9.6 KiB
Markdown
156 lines
9.6 KiB
Markdown
# DNS-Manager
|
|
|
|
A CLI toolset to manage [Bind](https://www.isc.org/bind/) DNS zones and dynamic
|
|
records without hand-editing zone files or reloading Bind manually. It provides
|
|
a small set of commands for day-to-day operations: listing zones, adding and
|
|
deleting zones, and adding, listing and deleting records.
|
|
|
|
Records are read via AXFR zone transfers and written live via DDNS/TSIG, so
|
|
record changes take effect immediately without a reload. Zones are added or
|
|
deleted by writing (or removing) a per-zone `.conf` and zone file, regenerating
|
|
the per-view config that `named.conf` includes, and running `rndc reconfig`.
|
|
Bind itself is inspected and driven through `named-checkconf` and `rndc`.
|
|
|
|
Configuration is keyed by Bind *view* and supports multiple views, optional
|
|
automatic management of catalog-zone membership, and user-defined hooks that run
|
|
around zone and record mutations.
|
|
|
|
## Requirements
|
|
|
|
* [Bind](https://www.isc.org/bind/)
|
|
* [Bind-Tools](https://www.isc.org/bind/) (if not bundled with Bind)
|
|
* [dnspython](https://www.dnspython.org)
|
|
* [prettytable](https://zetcode.com/python/prettytable/)
|
|
* [pyyaml](https://pyyaml.org)
|
|
|
|
A running Bind server and a config file are required to run any command.
|
|
|
|
## Installation
|
|
|
|
Install directly from the git repository:
|
|
|
|
```
|
|
pip install git+ssh://git@git.ccc-rheintal.ch/spacefreak/dns-manager.git
|
|
```
|
|
|
|
## Configuration
|
|
|
|
By default the tools read `/etc/dns-manager/config.yml` (override with `-c`).
|
|
A documented example config is provided in [`files/config.yml`](files/config.yml).
|
|
|
|
The per-view configuration lives under `zones_config`, keyed by Bind view; the
|
|
default view is `_default`. A TSIG key file is mandatory for any non-default view
|
|
(and for any zone that requires a key to transfer or update). A view may also
|
|
define a catalog zone, which is then managed automatically when zones are added
|
|
or deleted.
|
|
|
|
### Top-level options
|
|
|
|
| Option | Default | Description |
|
|
| ----------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
| `etc_dir` | `/etc/dns-manager` | Base config directory; used to derive other defaults. |
|
|
| `named_checkconf` | auto-detected on `PATH` | Path to the `named-checkconf` binary (used to list zones). |
|
|
| `rndc` | `rndc` on `PATH` | Path to the `rndc` binary (used to reconfigure Bind). |
|
|
| `named_conf` | Bind default | Path to `named.conf`, passed to `named-checkconf` when set. |
|
|
| `dns_ip` | `127.0.0.1` | IP address of the DNS server for AXFR and DDNS. |
|
|
| `hooks_dir` | `<etc_dir>/hooks` | Base directory of the [hook](#hooks) tree. |
|
|
| `dns_keyfiles` | — | Map of `view` or `zone@view` → TSIG key file, used for transfers and DDNS updates. **Mandatory for any non-default view** or zone needing a key. The first key found in a file wins. |
|
|
| `control_key` | rndc default key | Key file passed to `rndc -k` when reconfiguring Bind on zone add/delete. |
|
|
| `zones_config` | — | **Mandatory.** Map of Bind view → per-view options (see below). |
|
|
|
|
### Per-view options (`zones_config.<view>`)
|
|
|
|
| Option | Default | Description |
|
|
| ------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| `config_dir` | `<etc_dir>/<view>.zones` | Directory holding one `.conf` per managed zone. |
|
|
| `config_file` | — | **Mandatory.** File included from `named.conf`; every `.conf` in `config_dir` is concatenated into it (Bind cannot wildcard-include). |
|
|
| `zone_dir` | — | **Mandatory.** Directory holding this view's Bind zone files (typically `/etc/bind/dyn` in a single-view setup). |
|
|
| `catalog_zone` | — | Catalog zone (optionally `zone@view`) that will be managed automatically on zone add/delete. Best created manually in Bind to avoid accidental deletion. |
|
|
| `templates.config` | — | Config template used when creating a zone. Required to add a zone unless overridden with `dns-zone-add -t`. |
|
|
| `templates.zone` | — | Zone-file template used when creating a zone. Required to add a zone unless overridden with `dns-zone-add -z`. |
|
|
|
|
## Commands
|
|
|
|
| Command | Description |
|
|
| ------------------- | ------------------------------------------------------ |
|
|
| `dns-list-zones` | List zones (view, status, managed). |
|
|
| `dns-zone-add` | Add a zone (and its catalog member, if configured). |
|
|
| `dns-zone-delete` | Delete a zone (and its catalog member, if configured). |
|
|
| `dns-zone-list` | Show the records of a zone. |
|
|
| `dns-record-add` | Add a record via DDNS. |
|
|
| `dns-record-delete` | Delete a record via DDNS. |
|
|
| `dns-confgen` | Regenerate per-view Bind config and run `rndc reconfig`. |
|
|
|
|
All commands support `--help` for the full list of options.
|
|
|
|
Commands prompt interactively when arguments are omitted and ask for
|
|
confirmation before applying changes. Pass `-b`/`--batch` to require all
|
|
arguments and skip prompts for non-interactive use.
|
|
|
|
## Usage
|
|
|
|
Zones are addressed as `ZONE[@VIEWS]`, where `VIEWS` is a comma-separated list
|
|
of views or `*` for all views. Omitting `@VIEWS` only works when the target is
|
|
unambiguously in the default view. In record names, `@` refers to the zone apex.
|
|
|
|
```
|
|
# List all managed zones
|
|
dns-list-zones
|
|
|
|
# Add a zone
|
|
dns-zone-add example.tld
|
|
|
|
# Show the records of a zone
|
|
dns-zone-list example.tld
|
|
|
|
# Add an A record
|
|
dns-record-add example.tld www 3600 A 192.0.2.1
|
|
```
|
|
|
|
## Hooks
|
|
|
|
Executable scripts placed in the hooks base directory (`hooks_dir`, default
|
|
`<etc_dir>/hooks`) are run around zone and record mutations. The tree narrows
|
|
progressively and every level is optional:
|
|
|
|
```
|
|
hooks/ -> every action and phase (zone+record, add+delete, pre+post)
|
|
zone/ -> all zone actions/phases
|
|
add/ -> zone add, both phases
|
|
pre/ -> zone add, pre only
|
|
post/ -> zone add, post only
|
|
delete/{pre,post}/
|
|
record/
|
|
add/{pre,post}/
|
|
delete/{pre,post}/
|
|
```
|
|
|
|
For a given event `(kind, action, phase)` all matching hooks across every
|
|
existing level along that event's path (`hooks/` → `hooks/<kind>/` →
|
|
`hooks/<kind>/<action>/` → `hooks/<kind>/<action>/<phase>/`) are collected and
|
|
run sorted by filename (run-parts style), so a numeric prefix (e.g. `50-`)
|
|
controls execution order regardless of directory depth. A hook placed shallower
|
|
in the tree fires for more events; distinguish the concrete event via the
|
|
environment variables. Each hook inherits the terminal, so its stdout and stderr
|
|
appear live and in order, and a hook may be interactive: it can print prompts and
|
|
read the user's input from stdin. In batch mode (`-b`) stdin is redirected to
|
|
`/dev/null`, so a hook that reads input gets an immediate EOF instead of blocking
|
|
(hooks that prompt should guard on a tty/EOF).
|
|
Only executable regular files are run; everything else (including the
|
|
`zone`/`record`/`add`/`delete`/`pre`/`post` subdirectories) is skipped, and
|
|
missing directories are no-ops.
|
|
|
|
Each hook receives context via environment variables:
|
|
|
|
* Common env: `DNSMGR_KIND` (zone|record), `DNSMGR_ACTION` (add|delete),
|
|
`DNSMGR_PHASE` (pre|post), `DNSMGR_ZONE` (origin, no trailing dot), `DNSMGR_VIEW`.
|
|
* Record-only env: `DNSMGR_RECORD_NAME`, `DNSMGR_RECORD_TTL`,
|
|
`DNSMGR_RECORD_TYPE`, `DNSMGR_RECORD_VALUE` (values joined by newlines).
|
|
* `DNSMGR_ZONE_FILE` (zone file path): set only for managed zones and not for zone add pre-hooks and not for zone delete post-hooks.
|
|
|
|
A `pre` hook exiting non-zero aborts the operation before any change is applied
|
|
(exit code 190); a `post` hook failure only prints an `ERROR:` and continues.
|
|
|
|
Pass `-n`/`--no-hooks` to `dns-zone-add`, `dns-zone-delete`, `dns-record-add` or
|
|
`dns-record-delete` to skip all hook execution for that run.
|