Cascade: Start your engines!

Cascade: Start your engines!

By Ximon Eighteen

Cascade beta 1 “Slàinte mhath” is out, so this is your opportunity to kick the tires and take it for a spin around your testing grounds!

Cascade is our new purpose built hidden DNSSEC signer. Those lucky enough to be at DNS OARC 46 in Edinburgh in May got a sneak preview and today we're happy to be able to make the beta 1 release available to everyone to test.

🎗️
This is the first in a series of releases where we add improvements that we still have in the pipeline which we consider essential for production use. It will also give us an opportunity to take your feedback on board.

Why are we building a new hidden DNSSEC signer? What about OpenDNSSEC? If you missed the announcement last year, please be aware that OpenDNSSEC will be end-of-life as of October 2027. Until then, no new features will be developed, only critical bug fixes and security updates will be released. Users are encouraged to begin evaluating Cascade.

For those new to Cascade it is a so-called hidden bump-in-the-wire signer like OpenDNSSEC, but written in Rust and updated to match modern operational needs, such as fine grained observability.

Architecturally it looks something like this:

With Cascade we have applied the lessons learned from OpenDNSSEC, use sensible defaults based on current best practices, provide a fresh user interface designed to be clear, transparent and simple for the operator, and offer built-in pre-signing and pre-publication review hook functionality.

In this article we'll take you through what’s changed since the alpha releases, what you can expect from Cascade in this release and what you should factor in to your planning.

Are you testing Cascade or have some thoughts about it? Let us know using our community forum or raise a bug report or feature request on GitHub (and later this year Codeberg, when we have fully migrated).

🧩
If you are currently running an alpha release of Cascade please be aware that the beta release is not backward compatible. Make a backup of your current Cascade installation and start fresh with the beta. Of course this limitation won't apply to production releases of Cascade!

What's changed?

Almost everything you knew about Cascade until now still applies, we worked hard to preserve the user interfaces of the alpha series except where we felt change was clearly needed. However, internally a lot has changed, and of course new functionality has been added.

Compared to alpha-5, beta-1 has approximately:

  • 1.5x as many lines of actual Rust code.
  • 1.75x as many lines of end-user documentation.
  • 2k lines of new integration test code.
  • 221 pull requests merged.
  • 114 issues closed.
  • 7 contributors touched 251 files over 363 commits.
  • In total 125 files changed, 7302 insertions(+), 5882 deletions(-), 47 files removed.

Wow. 😮

All change without change

While you won't see it directly, the most important changes are to the core of Cascade which has been re-written from the ground up. The event producer-consumer architecture has been replaced by a state machine based architecture, ensuring that each zone pipeline is in a single consistent state at all times, resolving the inconsistent state issues observed with the alpha releases.

(almost) Ready to go!

We're getting closer to a production ready release of Cascade, but we're not quite there yet. The beta release adds:

  • Incremental signing.
  • Upstream and downstream TSIG message authentication.
  • Downstream IXFR.
  • Zone and diff persistence.
  • Better compatibility with BIND.
  • Support for missing DNS record types.
  • Extended review functionality.
  • Prometheus metrics.
  • Plus a bunch of smaller fixes and quality of life improvements.
🫶
Thanks to the grants graciously provided by the Sovereign Tech Agency and the Nominet DNS Fund, we were able to build all of this functionality over the last year with a dedicated team of developers. We are eternally grateful for their support, because it lets us bootstrap a brand new open-source project without having to juggle resources. In time, Cascade will be self-sustaining through support agreements with organisations who run our DNSSEC signer in their critical infrastructure.

Now, let's dive into the details...

A new face

One of the key goals of Cascade is to be more transparent and obvious regarding what it is doing. The cascade zone status command of the alpha provided too much information at once, overwhelming the user. The cascade zone status command has been updated in the beta to be more refined, more selective and helpful regarding what it displays and uses layout and colour more effectively to make it easier to see the information being presented.

> cascade zone status example.com
zone: example.com
policy: default
source: /tmp/example.com.zone

review
  loaded: off
  signed: off

last published
  <no versions published yet>

status: idle

An error occurred during the last operation:
    ERROR: the zonefile could not be loaded: 2:5: unknown control: $TT
    Run `cascade zone history example.com` for more information.

As with the alpha using --detailed will also report detailed information about the DNSSEC keys used to sign the zone and information about any rollovers in progress.

One key change is the inclusion of important notices in the cascade zone status output. In this example we see that an attempt to reload the zone from the source failed due to a typo in the zonefile.

This is just the beginning of what we want to achieve with Cascade to make it operator friendly, expect more improvements to come!

Incremental signing

Cascade now has incremental signing which works out of the box. There are a small number of settings in policy that you can tweak, but Cascade ships with sensible defaults.

