Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions .env.default
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,6 @@ DESECSTACK_NSLORD_CARBONSERVER=
DESECSTACK_NSLORD_CARBONOURNAME=
DESECSTACK_NSLORD_DEFAULT_TTL=3600

# nsmaster-related
DESECSTACK_DBMASTER_PASSWORD_pdns=
DESECSTACK_NSMASTER_ALSO_NOTIFY=
DESECSTACK_NSMASTER_APIKEY=
DESECSTACK_NSMASTER_CARBONSERVER=
DESECSTACK_NSMASTER_CARBONOURNAME=
DESECSTACK_NSMASTER_TSIGKEY=

# monitoring
DESECSTACK_WATCHDOG_SECONDARIES=ns1.example.org ns2.example.net
DESECSTACK_PROMETHEUS_PASSWORD=
10 changes: 5 additions & 5 deletions .env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ DESECSTACK_API_PCH_API=https://localhost/pch/api
DESECSTACK_API_PCH_API_TOKEN=insecure
DESECSTACK_DBAPI_PASSWORD_desec=insecure
DESECSTACK_MINIMUM_TTL_DEFAULT=3600
# test
DESECSTACK_DJANGO_TEST=1
DJANGO_SETTINGS_MODULE=api.settings_quick_test

# nslord-related
DESECSTACK_DBLORD_PASSWORD_pdns=insecure
Expand All @@ -34,11 +37,8 @@ DESECSTACK_NSLORD_CARBONSERVER=
DESECSTACK_NSLORD_CARBONOURNAME=
DESECSTACK_NSLORD_DEFAULT_TTL=3600

# nsmaster-related
DESECSTACK_DBMASTER_PASSWORD_pdns=insecure
DESECSTACK_NSMASTER_APIKEY=insecure
DESECSTACK_NSMASTER_CARBONSERVER=
DESECSTACK_NSMASTER_CARBONOURNAME=
# nsmaster-related (Knot DNS; no HTTP API, no Postgres backend)
DESECSTACK_NSMASTER_SOCKET=/run/knot/knot.sock

# monitoring
DESECSTACK_WATCHDOG_SECONDARIES=
Expand Down
8 changes: 2 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ env:
DESECSTACK_DBAPI_PASSWORD_desec: 9Fn33T5yGueeee
DESECSTACK_NSLORD_APIKEY: 9Fn33T5yGukjekwjew
DESECSTACK_NSLORD_DEFAULT_TTL: 1234
DESECSTACK_DBMASTER_PASSWORD_pdns: 9Fn33T5yGukjwelt
DESECSTACK_NSMASTER_ALSO_NOTIFY:
DESECSTACK_NSMASTER_APIKEY: LLq1orOQuXCINUz4TV
DESECSTACK_NSMASTER_TSIGKEY: +++undefined/undefined/undefined/undefined/undefined/undefined/undefined/undefined+++A==
DESECSTACK_IPV4_REAR_PREFIX16: 172.16
DESECSTACK_IPV6_SUBNET: bade:affe:dead:beef:b011::/80
DESECSTACK_IPV6_ADDRESS: bade:affe:dead:beef:b011:0642:ac10:0080
Expand Down Expand Up @@ -62,7 +58,7 @@ jobs:
- name: Build images
uses: ./.github/workflows/build
with:
images: api dbapi nslord nsmaster dblord dbmaster
images: api dbapi nslord nsmaster dblord
- name: Check for missing migrations
run: docker compose run -T api sh -c "./wait-dbapi && python manage.py makemigrations --check"

Expand Down Expand Up @@ -92,7 +88,7 @@ jobs:
- name: Build images
uses: ./.github/workflows/build
with:
images: api dbapi nslord nsmaster dblord dbmaster
images: api dbapi nslord nsmaster dblord
- name: Run API Tests
run: docker compose -f docker-compose.yml -f docker-compose.test-api.yml run -T api bash -c "./entrypoint-tests.sh"
- name: API Tests Logs and Cleanup
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# python virtualenv and test files
.env
.env.dev
api/venv

