Skip to content

feat(dns): govern unattended provider automation - #554

Merged
dviejokfs merged 6 commits into
mainfrom
feat/dns-provider-governance
Aug 6, 2026
Merged

feat(dns): govern unattended provider automation#554
dviejokfs merged 6 commits into
mainfrom
feat/dns-provider-governance

Conversation

@dviejokfs

@dviejokfs dviejokfs commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a fail-closed policy boundary for unattended ACME DNS-01 record publication
  • add dedicated DNS provider read, write, and automation permissions for roles and API keys
  • reject inactive providers before credential decryption or any provider network call
  • bind manual and unattended DNS mutations to verified authoritative zones
  • canonicalize managed zones and fail closed on ambiguous legacy ownership
  • add durable, redacted audit events for governance and publication outcomes
  • resolve managed providers with a bounded, indexed SQL lookup

Security properties

  • missing policy registration denies unattended DNS changes
  • manual DNS setup requires both domain-write and DNS-provider-write authority
  • enabling managed DNS automation requires DNS-automation-write authority
  • disabled provider credentials cannot be decrypted, tested, listed, verified, masked for responses, or used for mutations
  • caller-selected providers must own a verified managed zone covering the certificate domain
  • provider credentials are decrypted only after the exact ACME mutation request is authorized
  • the mutation boundary validates provider identity, authoritative zone, exact ACME owner names, TXT type, and non-empty values
  • policy-provided free-form reasons cannot reach logs or durable audit data
  • ACME values, provider credentials, and URL query secrets remain redacted

Compatibility

Existing custom roles and API keys that relied on settings permissions must be explicitly granted the new DNS permissions. There is intentionally no implicit compatibility bridge because DNS provider access must remain fail-closed.

Evidence

Compile, formatting, and lint

cargo check -p temps-cli -p temps-core -p temps-dns -p temps-domains -p temps-migrations
cargo clippy --all-targets --all-features -- -D warnings
cargo fmt --all -- --check

Results: all exited 0 with no code warnings or errors. Cargo emitted only existing workspace/build notices.

Real PostgreSQL migration lifecycle and query plan

cargo test -p temps-migrations --test normalized_managed_domain_index_test -- --nocapture

Result with Docker access: 1 passed, 0 failed in 5.49s. The test directly executes the migration twice, verifies transaction-local lock and statement timeouts, checks the exact index definition and query plan, executes down, and reapplies up.

HTTP permissions, inactive-provider handling, ambiguity, and audits

cargo test -p temps-dns --test governance_router_test -- --nocapture
cargo test -p temps-domains --test dns_governance_router_test -- --nocapture

Results with Docker access:

  • provider and managed-domain router: 13 passed, 0 failed in 11.73s
  • domain DNS setup router: 4 passed, 0 failed in 7.43s

Coverage includes provider read/write/automation permission combinations, hostname sync authorization before database access, successful mutation audits, inactive-provider no-touch behavior, canonical duplicate conflict handling, ambiguous ownership failure, both setup-DNS permission guards, authoritative-zone wiring, and RFC 7807 responses.

DNS-01 scheduler and authorization ordering

cargo test -p temps-domains --lib dns01_ -- --nocapture

Result with Docker access and loopback ACME/DNS mocks: 4 passed, 0 failed, 1 ignored in 10.73s. The relevant tests exercise the public renewal scheduler, provider discovery, missing/deny/error policy fallback before credential decryption, persisted pending orders, successful TXT cleanup/publication, propagation, finalization, reporting, and redacted audit outcomes. The ignored test is a pre-existing separately gated external integration case.

Credential and audit redaction regressions

cargo test -p temps-dns --lib test_list_zones_transport_failure_redacts_api_key -- --nocapture
cargo test -p temps-dns --lib masked_credentials_for_inactive_provider_fail_before_decryption -- --nocapture
cargo test -p temps-domains --lib does_not_touch_provider -- --nocapture

Results: Namecheap URL-secret redaction 1 passed; inactive masked-credential no-decryption 1 passed; policy reason reflection 2 passed.

Independent review gates

  • security audit: APPROVE, no reproducible findings
  • full PR review: APPROVE, no blocking, major, minor, or nit findings
  • migration and runtime-evidence review: APPROVE

Add a fail-closed policy boundary for background ACME DNS-01 writes, dedicated human permissions, and durable audit coverage.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

📓 Changelog preview

This is what your commits will add to the generated CHANGELOG.md at release time (via git-cliff). Do not edit CHANGELOG.md by hand — it is generated from your Conventional Commit messages.

## [Unreleased]

### Added

- **dns:** Govern unattended provider automation

### Fixed

- **dns:** Close provider governance gaps
- **dns:** Redact Namecheap request values
- **dns:** Enforce provider governance boundaries
- **dns:** Harden automation authorization boundaries

Require provider authority for manual DNS setup, bind automation to verified zones, validate mutation scope, and redact ACME values.
Keep ACME TXT and existing DNS record values out of provider debug logs.
Reject inactive providers before credential use, enforce automation permissions on resulting managed-domain state, and resolve active authoritative zones with an indexed query. Add direct HTTP, scheduler, and migration lifecycle regressions.
@dviejokfs
dviejokfs merged commit c64e8f9 into main Aug 6, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant