<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: When It Runs</title>
    <description>The latest articles on DEV Community by When It Runs (@whenitruns).</description>
    <link>https://dev.to/whenitruns</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4118444%2F36ee0d72-5bca-406c-8725-30649535d244.png</url>
      <title>DEV Community: When It Runs</title>
      <link>https://dev.to/whenitruns</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/whenitruns"/>
    <language>en</language>
    <item>
      <title>When cert-manager's Ready Condition Runs Past Expiry Until a Reconcile</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Sat, 24 Oct 2026 00:21:22 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-cert-managers-ready-condition-runs-past-expiry-until-a-reconcile-4442</link>
      <guid>https://dev.to/whenitruns/when-cert-managers-ready-condition-runs-past-expiry-until-a-reconcile-4442</guid>
      <description>&lt;p&gt;&lt;em&gt;On cert-manager v1.21.2, a renewal-blocked Certificate kept &lt;code&gt;Ready=True&lt;/code&gt; ("Certificate is up to date and has not expired") past &lt;code&gt;notAfter&lt;/code&gt; through our 30-minute window, until a restart reconciled it.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR10&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; cert-manager · the Certificate &lt;code&gt;Ready&lt;/code&gt; condition (readiness controller) after &lt;code&gt;status.notAfter&lt;/code&gt; has passed, when renewal is blocked&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; &lt;em&gt;measured&lt;/em&gt; — cert-manager &lt;strong&gt;v1.21.2&lt;/strong&gt; (the latest release as of 2026-09-11; v1.21.3, released on 2026-10-23, was not measured; single version). &lt;em&gt;reported&lt;/em&gt; — v1.18.2 (issue #7895; a report-layer detail, not measured here). &lt;em&gt;source-read&lt;/em&gt; — the v1.21.2 tag.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; a single-node &lt;code&gt;kind&lt;/code&gt; cluster (node &lt;code&gt;kindest/node:v1.33.4&lt;/code&gt;, digest-pinned) on a dedicated test environment; a SelfSigned &lt;code&gt;Issuer&lt;/code&gt; → a &lt;code&gt;Certificate&lt;/code&gt; (&lt;code&gt;duration: 1h&lt;/code&gt;, &lt;code&gt;renewBefore: 55m&lt;/code&gt;, RSA-2048); renewal blocked by &lt;strong&gt;deleting the Issuer after issuance&lt;/strong&gt; (a block that generates no further events); 30-second polling; an observation window of &lt;strong&gt;≥30 minutes past &lt;code&gt;notAfter&lt;/code&gt;&lt;/strong&gt;; then a controller restart.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-10-23 (desk sources re-checked; PR #8529 open and unmerged, and v1.21.3 the latest release) · lab measured 2026-09-28 on v1.21.2.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; cert-manager v1.21.2 &lt;code&gt;Certificate&lt;/code&gt;s whose renewal is blocked &lt;strong&gt;and whose state produces no further change events&lt;/strong&gt; on the Certificate, its Secret, or its CertificateRequest (measured here: the Issuer was deleted; reported elsewhere: e.g. an ACME DNS01 failure): after &lt;code&gt;status.notAfter&lt;/code&gt; passes, &lt;code&gt;Ready=True&lt;/code&gt; and the message "Certificate is up to date and has not expired" &lt;strong&gt;can remain until the next reconcile&lt;/strong&gt; (an event, the informer resync, or a restart). The length of that window is only what we measured, within this condition.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; On cert-manager v1.21.2, a renewal-blocked 1-hour &lt;code&gt;Certificate&lt;/code&gt; stayed &lt;code&gt;READY=True&lt;/code&gt; with "Certificate is up to date and has not expired" for the whole 30-minute window we watched after the certificate in its Secret had actually expired, and changed to &lt;code&gt;Ready=False&lt;/code&gt; ("Certificate expired on …") only after the controller was restarted, about 34 minutes past expiry — while the API defines &lt;code&gt;Ready&lt;/code&gt; to mean, among other things, "a certificate that has not expired."  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-cert-managers-ready-condition" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-cert-managers-ready-condition&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-cert-managers-ready-condition-runs-past-expiry-until-a-reconcile" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-cert-managers-ready-condition-runs-past-expiry-until-a-reconcile&lt;/a&gt;&lt;/p&gt;

</description>
      <category>certmanager</category>
      <category>kubernetes</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>When an Argo CD App-of-Apps Wave Runs Past a Child With a Missing Resource</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Sat, 17 Oct 2026 19:16:10 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-an-argo-cd-app-of-apps-wave-runs-past-a-child-with-a-missing-resource-4cb</link>
      <guid>https://dev.to/whenitruns/when-an-argo-cd-app-of-apps-wave-runs-past-a-child-with-a-missing-resource-4cb</guid>
      <description>&lt;p&gt;&lt;em&gt;With the documented &lt;code&gt;argoproj.io_Application&lt;/code&gt; health check, Argo CD v3.5.3 started wave 2 while a child missing a resource read &lt;code&gt;Healthy&lt;/code&gt;; on v3.3.14 that child read &lt;code&gt;Missing&lt;/code&gt; and the gate held.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR09&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; Argo CD · the sync-wave gate of an app-of-apps parent — what the parent waits for before it starts the next wave of child Applications, when it uses the Application health check from Argo CD's documentation&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; &lt;em&gt;measured&lt;/em&gt; — Argo CD &lt;strong&gt;v3.5.3&lt;/strong&gt; (the latest release as of 2026-09-26; v3.5.4 and v3.5.5, released on 2026-10-06 and 2026-10-12, were not measured) and &lt;strong&gt;v3.3.14&lt;/strong&gt; (the latest 3.3 release as of 2026-09-26; v3.3.15 and v3.3.16, released on 2026-10-06 and 2026-10-12, were not measured), with identical inputs; both are supported releases. &lt;em&gt;source-read&lt;/em&gt; — &lt;code&gt;controller/health.go&lt;/code&gt; at both tags. The behavior change came in v3.4.0 (pull request #25962).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; a single-node &lt;code&gt;kind&lt;/code&gt; cluster (node &lt;code&gt;kindest/node:v1.33.4&lt;/code&gt;, digest-pinned; a Kubernetes version both releases list as tested), a fresh cluster per release, Argo CD installed from the release's official &lt;code&gt;install.yaml&lt;/code&gt;; in &lt;code&gt;argocd-cm&lt;/code&gt;, the documented &lt;code&gt;argoproj.io_Application&lt;/code&gt; health check plus a health check registered for the kind that fails to apply; a local Git server holding one commit; a parent Application and three child Applications in sync waves 0, 1 and 2 (automated sync); the wave-1 child applies a Job (inner wave 0) and a custom resource whose CRD is not installed (inner wave 1, &lt;code&gt;SkipDryRunOnMissingResource=true&lt;/code&gt;); 10-second polling for 10 minutes.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-10-13 (desk sources re-checked; v3.5.5 was the latest release and v3.3.16 the latest 3.3 release) · lab measured 2026-09-27 on v3.5.3 and v3.3.14.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; Argo CD 3.4 and later (measured: v3.5.3) app-of-apps setups that gate sync waves on child Applications with the documented &lt;code&gt;argoproj.io_Application&lt;/code&gt; health check: a child Application with a resource that failed to apply — of a kind that has a health check, with its dry run skipped — can report &lt;code&gt;Healthy&lt;/code&gt;, and the parent can start the next wave. With the same inputs, v3.3.14 reports that child as &lt;code&gt;Missing&lt;/code&gt; and holds the gate.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; On Argo CD v3.5.3, an app-of-apps parent using the documented Application health check began creating its wave-2 child 6 seconds after the parent was created, while the wave-1 child reported &lt;code&gt;Healthy&lt;/code&gt; with its custom resource (whose CRD is not installed) still unapplied; that resource failed to apply 36 milliseconds later, and the child stayed &lt;code&gt;Healthy&lt;/code&gt; and &lt;code&gt;OutOfSync&lt;/code&gt; for the rest of the 10-minute window. With the same inputs, v3.3.14 reported that child as &lt;code&gt;Missing&lt;/code&gt; and held the gate for the whole window.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-an-argo-cd-app-of-apps-wave" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-an-argo-cd-app-of-apps-wave&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-an-argo-cd-app-of-apps-wave-runs-past-a-child-with-a-missing-resource" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-an-argo-cd-app-of-apps-wave-runs-past-a-child-with-a-missing-resource&lt;/a&gt;&lt;/p&gt;

</description>
      <category>argocd</category>
      <category>kubernetes</category>
      <category>gitops</category>
      <category>devops</category>
    </item>
    <item>
      <title>When a cert-manager Keystore Runs Behind a Password Change</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Sat, 17 Oct 2026 15:10:51 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-a-cert-manager-keystore-runs-behind-a-password-change-3i35</link>
      <guid>https://dev.to/whenitruns/when-a-cert-manager-keystore-runs-behind-a-password-change-3i35</guid>
      <description>&lt;p&gt;&lt;em&gt;cert-manager v1.21.2's API reference: "The keystore file will be updated immediately." After a password change, the keystores opened only with the old password throughout our 30-minute window.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR08&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; cert-manager · the keystore outputs of a &lt;code&gt;Certificate&lt;/code&gt; (&lt;code&gt;spec.keystores.jks&lt;/code&gt; / &lt;code&gt;spec.keystores.pkcs12&lt;/code&gt; with &lt;code&gt;create: true&lt;/code&gt;) — what the keystore entries in the target Secret hold after the keystore password is changed&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; &lt;em&gt;measured&lt;/em&gt; — cert-manager &lt;strong&gt;v1.21.2&lt;/strong&gt; (current supported release; latest as of 2026-09-11; single version). &lt;em&gt;source-read&lt;/em&gt; — the v1.21.2 tag. &lt;em&gt;quoted, not measured&lt;/em&gt; — the same API comment at the v1.10.0 and v1.11.0 tags.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; a single-node &lt;code&gt;kind&lt;/code&gt; cluster (node &lt;code&gt;kindest/node:v1.33.4&lt;/code&gt;, digest-pinned) on a dedicated test environment; a SelfSigned &lt;code&gt;Issuer&lt;/code&gt; → &lt;code&gt;Certificate&lt;/code&gt;s with &lt;code&gt;keystores.jks&lt;/code&gt; and &lt;code&gt;keystores.pkcs12&lt;/code&gt; (&lt;code&gt;profile: Modern2023&lt;/code&gt;), both &lt;code&gt;create: true&lt;/code&gt;; the keystore password supplied through &lt;code&gt;passwordSecretRef&lt;/code&gt; (two Certificates) or the inline &lt;code&gt;password&lt;/code&gt; field (one Certificate); the password changed in place (the referenced Secret updated, the inline field patched); 30-second polling; an observation window of &lt;strong&gt;≥30 minutes&lt;/strong&gt;; then a manual re-issuance with &lt;code&gt;cmctl renew&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-10-13 (desk sources re-checked; cert-manager v1.21.2 was the latest release) · lab measured 2026-09-26 on v1.21.2.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; cert-manager v1.21.2 &lt;code&gt;Certificate&lt;/code&gt;s with &lt;code&gt;keystores.jks&lt;/code&gt; or &lt;code&gt;keystores.pkcs12&lt;/code&gt; set to &lt;code&gt;create: true&lt;/code&gt;: after the keystore password is changed — in the Secret referenced by &lt;code&gt;passwordSecretRef&lt;/code&gt;, or in the inline &lt;code&gt;password&lt;/code&gt; field — the keystore entries in the target Secret stay encrypted with the previous password until the certificate is next issued (observed for the 30-minute window we watched; beyond it, from the source), while the &lt;code&gt;Certificate&lt;/code&gt; stays &lt;code&gt;Ready=True&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; On cert-manager v1.21.2, after the keystore password was changed in the Secret referenced by &lt;code&gt;passwordSecretRef&lt;/code&gt; (or in the inline &lt;code&gt;password&lt;/code&gt; field), &lt;code&gt;keystore.jks&lt;/code&gt; and &lt;code&gt;keystore.p12&lt;/code&gt; in the target Secret still opened only with the old password for the whole 30-minute window we watched, while the &lt;code&gt;Certificate&lt;/code&gt; stayed &lt;code&gt;Ready&lt;/code&gt;; re-issuing the certificate switched them to the new password — yet the API reference says the keystore file "will be updated immediately."  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-a-cert-manager-keystore-runs" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-a-cert-manager-keystore-runs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-a-cert-manager-keystore-runs-behind-a-password-change" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-a-cert-manager-keystore-runs-behind-a-password-change&lt;/a&gt;&lt;/p&gt;

</description>
      <category>certmanager</category>
      <category>kubernetes</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>When Keycloak's Event Store Runs on Defaults Without `enabled_event_types`</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Wed, 14 Oct 2026 21:54:39 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-keycloaks-event-store-runs-on-defaults-without-enabledeventtypes-g8f</link>
      <guid>https://dev.to/whenitruns/when-keycloaks-event-store-runs-on-defaults-without-enabledeventtypes-g8f</guid>
      <description>&lt;p&gt;&lt;em&gt;Keycloak 26.7.4 + keycloak provider v5.9.0, &lt;code&gt;enabled_event_types&lt;/code&gt; omitted ("Omitting this field enables all event types"): the event store kept &lt;code&gt;LOGIN&lt;/code&gt;, not &lt;code&gt;REFRESH_TOKEN&lt;/code&gt;; the log listener got both.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR07&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; Keycloak · realm user-event storage (the event store) — what gets saved when user events are turned on through the keycloak organization's IaC provider (&lt;code&gt;keycloak_realm_events&lt;/code&gt;) with &lt;code&gt;enabled_event_types&lt;/code&gt; left out&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; &lt;em&gt;measured&lt;/em&gt; — Keycloak &lt;strong&gt;26.7.4&lt;/strong&gt; with the keycloak provider &lt;strong&gt;v5.9.0&lt;/strong&gt; (&lt;code&gt;keycloak/terraform-provider-keycloak&lt;/code&gt;; both the latest release as of 2026-09-26; Keycloak 26.7.5, 26.8.0 and 26.8.1, released on 2026-09-30, 2026-10-01 and 2026-10-13, and provider v5.10.0, released on 2026-10-05, were not measured; a single version pair), applied with OpenTofu 1.12.6. &lt;em&gt;source-read&lt;/em&gt; — the Keycloak 26.7.4 and provider v5.9.0 tags.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; the official image &lt;code&gt;quay.io/keycloak/keycloak:26.7.4&lt;/code&gt; (digest-pinned) in &lt;code&gt;start-dev&lt;/code&gt; mode on a dedicated test VM, with the event listener's log category at &lt;code&gt;debug&lt;/code&gt;; through OpenTofu, two realms with &lt;code&gt;keycloak_realm_events&lt;/code&gt; (&lt;code&gt;events_enabled = true&lt;/code&gt;, &lt;code&gt;events_listeners = ["jboss-logging"]&lt;/code&gt;) — &lt;code&gt;enabled_event_types&lt;/code&gt; &lt;strong&gt;left out&lt;/strong&gt; in &lt;code&gt;rr07&lt;/code&gt;, set to four types in the comparison realm &lt;code&gt;rr07-explicit&lt;/code&gt;; in each realm a public client with direct access grants and one user; a successful and a failed password grant, then a successful and a failed refresh-token grant.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-10-13 (desk sources re-checked; Keycloak 26.8.1 and provider v5.10.0 were the latest releases) · lab measured 2026-09-27 on Keycloak 26.7.4 with provider v5.9.0.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; Keycloak 26.7.4 realms whose user-event saving is turned on through the keycloak provider v5.9.0 &lt;code&gt;keycloak_realm_events&lt;/code&gt; resource with &lt;code&gt;enabled_event_types&lt;/code&gt; left out: the event store keeps only Keycloak's default saved types, so &lt;code&gt;REFRESH_TOKEN&lt;/code&gt; and &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt; are not saved (checked 5 and 120 seconds after the requests). Event listeners, such as the &lt;code&gt;jboss-logging&lt;/code&gt; log listener, still receive those events.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; With Keycloak 26.7.4 and the keycloak provider v5.9.0, turning on realm events without &lt;code&gt;enabled_event_types&lt;/code&gt;, which the provider documents as "Omitting this field enables all event types," saved &lt;code&gt;LOGIN&lt;/code&gt; and &lt;code&gt;LOGIN_ERROR&lt;/code&gt; to the event store but not &lt;code&gt;REFRESH_TOKEN&lt;/code&gt; or &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt;, which reached only the log listener.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. The Claim
&lt;/h2&gt;

&lt;p&gt;The claim here is the keycloak organization's own IaC provider documentation, set against what Keycloak's event store actually keeps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the provider documents.&lt;/strong&gt; The keycloak provider (&lt;code&gt;keycloak/terraform-provider-keycloak&lt;/code&gt;, used from Terraform or OpenTofu) documents the &lt;code&gt;enabled_event_types&lt;/code&gt; field of its &lt;code&gt;keycloak_realm_events&lt;/code&gt; resource as follows (&lt;code&gt;docs/resources/realm_events.md&lt;/code&gt; at the v5.9.0 tag, L45; checked 2026-09-26):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"&lt;code&gt;enabled_event_types&lt;/code&gt; - (Optional) The event types that will be saved to the database. Omitting this field enables all event types. Defaults to &lt;code&gt;[]&lt;/code&gt; or all event types."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The example on the same page carries the comment &lt;em&gt;"When omitted or left empty, keycloak will enable all event types"&lt;/em&gt; (L26), and describes &lt;code&gt;events_enabled&lt;/code&gt; as: &lt;em&gt;"When &lt;code&gt;true&lt;/code&gt;, events from &lt;code&gt;enabled_event_types&lt;/code&gt; are saved to the database, making them available through the admin console. Defaults to &lt;code&gt;false&lt;/code&gt;."&lt;/em&gt; (L43).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How the default is commonly read.&lt;/strong&gt; A third-party Keycloak auditing guide (skycloak.io; published 2026-06-15, updated 2026-09-07; checked 2026-09-26) describes the same setting in the admin console the same way: &lt;em&gt;"The default is all types; for a lean DB footprint, select only the types you actively query."&lt;/em&gt; The same guide later suggests alerting on &lt;em&gt;"Spikes in &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt; or &lt;code&gt;CODE_TO_TOKEN_ERROR&lt;/code&gt;"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Keycloak documents.&lt;/strong&gt; Keycloak's server administration guide presents the saved event types as a list you add to — &lt;em&gt;"Click *Add saved types&lt;/em&gt; to see other events you can save."* (&lt;code&gt;docs/documentation/server_admin/topics/events/login.adoc&lt;/code&gt; L20, 26.7.4) — and the &lt;code&gt;EventType&lt;/code&gt; Javadoc describes &lt;code&gt;isSaveByDefault()&lt;/code&gt; as: &lt;em&gt;"Determines whether this event is stored when the admin has not set a specific set of event types to save."&lt;/em&gt; So Keycloak does say that an empty setting means a default subset. The gap this report looks at is between that behavior and the provider's "Omitting this field enables all event types."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it would behave that way (source layer).&lt;/strong&gt; In Keycloak 26.7.4, &lt;code&gt;EventBuilder.sendNow&lt;/code&gt; (&lt;code&gt;server-spi-private/src/main/java/org/keycloak/events/EventBuilder.java&lt;/code&gt; L261–277) stores an event only if:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eventTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getType&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;isSaveByDefault&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;eventTypes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getType&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;— that is, when the realm's list of saved types is empty, only types flagged "save by default" go to the event store. Then, outside that condition, every configured event listener receives the event (L270–276). In &lt;code&gt;EventType.java&lt;/code&gt;, &lt;code&gt;LOGIN(0, true)&lt;/code&gt; (L29) and &lt;code&gt;LOGIN_ERROR&lt;/code&gt; (L30) are flagged &lt;code&gt;true&lt;/code&gt;, while &lt;code&gt;REFRESH_TOKEN(5, false)&lt;/code&gt; (L42) and &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt; (L43) are flagged &lt;code&gt;false&lt;/code&gt;. When the list is empty, &lt;code&gt;GET …/events/config&lt;/code&gt; answers with the default-saved types filled in rather than an empty list (&lt;code&gt;RealmAdminResource.java&lt;/code&gt; L845–850). On the provider side (v5.9.0), omitting &lt;code&gt;enabled_event_types&lt;/code&gt; sends an empty list (&lt;code&gt;provider/resource_keycloak_realm_events.go&lt;/code&gt; L60; the API field &lt;code&gt;enabledEventTypes&lt;/code&gt; has no &lt;code&gt;omitempty&lt;/code&gt;, &lt;code&gt;keycloak/realm_events.go&lt;/code&gt; L11), and the field is read back into state only when it is set in the configuration (L94) — which suggests &lt;code&gt;tofu plan&lt;/code&gt; would report no difference, something we checked in the lab (§3).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this report tests.&lt;/strong&gt; When realm events are turned on through &lt;code&gt;keycloak_realm_events&lt;/code&gt; with &lt;code&gt;enabled_event_types&lt;/code&gt; left out — which the provider documents as "Omitting this field enables all event types" — does Keycloak save all event types, or only its default saved types, leaving &lt;code&gt;REFRESH_TOKEN&lt;/code&gt; (success and error) and similar events out of the event store? The event store is what the admin console's &lt;em&gt;Events&lt;/em&gt; tab, the admin REST events API, and the event database table show. Event listeners are a separate path: per the source above they receive every event regardless of the saved types, and we observed the &lt;code&gt;jboss-logging&lt;/code&gt; listener separately (§3).&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Environment:&lt;/strong&gt; a dedicated test VM with Docker; Keycloak from the official image &lt;code&gt;quay.io/keycloak/keycloak:26.7.4&lt;/code&gt;, pinned by digest (&lt;code&gt;sha256:82a77884f3af238beab1e7afd63b5f530e1b5c0590bd7aa60b40a40463e29b2c&lt;/code&gt;; the linux/amd64 image in it, &lt;code&gt;sha256:3d911baa186f352563854039b95f21a7e2c01c76b527fdc64f24a0885b927bdf&lt;/code&gt;, is what ran), started with &lt;code&gt;start-dev&lt;/code&gt; and the bootstrap-admin variables from Keycloak's container guide. The log level is &lt;code&gt;INFO,org.keycloak.events:debug&lt;/code&gt;: &lt;code&gt;org.keycloak.events&lt;/code&gt; is the category of the &lt;code&gt;jboss-logging&lt;/code&gt; event listener, which logs successful events at &lt;code&gt;debug&lt;/code&gt; by default, so this makes its success lines visible; it does not change what the event store keeps. &lt;code&gt;curl&lt;/code&gt; 8.5.0 and &lt;code&gt;jq&lt;/code&gt; 1.7 for the REST calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version:&lt;/strong&gt; Keycloak &lt;strong&gt;26.7.4&lt;/strong&gt; · the keycloak provider &lt;strong&gt;v5.9.0&lt;/strong&gt; (release asset &lt;code&gt;terraform-provider-keycloak_5.9.0_linux_amd64.zip&lt;/code&gt;, sha256 matching the release's SHA256SUMS) · OpenTofu &lt;strong&gt;1.12.6&lt;/strong&gt; (release asset sha256 matching its SHA256SUMS). A single version pair.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration:&lt;/strong&gt; one OpenTofu configuration (§4) creating two realms. In &lt;code&gt;rr07&lt;/code&gt;, &lt;code&gt;keycloak_realm_events&lt;/code&gt; sets &lt;code&gt;events_enabled = true&lt;/code&gt; and &lt;code&gt;events_listeners = ["jboss-logging"]&lt;/code&gt; and &lt;strong&gt;leaves &lt;code&gt;enabled_event_types&lt;/code&gt; out&lt;/strong&gt;. In &lt;code&gt;rr07-explicit&lt;/code&gt;, it is the same except &lt;code&gt;enabled_event_types = ["LOGIN", "LOGIN_ERROR", "REFRESH_TOKEN", "REFRESH_TOKEN_ERROR"]&lt;/code&gt;. &lt;code&gt;events_listeners&lt;/code&gt; is set explicitly in both, as in the provider's own example. Each realm has a public client &lt;code&gt;rr07-app&lt;/code&gt; with direct access grants and a user &lt;code&gt;alice&lt;/code&gt; with a dummy password. In each realm, in the same order: a successful password grant (&lt;code&gt;LOGIN&lt;/code&gt;), a password grant with a wrong password (&lt;code&gt;LOGIN_ERROR&lt;/code&gt;), a successful refresh-token grant (&lt;code&gt;REFRESH_TOKEN&lt;/code&gt;), and a refresh-token grant with an altered token (&lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt;). The event store is queried 5 seconds and 120 seconds after the last request.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Expected vs. Observed — with &lt;code&gt;enabled_event_types&lt;/code&gt; left out, which events does the event store keep?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Expected&lt;/strong&gt; (from the provider documentation): "Omitting this field enables all event types" — so in &lt;code&gt;rr07&lt;/code&gt; all four event types would be saved, the same as in &lt;code&gt;rr07-explicit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observed&lt;/strong&gt; (Keycloak 26.7.4 with provider v5.9.0 via OpenTofu 1.12.6, measured 2026-09-27; all times UTC; raw in our lab record):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Apply, then plan:&lt;/strong&gt; &lt;code&gt;tofu apply&lt;/code&gt; created the eight resources — "Apply complete! Resources: 8 added, 0 changed, 0 destroyed." — and &lt;code&gt;tofu plan -detailed-exitcode&lt;/code&gt; right after it exited &lt;code&gt;0&lt;/code&gt; with "No changes. Your infrastructure matches the configuration." Run again after the requests, it again exited &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The saved types the server reports (&lt;code&gt;GET …/events/config&lt;/code&gt;):&lt;/strong&gt; for &lt;code&gt;rr07&lt;/code&gt;, &lt;code&gt;eventsEnabled: true&lt;/code&gt;, &lt;code&gt;eventsListeners: ["jboss-logging"]&lt;/code&gt;, and an &lt;code&gt;enabledEventTypes&lt;/code&gt; list of 103 types that includes &lt;code&gt;LOGIN&lt;/code&gt; and &lt;code&gt;LOGIN_ERROR&lt;/code&gt; but not &lt;code&gt;REFRESH_TOKEN&lt;/code&gt; or &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt; — the list the server returns when the realm's own list is empty (§1); for &lt;code&gt;rr07-explicit&lt;/code&gt;, the four listed types.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The requests&lt;/strong&gt; (23:03:37–23:03:39): in both realms, the password grant returned HTTP 200; the wrong password, 400 &lt;code&gt;invalid_grant&lt;/code&gt; ("Invalid user credentials"); the refresh, 200; the altered refresh token, 400 &lt;code&gt;invalid_grant&lt;/code&gt; ("Invalid refresh token").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The event store (&lt;code&gt;GET /admin/realms/&amp;lt;realm&amp;gt;/events&lt;/code&gt;, at +5 s and +120 s):&lt;/strong&gt; the same at both times — &lt;code&gt;rr07&lt;/code&gt; held two events, one &lt;code&gt;LOGIN&lt;/code&gt; and one &lt;code&gt;LOGIN_ERROR&lt;/code&gt;, and no &lt;code&gt;REFRESH_TOKEN&lt;/code&gt; or &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt;; &lt;code&gt;rr07-explicit&lt;/code&gt; held one of each of the four.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The listener (the &lt;code&gt;jboss-logging&lt;/code&gt; lines in the container log):&lt;/strong&gt; in both realms, one line for each of the four types — &lt;code&gt;LOGIN&lt;/code&gt; and &lt;code&gt;REFRESH_TOKEN&lt;/code&gt; at &lt;code&gt;DEBUG&lt;/code&gt;, &lt;code&gt;LOGIN_ERROR&lt;/code&gt; and &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt; at &lt;code&gt;WARN&lt;/code&gt; (the latter with &lt;code&gt;error="invalid_token"&lt;/code&gt; and &lt;code&gt;reason="Invalid refresh token"&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raw evidence: the OpenTofu output, the &lt;code&gt;events/config&lt;/code&gt; responses, each request with its HTTP status and response, the event-store responses at both query times, and the container log, all kept in our lab record.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Reproduction
&lt;/h2&gt;

&lt;p&gt;The minimal reproduction (raw output is kept in our lab record; the configuration and the commands below are in the reproduction repo linked below). All times UTC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 0. Start Keycloak 26.7.4 (official image, digest-pinned) in dev mode, with the event listener's&lt;/span&gt;
&lt;span class="c"&gt;#    log category at debug so its success lines are visible, and wait until it has started.&lt;/span&gt;
&lt;span class="c"&gt;#      docker run -d --name rr07-kc -p 8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=change_me quay.io/keycloak/keycloak:26.7.4@sha256:82a77884f3af238beab1e7afd63b5f530e1b5c0590bd7aa60b40a40463e29b2c start-dev --log-level="INFO,org.keycloak.events:debug"&lt;/span&gt;
&lt;span class="c"&gt;#      for i in $(seq 1 60); do docker logs rr07-kc 2&amp;gt;&amp;amp;1 | grep -E 'Keycloak 26\.7\.4 on JVM .* started' &amp;amp;&amp;amp; break; sleep 3; done   # the startup line, at most 3 minutes&lt;/span&gt;

&lt;span class="c"&gt;# 1. Apply the OpenTofu configuration below (main.tf; OpenTofu 1.12.6, provider keycloak/keycloak 5.9.0),&lt;/span&gt;
&lt;span class="c"&gt;#    then check for drift right away (exit code 0 = no changes, 2 = changes).&lt;/span&gt;
&lt;span class="c"&gt;#      tofu init&lt;/span&gt;
&lt;span class="c"&gt;#      tofu apply -auto-approve&lt;/span&gt;
&lt;span class="c"&gt;#      tofu plan -detailed-exitcode&lt;/span&gt;

&lt;span class="c"&gt;# 2. Read the saved types the server reports for each realm (admin token from the master realm).&lt;/span&gt;
&lt;span class="c"&gt;#      TOKEN=$(curl -s -d grant_type=password -d client_id=admin-cli -d username=admin -d password=change_me http://localhost:8080/realms/master/protocol/openid-connect/token | jq -r .access_token)&lt;/span&gt;
&lt;span class="c"&gt;#      curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8080/admin/realms/rr07/events/config | jq .&lt;/span&gt;
&lt;span class="c"&gt;#      curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8080/admin/realms/rr07-explicit/events/config | jq .&lt;/span&gt;

&lt;span class="c"&gt;# 3. Generate the four events in each realm (run once with REALM=rr07, then with REALM=rr07-explicit).&lt;/span&gt;
&lt;span class="c"&gt;#      T=http://localhost:8080/realms/$REALM/protocol/openid-connect/token&lt;/span&gt;
&lt;span class="c"&gt;#      RT=$(curl -s -d grant_type=password -d client_id=rr07-app -d username=alice -d password=alice-pass-1 $T | jq -r .refresh_token)   # LOGIN&lt;/span&gt;
&lt;span class="c"&gt;#      curl -s -d grant_type=password -d client_id=rr07-app -d username=alice -d password=wrong-password $T                                  # LOGIN_ERROR&lt;/span&gt;
&lt;span class="c"&gt;#      curl -s -d grant_type=refresh_token -d client_id=rr07-app -d refresh_token="$RT" $T                                                   # REFRESH_TOKEN&lt;/span&gt;
&lt;span class="c"&gt;#      curl -s -d grant_type=refresh_token -d client_id=rr07-app -d refresh_token="${RT}x" $T                                                # REFRESH_TOKEN_ERROR (altered token)&lt;/span&gt;

&lt;span class="c"&gt;# 4. Query each realm's event store 5 seconds and 120 seconds after the last request (fresh admin token each time).&lt;/span&gt;
&lt;span class="c"&gt;#      TOKEN=$(curl -s -d grant_type=password -d client_id=admin-cli -d username=admin -d password=change_me http://localhost:8080/realms/master/protocol/openid-connect/token | jq -r .access_token)&lt;/span&gt;
&lt;span class="c"&gt;#      for REALM in rr07 rr07-explicit; do echo "== $REALM"; curl -s -H "Authorization: Bearer $TOKEN" "http://localhost:8080/admin/realms/$REALM/events?max=100" | jq -r '.[].type' | sort | uniq -c; done&lt;/span&gt;

&lt;span class="c"&gt;# 5. Look at what the jboss-logging listener wrote for the same requests.&lt;/span&gt;
&lt;span class="c"&gt;#      docker logs --timestamps rr07-kc 2&amp;gt;&amp;amp;1 | grep 'org.keycloak.events'&lt;/span&gt;

&lt;span class="c"&gt;# 6. Tear down (the test container only).&lt;/span&gt;
&lt;span class="c"&gt;#      docker rm -f rr07-kc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The OpenTofu configuration for step 1 (&lt;code&gt;main.tf&lt;/code&gt;), exactly as we applied it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;keycloak&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"keycloak/keycloak"&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"5.9.0"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"keycloak"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"admin-cli"&lt;/span&gt;
  &lt;span class="nx"&gt;username&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"admin"&lt;/span&gt;
  &lt;span class="nx"&gt;password&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"change_me"&lt;/span&gt;
  &lt;span class="nx"&gt;url&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"http://localhost:8080"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Realm rr07: user events on, enabled_event_types left out.&lt;/span&gt;
&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"keycloak_realm"&lt;/span&gt; &lt;span class="s2"&gt;"rr07"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;realm&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rr07"&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"keycloak_realm_events"&lt;/span&gt; &lt;span class="s2"&gt;"rr07"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;realm_id&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keycloak_realm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rr07&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;events_enabled&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;events_listeners&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jboss-logging"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Realm rr07-explicit: the same, with the four types listed.&lt;/span&gt;
&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"keycloak_realm"&lt;/span&gt; &lt;span class="s2"&gt;"rr07_explicit"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;realm&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rr07-explicit"&lt;/span&gt;
  &lt;span class="nx"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"keycloak_realm_events"&lt;/span&gt; &lt;span class="s2"&gt;"rr07_explicit"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;realm_id&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keycloak_realm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rr07_explicit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;events_enabled&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;events_listeners&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"jboss-logging"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;enabled_event_types&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"LOGIN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"LOGIN_ERROR"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"REFRESH_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"REFRESH_TOKEN_ERROR"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# In each realm: a public client with direct access grants, and one user.&lt;/span&gt;
&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;realm_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"rr07"&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keycloak_realm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rr07&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
    &lt;span class="s2"&gt;"rr07-explicit"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keycloak_realm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rr07_explicit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"keycloak_openid_client"&lt;/span&gt; &lt;span class="s2"&gt;"app"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;realm_ids&lt;/span&gt;
  &lt;span class="nx"&gt;realm_id&lt;/span&gt;                     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="nx"&gt;client_id&lt;/span&gt;                    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rr07-app"&lt;/span&gt;
  &lt;span class="nx"&gt;access_type&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"PUBLIC"&lt;/span&gt;
  &lt;span class="nx"&gt;standard_flow_enabled&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;direct_access_grants_enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"keycloak_user"&lt;/span&gt; &lt;span class="s2"&gt;"alice"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;realm_ids&lt;/span&gt;
  &lt;span class="nx"&gt;realm_id&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="nx"&gt;username&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"alice"&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"alice@example.com"&lt;/span&gt;
  &lt;span class="nx"&gt;email_verified&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;first_name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Alice"&lt;/span&gt;
  &lt;span class="nx"&gt;last_name&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Example"&lt;/span&gt;

  &lt;span class="nx"&gt;initial_password&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;value&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"alice-pass-1"&lt;/span&gt;
    &lt;span class="nx"&gt;temporary&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outputs for each step land in §3 (above) and our lab record.&lt;/p&gt;

&lt;p&gt;A recorded run of this reproduction: &lt;a href="https://youtu.be/yFowKYN7kcw" rel="noopener noreferrer"&gt;https://youtu.be/yFowKYN7kcw&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reproduction repo: &lt;a href="https://github.com/whenitruns/when-keycloaks-event-store-runs-on-defaults-without-enabled-event-types" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-keycloaks-event-store-runs-on-defaults-without-enabled-event-types&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Impact
&lt;/h2&gt;

&lt;p&gt;An audit that relies on the event store — the admin console's &lt;em&gt;Events&lt;/em&gt; tab, the admin REST events API, or the event database table — has no record of refresh-token activity, successful or failed, in a realm whose events were turned on through this provider with &lt;code&gt;enabled_event_types&lt;/code&gt; left out — in our run, neither event type was stored. The belief this quietly breaks is &lt;em&gt;"the provider says omitting the list saves all event types, so refresh-token failures would be there."&lt;/em&gt; An investigator who finds no &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt; entries can read that as "no refresh failures happened." The log-listener path is a different matter: in our run, the &lt;code&gt;jboss-logging&lt;/code&gt; listener wrote those events to the server log. This is about the completeness of an audit configuration, not a way around authentication: refresh tokens are validated as usual; the events simply are not stored.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. What We Couldn't Conclude
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Other listeners and log settings.&lt;/strong&gt; We observed the &lt;code&gt;jboss-logging&lt;/code&gt; listener with its log category at &lt;code&gt;debug&lt;/code&gt;. Other listeners, and other log levels, were not measured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The plan result beyond our run.&lt;/strong&gt; The &lt;code&gt;tofu plan&lt;/code&gt; result in §3 is what we observed in this run; we make no broader claim about when OpenTofu or Terraform would or would not report a difference.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realms that already have a saved-types list.&lt;/strong&gt; In the source, the provider sends an explicit empty list when the field is left out, and Keycloak replaces a realm's saved types with any list it receives that is not null. We measured only newly created realms and did not measure what happens when this configuration is applied to a realm that already has a custom list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other tools using this provider.&lt;/strong&gt; We applied the provider with OpenTofu only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other versions.&lt;/strong&gt; Only Keycloak 26.7.4 with provider v5.9.0; we make no claim about other versions. Keycloak 26.7.5, 26.8.0 and 26.8.1 (released on 2026-09-30, 2026-10-01 and 2026-10-13) and provider v5.10.0 (released on 2026-10-05) were not measured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which other types are left out by default.&lt;/strong&gt; We name only the two we measured. To see which types your realm saves, read &lt;code&gt;GET /admin/realms/&amp;lt;realm&amp;gt;/events/config&lt;/code&gt; or the saved-types list in the admin console.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why the provider documents "all event types."&lt;/strong&gt; We don't know, and we don't infer it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admin events.&lt;/strong&gt; Admin events are a separate setting and are not covered here.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Conclusion
&lt;/h2&gt;

&lt;p&gt;With Keycloak 26.7.4 and the keycloak provider v5.9.0, in the setup recorded above, turning on realm events with &lt;code&gt;enabled_event_types&lt;/code&gt; left out kept &lt;code&gt;LOGIN&lt;/code&gt; and &lt;code&gt;LOGIN_ERROR&lt;/code&gt; in the event store but not &lt;code&gt;REFRESH_TOKEN&lt;/code&gt; or &lt;code&gt;REFRESH_TOKEN_ERROR&lt;/code&gt;, while listing the four types in the comparison realm saved all four. The provider documents the omitted field as "Omitting this field enables all event types"; Keycloak applies its default saved types when the list is empty, and its admin guide presents the saved types as a list you add to. The point of this report is the gap between those two descriptions, recorded as of the Verified-on date and within this scope only.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>security</category>
      <category>opentofu</category>
      <category>devops</category>
    </item>
    <item>
      <title>When a Renewed cert-manager CA Runs on the Same Key but a New Key Identifier</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Wed, 14 Oct 2026 13:14:31 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-a-renewed-cert-manager-ca-runs-on-the-same-key-but-a-new-key-identifier-kfb</link>
      <guid>https://dev.to/whenitruns/when-a-renewed-cert-manager-ca-runs-on-the-same-key-but-a-new-key-identifier-kfb</guid>
      <description>&lt;p&gt;&lt;em&gt;On cert-manager v1.21.2, a v1.18.6-issued &lt;code&gt;rotationPolicy: Never&lt;/code&gt; CA renewed with the same key got a new SKI (SHA-1 → truncated SHA-256); OpenSSL accepted a pre-renewal leaf only with the old CA too.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR06&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; cert-manager · Subject Key Identifier generation on the CA &lt;code&gt;Certificate&lt;/code&gt; renewal path (the controller's Go &lt;code&gt;crypto/x509&lt;/code&gt; &lt;code&gt;CreateCertificate&lt;/code&gt;, with &lt;code&gt;rotationPolicy: Never&lt;/code&gt;)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; &lt;em&gt;measured&lt;/em&gt; — cert-manager &lt;strong&gt;v1.18.6&lt;/strong&gt; issuing (the latest 1.18 patch; vendor-listed &lt;strong&gt;EOL 2026-03-10&lt;/strong&gt;) → in-place upgrade through &lt;strong&gt;v1.19.6 → v1.20.4&lt;/strong&gt; (each minor's latest patch, following the vendor upgrade guidance; no behavioral assertions on the transit versions) → &lt;strong&gt;v1.21.2&lt;/strong&gt; renewing (current supported release; latest as of 2026-09-11). &lt;em&gt;source-read&lt;/em&gt; — the controller &lt;code&gt;cmd/controller/go.mod&lt;/code&gt; &lt;code&gt;go&lt;/code&gt; line: v1.18.6 &lt;code&gt;go 1.24.0&lt;/code&gt; · &lt;strong&gt;v1.19.0 &lt;code&gt;go 1.25.0&lt;/code&gt;&lt;/strong&gt; (the first affected version; the 1.19 line is EOL 2026-07-08) · v1.21.2 &lt;code&gt;go 1.26.0&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; a single-node &lt;code&gt;kind&lt;/code&gt; cluster (node &lt;code&gt;kindest/node:v1.33.4&lt;/code&gt;, digest-pinned) on a dedicated test environment; a SelfSigned &lt;code&gt;Issuer&lt;/code&gt; → a CA &lt;code&gt;Certificate&lt;/code&gt; (&lt;code&gt;isCA: true&lt;/code&gt;, &lt;code&gt;rotationPolicy: Never&lt;/code&gt;, RSA-2048) → a CA &lt;code&gt;Issuer&lt;/code&gt; → a leaf &lt;code&gt;Certificate&lt;/code&gt;; the CA renewed in place with the same key.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-10-13 (desk sources re-checked; the &lt;code&gt;go.mod&lt;/code&gt; lines, PR #8480 open and unmerged, and v1.21.2 the current supported release) · lab measured 2026-09-24 (v1.18.6 → v1.21.2).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; cert-manager CA &lt;code&gt;Certificate&lt;/code&gt;s that were issued with &lt;code&gt;rotationPolicy: Never&lt;/code&gt; on &lt;strong&gt;≤1.18&lt;/strong&gt; and are then &lt;strong&gt;renewed with the same key&lt;/strong&gt; on &lt;strong&gt;≥1.19&lt;/strong&gt;. The controller does not set the certificate's Subject Key Identifier itself, and from v1.19.0 the controller is built with &lt;code&gt;go 1.25.0&lt;/code&gt;, whose &lt;code&gt;crypto/x509&lt;/code&gt; fills a missing SKI with a truncated SHA-256 (earlier: SHA-1). A leaf issued &lt;strong&gt;before&lt;/strong&gt; the renewal therefore carries an Authority Key Identifier derived from the old SHA-1 CA SKI, which no longer matches the renewed CA's SHA-256 SKI. Whether this breaks path building/verification is &lt;strong&gt;client-dependent&lt;/strong&gt; — see §5 and §6; measured: with OpenSSL 3.0.13's &lt;code&gt;openssl verify&lt;/code&gt;, the pre-renewal leaf failed against a trust store holding only the renewed CA and verified against the old and renewed CA bundled together.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; On cert-manager v1.21.2, renewing a v1.18.6-issued &lt;code&gt;rotationPolicy: Never&lt;/code&gt; CA with the same key left the public key unchanged but changed the CA's Subject Key Identifier from SHA-1 to a truncated SHA-256, so a pre-renewal leaf's Authority Key Identifier no longer matched the renewed CA — and &lt;code&gt;openssl verify&lt;/code&gt; (OpenSSL 3.0.13) rejected that leaf against the renewed CA alone ("unable to get local issuer certificate") while accepting it against the old and renewed CA bundled.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. The Claim
&lt;/h2&gt;

&lt;p&gt;This report starts from a promise operators lean on, a change recorded only one layer down, and a report that connects the two.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What the docs promise about &lt;code&gt;rotationPolicy: Never&lt;/code&gt;.&lt;/strong&gt; cert-manager's &lt;code&gt;Certificate&lt;/code&gt; usage documentation, describing the &lt;code&gt;rotationPolicy&lt;/code&gt; field, states (checked 2026-09-14) that with this setting &lt;em&gt;"cert-manager reuses the existing private key on each issuance"&lt;/em&gt;, and:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"With &lt;code&gt;rotationPolicy: Never&lt;/code&gt;, a private key is only generated if one does not already exist in the target Secret resource (using the &lt;code&gt;tls.key&lt;/code&gt; key). All further issuances will re-use this private key."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;Never&lt;/code&gt; was the default until cert-manager 1.18: the &lt;strong&gt;1.18 release notes&lt;/strong&gt; announce &lt;em&gt;"We have changed the default value of &lt;code&gt;Certificate.Spec.PrivateKey.RotationPolicy&lt;/code&gt; from &lt;code&gt;Never&lt;/code&gt; to &lt;code&gt;Always&lt;/code&gt;"&lt;/em&gt; and advise operators to &lt;em&gt;"Explicitly set &lt;code&gt;rotationPolicy: Never&lt;/code&gt; on your Certificate resources"&lt;/em&gt; to keep the old behavior (checked 2026-09-14). So a long-lived CA issued on an older release, and kept on the old behavior, re-uses one private key across renewals. The surface an operator reads promises &lt;strong&gt;private-key&lt;/strong&gt; continuity. It does not say anything about the continuity of the certificate's &lt;strong&gt;identifiers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where the identifier change is actually recorded.&lt;/strong&gt; The Subject Key Identifier is generated by the Go standard library, and its generation changed. The &lt;strong&gt;Go 1.25 release notes&lt;/strong&gt; state (checked 2026-09-14):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"&lt;code&gt;CreateCertificate&lt;/code&gt; now uses truncated SHA-256 to populate the &lt;code&gt;SubjectKeyId&lt;/code&gt; if it is missing. The &lt;code&gt;GODEBUG&lt;/code&gt; setting &lt;code&gt;x509sha256skid=0&lt;/code&gt; reverts to SHA-1."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whether a given build generates SKIs the new way (truncated SHA-256) or the old way (SHA-1) is decided by the &lt;code&gt;go&lt;/code&gt; line of the main module, per Go's &lt;code&gt;godebug&lt;/code&gt; documentation (checked 2026-09-14): a GODEBUG setting's default &lt;em&gt;"is derived from … the defaults for the Go toolchain used to build the program, amended to match the Go version listed in &lt;code&gt;go.mod&lt;/code&gt;, and then overridden by explicit &lt;code&gt;//go:debug&lt;/code&gt; lines in the program."&lt;/em&gt; cert-manager's controller module declares &lt;code&gt;go 1.25.0&lt;/code&gt; from &lt;strong&gt;v1.19.0&lt;/strong&gt; onward (v1.18.6 declares &lt;code&gt;go 1.24.0&lt;/code&gt;; v1.21.2 declares &lt;code&gt;go 1.26.0&lt;/code&gt; — read from the tagged &lt;code&gt;go.mod&lt;/code&gt;), its packet-of-interest source does not set &lt;code&gt;SubjectKeyId&lt;/code&gt; itself, and there is no &lt;code&gt;//go:debug x509sha256skid=…&lt;/code&gt; or GODEBUG override in the module. A cert-manager ≥1.19 build therefore generates SHA-256 CA SKIs by default, and a ≤1.18 build generated SHA-1 ones. cert-manager's own release notes for 1.18 through 1.21 and its 1.17→1.18 and 1.18→1.19 upgrade guides do not mention this change (checked 2026-09-14).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The report this test is built on.&lt;/strong&gt; In issue &lt;a href="https://github.com/cert-manager/cert-manager/issues/8289" rel="noopener noreferrer"&gt;#8289&lt;/a&gt; (checked 2026-09-14) a user described issuing a &lt;code&gt;rotationPolicy: Never&lt;/code&gt; CA &lt;code&gt;Certificate&lt;/code&gt; on v1.10.0, then — after upgrading to v1.19.1 — renewing it and finding that the private key was unchanged but the CA's SKI was different. The reporter traced the cause to the Go 1.25 change and closed the issue themselves as &lt;em&gt;"not a bug."&lt;/em&gt; Two later comments recorded operational impact (for example, disruption to Galera clusters) — a &lt;strong&gt;report layer&lt;/strong&gt; this report does not itself reproduce.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this report tests.&lt;/strong&gt; Not whether the docs are wrong or whether Go's default is wrong — both are documented where they live. The gap is that a &lt;code&gt;rotationPolicy: Never&lt;/code&gt; CA renewed across the &lt;code&gt;go 1.24 → 1.25&lt;/code&gt; boundary keeps its key but changes its SKI, so a leaf signed &lt;strong&gt;before&lt;/strong&gt; that renewal carries an Authority Key Identifier that points at an SKI the renewed CA no longer has. §3 measures the identifiers before and after the renewal; whether any given client then fails to build a path is a separate, client-dependent question handled in §5 and §6.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The Setup
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Environment:&lt;/strong&gt; a single-node &lt;code&gt;kind&lt;/code&gt; cluster on a dedicated Linux test VM (GNU coreutils), node image &lt;code&gt;kindest/node:v1.33.4&lt;/code&gt; (digest-pinned). k8s v1.33 is inside the vendor-listed supported range of every cert-manager version exercised here (1.18: k8s 1.29–1.33; 1.19: 1.31–1.35; 1.20: 1.32–1.35; 1.21: 1.33–1.36), so one node version covers the whole issue → upgrade → renew sequence; &lt;code&gt;kubectl&lt;/code&gt; within ±1 minor of the node. The SKI mechanism is independent of the Kubernetes version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version:&lt;/strong&gt; cert-manager &lt;strong&gt;v1.18.6&lt;/strong&gt; to issue (installed from the official Helm chart &lt;code&gt;cert-manager-v1.18.6.tgz&lt;/code&gt; from charts.jetstack.io with one non-default value, &lt;code&gt;crds.enabled=true&lt;/code&gt;, so the chart installs the CRDs (chart default &lt;code&gt;false&lt;/code&gt;); the in-place upgrades below use each minor's official chart with the same value; image digests and chart hashes recorded in our lab record). The 1.18 line is &lt;strong&gt;EOL&lt;/strong&gt; (vendor-listed 2026-03-10); v1.18.6 is its latest patch. The controller is then upgraded &lt;strong&gt;in place&lt;/strong&gt; to &lt;strong&gt;v1.19.6 → v1.20.4 → v1.21.2&lt;/strong&gt; — one minor at a time, each the minor's latest patch, following the vendor guidance &lt;em&gt;"We recommend that you upgrade cert-manager one minor version at a time, always choosing the latest patch version for the minor version."&lt;/em&gt; No behavior is asserted on the transit versions; the renewal is measured on &lt;strong&gt;v1.21.2&lt;/strong&gt; (the current supported release). The first affected version, &lt;strong&gt;v1.19.0&lt;/strong&gt; (&lt;code&gt;go 1.25.0&lt;/code&gt;), is read from source only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration:&lt;/strong&gt; a SelfSigned &lt;code&gt;Issuer&lt;/code&gt;; a CA &lt;code&gt;Certificate&lt;/code&gt; with &lt;code&gt;isCA: true&lt;/code&gt;, &lt;code&gt;rotationPolicy: Never&lt;/code&gt;, RSA-2048; a CA &lt;code&gt;Issuer&lt;/code&gt; referencing that CA's Secret; and a leaf &lt;code&gt;Certificate&lt;/code&gt; issued by the CA &lt;code&gt;Issuer&lt;/code&gt; before the upgrade. After upgrading to v1.21.2 the CA &lt;code&gt;Certificate&lt;/code&gt; is renewed in place, which under &lt;code&gt;rotationPolicy: Never&lt;/code&gt; keeps the same private key.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Expected vs. Observed — does a same-key CA renewal keep the CA's Subject Key Identifier stable?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Expected&lt;/strong&gt; (what the &lt;code&gt;rotationPolicy: Never&lt;/code&gt; promise, read by itself, suggests): renewing the CA with the same key keeps the CA's identity stable, so a leaf issued before the renewal still chains to the renewed CA.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observed&lt;/strong&gt; (measured 2026-09-24; raw in our lab record). The measurements taken, before the renewal (on v1.18.6) and after (on v1.21.2):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CA public-key fingerprint before vs. after the renewal: &lt;strong&gt;unchanged&lt;/strong&gt; — SPKI SHA-256 &lt;code&gt;84b323b6927d5dfe25b242dce19f4287ed28c1f2b456d3f4f603588eb2bf1a57&lt;/code&gt; both times. The renewal kept the key; only the certificate was re-issued (serial &lt;code&gt;25034c5688dd96891327b113cfc02eb4&lt;/code&gt; → &lt;code&gt;19b489e55575e31270275311b74a2454832fb881&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;CA Subject Key Identifier before (v1.18.6): &lt;code&gt;42b062a23924df0a7492534af9e3d64925be0106&lt;/code&gt; (20 bytes) — equal to the SHA-1 of the CA's public key (the subjectPublicKey bit string), which we computed from the certificate itself.&lt;/li&gt;
&lt;li&gt;CA Subject Key Identifier after the renewal (v1.21.2): &lt;code&gt;9de807cf05452aca93f19f6f1ca515f1ceba4809&lt;/code&gt; (20 bytes) — equal to the first 20 bytes of the SHA-256 of that same public key (the truncated SHA-256 form), and different from the value above. The in-place upgrades to v1.19.6, v1.20.4 and v1.21.2 did not re-issue the CA or the leaf on their own (both certificates were byte-identical after each step); the renewal was triggered on v1.21.2 with &lt;code&gt;cmctl renew&lt;/code&gt; (cmctl v2.6.1).&lt;/li&gt;
&lt;li&gt;the pre-renewal leaf's Authority Key Identifier vs. the renewed CA's Subject Key Identifier: the leaf issued on v1.18.6 carries AKI &lt;code&gt;42b062a23924df0a7492534af9e3d64925be0106&lt;/code&gt; — the old CA SKI — which does &lt;strong&gt;not&lt;/strong&gt; match the renewed CA's SKI &lt;code&gt;9de807cf05452aca93f19f6f1ca515f1ceba4809&lt;/code&gt;. The leaf itself carries no SKI.&lt;/li&gt;
&lt;li&gt;client verification of the pre-renewal leaf against each measured trust store (the client-verification step): one client, OpenSSL 3.0.13 (&lt;code&gt;openssl verify -show_chain -CAfile &amp;lt;store&amp;gt; &amp;lt;leaf&amp;gt;&lt;/code&gt;). (a) Renewed CA alone: &lt;code&gt;error 20 at 0 depth lookup: unable to get local issuer certificate&lt;/code&gt;, exit code 2. (b) Old CA + renewed CA bundled: &lt;code&gt;OK&lt;/code&gt; (chain depth 1 &lt;code&gt;CN = rr06-ca&lt;/code&gt;), exit code 0. No optional client (GnuTLS, Java, Go) was run in this round; the trust-store file hashes are in our lab record.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Raw evidence: the CA certificate before and after the renewal and the pre-renewal leaf, the &lt;code&gt;openssl x509&lt;/code&gt; output of their Subject Key Identifier and Authority Key Identifier extensions, and the public-key fingerprints (hex) are kept in our lab record.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Reproduction
&lt;/h2&gt;

&lt;p&gt;The minimal reproduction (raw output is kept in our lab record; the manifest and the commands below are in the reproduction repo linked below):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 0. Bring up a kind cluster (node k8s v1.33.4) on the test VM and install cert-manager v1.18.6&lt;/span&gt;
&lt;span class="c"&gt;#    from the official Helm chart, with the CRDs (chart hash + image digests recorded; rollout&lt;/span&gt;
&lt;span class="c"&gt;#    confirmed before any measurement):&lt;/span&gt;
&lt;span class="c"&gt;#      kind create cluster --name rr06 --image kindest/node:v1.33.4@sha256:25a6018e48dfcaee478f4a59af81157a437f15e6e140bf103f85a2e7cd0cbbf2&lt;/span&gt;
&lt;span class="c"&gt;#      helm install cert-manager https://charts.jetstack.io/charts/cert-manager-v1.18.6.tgz \&lt;/span&gt;
&lt;span class="c"&gt;#        -n cert-manager --create-namespace --set crds.enabled=true --wait&lt;/span&gt;
&lt;span class="c"&gt;#      for d in cert-manager cert-manager-webhook cert-manager-cainjector; do kubectl -n cert-manager rollout status "deploy/$d" --timeout=300s; done&lt;/span&gt;

&lt;span class="c"&gt;# 1. Create a SelfSigned Issuer, then a CA Certificate that re-uses one key across issuances&lt;/span&gt;
&lt;span class="c"&gt;#    (Issuer: spec.selfSigned: {}; Certificate: spec.isCA: true, spec.privateKey.rotationPolicy: Never,&lt;/span&gt;
&lt;span class="c"&gt;#    algorithm RSA size 2048, issuerRef -&amp;gt; the SelfSigned Issuer, secretName -&amp;gt; the CA secret).&lt;/span&gt;
&lt;span class="c"&gt;#    Then a CA Issuer referencing that CA secret, and a leaf Certificate issued by the CA Issuer.&lt;/span&gt;
&lt;span class="c"&gt;#      kubectl apply -f step1-manifest.yaml   # the manifest below, saved to this file&lt;/span&gt;
&lt;span class="c"&gt;#      kubectl -n rr06 wait --for=condition=Ready certificate/rr06-ca --timeout=120s&lt;/span&gt;
&lt;span class="c"&gt;#      kubectl -n rr06 wait --for=condition=Ready issuer/rr06-ca-issuer --timeout=120s&lt;/span&gt;
&lt;span class="c"&gt;#      kubectl -n rr06 wait --for=condition=Ready certificate/leaf1 --timeout=120s&lt;/span&gt;

&lt;span class="c"&gt;# 2. RECORD #1 (still on v1.18.6): the CA's Subject Key Identifier (SHA-1, 20 bytes) and public key,&lt;/span&gt;
&lt;span class="c"&gt;#    the leaf's Authority Key Identifier (== the CA SKI above), and the CA public-key fingerprint (SPKI SHA-256).&lt;/span&gt;
&lt;span class="c"&gt;#      kubectl -n rr06 get secret rr06-ca-tls -o jsonpath='{.data.tls\.crt}' | base64 -d &amp;gt; ca-1_v1.18.6.pem&lt;/span&gt;
&lt;span class="c"&gt;#      kubectl -n rr06 get secret leaf1-tls -o jsonpath='{.data.tls\.crt}' | base64 -d &amp;gt; leaf1-1_v1.18.6.pem&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-1_v1.18.6.pem -noout -subject -issuer -serial -ext subjectKeyIdentifier,authorityKeyIdentifier&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-1_v1.18.6.pem -noout -pubkey | openssl pkey -pubin -outform DER | sha256sum   # CA public-key fingerprint (SPKI SHA-256)&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-1_v1.18.6.pem -noout -pubkey | openssl rsa -pubin -RSAPublicKey_out -outform DER 2&amp;gt;/dev/null | sha1sum   # SHA-1 of the public key (the subjectPublicKey bit string)&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-1_v1.18.6.pem -noout -pubkey | openssl rsa -pubin -RSAPublicKey_out -outform DER 2&amp;gt;/dev/null | sha256sum | cut -c1-40   # the first 20 bytes of its SHA-256&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in leaf1-1_v1.18.6.pem -noout -subject -issuer -serial -ext subjectKeyIdentifier,authorityKeyIdentifier&lt;/span&gt;

&lt;span class="c"&gt;# 3. Upgrade cert-manager IN PLACE, one minor at a time, each the latest patch, per the vendor guidance:&lt;/span&gt;
&lt;span class="c"&gt;#    v1.18.6 -&amp;gt; v1.19.6 -&amp;gt; v1.20.4 -&amp;gt; v1.21.2&lt;/span&gt;
&lt;span class="c"&gt;#      helm upgrade cert-manager https://charts.jetstack.io/charts/cert-manager-v1.19.6.tgz \&lt;/span&gt;
&lt;span class="c"&gt;#        -n cert-manager --set crds.enabled=true --wait&lt;/span&gt;
&lt;span class="c"&gt;#      helm upgrade cert-manager https://charts.jetstack.io/charts/cert-manager-v1.20.4.tgz \&lt;/span&gt;
&lt;span class="c"&gt;#        -n cert-manager --set crds.enabled=true --wait&lt;/span&gt;
&lt;span class="c"&gt;#      helm upgrade cert-manager https://charts.jetstack.io/charts/cert-manager-v1.21.2.tgz \&lt;/span&gt;
&lt;span class="c"&gt;#        -n cert-manager --set crds.enabled=true --wait&lt;/span&gt;
&lt;span class="c"&gt;#    (confirm rollout + version at each step; no renewal, no assertions on the transit versions.)&lt;/span&gt;

&lt;span class="c"&gt;# 4. On v1.21.2, RENEW the CA Certificate with the same key (rotationPolicy: Never keeps the key):&lt;/span&gt;
&lt;span class="c"&gt;#    trigger an in-place renewal of the CA Certificate and wait for it to complete: the revision has&lt;/span&gt;
&lt;span class="c"&gt;#    changed and Ready is True (at most 120 one-second reads).&lt;/span&gt;
&lt;span class="c"&gt;#      rev0=$(kubectl -n rr06 get certificate rr06-ca -o jsonpath='{.status.revision}'); echo "CA revision before: $rev0"&lt;/span&gt;
&lt;span class="c"&gt;#      cmctl renew -n rr06 rr06-ca&lt;/span&gt;
&lt;span class="c"&gt;#      for i in $(seq 1 120); do rev=$(kubectl -n rr06 get certificate rr06-ca -o jsonpath='{.status.revision}'); rdy=$(kubectl -n rr06 get certificate rr06-ca -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'); [ "$rev" != "$rev0" ] &amp;amp;&amp;amp; [ "$rdy" = True ] &amp;amp;&amp;amp; break; sleep 1; done&lt;/span&gt;
&lt;span class="c"&gt;#      echo "CA revision after: $rev (Ready=$rdy)"&lt;/span&gt;

&lt;span class="c"&gt;# 5. RECORD #2 (on v1.21.2, after the renewal): the CA's Subject Key Identifier now, compared to RECORD #1;&lt;/span&gt;
&lt;span class="c"&gt;#    the CA public-key fingerprint, compared to RECORD #1 (expected unchanged); and the pre-renewal leaf's&lt;/span&gt;
&lt;span class="c"&gt;#    Authority Key Identifier, compared to the renewed CA's Subject Key Identifier.&lt;/span&gt;
&lt;span class="c"&gt;#      kubectl -n rr06 get secret rr06-ca-tls -o jsonpath='{.data.tls\.crt}' | base64 -d &amp;gt; ca-2_v1.21.2_renewed.pem&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-2_v1.21.2_renewed.pem -noout -subject -issuer -serial -ext subjectKeyIdentifier,authorityKeyIdentifier&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-2_v1.21.2_renewed.pem -noout -pubkey | openssl pkey -pubin -outform DER | sha256sum   # CA public-key fingerprint (SPKI SHA-256)&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-2_v1.21.2_renewed.pem -noout -pubkey | openssl rsa -pubin -RSAPublicKey_out -outform DER 2&amp;gt;/dev/null | sha1sum   # SHA-1 of the public key (the subjectPublicKey bit string)&lt;/span&gt;
&lt;span class="c"&gt;#      openssl x509 -in ca-2_v1.21.2_renewed.pem -noout -pubkey | openssl rsa -pubin -RSAPublicKey_out -outform DER 2&amp;gt;/dev/null | sha256sum | cut -c1-40   # the first 20 bytes of its SHA-256&lt;/span&gt;

&lt;span class="c"&gt;# 6. CLIENT VERIFICATION of the pre-renewal leaf, in two trust stores:&lt;/span&gt;
&lt;span class="c"&gt;#    (a) the renewed CA alone;   (b) the old CA + the renewed CA, bundled.&lt;/span&gt;
&lt;span class="c"&gt;#    Required client (path that reads AKI/SKI): openssl verify. OpenSSL's issuer test, in addition to&lt;/span&gt;
&lt;span class="c"&gt;#    matching the issuer DN, compares the sub-fields of the subject's authorityKeyIdentifier (keyid,&lt;/span&gt;
&lt;span class="c"&gt;#    serial, issuer) against the issuer's subjectKeyIdentifier, serial number, and issuer when present&lt;/span&gt;
&lt;span class="c"&gt;#    (X509_check_issued(3)). Optional, recorded without a path classification: GnuTLS certtool --verify,&lt;/span&gt;
&lt;span class="c"&gt;#    Java keytool/PKIX, Go crypto/x509 Verify. Client names, versions, and trust-store file hashes: our lab record.&lt;/span&gt;
&lt;span class="c"&gt;#      cp ca-2_v1.21.2_renewed.pem store-a_renewed-CA-only.pem&lt;/span&gt;
&lt;span class="c"&gt;#      cat ca-1_v1.18.6.pem ca-2_v1.21.2_renewed.pem &amp;gt; store-b_old-CA+renewed-CA.pem&lt;/span&gt;
&lt;span class="c"&gt;#      openssl verify -show_chain -CAfile store-a_renewed-CA-only.pem leaf1-1_v1.18.6.pem   # (a)&lt;/span&gt;
&lt;span class="c"&gt;#      openssl verify -show_chain -CAfile store-b_old-CA+renewed-CA.pem leaf1-1_v1.18.6.pem   # (b)&lt;/span&gt;

&lt;span class="c"&gt;# 7. Tear down (the test cluster only).&lt;/span&gt;
&lt;span class="c"&gt;#      kind delete cluster --name rr06&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The manifest for step 1 — the SelfSigned &lt;code&gt;Issuer&lt;/code&gt;, the CA &lt;code&gt;Certificate&lt;/code&gt;, the CA &lt;code&gt;Issuer&lt;/code&gt;, and the leaf &lt;code&gt;Certificate&lt;/code&gt;, in their own namespace — exactly as we applied it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Namespace&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Issuer&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;selfsigned&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selfSigned&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Certificate&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06-ca&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;isCA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;commonName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06-ca&lt;/span&gt;
  &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06-ca-tls&lt;/span&gt;
  &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;algorithm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RSA&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2048&lt;/span&gt;
    &lt;span class="na"&gt;rotationPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Never&lt;/span&gt;
  &lt;span class="na"&gt;issuerRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;selfsigned&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Issuer&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Issuer&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06-ca-issuer&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ca&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06-ca-tls&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cert-manager.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Certificate&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;leaf1&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;commonName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;leaf1.rr06.example.test&lt;/span&gt;
  &lt;span class="na"&gt;dnsNames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;leaf1.rr06.example.test&lt;/span&gt;
  &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;leaf1-tls&lt;/span&gt;
  &lt;span class="na"&gt;privateKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;algorithm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RSA&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2048&lt;/span&gt;
  &lt;span class="na"&gt;issuerRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rr06-ca-issuer&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Issuer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outputs for each RECORD step land in §3 (above) and our lab record.&lt;/p&gt;

&lt;p&gt;A recorded run of this reproduction: &lt;a href="https://youtu.be/GMwCRX-3BhU" rel="noopener noreferrer"&gt;https://youtu.be/GMwCRX-3BhU&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reproduction repo: &lt;a href="https://github.com/whenitruns/when-a-renewed-cert-manager-ca-runs-on-the-same-key-but-a-new-key-identifier" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-a-renewed-cert-manager-ca-runs-on-the-same-key-but-a-new-key-identifier&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Impact
&lt;/h2&gt;

&lt;p&gt;A client that builds a chain by matching a leaf's Authority Key Identifier to a CA's Subject Key Identifier can, against a trust store that holds only the &lt;strong&gt;renewed&lt;/strong&gt; CA, fail to build a path for a leaf that was issued &lt;strong&gt;before&lt;/strong&gt; the renewal — even though the CA's key never changed and the leaf has not expired (the exact clients and trust stores are measured in the client-verification step; in this run, &lt;code&gt;openssl verify&lt;/code&gt; failed with the renewed CA alone and succeeded with the old and renewed CA bundled). The belief this quietly breaks is &lt;em&gt;"the key didn't change, so certificates already issued by this CA keep working."&lt;/em&gt; Renewing a &lt;code&gt;rotationPolicy: Never&lt;/code&gt; CA in place is the kind of routine action taken for exactly that reason. This is an availability and interoperability property, not a security weakness: nothing here lets a certificate be forged or a check be bypassed. Reported production incidents (e.g. Galera clusters) sit in the report layer of #8289 and are not reproduced here.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. What We Couldn't Conclude
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client behavior is not exhaustive.&lt;/strong&gt; We report only the clients and trust-store configurations we measured (the client-verification step). Whether a given library, language runtime, or middlebox builds the path by DN, by key identifier, or by trying alternates is a per-client question; "TLS verification breaks" is not a general claim of this report. The reporter's own note in #8289 — that &lt;em&gt;"openssl verify does succeed"&lt;/em&gt; for the bundled certificate while some applications do not — is consistent with that client-dependence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The private key.&lt;/strong&gt; This report's claim is about the identifier, not the key. If a renewal ever changed the public-key fingerprint, that would be key rotation — a different mechanism, outside this report — and we record the before/after fingerprint precisely so that case is visible rather than assumed. The #8289 reporter confirmed the key was unchanged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"Before the renewal," not "before the upgrade."&lt;/strong&gt; The affected leaf is one issued &lt;strong&gt;before the CA is renewed&lt;/strong&gt;. We do not measure every issue-time/upgrade-time ordering.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The reported production impact&lt;/strong&gt; (Galera and similar) is a report-layer account by other users, not our reproduction; we do not attribute those incidents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Out of measured scope:&lt;/strong&gt; other trust-store shapes, other key algorithms, and intermediate-CA topologies are not covered. The transit versions (v1.19.6, v1.20.4) and the first affected version (v1.19.0) are not measured for renewal behavior — v1.19.0 is read from &lt;code&gt;go.mod&lt;/code&gt; only; the renewal is measured on v1.21.2.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clients that tolerate the mismatch.&lt;/strong&gt; A client whose path logic tolerates the AKI/SKI mismatch could still verify the pre-renewal leaf, and that outcome would belong to this finding too: the mechanism (key unchanged, SKI SHA-1 → SHA-256, AKI/SKI link broken) holds whether or not a given client tolerates it. In this run, &lt;code&gt;openssl verify&lt;/code&gt; did not tolerate it — it failed against the renewed CA alone (§3, §5).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. Conclusion
&lt;/h2&gt;

&lt;p&gt;On the versions and in the configuration recorded above, renewing a &lt;code&gt;rotationPolicy: Never&lt;/code&gt; CA &lt;code&gt;Certificate&lt;/code&gt; across cert-manager's &lt;code&gt;go 1.24 → 1.25&lt;/code&gt; build boundary kept the CA's private key while changing its Subject Key Identifier from SHA-1 to a truncated SHA-256, leaving a pre-renewal leaf's Authority Key Identifier pointed at an identifier the renewed CA no longer carries — and &lt;code&gt;openssl verify&lt;/code&gt; then rejected that leaf against the renewed CA alone while accepting it with the old CA bundled in; the measured identifiers and the client-verification results are recorded as of the Verified-on date and within this scope only. The change is documented where it originates — the Go 1.25 release notes and the &lt;code&gt;godebug&lt;/code&gt; reference — and cert-manager does not set the identifier itself; the point of this report is that the surface an operator reads for &lt;code&gt;rotationPolicy: Never&lt;/code&gt;, which promises key re-use, is not where the identifier change is written down.&lt;/p&gt;

</description>
      <category>certmanager</category>
      <category>kubernetes</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>When a Kyverno Wildcard Guardrail Runs Past a Post-Policy CRD Until a Restart</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Sat, 26 Sep 2026 09:48:11 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-a-kyverno-wildcard-guardrail-runs-past-a-post-policy-crd-until-a-restart-226l</link>
      <guid>https://dev.to/whenitruns/when-a-kyverno-wildcard-guardrail-runs-past-a-post-policy-crd-until-a-restart-226l</guid>
      <description>&lt;p&gt;&lt;em&gt;`kinds: ["&lt;/em&gt;/&lt;em&gt;"]&lt;code&gt; + &lt;/code&gt;operations: [DELETE]&lt;code&gt; on Kyverno v1.19.1 (&lt;/code&gt;crdWatcher` on): "no policies matched admission request" for a post-policy CRD's custom resource until the admission controller restarted — a pre-policy CRD's resource was denied before and after.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR05&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; Kyverno · ClusterPolicy wildcard matching (&lt;code&gt;kinds: ["*/*"]&lt;/code&gt;) and the admission controller's policy cache&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; Kyverno &lt;strong&gt;v1.19.1&lt;/strong&gt; (current release as of the desk check, published 2026-09-10; re-confirmed as current at lab start on 2026-09-13), installed from the official Helm chart &lt;code&gt;kyverno/kyverno&lt;/code&gt; 3.9.1 (repo &lt;code&gt;https://kyverno.github.io/kyverno/&lt;/code&gt;); admission-controller image &lt;code&gt;reg.kyverno.io/kyverno/kyverno:v1.19.1&lt;/code&gt; at digest &lt;code&gt;sha256:b31d8511ae5fd6010e2a01ea72ebae08eb82fa51d91af14a1d9fe989949b4edb&lt;/code&gt;. The documentation strings and issue/PR states were checked against the live docs and GitHub on 2026-09-12 and re-confirmed on 2026-09-13.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; A single-node &lt;code&gt;kind&lt;/code&gt; cluster running the Kyverno v1.19.1 admission controller with &lt;code&gt;crdWatcher&lt;/code&gt; enabled (Helm value &lt;code&gt;admissionController.crdWatcher=true&lt;/code&gt;; the live container args included &lt;code&gt;--crdWatcher=true&lt;/code&gt;, alongside &lt;code&gt;--resyncPeriod=15m&lt;/code&gt; and &lt;code&gt;--v=4&lt;/code&gt;); a wildcard &lt;code&gt;ClusterPolicy&lt;/code&gt;; and a benign CRD (plus one of its custom resources) installed &lt;em&gt;after&lt;/em&gt; the policy. Node Kubernetes version v1.34.0.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-09-24 (desk sources re-checked; v1.19.1 is still the current release) · lab measured 2026-09-13 on v1.19.1.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; Kyverno ClusterPolicies that rely on a &lt;code&gt;kinds: ["*/*"]&lt;/code&gt; wildcard &lt;code&gt;deny&lt;/code&gt; rule (&lt;code&gt;operations: [DELETE]&lt;/code&gt;) to cover CRDs installed after the policy is applied (v1.19.1, &lt;code&gt;crdWatcher&lt;/code&gt; enabled; measured: the deletion was allowed — the guardrail did not match — until the admission controller was restarted).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; On Kyverno v1.19.1 (Kubernetes v1.34.0, &lt;code&gt;crdWatcher&lt;/code&gt; enabled), a &lt;code&gt;kinds: ["*/*"]&lt;/code&gt; wildcard &lt;code&gt;deny&lt;/code&gt; ClusterPolicy did not deny deletion of a labeled custom resource whose CRD was installed &lt;em&gt;after&lt;/em&gt; the policy — the deletion was allowed at every poll across a ~32-minute window (past the 15-minute informer resync) and became denied only after the admission controller was restarted, while a pre-policy CRD's custom resource was denied throughout (control).  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-a-kyverno-wildcard-guardrail" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-a-kyverno-wildcard-guardrail&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-a-kyverno-wildcard-guardrail-runs-past-a-post-policy-crd-until-a-restart" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-a-kyverno-wildcard-guardrail-runs-past-a-post-policy-crd-until-a-restart&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kyverno</category>
      <category>kubernetes</category>
      <category>policy</category>
      <category>devops</category>
    </item>
    <item>
      <title>When OPA's `semver.is_valid` Runs on What SemVer Rejects</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Thu, 24 Sep 2026 05:26:00 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-opas-semverisvalid-runs-on-what-semver-rejects-mmh</link>
      <guid>https://dev.to/whenitruns/when-opas-semverisvalid-runs-on-what-semver-rejects-mmh</guid>
      <description>&lt;p&gt;&lt;em&gt;On OPA v1.20.2, &lt;code&gt;semver.is_valid&lt;/code&gt; returns &lt;code&gt;true&lt;/code&gt; for leading-zero versions (&lt;code&gt;01.2.3&lt;/code&gt;, &lt;code&gt;1.02.3&lt;/code&gt;) and empty pre-release/build sections (&lt;code&gt;1.2.3-&lt;/code&gt;, &lt;code&gt;1.2.3+&lt;/code&gt;), and &lt;code&gt;semver.compare&lt;/code&gt; compares &lt;code&gt;1.02.3&lt;/code&gt; and &lt;code&gt;1.2.3&lt;/code&gt; as equal.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR04&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; OPA (Open Policy Agent) · SemVer built-ins — &lt;code&gt;semver.is_valid&lt;/code&gt; and &lt;code&gt;semver.compare&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; OPA &lt;strong&gt;v1.20.2&lt;/strong&gt; (official &lt;code&gt;opa_linux_amd64_static&lt;/code&gt; release; measured on our lab — see §2). The documentation strings and the built-in's source were checked against the live docs and the v1.20.2 source tag (2026-09-12).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; A single official &lt;code&gt;opa&lt;/code&gt; binary; expressions evaluated with &lt;code&gt;opa eval --format pretty&lt;/code&gt;, in both the default (non-strict) mode and &lt;code&gt;--strict-builtin-errors&lt;/code&gt; (see §2 and §4).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-09-25 (re-measured on v1.21.0, the current release — see the update below) · lab measured 2026-09-12 on v1.20.2; desk sources re-checked 2026-09-22.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; OPA policies that use &lt;code&gt;semver.is_valid&lt;/code&gt; or &lt;code&gt;semver.compare&lt;/code&gt; as a version trust gate — for example "reject the supplied version unless it is valid SemVer," or "allow when declared ≥ minimum" (measured on v1.20.2; on v1.21.0 these inputs are rejected — see the update below).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; OPA's docs describe &lt;code&gt;semver.is_valid&lt;/code&gt; as validating &lt;em&gt;"that the input is a valid SemVer string"&lt;/em&gt;, but on v1.20.2 it returns &lt;code&gt;true&lt;/code&gt; for strings the SemVer spec rejects — leading-zero numbers (&lt;code&gt;01.2.3&lt;/code&gt;, &lt;code&gt;1.02.3&lt;/code&gt;) and empty pre-release/build sections (&lt;code&gt;1.2.3-&lt;/code&gt;, &lt;code&gt;1.2.3+&lt;/code&gt;) — and &lt;code&gt;semver.compare&lt;/code&gt; compares &lt;code&gt;1.02.3&lt;/code&gt; and &lt;code&gt;1.2.3&lt;/code&gt; as equal rather than erroring the way it does for other malformed input like &lt;code&gt;1.2&lt;/code&gt;; OPA v1.21.0, released 2026-09-24, no longer shows either behavior in our re-run.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-opas-semveris_valid-runs-on" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-opas-semveris_valid-runs-on&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-opas-semver-is-valid-runs-on-what-semver-rejects" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-opas-semver-is-valid-runs-on-what-semver-rejects&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opa</category>
      <category>rego</category>
      <category>semver</category>
      <category>devops</category>
    </item>
    <item>
      <title>When OPA's Bundle Loader Runs Past a `.manifest` Typo</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Tue, 22 Sep 2026 22:53:25 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-opas-bundle-loader-runs-past-a-manifest-typo-1d57</link>
      <guid>https://dev.to/whenitruns/when-opas-bundle-loader-runs-past-a-manifest-typo-1d57</guid>
      <description>&lt;p&gt;&lt;em&gt;In bundle mode, a one-character &lt;code&gt;.manifest&lt;/code&gt; key typo (&lt;code&gt;rego_verison&lt;/code&gt; for &lt;code&gt;rego_version&lt;/code&gt;) draws no diagnostic that names the key; the failure can surface as &lt;code&gt;rego_parse_error&lt;/code&gt; pointing at your &lt;code&gt;.rego&lt;/code&gt; — OPA v1.20.1&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR03&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; OPA (Open Policy Agent) · bundle &lt;code&gt;.manifest&lt;/code&gt; loading — unknown top-level keys and &lt;code&gt;rego_version&lt;/code&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; OPA &lt;strong&gt;v1.20.1&lt;/strong&gt; (official &lt;code&gt;opa_linux_amd64_static&lt;/code&gt; release, Build 2026-08-28; measured on our lab VM — see §2). Documentation, published schema, and source facts checked against the live docs and the v1.20.1 source tag (2026-09-02).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; Single official &lt;code&gt;opa&lt;/code&gt; binary; minimal two-file bundles (&lt;code&gt;.manifest&lt;/code&gt; + one &lt;code&gt;policy.rego&lt;/code&gt;, full contents in §2); one minimal &lt;code&gt;config.yaml&lt;/code&gt; used only for the contrast check in §4.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-09-22 (desk sources re-checked; v1.20.2 is the current release) · lab measured 2026-09-11 on v1.20.1.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; OPA bundles whose &lt;code&gt;.manifest&lt;/code&gt; carries a mistyped or unknown top-level key — for example &lt;code&gt;rego_verison&lt;/code&gt; instead of &lt;code&gt;rego_version&lt;/code&gt; (measured on v1.20.1).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; OPA's own docs state that the bundle loader &lt;em&gt;"has always ignored unknown top-level keys"&lt;/em&gt; in &lt;code&gt;.manifest&lt;/code&gt;, so when a bundle is loaded in bundle mode (&lt;code&gt;opa build -b&lt;/code&gt;, or at runtime) a mistyped &lt;code&gt;rego_version&lt;/code&gt; produces no diagnostic that names the key (measured on OPA v1.20.1) — the failure can surface instead as &lt;code&gt;rego_parse_error: `if` keyword is required before rule body&lt;/code&gt; pointing at your &lt;code&gt;.rego&lt;/code&gt; source file, while a mistyped key in the sibling &lt;code&gt;config.yaml&lt;/code&gt; has drawn an explicit &lt;code&gt;unknown configuration option&lt;/code&gt; warning since v1.19.0.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-opas-bundle-loader-runs-past" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-opas-bundle-loader-runs-past&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-opas-bundle-loader-runs-past-a-manifest-typo" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-opas-bundle-loader-runs-past-a-manifest-typo&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opa</category>
      <category>rego</category>
      <category>kubernetes</category>
      <category>devops</category>
    </item>
    <item>
      <title>When the `Contact K8S API Server From Container` Rule Runs Silent</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Wed, 16 Sep 2026 11:51:01 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-the-contact-k8s-api-server-from-container-rule-runs-silent-32g3</link>
      <guid>https://dev.to/whenitruns/when-the-contact-k8s-api-server-from-container-rule-runs-silent-32g3</guid>
      <description>&lt;p&gt;&lt;em&gt;The shipped &lt;code&gt;k8s_api_server&lt;/code&gt; FQDN condition (&lt;code&gt;fd.sip.name="kubernetes.default.svc.cluster.local"&lt;/code&gt;) fired on neither Falco 0.43.1 nor 0.40.0 in our lab — and the falco.org example still shows pre-v0.19.0 &lt;code&gt;fd.sip="1.2.3.4"&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR02&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; Falco · the &lt;code&gt;k8s_api_server&lt;/code&gt; macro and the &lt;code&gt;Contact K8S API Server From Container&lt;/code&gt; rule (published docs vs. shipped default)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; Docs — live on falco.org (checked 2026-08-18). Shipped rule defaults — 0.18.0, 0.19.0, and current &lt;code&gt;falcosecurity/rules&lt;/code&gt; main. Runtime firing — our lab (2026-08-18, one kind cluster): Falco &lt;strong&gt;0.43.1&lt;/strong&gt; and &lt;strong&gt;0.40.0&lt;/strong&gt;, both observed &lt;strong&gt;not firing&lt;/strong&gt; on a benign in-cluster API-server contact.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; Default shipped rules, no override — for the desk layers, the published documentation and versioned shipped rule files; for the lab, each image's bundled &lt;code&gt;falco_rules.yaml&lt;/code&gt; as shipped (plus one added observation-only rule that changes no detection logic; full text in §2).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-09-14 (desk sources re-checked: the falco.org example, the shipped rule conditions, and #3834; Falco 0.44.1 was then the current release) · lab measured 2026-08-18 on Falco 0.43.1 and 0.40.0.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; Operators who set the &lt;code&gt;k8s_api_server&lt;/code&gt; macro by following the currently published example, and environments where the shipped DNS-associated condition never matches — as in a community report (#3834) and in our own lab.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; Falco's published &lt;code&gt;k8s_api_server&lt;/code&gt; override example still shows the placeholder &lt;code&gt;1.2.3.4:8080&lt;/code&gt; that the shipped rules replaced with a DNS-associated FQDN condition in v0.19.0 — and in our lab that current condition fired on neither Falco 0.43.1 nor 0.40.0 for a benign in-cluster API-server contact, because the field it matches on (&lt;code&gt;fd.sip.name&lt;/code&gt;) stayed empty.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-the-contact-k8s-api-server-from" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-the-contact-k8s-api-server-from&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-the-contact-k8s-api-server-from-container-rule-runs-silent" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-the-contact-k8s-api-server-from-container-rule-runs-silent&lt;/a&gt;&lt;/p&gt;

</description>
      <category>falco</category>
      <category>kubernetes</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>When Falco Runs Out of Metadata</title>
      <dc:creator>When It Runs</dc:creator>
      <pubDate>Mon, 14 Sep 2026 12:27:36 +0000</pubDate>
      <link>https://dev.to/whenitruns/when-falco-runs-out-of-metadata-3i3e</link>
      <guid>https://dev.to/whenitruns/when-falco-runs-out-of-metadata-3i3e</guid>
      <description>&lt;p&gt;&lt;em&gt;&lt;code&gt;user.uid&lt;/code&gt;, &lt;code&gt;user.loginuid&lt;/code&gt;, and &lt;code&gt;fd.name&lt;/code&gt; under absent metadata on Falco 0.44.1 — plus the reported &lt;code&gt;4294967295&lt;/code&gt; and &lt;code&gt;/&amp;lt;NA&amp;gt;&lt;/code&gt; forms (0.31.0–0.40.0)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When It Runs — Run Report #RR01&lt;/strong&gt; · &lt;em&gt;Testing what infrastructure actually does.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider · Component:&lt;/strong&gt; Falco · alert output field rendering when metadata is absent (&lt;code&gt;user.uid&lt;/code&gt;, &lt;code&gt;user.loginuid&lt;/code&gt;, &lt;code&gt;user.name&lt;/code&gt;, &lt;code&gt;fd.name&lt;/code&gt;)&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Versions tested:&lt;/strong&gt; Falco &lt;strong&gt;0.44.1&lt;/strong&gt; (our lab, 2026-08-18 — modern_ebpf, standard Ubuntu 24.04 kernel). Publicly reported across 0.31.0 (2022) through 0.40.0 (2025) — quoted as reported, not re-measured.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Config profile:&lt;/strong&gt; Default &lt;code&gt;falco.yaml&lt;/code&gt; as shipped in the official 0.44.1 image, with &lt;code&gt;json_output=true&lt;/code&gt; and one custom output rule (full text in §2).&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verified on:&lt;/strong&gt; 2026-08-18 (desk sources re-checked; lab run on 0.44.1 the same day) — re-verification against the then-current release happens at publication.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Affects:&lt;/strong&gt; Anyone consuming Falco alert fields as values — dashboards, filters, and correlation that treat an absent field as a real one.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;TL;DR:&lt;/strong&gt; On Falco 0.44.1 we observed absent metadata rendered in value-like forms — &lt;code&gt;user.loginuid&lt;/code&gt; as &lt;code&gt;-1&lt;/code&gt; (the one documented substitution), &lt;code&gt;fd.name&lt;/code&gt; as &lt;code&gt;&amp;lt;NA&amp;gt;&lt;/code&gt;/&lt;code&gt;null&lt;/code&gt;, and one alert carrying a real uid, &lt;code&gt;-1&lt;/code&gt;, and &lt;code&gt;null&lt;/code&gt; side by side — while the reported forms &lt;code&gt;user.uid&lt;/code&gt; = &lt;code&gt;4294967295&lt;/code&gt; and the path-shaped &lt;code&gt;/&amp;lt;NA&amp;gt;&lt;/code&gt; (#1921, #2126, #3246) did not appear in our scenarios and stand on those reports.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Full report:&lt;/strong&gt; &lt;a href="https://whenitruns.substack.com/p/when-falco-runs-out-of-metadata" rel="noopener noreferrer"&gt;https://whenitruns.substack.com/p/when-falco-runs-out-of-metadata&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reproduction repo:&lt;/strong&gt; &lt;a href="https://github.com/whenitruns/when-falco-runs-out-of-metadata" rel="noopener noreferrer"&gt;https://github.com/whenitruns/when-falco-runs-out-of-metadata&lt;/a&gt;&lt;/p&gt;

</description>
      <category>falco</category>
      <category>kubernetes</category>
      <category>security</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
