Skip to content
Back to skills

Powerdns

BSecurity

Expert coverage of the PowerDNS suite (Authoritative Server 5.0, Recursor 5.4, and DNSdist 2.0): pluggable backends (MySQL/PostgreSQL/LDAP), DNSSEC auto-signing, REST API, Lua scripting, views, RPZ threat blocking, YAML configuration, DoH/DoT termination, and DNS load balancing. Use for \"PowerDNS\", \"pdns\", \"pdnsutil\", \"Recursor\", \"DNSdist\", \"PowerDNS API\", \"PowerDNS backend\", \"PowerDNS DNSSEC\". Do NOT use for cross-vendor comparison, platform selection, or category-wide archit...

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
databasesrustgobashsqlnodetestingdebuggingapidatabasefrontend

Works with

  • cursor
  • cli
  • api

Security analysis

B88/100
  • criticalExfiltrates credentials via HTTP — exact pattern from Snyk ToxicSkills study

Pro scans all 2 files and shows the line behind each finding

Scanned September 24, 2026

npx -y skills add chrishuffman5/domain-expert --skill powerdns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Powerdns?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Powerdns
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/chrishuffman5-powerdns/badge)](https://www.skillsdirectory.com/skills/chrishuffman5-powerdns)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: powerdns
description: "Expert coverage of the PowerDNS suite (Authoritative Server 5.0, Recursor 5.4, and DNSdist 2.0): pluggable backends (MySQL/PostgreSQL/LDAP), DNSSEC auto-signing, REST API, Lua scripting, views, RPZ threat blocking, YAML configuration, DoH/DoT termination, and DNS load balancing. Use for \"PowerDNS\", \"pdns\", \"pdnsutil\", \"Recursor\", \"DNSdist\", \"PowerDNS API\", \"PowerDNS backend\", \"PowerDNS DNSSEC\". Do NOT use for cross-vendor comparison, platform selection, or category-wide architecture -- use the `dns` skill."
license: MIT
---

# PowerDNS

This skill covers the PowerDNS suite -- three distinct products with separate roles. Areas of expertise include:

- **Authoritative Server 5.0**: pluggable backends (gmysql, gpgsql, gsqlite3, gldap, bind, pipe, remote), DNSSEC auto-signing with `pdnsutil`, REST API for zone/record CRUD, Lua scripting hooks, views for split-horizon DNS
- **Recursor 5.4**: high-performance recursive resolver, YAML configuration, DNSSEC validation, RPZ (Response Policy Zones) for threat blocking, Lua scripting, serve-stale/serve-expired resilience, conditional forwarding
- **DNSdist 2.0**: DNS load balancer and protocol frontend, YAML configuration (2.0), DoH/DoT/DoQ termination, rate limiting, DDoS protection, query routing rules, DNSdist Defender for advanced threat mitigation

## How to Approach Tasks

1. **Classify** the request:
   - **Authoritative DNS** -- Backend selection, zone management, DNSSEC, API, Lua hooks, views
   - **Recursive resolution** -- Recursor configuration, DNSSEC validation, RPZ, forwarding
   - **Load balancing / Security** -- DNSdist deployment, DoH/DoT, rate limiting, DDoS protection
   - **Architecture** -- Load `references/architecture.md` for component relationships and deployment patterns

2. **Identify component** -- Authoritative, Recursor, or DNSdist. These are separate binaries with separate configurations. Never combine authoritative and recursive in the same PowerDNS instance.

3. **Identify version** -- Auth 5.0 introduces views and enhanced Lua hooks. Recursor 5.2+ uses YAML as recommended config format. DNSdist 2.0 introduces YAML configuration alternative to Lua.

4. **Recommend** -- Provide specific configuration (YAML for Recursor/DNSdist, pdnsutil commands for Auth, API calls for automation).

## Authoritative Server 5.0

### Backend Architecture

PowerDNS Auth does NOT perform recursive lookups. It answers queries for zones it is authoritative for, using pluggable backends:

| Backend | Database | Use Case |
|---|---|---|
| gmysql | MySQL/MariaDB | Most common; production |
| gpgsql | PostgreSQL | Production; advanced SQL |
| gsqlite3 | SQLite3 | Dev/small deployments |
| gldap | LDAP | ISP/hosting with directory |
| bind | Zone files | Legacy compatibility |
| pipe | External process | Custom backends |
| remote | JSON/REST/Unix | Custom resolver integration |

### DNSSEC

Built-in with automated key management:

```bash
pdnsutil secure-zone example.com           # enable DNSSEC
pdnsutil set-nsec3 example.com             # enable NSEC3
pdnsutil show-zone example.com             # view DNSKEY + DS hashes
```

Supported algorithms: ED25519, ED448, ECDSA P-256/P-384, RSA. Online signing with key material stored in database. Auto ZSK rollover; manual KSK rollover with DS publication at parent.

### REST API

Full CRUD for zone and record management:

```bash
# Create zone
curl -X POST http://localhost:8081/api/v1/servers/localhost/zones \
  -H "X-API-Key: secret" \
  -d '{"name":"example.com.","kind":"Native","nameservers":["ns1.example.com."]}'

# Add/replace record
curl -X PATCH http://localhost:8081/api/v1/servers/localhost/zones/example.com. \
  -H "X-API-Key: secret" \
  -d '{"rrsets":[{"name":"www.example.com.","type":"A","ttl":300,
       "changetype":"REPLACE","records":[{"content":"10.1.1.1","disabled":false}]}]}'
```

### Lua Scripting

Dynamic query/response handling via hooks: `preresolve`, `postresolve`, `preaxfr`, `nodata`, `nxdomain`. Use cases: geo-based responses, A/B testing, real-time block lists.

### Views (5.0)

Split-horizon DNS -- different responses based on client source:

```yaml
views:
  internal:
    networks: [10.0.0.0/8, 192.168.0.0/16]
    zones:
      - name: example.com
        backend: gmysql
        database: internal_db
  external:
    networks: [0.0.0.0/0]
    zones:
      - name: example.com
        backend: gmysql
        database: external_db
```

## Recursor 5.4

### YAML Configuration (Recommended)

```yaml
dnssec:
  validate: validate                       # validate | log-fail | off

incoming:
  listen: ["0.0.0.0:53", "[::]:53"]
  allow_from: ["127.0.0.0/8", "192.168.0.0/16"]

forwarding:
  zones:
    - zone: internal.corp
      recurse: false
      forwarders: ["10.0.0.53"]

rpz:
  - name: security-policy
    url: https://rpz.example.com/feed.zone
    defpol: Policy.Drop
    refresh: 300
```

### DNSSEC Validation

Modes: `off`, `process` (log failures), `log-fail` (log + continue), `validate` (strict -- BOGUS = SERVFAIL). Built-in root zone trust anchors with automatic updates.

### RPZ (Response Policy Zones)

DNS-based threat blocking with feed support:
- Actions: NXDOMAIN, DROP, PASSTHRU, NODATA, REDIRECT to walled garden
- Multiple feeds with priority ordering
- Providers: Spamhaus, SURBL, self-managed
- 5.4 feature: `includeSoA` for RPZ zone SOA propagation

### Serve-Stale / Serve-Expired

Return expired cache entries when upstream unreachable. Configurable max-stale age. Essential for DNS resilience during outages.

## DNSdist 2.0

### Architecture

Sits in front of DNS servers providing: load balancing, DoH/DoT/DoQ frontend termination, rate limiting, DDoS protection, query routing.

### YAML Configuration (2.0)

```yaml
listen_addresses:
  - "0.0.0.0:53"
  - "0.0.0.0:853"                          # DoT
  - "0.0.0.0:443"                          # DoH

backends:
  - address: "192.168.1.10:53"
    name: "recursor1"
  - address: "192.168.1.11:53"
    name: "recursor2"

policy: "leastOutstanding"

tls:
  certificates:
    - cert: "/etc/ssl/dns.pem"
      key: "/etc/ssl/dns.key"

doh:
  paths: ["/dns-query"]
  http_version: "h2"
```

### Rules Engine (Lua)

```lua
addAction(MaxQPSIPRule(100), DropAction())                    # rate limit per IP
addAction(QTypeRule(dnsdist.ANY), RCodeAction(dnsdist.REFUSED))  # block ANY queries
addAction(SuffixMatchNodeRule(newSuffixMatchNode({"internal.corp."})),
          PoolAction("internal"))                              # route internal queries
```

### DNSdist Defender

Advanced threat mitigation: DNS tunneling detection, PRSD (pseudo-random subdomain) attack mitigation, amplification/reflection prevention, CEF/syslog threat intelligence export.

### Health Checks and Monitoring

```yaml
backends:
  - address: "192.168.1.10:53"
    name: "recursor1"
    healthcheck: true
    check_interval: 5
```

Built-in web dashboard, Prometheus metrics endpoint, Carbon/Graphite export. Per-backend query statistics, latency percentiles, error rates.

## Deployment Patterns

### Authoritative + Recursor Behind DNSdist

```
Internet ──► DNSdist (port 53, DoH, DoT)
                │
       ┌────────┴────────┐
       │                 │
  Auth Server       Recursor
  (zones you own)   (recursive for clients)
```

DNSdist routes based on zone ownership. Queries for hosted zones go to Auth; everything else goes to Recursor.

### Authoritative with Database Backend

```
DNSdist ──► Auth Server 1 ──► MySQL Primary
                │                    │
            Auth Server 2 ──► MySQL Replica (read)
```

Multiple Auth instances load-balanced by DNSdist. MySQL replication for zone data redundancy. Native zone replication via AXFR/IXFR also supported.

### Recursor with RPZ Threat Blocking

```
Internal clients ──► Recursor
                        ├── RPZ Feed 1 (Spamhaus)
                        ├── RPZ Feed 2 (SURBL)
                        └── RPZ Feed 3 (Custom blocklist)
```

Multiple RPZ feeds loaded with priority ordering. Blocked domains return NXDOMAIN, NODATA, or redirect to walled garden.

### High Availability with DNSdist

```
Anycast VIP ──► DNSdist Active
                    │
                DNSdist Standby (keepalived)
                    │
            ┌───────┴───────┐
            │               │
       Recursor 1      Recursor 2
```

DNSdist HA via keepalived with shared anycast VIP. Backend health checks with automatic failover.

## Authoritative Server Configuration

### pdns.conf Core Settings

```ini
# Backend
launch=gmysql
gmysql-host=127.0.0.1
gmysql-dbname=pdns
gmysql-user=pdns
gmysql-password=secret

# API
api=yes
api-key=changeme
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=10.0.0.0/8

# Performance
receiver-threads=4
distributor-threads=4
cache-ttl=60
query-cache-ttl=60
negquery-cache-ttl=60

# DNSSEC
default-soa-content=ns1.example.com hostmaster.@ 0 10800 3600 604800 300

# Security
allow-axfr-ips=10.0.0.0/8
disable-axfr=no
only-notify=10.0.0.100,10.0.0.101
```

### Zone Management via pdnsutil

```bash
# Create zone
pdnsutil create-zone example.com ns1.example.com

# Add records
pdnsutil add-record example.com www A 300 10.1.1.1
pdnsutil add-record example.com @ MX 300 "10 mail.example.com"
pdnsutil add-record example.com @ TXT 300 "v=spf1 ip4:10.1.1.0/24 -all"

# List zone contents
pdnsutil list-zone example.com

# DNSSEC operations
pdnsutil secure-zone example.com
pdnsutil show-zone example.com
pdnsutil set-nsec3 example.com '1 0 1 -' optout
pdnsutil rectify-zone example.com

# Zone transfer management
pdnsutil increase-serial example.com
```

## Recursor Lua Scripting

### Request Filtering

```lua
function preresolve(dq)
    -- Block specific domain
    if dq.qname:equal(newDN("malware.example.com")) then
        dq.rcode = pdns.NXDOMAIN
        return true
    end

    -- Log all queries from specific subnet
    if dq.remoteaddr:isPartOf(newNMG({"10.100.0.0/16"})) then
        pdnslog("Query from monitored subnet: " .. dq.qname:toString())
    end

    return false
end
```

### Response Modification

```lua
function postresolve(dq)
    -- Add response header for debugging
    if dq.qtype == pdns.A then
        for i, rec in ipairs(dq:getRecords()) do
            pdnslog("Response: " .. rec:getContent())
        end
    end
    return false
end
```

### Geo-Based Responses (Auth Lua)

```lua
function preresolve(dq)
    if dq.qname:equal(newDN("geo.example.com")) then
        local src = dq.remoteaddr:toString()
        -- Route based on source network
        if dq.remoteaddr:isPartOf(newNMG({"10.0.0.0/8"})) then
            dq:addAnswer(pdns.A, "10.1.1.1", 60)
        else
            dq:addAnswer(pdns.A, "203.0.113.1", 60)
        end
        return true
    end
    return false
end
```

## Common Pitfalls

1. **Mixing authoritative and recursive** -- PowerDNS Auth and Recursor are separate products. Never configure recursion on Auth or authoritative zones on Recursor. Use DNSdist to combine them behind a single IP.
2. **DNSSEC without DS at parent** -- Securing a zone with `pdnsutil secure-zone` only signs locally. The DS record must be published at the parent registrar, or DNSSEC validation will fail for resolvers.
3. **RPZ startup race** -- Recursor may serve unprotected queries before RPZ zones finish loading. Enable `servfail-until-ready` for strict RPZ enforcement.
4. **gmysql schema version** -- Auth 5.0 requires updated database schema. Run schema migration scripts before upgrading from 4.x.
5. **DNSdist YAML vs Lua confusion** -- DNSdist 2.0 supports both YAML and Lua configuration. Do not mix them in the same deployment. Choose one format and use consistently.
6. **Recursor YAML migration** -- Recursor 5.2+ recommends YAML but still supports legacy config format. Plan migration to YAML for future compatibility.

## Reference Files

- `references/architecture.md` -- Auth Server (backends, DNSSEC, API), Recursor (RPZ, Lua), DNSdist (LB, DoH/DoT)

Files in this skill

  • SKILL.md11.9 KB
  • references/architecture.md9.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…