Skip to content

docs: clarify admission export record size and spool retention limits - #4783

Open
ShiyunXu wants to merge 2 commits into
open-policy-agent:masterfrom
ShiyunXu:docs-admission-export-limits
Open

docs: clarify admission export record size and spool retention limits#4783
ShiyunXu wants to merge 2 commits into
open-policy-agent:masterfrom
ShiyunXu:docs-admission-export-limits

Conversation

@ShiyunXu

Copy link
Copy Markdown

What this changes

Documentation-only. Explains the 64 KiB admission export record limit and the disk spool retention behavior, and corrects one inaccurate statement about log rate limiting.

No functional change. Every line changed under pkg/ is a comment:

git diff -U0 origin/master -- pkg/ | grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | grep -vE '^[+-]\s*//' | grep -vE '^[+-]\s*$'

returns nothing.

Why

The existing text says the 64 KiB limit "leaves room for normal policy and request metadata," but never says how much room, so it is hard to tell what would actually exceed it. The limit is easy to misread as applying to the violation message. It does not — it applies to the whole encoded record, and the fields most likely to exhaust it are ones a policy author does not control.

Measured basis for the numbers

To check whether 64 KiB is well chosen, I measured the message templates shipped by gatekeeper-library and modelled full encoded records around them.

Message templates extracted from 48 src.rego files (132 templates):

min p50 p95 max
Template length 5 B 59 B 114 B 269 B

Full encoded ExportMsg built around each template, including constraint identity, request identity, eight resource labels, five constraint annotations, and three user groups:

p50 p95 max
Complete record 1,669 B 1,787 B 1,926 B (2.9% of the limit)

A bare envelope with a one-character message and no labels or annotations is 804 B.

So message content does not approach the limit — roughly 30x headroom on the largest realistic record. What can approach it is the pass-through metadata. Holding everything else fixed, the limit is reached at:

  • ~66 constraint annotations of ~950 B (~61 KiB of annotations); Kubernetes permits up to 256 KiB per object, which is ~3.8x the record limit
  • ~600 resource labels at the 63-character value cap
  • ~1,500 request user groups

That asymmetry is what the new documentation and the constant comment try to make visible, along with its two operational consequences: the condition is systematic per-constraint rather than occasional, and it is silent apart from metrics.

Correction included

website/docs/export.md claimed drop and publish-error logs are limited to "one per minute for each class." There are two limiters, not five: lastDropLog and lastPublishLog (pkg/webhook/export.go). All five drop reasons share lastDropLog, so a queue_full burst suppresses a message_too_large line for the same minute. The bullet now says so and points to the metrics, which do count per reason.

Also documented

The 24-hour spool TTL is effectively unreachable under sustained load. Above roughly ten records per minute the 20-segment count limit evicts segments first, so the spool is a buffer measured in minutes rather than a day of history. Evictions that happen before a reader consumes a segment are not surfaced in ConnectionPodStatus.

Testing

Documentation and comments only; no behavior to test. I was not able to run make lint or go build in the environment where this was written, so please let CI confirm gofmt is happy with the reflowed comment block.

Record the measured basis for the 64 KiB bound and why oversized
records are dropped rather than truncated.

Signed-off-by: ShiyunXu <ShiyunXu@users.noreply.github.com>
Explain what counts toward the 64 KiB record, add spool retention
guidance, and correct the log rate-limit description: all drop
reasons share one limiter, not one per class.

Signed-off-by: ShiyunXu <ShiyunXu@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings August 25, 2026 07:27
@ShiyunXu
ShiyunXu requested a review from a team as a code owner August 25, 2026 07:27
@linux-foundation-easycla

Copy link
Copy Markdown

CLA Not Signed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Clarifies admission export record sizing, spool retention, and rate-limited logging behavior.

Changes:

  • Documents the complete-record 64 KiB limit.
  • Explains disk segment rotation and retention.
  • Corrects shared log-limiter documentation.
Show a summary per file
File Description
website/docs/export.md Expands operational guidance.
pkg/webhook/export.go Documents the record-size bound.
pkg/export/disk/disk.go Clarifies disk segment sizing.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Suppressed comments (5)

website/docs/export.md:163

  • Violation messages are not bounded by the community templates' static text: result.Msg is copied directly into the record and may include arbitrarily large policy-interpolated input. The measured sample supports an ordinary-case estimate, but not the claim that message content cannot exhaust the limit.
In practice a violation record encodes to **around 1.7 KiB**, so the limit is far from ordinary output. Violation messages are not the constraining factor: messages produced by community policy libraries are typically 60–110 bytes and rarely exceed 350 bytes even when a policy interpolates an entire allow-list into the message. The remaining space is the envelope described below.

website/docs/export.md:172

  • The list of unbounded fields omits message, even though policy output is copied without a size bound before the complete record is checked. Include it so the following claim that oversized records arise from one of these fields remains accurate.
| `details` | Returned by the policy itself | Determined by the policy author |

website/docs/export.md:181

  • This troubleshooting advice incorrectly rules out the violation message and also omits details and user groups. Each is copied into ExportMsg without a bound and can independently cause message_too_large, so users need to inspect all large record fields.
If you observe `message_too_large` drops, inspect the annotations on the constraint and the labels on the objects being reviewed rather than the violation message.

website/docs/export.md:187

  • This paragraph gives an unsupported ten-records-per-minute threshold and points to telemetry that cannot detect the stated loss. A continuously active stream already rotates on the one-minute timer, and successful retention eviction increments no metric or status error; the existing admission export metrics only cover queue drops and backend publish outcomes.
At sustained volume the 24-hour age limit is effectively unreachable: once the workload produces more than about ten records per minute, the 20-segment count limit evicts segments first. Treat the spool as a short buffer sized in minutes, not as a day of history. Segments removed before a reader consumes them are not reported in `ConnectionPodStatus`; use the admission export metrics to detect a reader that has fallen behind.

pkg/webhook/export.go:48

  • Being below the segment size guarantees only that the record fits in a fresh segment; writes can still fail because of the total-spool reservation, free-space guard, or I/O errors. Avoid saying it can always be written.
	// driver's per-segment size so a single record can always be written.
  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread website/docs/export.md
The 64 KiB record limit applies to the entire JSON object after encoding, not only to the violation message. JSON field names and escaping, policy-provided details, constraint annotations, resource labels, and request identity all count toward the limit. KiB measures bytes, so the number of characters that fit varies with UTF-8 and JSON escaping. The limit leaves room for normal policy and request metadata while preventing one user-influenced result from consuming a disproportionate share of the queue and disk spool. The `kubectl.kubernetes.io/last-applied-configuration` constraint annotation is omitted, but other annotations still count. An oversized record is dropped before enqueue and reported with drop reason `message_too_large`.
#### Understanding the 64 KiB record limit

The 64 KiB limit applies to the **entire JSON object after encoding**, not only to the violation message. Everything in the record counts: JSON field names and escaping, the constraint identity, policy-provided `details`, constraint annotations, resource labels, and request identity. Because KiB measures bytes, the number of characters that fit varies with UTF-8 and JSON escaping — roughly 64,000 ASCII characters, but only about half that for escape-heavy content and about a quarter for CJK or emoji. Gatekeeper accounts for escaping exactly when it measures a record, so a string of quotes, control characters, or `<`, `>`, and `&` consumes more budget than its raw length suggests.
Comment thread pkg/webhook/export.go
Comment on lines +30 to +44
// A typical record encodes to roughly 1.7 KiB: violation messages in
// community policy libraries top out near 350 bytes, and the surrounding
// envelope of constraint identity, request identity, resource labels, and
// annotations accounts for the rest. 64 KiB therefore accepts a normal
// record with roughly thirty times headroom, so the limit is not reached by
// message content alone.
//
// The headroom exists for the fields this package cannot bound. Constraint
// annotations, resource labels, request user groups, and policy-provided
// details are copied through verbatim, and Kubernetes permits far more
// annotation data on a single object than a record may occupy. Truncating
// those fields would silently misreport a violation, so an oversized record
// is dropped whole and counted under admissionExportDropReasonMessageTooLarge.
// Keeping the bound well above ordinary records makes that outcome a signal
// of unusual metadata rather than routine policy output.
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.

2 participants