🪜
What is incremental signing? Incremental signing is only making the minimal changes to the signed zone that are needed to account for changes in the input zone, changes in the signing keys/configuration to use and/or re-generation of signatures nearing expiration.

Why do we need incremental signing?

Cascade was already capable of re-signing a zone to account for changes in the input zone, or at intervals to keep signatures fresh, but only by fully re-signing the entire zone. Every single RRSIG record in the zone had to be discarded and re-created.

For those using an HSM (which unlike OpenDNSSEC is not required with Cascade) this causes a lot of round trips to the HSM which may be slow, and for signatures that don't need to change is completely unnecessary. Even without an HSM it is still desirable to make fewer changes to the signed zone at once as it allows smaller IXFR diffs to be created and served to downstream nameservers. Without incremental signing each IXFR diff would have to replace so many records in the zone that it might not be more efficient than requiring downstream nameservers to retransfer the entire zone via AXFR on every change. And each downstream nameserver would have to process many more records on each update. For smaller zones this may not matter much, but for larger zones, especially with downstream nameservers on unreliable or slow network links, smaller IXFR diffs are an operational necessity.

We can see this speed difference by looking at the timings in the output of the cascade zone history command. First, the time taken to fully sign a zone (in this case one with 21,587,503 records):

2026-06-03T11:32:33Z 2026060326 New version received
2026-06-03T11:32:33Z -          Unsigned zone review approved
2026-06-03T11:33:31Z 2026060300 Signing succeeded (triggered by loading a new instance)

And now the time taken to re-sign that same zone:

2026-06-03T11:34:31Z            Started resign
2026-06-03T11:35:10Z 2026060301 Signing succeeded (triggered by signatures needing refresh)

How much time is needed depends of course on how many changes were made to the zone, but clearly it is going to be faster than re-signing the entire zone.

Unless you set serial policy to "keep" (which is not the default), your zone will automatically be partially re-signed in stages at intervals, ensuring that signatures nearing expiration are refreshed and that the impact of signing is spread out over time. Unlike OpenDNSSEC the spreading out of signature generation is not achieved by means of adding "jitter" to signature expiration timestamps but instead by deterministically refreshing the zone one chunk at a time.

🧐
Why doesn't incremental signing work automatically when using the "keep" serial policy? With "keep" Cascade is not allowed to automatically produce a new version of the zone containing updated signatures as it would need to generate an updated SOA SERIAL number which would conflict with the purpose of the "keep" policy: that you the operator control the SOA SERIAL number at all times. When using "keep" incremental signing will still occur but only when new versions of the source zone (containing an updated SOA SERIAL number) are received, either via XFR from an upstream nameserver or via explicit operator invocation of the cascade zone reload command.

Persistence

Unlike the alpha series, the Cascade beta persists generated IXFR diffs (and the entire signed zone) to disk. On restart of the Cascade daemon the persisted data is reloaded, without which the generated IXFR diffs would have been lost and once again downstream nameservers would be forced to request the entire zone via AXFR, potentially also resulting in a thundering herd of nameservers all trying to fetch the entire zone at the same time!

TSIG message authentication

When accepting or providing zone content via zone transfers operators often want to restrict access to known parties and this is typically done using TSIG message authentication. With the beta Cascade now supports this.

> cascade zone status example.com
zone: example.com
policy: default
source: 127.0.0.1:53 with TSIG key 'my-tsig-key'

review
  loaded: off
  signed: off

last published
  <no versions published yet>

status: loading

• load | serial: <not yet known>
| start time: 2026-06-02T21:31:14 (7s ago)
|
• review loaded zone (disabled)
• sign
• review signed zone (disabled)
• publish

Above we see again our improved cascade zone status output, this time showing that Cascade is configured to authenticate zone transfer from the upstream nameserver source using a specified TSIG key. This example also shows the updated progress reporting while a zone is being loaded.

Adding a TSIG is done using the new cascade tsig add subcommand:

> cascade tsig add my-key-name hmac-sha256 <base64 encoded secret key>
Added TSIG key 'my-key-name'
🔐
For improved security it is also possible to load the secret key from a file instead of via command line argument.

Once a TSIG key has been added it can be referenced using the ^<tsig key name> suffix to the source when adding a zone:

> cascade zone add --source <upstream nameserver IP>^<tsig key name> ...

Downstream IXFR

The Cascade alpha series could receive zone records from an upstream nameserver via IXFR but could not serve IXFR to a downstream nameserver. This is now possible with the beta.

> dig @127.0.0.1 -p 2005 -t IXFR=2026060200 example.com
; <<>> DiG 9.18.49 <<>> @127.0.0.1 -p 2005 -t IXFR=2026060200
; (1 server found)
;; global options: +cmd
example.com.            240     IN      SOA     rusty.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2026060201 28800 7200 604800 240
example.com.            240     IN      SOA     rusty.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2026060200 28800 7200 604800 240
example.com.            240     IN      RRSIG   SOA 13 2 240 20260616214756 20260601214756 28535 example.com. lAc2oopb7vikkd4jKxсбeA==
example.com.            240     IN      SOA     rusty.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2026060201 28800 7200 604800 240
example.com.            240     IN      RRSIG   SOA 13 2 240 20260616214856 20260601214856 28535 example.com. PYpws5rNsK5fL1S+AGXHwg==
example.com.            240     IN      SOA     rusty.nlnetlabs.nl. hostmaster.nlnetlabs.nl. 2026060201 28800 7200 604800 240
;; Query time: 0 msec
;; SERVER: 127.0.0.1#2005(127.0.0.1) (TCP)
;; WHEN: Tue Jun 02 23:49:05 CEST 2026
XFR size: 6 records (messages 1, bytes 634)
An IXFR response from Cascade.

Here we see an IXFR response served by Cascade showing the changes between zone serial 2026060200 and 2026060201.

Better compatibility with BIND

Users reported issues with the alpha when used in combination with upstream and downstream BIND nameserver instances, both relating to DNS NOTIFY messages. These issues have been fixed in the beta release.

Support for missing DNS record types

Support for parsing incoming zone files containing the DNS record types including IPSECKEY, RP, OPENPGPKEY, SSHFP or TLSA has been added in the Cascade beta.

Extended review functionality

Cascade supports the idea of pre-signing and pre-publication customer defined zone review to ensure that loaded and signed zones meet expectations and requirements before being published.

With the alpha versions of Cascade, review was either disabled or automatic via user supplied scripts. The beta extends this model in several ways:

  1. More explicit specification of manual review mode: Policy settings (both for loader and signer) review.required and review.hook_cmd have been replaced by review.mode (off, manual or script) and review.hook.
  2. New review.on-reject policy setting: Setting on-reject to halt in combination with setting mode to script allows an operator to manually inspect a zone when a review script decides to reject it, and either to accept the decision via cascade zone reset or to override it via cascade zone override. Note that while halted no automatic incremental re-signing of the zone will occur so use with care as this can allow signatures to expire!
  3. New subcommand cascade zone maintenance enable: Existing operations such as loading and signing will be allowed to complete but new operations will be blocked, including automatic re-signing of the zone. This allows the operator to be sure that the zone is idle if needed.

Prometheus metrics

Cascade aims to be transparent and easy to monitor. Offering metrics through standard systems like Prometheus is key to that. In the alpha versions of Cascade we set up all of the required scaffolding to expose metrics. Now, with the beta release, we’re providing a basic set of metrics.

To get started, we’re providing zone file related gauges, such as the number of zones configured, loaded and active.

📊
Instead of trying to guess what metrics are essential to each of you, we are keen to hear your input. Let us know on the community forum!

Managing expectations

Let's be honest, how far have we come so far with Cascade?

For smaller zones that don't change very often, like cascade.nlnetlabs.nl, the beta is clearly superior compared to the alpha series and good enough to use in a test environment. We run it in production but we don't advise others to do that just yet.

For larger or more rapidly changing zones however some work is still needed so please try it out, give us your feedback, and note that we are actively developing Cascade so these gaps will be closed and closed soon:

  • For like-for-like functionality memory usage is less than that of the alpha series. However the new incremental signing functionality uses a lot of memory and we need to tune that.
  • Performance has been improved in several areas, but initial full zone signing and signing with an HSM is currently slower than with the alpha series. Our rewrite of the full zone signing code doesn't yet include the parallelized signing ability of the alpha but we're very close to adding that back.
  • The new IXFR downstream support will accumulate diffs ad infinitum. A subsequent beta release will purge diffs beyond some threshold but until then memory and disk usage will grow over time.

Planning for the future

Cascade for production use is coming. Start planning your testing of Cascade if you haven't already. If it's missing something you need or you have questions about it let us know, or raise bug reports and feature requests on GitHub.

The gap between the alpha release and the beta release was longer than we hoped, it was a lot of work, but that work has built a solid foundation. We have addressed the key architectural limitations of the alpha series, with that behind us our dedicated Cascade development team can focus on closing the relatively few remaining gaps between the beta and a production ready release of Cascade.

So, what's left? In no particular order, items left to do include things like:

  • Testing, testing, testing!
  • Documentation, documentation, documentation!
  • Purge no longer needed IXFR outbound diffs.
  • Add missing CLI commands, e.g. cascade hsm remove.
  • Reduce memory usage.
  • Extend the set of Prometheus metrics.
  • Re-parallelize full zone signing.
  • More support for migration from existing signing setups.
  • More insight into what Cascade is doing now and will do in the future.
  • Quality of life improvements.

There are more, we have lots of ideas, but the core of Cascade is basically ready and we are now in the home straight heading for the finish line.

So, get your engines started, it won't be long!