You've already forked coredns-powerdns-api-wrapper
89 lines
3.3 KiB
Markdown
89 lines
3.3 KiB
Markdown
# PowerDNS APIs for CoreDNS
|
|
|
|
A Go service exposing the subset of the PowerDNS Authoritative HTTP API that
|
|
acme.sh's `dns_pdns` provider uses, translating rrset operations into the
|
|
MySQL table read by the CoreDNS `mysql` plugin. Contract in one sentence:
|
|
**PowerDNS at the HTTP edge, CoreDNS rows at the DB edge.**
|
|
|
|
## Configuration
|
|
|
|
Configuration is environment variables only — there is no config file.
|
|
|
|
| Variable | Purpose | Default |
|
|
|---|---|---|
|
|
| `PDNS_API_KEY` | Shared secret for `X-API-Key` | *(required, no default)* |
|
|
| `LISTEN_ADDR` | HTTP listen address | `:3000` |
|
|
| `MYSQL_DSN` | Go MySQL DSN (`user:pass@tcp(host:3306)/dbname?parseTime=true`) | *(required)* |
|
|
| `TABLE_PREFIX` | Table name prefix; must mirror the Corefile `table_prefix` directive (e.g. `coredns_`) | `coredns_` |
|
|
| `PDNS_SERVER_ID` | Server id in API paths | `localhost` |
|
|
| `DEFAULT_TTL` | TTL when acme.sh doesn't send one | `120` |
|
|
| `LOG_LEVEL` | `debug` / `info` / `warn` / `error` | `info` |
|
|
| `PUID` | UID to drop privileges to after startup | *(required)* |
|
|
| `PGID` | GID to drop privileges to after startup | *(required)* |
|
|
|
|
Startup fails fast, naming the missing variable, if a required one is absent.
|
|
|
|
## Privilege drop
|
|
|
|
The container starts the binary as root. Before serving any traffic, the
|
|
binary irrevocably drops to `PGID`/`PUID` (`setgroups` → `setgid` → `setuid`).
|
|
The image does **not** declare a `USER` directive — the drop is the binary's
|
|
job, not the container's. If started as a non-root user already, the drop is
|
|
skipped and the process serves as the invoking user.
|
|
|
|
## Running
|
|
|
|
```
|
|
docker run --rm \
|
|
--publish 3000:3000 \
|
|
--env PDNS_API_KEY=changeme \
|
|
--env MYSQL_DSN="coredns:coredns@tcp(127.0.0.1:3306)/coredns?parseTime=true" \
|
|
--env TABLE_PREFIX=coredns_ \
|
|
--env PDNS_SERVER_ID=localhost \
|
|
--env DEFAULT_TTL=120 \
|
|
--env LOG_LEVEL=info \
|
|
--env PUID=1000 \
|
|
--env PGID=1000 \
|
|
git.bjphoster.com/source/coredns-powerdns-api-wrapper:latest
|
|
```
|
|
|
|
`/healthz` is an unauthenticated health check that pings MySQL; it exposes no
|
|
data.
|
|
|
|
## acme.sh usage
|
|
|
|
```
|
|
docker run -it --rm -v ~/acme.sh:/acme.sh \
|
|
-e PDNS_Url="https://your-endpoint" \
|
|
-e PDNS_ServerId="localhost" \
|
|
-e PDNS_Token="$PDNS_API_KEY" \
|
|
-e PDNS_Ttl="120" \
|
|
neilpang/acme.sh --issue --staging --dns dns_pdns \
|
|
-d example.com -d www.example.com
|
|
```
|
|
|
|
For production issuance, drop `--staging` (and optionally add
|
|
`--server letsencrypt`).
|
|
|
|
Implemented API surface, all under `/api/v1`, all requiring `X-API-Key`:
|
|
|
|
- `GET /api/v1/servers/{server_id}/zones`
|
|
- `GET /api/v1/servers/{server_id}/zones/{zone_id}`
|
|
- `PATCH /api/v1/servers/{server_id}/zones/{zone_id}` (rrsets, `REPLACE`/`DELETE`)
|
|
- `PUT /api/v1/servers/{server_id}/zones/{zone_id}/notify`
|
|
|
|
## Propagation / --dnssleep guidance
|
|
|
|
Record writes to an **existing** zone are visible to CoreDNS immediately —
|
|
record lookups hit MySQL live, so no `--dnssleep` is needed for TXT changes.
|
|
Only newly created zones are subject to the Corefile's `zone_update_interval`
|
|
(120s), since that setting only gates the cached zone list. Verified
|
|
empirically; see `docs/SEMANTICS.md`.
|
|
|
|
## Known limitations
|
|
|
|
- Only the acme.sh API slice is implemented: no zone CRUD beyond `GET`, no
|
|
cryptokeys/metadata/search/TSIG, no DNSSEC.
|
|
- This service serves no DNS itself — CoreDNS remains the resolver.
|
|
- rrset types supported for writes: `TXT`, `A`, `AAAA`, `CNAME`, `NS`.
|