Learning DNS - PowerDNS API & Automation (IaC)
Series/Learning DNS/Episode 20
Episode 20 of 23

Learning DNS - PowerDNS API & Automation (IaC)

This episode covers the PowerDNS REST API: enabling the webserver with an API key, managing zones, records, TSIG, and crypto keys via /api/v1/servers/localhost/zones, provisioning with curl and Python, plus Terraform provider and ExternalDNS integration in Kubernetes.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Every capability you've built — zones, transfers, DNSSEC, dynamic updates — can be fully automated through the PowerDNS REST API. This is what makes database-driven DNS so valuable: DNS infrastructure is managed as code, not through a panel.

Episode 20 opens up the PowerDNS API: enabling it, basic operations with curl, Python scripting, then integration with Terraform and ExternalDNS in Kubernetes. After this episode, you can create zones automatically, create records in seconds, and manage DNS as part of your CI/CD pipeline.

Enabling the REST API

Webserver and API Key

The API lives in the Authoritative webserver. Enable it in pdns.conf:

Aktifkan API di pdns.conf
api=yes
api-key=sekret-api-key-panjang
webserver=yes
webserver-address=127.0.0.1
webserver-port=8081

api=yes enables the REST endpoints; api-key authenticates every call. webserver-address=127.0.0.1 keeps the API accessible only from the machine itself — proxy it through a reverse proxy if needed.

Testing the Connection

All operations run on the base path /api/v1/servers/localhost:

Cek server dan daftar zone
curl -s -H 'X-API-Key: sekret-api-key-panjang' \
  http://127.0.0.1:8081/api/v1/servers
curl -s -H 'X-API-Key: sekret-api-key-panjang' \
  http://127.0.0.1:8081/api/v1/servers/localhost/zones

curl -H 'X-API-Key: ...' is the pattern for every API request. The JSON responses contain the server list for the first call and all zones for the second.

Basic Operations with curl

Creating a Zone

Zones are created with a JSON POST:

Buat zone via API
curl -s -X POST -H 'X-API-Key: sekret-api-key-panjang' \
  -H 'Content-Type: application/json' \
  http://127.0.0.1:8081/api/v1/servers/localhost/zones \
  -d '{"name":"api-demo.example.com","kind":"Primary","masters":[],"nameservers":["ns1.example.com."]}'

Note the zone name format ends with a dot. kind determines the zone type: Primary, Secondary, or Native. The response returns the complete representation of the zone just created.

Adding Records

Add records with a PATCH on the zone endpoint:

Tambah record via API
curl -s -X PATCH -H 'X-API-Key: sekret-api-key-panjang' \
  -H 'Content-Type: application/json' \
  http://127.0.0.1:8081/api/v1/servers/localhost/zones/api-demo.example.com \
  -d '{"rrsets":[{"name":"app.api-demo.example.com","type":"A","ttl":300,"records":[{"content":"192.0.2.40","disabled":false}]}]}'

The rrsets payload contains the RRsets to add or replace. This pattern is used for all records: A, AAAA, MX, TXT, even DNSSEC records like DNSKEY.

TSIG and Crypto Keys

TSIG keys and DNSSEC keys are also managed via the API — the /zones/{zone}/metadata and /zones/{zone}/cryptokeys endpoints:

Daftar crypto keys zone
curl -s -H 'X-API-Key: sekret-api-key-panjang' \
  http://127.0.0.1:8081/api/v1/servers/localhost/zones/api-demo.example.com/cryptokeys

Python Scripting

Automatic Provisioning

With the requests library, provisioning becomes a function callable from any pipeline:

PythonProvisioning zone dengan Python
import requests
 
BASE = "http://127.0.0.1:8081/api/v1/servers/localhost"
HEADERS = {"X-API-Key": "sekret-api-key-panjang"}
 
def create_a_record(zone, name, ip, ttl=300):
    payload = {"rrsets": [{
        "name": f"{name}.{zone}",
        "type": "A",
        "ttl": ttl,
        "records": [{"content": ip, "disabled": False}],
    }]}
    r = requests.patch(f"{BASE}/zones/{zone}", json=payload, headers=HEADERS)
    r.raise_for_status()
 
create_a_record("api-demo.example.com", "web", "192.0.2.41")

The create_a_record function above adds an A record with a single API call. From this simple function, you can build complete tooling: automatic sync, auditing, even an internal self-service portal.

IaC Integration

Terraform Provider

Terraform officially uses the powerdns/pdns provider. With it, entire zones and records are declared as code:

Terraform resource PowerDNS
provider "pdns" {
  api_url  = "http://127.0.0.1:8081"
  api_key  = "sekret-api-key-panjang"
}
 
resource "powerdns_zone" "app" {
  name        = "app.example.com."
  type        = "Primary"
  nameservers = ["ns1.example.com.", "ns2.example.com."]
}
 
resource "powerdns_record" "www" {
  zone    = powerdns_zone.app.name
  name    = "www.app.example.com"
  type    = "A"
  ttl     = 300
  records = ["192.0.2.42"]
}

With Terraform, terraform apply creates zones and records, and terraform destroy removes them — DNS becomes part of versioned, reviewed infrastructure-as-code.

ExternalDNS in Kubernetes

ExternalDNS synchronizes Kubernetes Services and Ingresses to DNS automatically:

Deployment ExternalDNS
kind: Deployment
metadata:
  name: external-dns
spec:
  template:
    spec:
      containers:
        - name: external-dns
          image: registry.k8s.io/external-dns/external-dns:v0.15.1
          args:
            - --source=service
            - --source=ingress
            - --provider=powerdns
            - --pdns-server=http://pdns-api:8081
            - --pdns-api-key=sekret-api-key-panjang
            - --domain-filter=app.example.com

Every annotated Service in the cluster is registered in PowerDNS DNS without human intervention — a perfect example of the autoprovisioning that is a main reason PowerDNS was designed to be database-driven.

Conclusion

Episode 20 turns you into a fully automated DNS operator: enabling the REST API, doing zone and record operations with curl, provisioning via Python, and declaring all of DNS as code with Terraform and ExternalDNS.

Key takeaways:

  • The API is enabled via api=yes and authenticated with api-key.
  • The API base path is /api/v1/servers/localhost.
  • Zones are created with POST, records modified with PATCH rrsets.
  • TSIG and crypto keys can also be managed via the API.
  • The powerdns/pdns Terraform provider makes DNS code.
  • ExternalDNS synchronizes Kubernetes Services and Ingresses to PowerDNS.

In episode 21, we'll cover production-ready stack and deployment — assembling the complete architecture from client to dnsdist, recursor, and authoritative via a database backend, deploying with Docker and Kubernetes, managing TLS certificates with ACME, and upgrading according to PowerDNS EOL policy.

Learning DNS - PowerDNS API & Automation (IaC) | Learning DNS