# IDE files
Expand All @@ -11,6 +12,9 @@ api/venv
# local certificates
/certs/

# Zone export directory (populated at migration time, not tracked)
/zones-export/

# Webapp development files
node_modules
package-lock.json
11 changes: 2 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ deSEC Stack
This is a docker compose application providing the basic stack for deSEC name services. It consists of

- `nslord`: Eventually authoritative DNS server (PowerDNS). DNSSEC keying material is generated here.
- `nsmaster`: Stealth authoritative DNS server (PowerDNS). Receives fully signed AXFR zone transfers from `nslord`. No access to keys.
- `nsmaster`: Intermediary authoritative DNS server (Knot DNS). Receives fully signed AXFR zone transfers from `nslord`. No access to keys.
- `api`: RESTful API to create deSEC users and domains, see [documentation](https://desec.readthedocs.io/).
- `dbapi`, `dblord`, `dbmaster`: Postgres databases for `api` and `nsmaster`, MariaDB database for `nslord`, respectively.
- `dbapi`, `dblord`: Postgres database for `api`, MariaDB database for `nslord`, respectively.
- `www`: nginx instance serving static website content and proxying to `api`
- `celery`: A shadow instance of the `api` code for performing asynchronous tasks (email delivery).
- `rabbitmq`: `celery`'s queue
Expand Down Expand Up @@ -61,13 +61,6 @@ Although most configuration is contained in this repository, some external depen
- `DESECSTACK_NSLORD_CARBONSERVER`: pdns `carbon-server` setting on nslord (optional)
- `DESECSTACK_NSLORD_CARBONOURNAME`: pdns `carbon-ourname` setting on nslord (optional)
- `DESECSTACK_NSLORD_DEFAULT_TTL`: TTL to use by default, including for default NS records
- nsmaster-related
- `DESECSTACK_DBMASTER_PASSWORD_pdns`: mysql password for pdns on nsmaster
- `DESECSTACK_NSMASTER_ALSO_NOTIFY`: Comma-separated list of additional IP addresses to notify of zone updates
- `DESECSTACK_NSMASTER_APIKEY`: pdns API key on nsmaster (required so that we can execute zone deletions on nsmaster, which replicates to the secondaries)
- `DESECSTACK_NSMASTER_CARBONSERVER`: pdns `carbon-server` setting on nsmaster (optional)
- `DESECSTACK_NSMASTER_CARBONOURNAME`: pdns `carbon-ourname` setting on nsmaster (optional)
- `DESECSTACK_NSMASTER_TSIGKEY`: Base64-encoded value of the default TSIG key used for talking to external secondaries (algorithm: HMAC-SHA256)
- monitoring-related
- `DESECSTACK_WATCHDOG_SECONDARIES`: space-separated list of secondary hostnames; used to check correct replication of recent DNS changes
- `DESECSTACK_PROMETHEUS_PASSWORD`: basic auth password for user `prometheus` at `https://${DESECSTACK_DOMAIN}/prometheus/`
Expand Down
7 changes: 2 additions & 5 deletions api/api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@

ROOT_URLCONF = "api.urls"

WSGI_APPLICATION = "desecapi.wsgi.application"
WSGI_APPLICATION = "api.wsgi.application"


DATABASES = {
Expand Down Expand Up @@ -170,12 +170,9 @@
PSL_RESOLVER = os.environ.get("DESECSTACK_API_PSL_RESOLVER")
LOCAL_PUBLIC_SUFFIXES = {"dedyn.%s" % os.environ["DESECSTACK_DOMAIN"]}

# PowerDNS-related
# nslord
NSLORD_PDNS_API = "http://nslord:8081/api/v1/servers/localhost"
NSLORD_PDNS_API_TOKEN = os.environ["DESECSTACK_NSLORD_APIKEY"]
NSMASTER_PDNS_API = "http://nsmaster:8081/api/v1/servers/localhost"
NSMASTER_PDNS_API_TOKEN = os.environ["DESECSTACK_NSMASTER_APIKEY"]
CATALOG_ZONE = "catalog.internal"

# Celery
# see https://docs.celeryproject.org/en/stable/history/whatsnew-4.0.html#latentcall-django-admonition
Expand Down
2 changes: 1 addition & 1 deletion api/desecapi/exception_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def _500():
handlers = {
IntegrityError: _409,
OSError: _500, # OSError happens on system-related errors, like full disk or getaddrinfo() failure.
PDNSException: _500, # nslord/nsmaster returned an error
PDNSException: _500, # nslord returned an error
}

for exception_class, handler in handlers.items():
Expand Down
95 changes: 95 additions & 0 deletions api/desecapi/knot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
Thin wrapper around libknot's control socket for managing zones on nsmaster (Knot DNS).

Replaces the nsmaster-facing functions that previously used the PowerDNS HTTP API:

Old (pdns.py, server=NSMASTER) New (knot.py)
───────────────────────────────── ──────────────────────────────────────────
create_zone_master(name) create_zone(name)
delete_zone_master(name) delete_zone(name)
axfr_to_master(zone) retrieve_zone(name)
get_serials() get_serials()
update_catalog / construct_catalog (removed — Knot updates catalog automatically)
"""

import os

from libknot.control import KnotCtl, KnotCtlType

SOCKET_PATH = os.environ.get("DESECSTACK_NSMASTER_SOCKET", "/run/knot/knot.sock")
SLAVE_TEMPLATE = "slave" # must match template id in knot.conf


def _ctl() -> KnotCtl:
"""Return a connected KnotCtl instance (caller must close it)."""
ctl = KnotCtl()
ctl.connect(SOCKET_PATH)
return ctl


def create_zone(name: str) -> None:
"""Register a new slave zone on nsmaster."""
name = name.rstrip(".") + "."
ctl = _ctl()
try:
ctl.send_block(cmd="conf-begin")
ctl.receive_block()
ctl.send_block(cmd="conf-set", section="zone", identifier=name)
ctl.receive_block()
ctl.send_block(
cmd="conf-set",
section="zone",
identifier=name,
item="template",
data=SLAVE_TEMPLATE,
)
ctl.receive_block()
ctl.send_block(cmd="conf-commit")
ctl.receive_block()
finally:
ctl.send(KnotCtlType.END)
ctl.close()


def delete_zone(name: str) -> None:
"""Remove a slave zone from nsmaster."""
name = name.rstrip(".") + "."
ctl = _ctl()
try:
ctl.send_block(cmd="conf-begin")
ctl.receive_block()
ctl.send_block(cmd="conf-unset", section="zone", identifier=name)
ctl.receive_block()
ctl.send_block(cmd="conf-commit")
ctl.receive_block()
finally:
ctl.send(KnotCtlType.END)
ctl.close()


def retrieve_zone(name: str) -> None:
"""Trigger an AXFR/IXFR retrieval from nslord for the given zone."""
name = name.rstrip(".") + "."
ctl = _ctl()
try:
ctl.send_block(cmd="zone-retransfer", zone=name)
ctl.receive_block()
finally:
ctl.send(KnotCtlType.END)
ctl.close()


def get_serials() -> dict[str, int]:
"""Return {zone_name: serial} for all zones known to nsmaster."""
ctl = _ctl()
try:
ctl.send_block(cmd="zone-status")
data = ctl.receive_block()
return {
zone: int(info.get("serial", 0))
for zone, info in data.items()
if info.get("serial")
}
finally:
ctl.send(KnotCtlType.END)
ctl.close()
72 changes: 0 additions & 72 deletions api/desecapi/management/commands/align-catalog-zone.py

This file was deleted.

4 changes: 2 additions & 2 deletions api/desecapi/management/commands/check-secondaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from django.utils import timezone
import dns.exception, dns.message, dns.query, dns.rdatatype

from desecapi import pdns
from desecapi import knot
from desecapi.models import Domain


Expand Down Expand Up @@ -76,7 +76,7 @@ def handle(self, *args, **options):
).values_list("name", flat=True)
serials = {
zone: s
for zone, s in pdns.get_serials().items()
for zone, s in knot.get_serials().items()
if zone.rstrip(".") in recent_domain_names
}

Expand Down
Loading
Loading