feat: add allowed_record_types and enforce append_only as superset check#1
Open
teunis90 wants to merge 1 commit into
Open
feat: add allowed_record_types and enforce append_only as superset check#1teunis90 wants to merge 1 commit into
teunis90 wants to merge 1 commit into
Conversation
661e558 to
2044773
Compare
Two new per-zone options in the proxy config:
**allowed_record_types** (list[str])
Restricts which DNS record types a token may write in a zone.
An empty list (the default) means all types are permitted.
**append_only** (bool)
Prevents any write from removing existing records:
- DELETE changesets are rejected with HTTP 403.
- REPLACE changesets are verified against the live PowerDNS state.
The incoming records must be a strict superset of what is currently
in PowerDNS for that name+type. Any missing record results in a 403.
Both flags can be combined. Example: a token that may only ever add TXT
records globally and can never remove any:
- name: "append-txt-only"
token_sha512: "..."
global_read_only: true
zones:
- name: ".*"
regex: true
allowed_record_types:
- "TXT"
append_only: true
Implementation notes:
- check_rrset_allowed() enforces allowed_record_types and blocks DELETE
for append_only zones (pure, no I/O).
- check_append_only_records_intact() is a new pure helper that compares
existing vs incoming records by content and returns False if any would
be lost.
- ensure_rrsets_request_allowed() gains an optional existing_rrsets param.
When zone.append_only is True, proxy.py fetches the current zone from
PowerDNS and passes the rrsets list in; all policy decisions stay in
config.py.
- 20 new unit tests covering allowed_record_types, append_only, combined
behaviour, and all edge cases of the superset check.
- README updated with documentation for both new zone options.
8db2622 to
27b053d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New zone-level config options
allowed_record_types(list[str])Restricts which DNS record types a token may write in a zone. An empty list (the default) means all types are permitted.
append_only(bool)Prevents any write from removing existing records:
DELETEchangesets are rejected with HTTP 403.REPLACEchangesets are verified against the live PowerDNS state. The incoming records must be a strict superset of what is currently in PowerDNS for that name+type. Any record missing from the payload results in a 403.Both flags can be combined. Example — a token that may only ever add TXT records globally and can never remove any:
Why
changetype: REPLACEneeded extra protectionPowerDNS's
REPLACEchangetype overwrites the entire RRset for a given name+type. Without this check, a client could silently drop existing records by sending a REPLACE with a subset of the current records — even withappend_only: true. The proxy now fetches the current zone state before forwarding any REPLACE on anappend_onlyzone and rejects the request if records would be lost.Implementation
models.pyallowed_record_typesandappend_onlyfields toProxyConfigZoneconfig.py—check_rrset_allowed()append_only; blocks wrong types whenallowed_record_typesis setconfig.py—check_append_only_records_intact()config.py—ensure_rrsets_request_allowed()existing_rrsetsparam; calls the superset check for REPLACE on append_only zonesproxy.py—update_zone_rrset()zone.append_only, passes rrsets toensure_rrsets_request_allowedAll policy logic stays in
config.pyand is fully unit-testable without mocking HTTP.proxy.pyonly does the I/O fetch.Tests
20 new unit tests covering:
allowed_record_types: allowed type, mismatched type, multiple types, no restrictionappend_only: REPLACE allowed, DELETE blocked, DELETE allowed without flagallowed_record_types+append_only: TXT REPLACE allowed, TXT DELETE blocked, wrong type blockedcheck_append_only_records_intact: no existing RRset, exact same records, superset, drops a record, different type, different nameensure_rrsets_request_allowedwithexisting_rrsets: superset passes, drop blocked with 403