DNSSEC Chain & Rollover Monitor avatar

DNSSEC Chain & Rollover Monitor

Pricing

$2.00 / 1,000 successful dnssec domain checks

Go to Apify Store
DNSSEC Chain & Rollover Monitor

DNSSEC Chain & Rollover Monitor

Monitor public domains for DS/DNSKEY chain mismatches, DNSSEC signature expiry, and key-rollover drift with persistent cross-run history.

Pricing

$2.00 / 1,000 successful dnssec domain checks

Rating

0.0

(0)

Developer

Maarten Vreeburg

Maarten Vreeburg

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

6 days ago

Last modified

Categories

Share

Monitor public DNSSEC-signed domains for parent DS / child DNSKEY mismatch, invalid DNSKEY or apex SOA signatures, expiring RRSIG records, recursive-resolver validation failure, and key-rollover drift. Results are structured for Apify schedules, datasets, webhooks, and downstream incident workflows.

This Actor is an independent DNS protocol monitor. It is not affiliated with or endorsed by Cloudflare, ICANN, IANA, any DNS operator, registry, registrar, or DNS provider. The default cloudflare.com target is a public interoperability/QA example only.

Why use it?

A DNSSEC chain can fail even while the zone and nameservers are reachable. A stale parent DS, an incomplete key rollover, or expired signatures can make validating resolvers return SERVFAIL. This Actor gives you a persistent, reviewable observation instead of a one-time checker page.

It does not guarantee availability, global propagation, or complete DNSSEC correctness. One run observes one configured recursive-resolver path. Treat changed, ds_dnskey_mismatch, invalid_signature, bogus_or_servfail, and expiry warnings as review signals and confirm material decisions with your authoritative DNS provider, registrar, and additional independent resolvers.

Input

{
"monitorId": "production-domains",
"domains": [
{
"domain": "example.com",
"label": "Customer portal",
"expectedKeyTags": [12345]
}
],
"warningHours": 24,
"timeoutSeconds": 15,
"maxConcurrency": 3
}
FieldRequiredLimitsPurpose
monitorIdyes1–200 charactersStable namespace for cross-run history. Reuse it on scheduled runs.
domainsyes1–50 unique public FQDNsA string or object containing domain, optional label, and up to 20 expected DNSKEY key tags.
warningHoursno1–720; default 24Warn when the earliest observed DNSKEY/SOA RRSIG expires in less than this window.
timeoutSecondsno3–30; default 15Bound for each DNS query/probe.
maxConcurrencyno1–5; default 3Maximum domains processed concurrently.

The Actor accepts domain names only—not URLs, IP ranges, resolver addresses, arbitrary record types, or credentials.

Output

One dataset row is emitted per domain. Important fields include:

  • status: initial_snapshot, unchanged, changed, or non-billable query_error
  • posture: secure_observed, unsigned, island_of_security, missing_dnskey, ds_dnskey_mismatch, invalid_signature, incomplete_signature_evidence, or indeterminate_digest_policy
  • normalized parent_ds records
  • normalized child_dnskeys with key tags, flags, algorithms, and SHA-256 fingerprints of public DNSKEY wire data (not raw key material)
  • matching_key_tags
  • dnskey_signature_valid and soa_signature_valid
  • earliest_rrsig_expiration, hours_until_earliest_rrsig_expiration, and rrsig_health
  • recursive_validation.status, including secure_ad, insecure_no_ad, bogus_or_servfail, or a bounded probe error
  • authoritative_nameserver and the pinned public authoritative_ip used for child-zone evidence
  • snapshot_hash, previous_snapshot_hash, and changed_fields
  • expected-key-tag matching when configured
  • state_store_mode, charged_event, and a bounded error field

Example:

{
"domain": "cloudflare.com",
"status": "unchanged",
"posture": "secure_observed",
"matching_key_tags": [2371],
"dnskey_signature_valid": true,
"soa_signature_valid": true,
"recursive_validation": {"status": "secure_ad", "ad": true},
"rrsig_health": "ok",
"authoritative_nameserver": "ns3.cloudflare.com",
"authoritative_ip": "162.159.0.33",
"state_store_mode": "named",
"charged_event": "dnssec_domain_check"
}

Key tags and RRSIG expiry times can legitimately change during a healthy rollover or signing cycle. changed means “review the structural chain evidence,” not “outage” or “attack.” Routine movement of only the RRSIG expiration timestamp does not flip the persistent structural status; use rrsig_health and hours_until_earliest_rrsig_expiration for expiry alerting.

Persistence

Successful observations are stored in the explicit named key-value store:

dnssec-chain-rollover-monitor-state-v1

Each state key is a SHA-256 digest of monitorId + domain. Reuse the same monitorId to get initial_snapshot → unchanged → changed behavior across Apify runs. Failed observations do not overwrite the last successful baseline.

Changing monitorId intentionally creates a new baseline. The default run-scoped store is not used for monitor history.

DNSSEC observation model and limitations

For each domain, the Actor:

  1. requests parent DS, resolves authoritative nameservers, blocks non-global destinations, and pins direct public authoritative queries for child DNSKEY and apex SOA evidence with DNSSEC records enabled so a broken chain can still be inspected;
  2. compares supported DS digests to observed DNSKEYs;
  3. cryptographically validates the DNSKEY RRset's self-signature and the apex SOA signature with the observed DNSKEY set;
  4. performs a separate normal recursive-resolver probe and records the AD result or a possible bogus/SERVFAIL outcome;
  5. compares the normalized observation with the previous successful snapshot.

Important boundaries:

  • The Actor does not run a globally distributed resolver network.
  • Parent DS discovery and the recursive AD probe use the runtime resolver; child DNSKEY/SOA signatures come from one pinned public authoritative nameserver.
  • Private, loopback, link-local, reserved, and otherwise non-global authoritative destinations are blocked before any direct query.
  • A recursive bogus_or_servfail response can also reflect an upstream resolver or network failure; confirm independently.
  • secure_observed is deliberately narrower than a guarantee: it proves matching/validating evidence in this observation, not universal propagation or future correctness.
  • The Actor does not modify DNS, registrar settings, trust anchors, or keys.
  • It does not enumerate subdomains or scan IP ranges.
  • Public DNS responses can change between queries during normal cache and rollover windows.

Pricing

The Actor uses pay per event:

  • event: dnssec_domain_check
  • one event per successfully queried, classified, compared, and stored domain observation
  • invalid input and query_error rows are not charged by this custom event

A run-level maximum charge limit is honored before domains are processed and charged.

  • Routine managed DNS: every 1–6 hours
  • Active KSK/ZSK rollover: every 15–60 minutes while respecting your DNS provider's guidance
  • Keep monitorId stable
  • Alert on status = changed, non-secure_observed posture for domains expected to be signed, recursive_validation.status = bogus_or_servfail, or rrsig_health != ok

Local development

python -m venv .venv
.venv/bin/pip install -r requirements.txt
APIFY_LOCAL_STORAGE_DIR="$PWD/storage" .venv/bin/python -m src
.venv/bin/python smoke_test.py
npx --yes apify-cli validate-schema

Run the Actor twice with the same input and storage directory to verify named-store reuse.