Skip to content

[Data governance/Reliability] Govern CDC dead-letter payload retention and replay authority #181

Description

@seonghobae

Buyer / data-governance gap

Protected develop@622e5e6c3d534f230c390f10e3832efadfc01825 configures replica-consumer failure recovery with Spring Kafka DeadLetterPublishingRecoverer and sends exhausted/non-retryable records to <source-topic>.DLT. The repository operations guide advertises this as a real reliability feature, but the repository has no corresponding DLT retention, access-control, encryption, redrive/replay, deletion, or data-classification contract.

This matters because the DLT is not merely a failure counter. Protected KafkaConfig constructs the standard recoverer without a custom producer-record sanitizer/transformer. Spring Kafka's maintained API documents that the default producer-record construction copies the failed consumer record key/value and adds original-record and DLT/exception headers; the framework exposes customization specifically when the contents sent to dead-letter/retry topics must change. Therefore business CDC payload retained for operational recovery can also become a second durable data copy with additional diagnostic metadata.

Primary Spring evidence to reverify at implementation time:

  • Spring for Apache Kafka DeadLetterPublishingRecoverer API (createProducerRecord default copies key/value and adds headers);
  • Spring Kafka reference, Managing Dead Letter Record Headers (original/exception header behavior and growth semantics).

RCA

  • Immediate cause: exhausted/non-retryable replica records are republished to .DLT through the default recoverer behavior.
  • Technical root cause: retry/recovery semantics exist, but durable dead-letter data ownership is not modeled as a governed product boundary.
  • Control failure: KafkaConfigTest proves that a dead-letter recoverer/backoff is configured, but does not prove payload/header classification, retention, ACLs, encryption, redrive authority, deletion, or bounded diagnostic headers; docs/cdc/ops-and-reliability.md names the DLT but contains no lifecycle/control contract.
  • Risk: DLT records can contain the same business/PII-bearing Debezium value/key data required for replay, plus failure/origin metadata. Blanket payload masking is not automatically acceptable because it may destroy recovery utility; the product needs purpose-bound governance instead.

Distinct remediation options / feasibility

Preferred — purpose-bound raw-record DLT with explicit governance

Keep replay-capable record key/value only if operational recovery genuinely requires it, but make the boundary explicit and testable:

  • versioned DLT naming/provisioning policy rather than undocumented accidental lifecycle;
  • bounded topic retention/deletion policy appropriate to supported deployments;
  • least-privilege producer/consumer ACL ownership and tenant/environment separation;
  • encryption in transit and broker/storage controls owned by the deployment profile;
  • explicit classification of key/value and retained original/exception headers;
  • exclude or bound exception stack/message headers when they can contain payload/provider/credential-adjacent diagnostics while retaining stable finite failure classification;
  • auditable redrive/replay authority and idempotency/fencing so replay cannot silently duplicate effects;
  • deletion/incident/runbook semantics and metrics without payload/high-cardinality identifiers.

Alternative — sanitized/quarantine envelope

Publish a bounded quarantine envelope with source identity, digest, stable failure code and an authorized pointer to separately protected payload evidence only if a real governed evidence store exists. Do not invent a new database/object store merely to avoid Kafka retention; this option needs a separately accepted persistence/authority design.

Reject

  • silently discarding payload by masking/truncating it when that prevents valid recovery;
  • retaining raw payload indefinitely with no ownership/retention decision;
  • logging DLT payloads as the diagnostic mechanism;
  • automatic replay without owner authorization, exact source identity, idempotency/fencing and duplicate-effect analysis;
  • assuming the broker's deployment-specific defaults constitute mightyETL's retention/security contract.

TDD / acceptance

Before production mutation, add a fail-first contract at the actual DeadLetterPublishingRecoverer/Kafka record boundary. The accepted design must prove, as applicable:

  1. the exact DLT producer record contents (key/value + allowed headers) are deliberate and bounded;
  2. credentials, JDBC URLs, SQL, raw exception stack/message material, and unrelated headers are not added merely for diagnostics;
  3. business payload remains available only when the selected recovery model explicitly requires it;
  4. DLT topic naming cannot collide across unsupported tenant/environment boundaries;
  5. supported deployment profiles provide an explicit finite retention/deletion policy rather than relying on unspecified broker defaults;
  6. producer/consumer/redrive authority is least-privilege and documented; ordinary app callers cannot invoke replay by knowing a topic name;
  7. redrive/replay uses a reviewed idempotent/fenced contract and does not claim exactly-once where the target cannot prove it;
  8. poison messages cannot loop indefinitely between source and DLT;
  9. topic/record/header size bounds and exception-header growth are handled fail-closed;
  10. observability contains finite outcome/failure classifications without payload, key, row ID, principal, SQL or exception text;
  11. canonical Data Governance/Security/Threat Model/Operability/Architecture/Traceability explains DLT ownership, retention, encryption, access, replay and deletion;
  12. exact-source CI, dependency, SBOM, SAST/security, non-vacuous coverage and review gates pass before protected integration.

Current implementation classification

planned / known_gap. Do not open a source PR until the exact payload-retention/redrive policy is selected from the evidence above and current CDC writer overlap is rechecked. This issue can advance in parallel through documentation/data-governance analysis without racing #139 acknowledgement, #170#174 diagnostics, or connector-retirement work.

Relationship: #139 owns Kafka acknowledgement-before-offset progress; #141 owns graceful CDC stop; #170#176 own diagnostic confidentiality; #159 owns canonical data-governance/operability traceability. This issue owns the durable dead-letter data lifecycle and replay authority, not ordinary logging.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: apiAPI, protocol, event, or external contractarea: authAuthentication, authorization, identity, or tenant isolationarea: dataDatabase, schema, migration, ETL, or lineagearea: securitySecurity boundary, hardening, or vulnerability preventionmaintenancepriority: mediumNormal-priority or P2 workstatus: triagedOpen issue has an organization taxonomy assignmenttype: featureNew or expanded product capability

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions