Browse Source

Deployed 40b04db45 to main with MkDocs 1.6.1 and mike 2.2.0

Skarlso 5 days ago
parent
commit
c774558338

+ 63 - 4
main/api/externalsecret/index.html

@@ -5380,13 +5380,34 @@ be transformed and saved as a <code>Kind=Secret</code>:</p>
 <h2 id="update-behavior-with-3-different-refresh-policies">Update behavior with 3 different refresh policies</h2>
 <h2 id="update-behavior-with-3-different-refresh-policies">Update behavior with 3 different refresh policies</h2>
 <p>You can control how and when the <code>ExternalSecret</code> is refreshed by setting the <code>spec.refreshPolicy</code> field. If not specified, the default behavior is <code>Periodic</code>.</p>
 <p>You can control how and when the <code>ExternalSecret</code> is refreshed by setting the <code>spec.refreshPolicy</code> field. If not specified, the default behavior is <code>Periodic</code>.</p>
 <h3 id="createdonce">CreatedOnce</h3>
 <h3 id="createdonce">CreatedOnce</h3>
-<p>With <code>refreshPolicy: CreatedOnce</code>, the controller will:</p>
+<p>With <code>refreshPolicy: CreatedOnce</code>, the controller syncs the <code>Kind=Secret</code> once per
+<code>ExternalSecret</code> object and then stops:</p>
 <ul>
 <ul>
-<li>Create the <code>Kind=Secret</code> only if it does not exist yet</li>
-<li>Never update the <code>Kind=Secret</code> afterwards if the source data changes</li>
-<li>Update/ Recreate the <code>Kind=Secret</code> if it gets changed/Deleted</li>
+<li>Runs a single sync on the first reconcile of the <code>ExternalSecret</code>, creating or
+  overwriting the target <code>Kind=Secret</code></li>
+<li>Does not refresh on a schedule or when the source data changes</li>
+<li>Still re-syncs if the target <code>Kind=Secret</code> is changed or deleted while the same
+  <code>ExternalSecret</code> object still exists</li>
 <li>Useful for immutable credentials or when you want to manage updates manually</li>
 <li>Useful for immutable credentials or when you want to manage updates manually</li>
 </ul>
 </ul>
+<p>The "once" is tracked on the <code>ExternalSecret</code>'s own status (<code>syncedResourceVersion</code>
+and <code>refreshTime</code>), not on whether the target Secret already exists.</p>
+<div class="admonition warning">
+<p class="admonition-title">Recreating the ExternalSecret re-syncs the target Secret</p>
+<p><code>CreatedOnce</code> does not check whether the target Secret already exists. If the
+<code>ExternalSecret</code> object itself is deleted and recreated (for example by a GitOps
+controller that prunes and re-applies it), its status resets and the controller
+performs a fresh sync that overwrites the existing target Secret. With a
+stateless generator such as the Password generator this produces a brand new
+value, so the target Secret and any credential already derived from the old
+value diverge with no way to recover the original.</p>
+<p><code>creationPolicy</code> does not guard against this: <code>Owner</code>, <code>Orphan</code>, <code>Merge</code> and
+<code>CreateOrMerge</code> all rewrite the managed keys on that sync. The only field that prevents an existing
+target Secret's data from being overwritten is <code>spec.target.immutable: true</code>,
+which skips the data update whenever the Secret already exists. Combine
+<code>refreshPolicy: CreatedOnce</code> with <code>spec.target.immutable: true</code> for credentials
+that must be generated once and never change.</p>
+</div>
 <p>Example:
 <p>Example:
 <div class="highlight"><pre><span></span><code><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">external-secrets.io/v1</span>
 <div class="highlight"><pre><span></span><code><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">external-secrets.io/v1</span>
 <span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ExternalSecret</span>
 <span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ExternalSecret</span>
@@ -5396,6 +5417,44 @@ be transformed and saved as a <code>Kind=Secret</code>:</p>
 <span class="w">  </span><span class="nt">refreshPolicy</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">CreatedOnce</span>
 <span class="w">  </span><span class="nt">refreshPolicy</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">CreatedOnce</span>
 <span class="w">  </span><span class="c1"># other fields...</span>
 <span class="w">  </span><span class="c1"># other fields...</span>
 </code></pre></div></p>
 </code></pre></div></p>
+<p>To generate a credential exactly once and never overwrite it afterward, even if
+the <code>ExternalSecret</code> object is recreated, combine <code>refreshPolicy: CreatedOnce</code> with
+<code>spec.target.immutable: true</code>. This is the correct pattern for a credential that an
+application persists on first run (for example a Keycloak admin password written
+into the application database at bootstrap): regenerating the value later would
+leave the target Secret out of sync with the live credential. <code>creationPolicy:
+Orphan</code> keeps the target Secret in place if the <code>ExternalSecret</code> is deleted, and
+<code>immutable: true</code> stops any later reconcile (including one triggered by recreating
+the <code>ExternalSecret</code>) from rewriting the existing data.</p>
+<div class="highlight"><pre><span></span><code><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">generators.external-secrets.io/v1alpha1</span>
+<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Password</span>
+<span class="nt">metadata</span><span class="p">:</span>
+<span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">keycloak-admin-password</span>
+<span class="nt">spec</span><span class="p">:</span>
+<span class="w">  </span><span class="nt">length</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">32</span>
+<span class="w">  </span><span class="nt">digits</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">5</span>
+<span class="w">  </span><span class="nt">symbols</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">5</span>
+<span class="w">  </span><span class="nt">allowRepeat</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
+<span class="nn">---</span>
+<span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">external-secrets.io/v1</span>
+<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ExternalSecret</span>
+<span class="nt">metadata</span><span class="p">:</span>
+<span class="w">  </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">keycloak-admin</span>
+<span class="nt">spec</span><span class="p">:</span>
+<span class="w">  </span><span class="nt">refreshPolicy</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">CreatedOnce</span>
+<span class="w">  </span><span class="nt">target</span><span class="p">:</span>
+<span class="w">    </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">keycloak-admin</span>
+<span class="w">    </span><span class="c1"># keep the Secret if this ExternalSecret is ever deleted</span>
+<span class="w">    </span><span class="nt">creationPolicy</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Orphan</span>
+<span class="w">    </span><span class="c1"># never rewrite the Secret data once it exists, even on recreation</span>
+<span class="w">    </span><span class="nt">immutable</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
+<span class="w">  </span><span class="nt">dataFrom</span><span class="p">:</span>
+<span class="w">    </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">sourceRef</span><span class="p">:</span>
+<span class="w">        </span><span class="nt">generatorRef</span><span class="p">:</span>
+<span class="w">          </span><span class="nt">apiVersion</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">generators.external-secrets.io/v1alpha1</span>
+<span class="w">          </span><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Password</span>
+<span class="w">          </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">keycloak-admin-password</span>
+</code></pre></div>
 <h3 id="periodic">Periodic</h3>
 <h3 id="periodic">Periodic</h3>
 <p>With <code>refreshPolicy: Periodic</code> (the default behavior), the controller will:</p>
 <p>With <code>refreshPolicy: Periodic</code> (the default behavior), the controller will:</p>
 <ul>
 <ul>

+ 7 - 1
main/api/spec/index.html

@@ -9513,7 +9513,13 @@ ExternalSecretStatus
 <th>Description</th>
 <th>Description</th>
 </tr>
 </tr>
 </thead>
 </thead>
-<tbody><tr><td><p>&#34;Merge&#34;</p></td>
+<tbody><tr><td><p>&#34;CreateOrMerge&#34;</p></td>
+<td><p>CreatePolicyCreateOrMerge creates the Secret if it is missing and merges
+data fields into it if it exists, without an ownerReference. A deleted
+target is recreated while the ExternalSecret exists, and the Secret is
+retained when the ExternalSecret is deleted.</p>
+</td>
+</tr><tr><td><p>&#34;Merge&#34;</p></td>
 <td><p>CreatePolicyMerge does not create the Secret, but merges the data fields to the Secret.</p>
 <td><p>CreatePolicyMerge does not create the Secret, but merges the data fields to the Secret.</p>
 </td>
 </td>
 </tr><tr><td><p>&#34;None&#34;</p></td>
 </tr><tr><td><p>&#34;None&#34;</p></td>

+ 279 - 10
main/guides/ownership-deletion-policy/index.html

@@ -2408,6 +2408,17 @@
     </span>
     </span>
   </a>
   </a>
   
   
+</li>
+        
+          <li class="md-nav__item">
+  <a href="#createormerge" class="md-nav__link">
+    <span class="md-ellipsis">
+      
+        CreateOrMerge
+      
+    </span>
+  </a>
+  
 </li>
 </li>
         
         
           <li class="md-nav__item">
           <li class="md-nav__item">
@@ -2424,6 +2435,17 @@
       </ul>
       </ul>
     </nav>
     </nav>
   
   
+</li>
+      
+        <li class="md-nav__item">
+  <a href="#immutable-target" class="md-nav__link">
+    <span class="md-ellipsis">
+      
+        Immutable target
+      
+    </span>
+  </a>
+  
 </li>
 </li>
       
       
         <li class="md-nav__item">
         <li class="md-nav__item">
@@ -2474,6 +2496,17 @@
       </ul>
       </ul>
     </nav>
     </nav>
   
   
+</li>
+      
+        <li class="md-nav__item">
+  <a href="#behavior-matrix" class="md-nav__link">
+    <span class="md-ellipsis">
+      
+        Behavior matrix
+      
+    </span>
+  </a>
+  
 </li>
 </li>
       
       
     </ul>
     </ul>
@@ -5294,6 +5327,17 @@
     </span>
     </span>
   </a>
   </a>
   
   
+</li>
+        
+          <li class="md-nav__item">
+  <a href="#createormerge" class="md-nav__link">
+    <span class="md-ellipsis">
+      
+        CreateOrMerge
+      
+    </span>
+  </a>
+  
 </li>
 </li>
         
         
           <li class="md-nav__item">
           <li class="md-nav__item">
@@ -5310,6 +5354,17 @@
       </ul>
       </ul>
     </nav>
     </nav>
   
   
+</li>
+      
+        <li class="md-nav__item">
+  <a href="#immutable-target" class="md-nav__link">
+    <span class="md-ellipsis">
+      
+        Immutable target
+      
+    </span>
+  </a>
+  
 </li>
 </li>
       
       
         <li class="md-nav__item">
         <li class="md-nav__item">
@@ -5360,6 +5415,17 @@
       </ul>
       </ul>
     </nav>
     </nav>
   
   
+</li>
+      
+        <li class="md-nav__item">
+  <a href="#behavior-matrix" class="md-nav__link">
+    <span class="md-ellipsis">
+      
+        Behavior matrix
+      
+    </span>
+  </a>
+  
 </li>
 </li>
       
       
     </ul>
     </ul>
@@ -5383,24 +5449,39 @@
 
 
 
 
 <h1 id="lifecycle">Lifecycle</h1>
 <h1 id="lifecycle">Lifecycle</h1>
-<p>The External Secrets Operator manages the lifecycle of secrets in Kubernetes. With <code>refreshPolicy</code>,   <code>creationPolicy</code> and <code>deletionPolicy</code> you get fine-grained control of its lifecycle.</p>
+<p>The External Secrets Operator manages the lifecycle of secrets in Kubernetes. With <code>refreshPolicy</code>, <code>creationPolicy</code> and <code>deletionPolicy</code> you get fine-grained control of its lifecycle.</p>
 <div class="admonition note">
 <div class="admonition note">
 <p class="admonition-title">Creation/Deletion Policy Combinations</p>
 <p class="admonition-title">Creation/Deletion Policy Combinations</p>
 <p>Some combinations of creationPolicy/deletionPolicy are not allowed as they would delete existing secrets:
 <p>Some combinations of creationPolicy/deletionPolicy are not allowed as they would delete existing secrets:
 <br/>- <code>deletionPolicy=Delete</code> &amp; <code>creationPolicy=Merge</code>
 <br/>- <code>deletionPolicy=Delete</code> &amp; <code>creationPolicy=Merge</code>
+<br/>- <code>deletionPolicy=Delete</code> &amp; <code>creationPolicy=CreateOrMerge</code>
 <br/>- <code>deletionPolicy=Delete</code> &amp; <code>creationPolicy=None</code>
 <br/>- <code>deletionPolicy=Delete</code> &amp; <code>creationPolicy=None</code>
 <br/>- <code>deletionPolicy=Merge</code> &amp; <code>creationPolicy=None</code></p>
 <br/>- <code>deletionPolicy=Merge</code> &amp; <code>creationPolicy=None</code></p>
 </div>
 </div>
 <h2 id="refresh-policy">Refresh Policy</h2>
 <h2 id="refresh-policy">Refresh Policy</h2>
-<p>The field <code>spec.refreshPolicy</code> defines how the operator refreshes the a secret.</p>
+<p>The field <code>spec.refreshPolicy</code> defines how the operator refreshes the secret.</p>
 <h3 id="periodic-default">Periodic (default)</h3>
 <h3 id="periodic-default">Periodic (default)</h3>
 <p>Refreshes the secret at a fixed interval via <code>spec.refreshInterval</code>. Due to backwards compatibility, setting a refresh interval of 0 will result in the same behavior as <code>CreatedOnce</code>.</p>
 <p>Refreshes the secret at a fixed interval via <code>spec.refreshInterval</code>. Due to backwards compatibility, setting a refresh interval of 0 will result in the same behavior as <code>CreatedOnce</code>.</p>
 <h3 id="onchange">OnChange</h3>
 <h3 id="onchange">OnChange</h3>
-<p>Refreshes the secret only when the ExternalSecret is updated.  </p>
+<p>Refreshes the secret only when the ExternalSecret is updated.</p>
 <h3 id="createdonce">CreatedOnce</h3>
 <h3 id="createdonce">CreatedOnce</h3>
-<p>Refreshes the secret only once, when the ExternalSecret is created.</p>
+<p>Refreshes the secret only once per <code>ExternalSecret</code> object, on its first reconcile.
+The sync state lives on the <code>ExternalSecret</code>'s status, so deleting and recreating the
+<code>ExternalSecret</code> resets it and triggers another one-time sync. Depending on the
+creation policy that sync may overwrite the operator-managed keys of an existing
+target Secret; <code>creationPolicy=None</code> does not update it, and <code>spec.target.immutable:
+true</code> prevents data rewrites.</p>
+<div class="admonition note">
+<p class="admonition-title">State is not persisted across ExternalSecret objects</p>
+<p>ESO is stateless across <code>ExternalSecret</code> objects: it does not persist sync claims
+or reclaim orphaned Secrets when an <code>ExternalSecret</code> is recreated. <code>creationPolicy</code>
+(including <code>Orphan</code>) does not protect a pre-existing target Secret from being
+rewritten on that sync. To keep an already-populated Secret from being overwritten
+on recreation, set <code>spec.target.immutable: true</code> (optionally together with
+<code>refreshPolicy: CreatedOnce</code>).</p>
+</div>
 <h2 id="creation-policy">Creation Policy</h2>
 <h2 id="creation-policy">Creation Policy</h2>
-<p>The field <code>spec.target.creationPolicy</code> defines how the operator creates the a secret.</p>
+<p>The field <code>spec.target.creationPolicy</code> defines how the operator creates the secret.</p>
 <h3 id="owner-default">Owner (default)</h3>
 <h3 id="owner-default">Owner (default)</h3>
 <p>The External Secret Operator creates secret and sets the <code>ownerReference</code> field on the Secret. This secret is subject to <a href="https://kubernetes.io/docs/concepts/architecture/garbage-collection/">garbage collection</a> if the initial <code>ExternalSecret</code> is absent. If a secret with the same name already exists that is not owned by the controller it will result in a conflict. The operator will just error out, not claiming the ownership.</p>
 <p>The External Secret Operator creates secret and sets the <code>ownerReference</code> field on the Secret. This secret is subject to <a href="https://kubernetes.io/docs/concepts/architecture/garbage-collection/">garbage collection</a> if the initial <code>ExternalSecret</code> is absent. If a secret with the same name already exists that is not owned by the controller it will result in a conflict. The operator will just error out, not claiming the ownership.</p>
 <div class="admonition note">
 <div class="admonition note">
@@ -5408,10 +5489,13 @@
 <p>If the secret exists and the ownerReference field is not found, the controller treats this secret as orphaned. It will take ownership of this secret by adding an <code>ownerReference</code> field and updating it.</p>
 <p>If the secret exists and the ownerReference field is not found, the controller treats this secret as orphaned. It will take ownership of this secret by adding an <code>ownerReference</code> field and updating it.</p>
 </div>
 </div>
 <h3 id="orphan">Orphan</h3>
 <h3 id="orphan">Orphan</h3>
-<p>Whenever triggered via <code>RefreshPolicy</code> conditions, the operator creates/updates 
-the target Secret according to the provider available information. 
-However, the operator will not watch on Secret Changes (delete/updates), nor trigger 
-<a href="https://kubernetes.io/docs/concepts/architecture/garbage-collection/">garbage collection</a> when the <code>ExternalSecret</code> object is deleted.</p>
+<p>Whenever triggered via <code>RefreshPolicy</code> conditions, the operator creates/updates
+the target Secret according to the provider available information.
+It does not set an <code>ownerReference</code>, so it does not trigger
+<a href="https://kubernetes.io/docs/concepts/architecture/garbage-collection/">garbage collection</a> of the Secret when the <code>ExternalSecret</code> object is deleted.
+The operator still watches the Secret, but for <code>Orphan</code> it re-syncs only when a refresh
+is due (see the warning below and the <a href="#behavior-matrix">behavior matrix</a>), not on
+every change to the Secret.</p>
 <div class="admonition warning">
 <div class="admonition warning">
 <p class="admonition-title">Unwanted reverts of manual changes</p>
 <p class="admonition-title">Unwanted reverts of manual changes</p>
 <p>If you set <code>spec.refreshPolicy</code> to <code>Periodic</code> or <code>OnChange</code> and <code>spec.target.creationPolicy</code> to <code>Orphan</code>,
 <p>If you set <code>spec.refreshPolicy</code> to <code>Periodic</code> or <code>OnChange</code> and <code>spec.target.creationPolicy</code> to <code>Orphan</code>,
@@ -5421,8 +5505,23 @@ Use <code>creationPolicy=Orphan</code> with caution.</p>
 </div>
 </div>
 <h3 id="merge">Merge</h3>
 <h3 id="merge">Merge</h3>
 <p>The operator does not create a secret. Instead, it expects the secret to already exist. Values from the secret provider will be merged into the existing secret. Note: the controller takes ownership of a field even if it is owned by a different entity. Multiple ExternalSecrets can use <code>creationPolicy=Merge</code> with a single secret as long as the fields don't collide - otherwise you end up in an oscillating state.</p>
 <p>The operator does not create a secret. Instead, it expects the secret to already exist. Values from the secret provider will be merged into the existing secret. Note: the controller takes ownership of a field even if it is owned by a different entity. Multiple ExternalSecrets can use <code>creationPolicy=Merge</code> with a single secret as long as the fields don't collide - otherwise you end up in an oscillating state.</p>
+<h3 id="createormerge">CreateOrMerge</h3>
+<p>Creates the Secret if it does not exist and, if it does, merges the provider values
+into it while preserving keys owned by others (like <code>Merge</code>), without setting an
+<code>ownerReference</code> (like <code>Orphan</code>). Unlike <code>Merge</code> it also creates a missing Secret,
+so a deleted target is recreated immediately (driven by the Secret watch) while the
+<code>ExternalSecret</code> exists; unlike <code>Owner</code> the Secret is retained when the
+<code>ExternalSecret</code> is deleted. Combined with <code>spec.target.immutable: true</code> it gives
+"create once, freeze, recreate if deleted, keep on ExternalSecret deletion". Note:
+<code>deletionPolicy=Delete</code> is not allowed, the controller does not own the Secret.</p>
 <h3 id="none">None</h3>
 <h3 id="none">None</h3>
 <p>The operator does not create or update the secret, this is basically a no-op.</p>
 <p>The operator does not create or update the secret, this is basically a no-op.</p>
+<h2 id="immutable-target">Immutable target</h2>
+<p>Setting <code>spec.target.immutable: true</code> marks the generated <code>Kind=Secret</code> as immutable,
+so its data is never rewritten once the Secret exists (Kubernetes itself also blocks
+edits to an immutable Secret's data). It does not affect whether a missing Secret is
+created or recreated, that is governed by <code>creationPolicy</code> and <code>refreshPolicy</code>. See the
+<a href="#behavior-matrix">behavior matrix</a> for the full interaction.</p>
 <h2 id="deletion-policy">Deletion Policy</h2>
 <h2 id="deletion-policy">Deletion Policy</h2>
 <p>DeletionPolicy defines what should happen if a given secret gets deleted <strong>from the provider</strong>.</p>
 <p>DeletionPolicy defines what should happen if a given secret gets deleted <strong>from the provider</strong>.</p>
 <p>DeletionPolicy is only supported on the specific providers, please refer to our <a href="../../introduction/stability-support/">stability/support table</a>.</p>
 <p>DeletionPolicy is only supported on the specific providers, please refer to our <a href="../../introduction/stability-support/">stability/support table</a>.</p>
@@ -5435,12 +5534,182 @@ SecretSyncedError status.</p>
 If a secret gets deleted on the provider side and is not accessible
 If a secret gets deleted on the provider side and is not accessible
 anymore this is not considered an error and the ExternalSecret
 anymore this is not considered an error and the ExternalSecret
 does not go into SecretSyncedError status. This is also true for new
 does not go into SecretSyncedError status. This is also true for new
-ExternalSecrets mapping to non-existing secrets in the provider.</p>
+ExternalSecrets mapping to non-existing secrets in the provider.
+<code>deletionPolicy=Delete</code> only takes effect with <code>creationPolicy=Owner</code>; the operator
+refuses to delete a Secret it does not own and reports a <code>SecretSyncedError</code> otherwise.</p>
 <h3 id="merge_1">Merge</h3>
 <h3 id="merge_1">Merge</h3>
 <p>Merge removes keys in the secret, but not the secret itself.
 <p>Merge removes keys in the secret, but not the secret itself.
 If a secret gets deleted on the provider side and is not accessible
 If a secret gets deleted on the provider side and is not accessible
 anymore this is not considered an error and the ExternalSecret
 anymore this is not considered an error and the ExternalSecret
 does not go into SecretSyncedError status.</p>
 does not go into SecretSyncedError status.</p>
+<h2 id="behavior-matrix">Behavior matrix</h2>
+<p>How <code>creationPolicy</code> and <code>refreshPolicy</code> combine to drive the Secret operations.
+<code>deletionPolicy</code> is a separate axis (covered below the table) that only fires when
+the provider returns no data.</p>
+<table>
+<thead>
+<tr>
+<th>creationPolicy</th>
+<th>refreshPolicy</th>
+<th>Create if missing</th>
+<th>Reflect source change</th>
+<th>Overwrite on ES re-create</th>
+<th>Recreate if Secret deleted</th>
+<th>Retain on ES delete</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><strong>Owner</strong></td>
+<td>Periodic</td>
+<td>Yes</td>
+<td>Yes (at interval)</td>
+<td>Yes</td>
+<td>Yes (immediate)</td>
+<td>No (GC via ownerRef)</td>
+</tr>
+<tr>
+<td><strong>Owner</strong></td>
+<td>OnChange</td>
+<td>Yes</td>
+<td>Only on ES change</td>
+<td>Yes</td>
+<td>Yes (immediate)</td>
+<td>No (GC via ownerRef)</td>
+</tr>
+<tr>
+<td><strong>Owner</strong></td>
+<td>CreatedOnce</td>
+<td>Yes</td>
+<td>No</td>
+<td>Yes</td>
+<td>Yes (immediate)</td>
+<td>No (GC via ownerRef)</td>
+</tr>
+<tr>
+<td><strong>Orphan</strong></td>
+<td>Periodic</td>
+<td>Yes</td>
+<td>Yes (at interval)</td>
+<td>Yes</td>
+<td>Yes (at interval)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>Orphan</strong></td>
+<td>OnChange</td>
+<td>Yes</td>
+<td>Only on ES change</td>
+<td>Yes</td>
+<td>No (until ES change)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>Orphan</strong></td>
+<td>CreatedOnce</td>
+<td>Yes</td>
+<td>No</td>
+<td>Yes</td>
+<td>No</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>Merge</strong></td>
+<td>Periodic</td>
+<td>No (waits)</td>
+<td>Yes (at interval)</td>
+<td>Yes (if target exists)</td>
+<td>No (never creates)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>Merge</strong></td>
+<td>OnChange</td>
+<td>No (waits)</td>
+<td>Only on ES change</td>
+<td>Yes (if target exists)</td>
+<td>No (never creates)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>Merge</strong></td>
+<td>CreatedOnce</td>
+<td>No (waits)</td>
+<td>No</td>
+<td>Yes (if target exists)</td>
+<td>No (never creates)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>CreateOrMerge</strong></td>
+<td>Periodic</td>
+<td>Yes</td>
+<td>Yes (at interval)</td>
+<td>Yes</td>
+<td>Yes (immediate)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>CreateOrMerge</strong></td>
+<td>OnChange</td>
+<td>Yes</td>
+<td>Only on ES change</td>
+<td>Yes</td>
+<td>Yes (immediate)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>CreateOrMerge</strong></td>
+<td>CreatedOnce</td>
+<td>Yes</td>
+<td>No</td>
+<td>Yes</td>
+<td>Yes (immediate)</td>
+<td>Yes</td>
+</tr>
+<tr>
+<td><strong>None</strong></td>
+<td>any</td>
+<td>No (no-op)</td>
+<td>No</td>
+<td>No</td>
+<td>No</td>
+<td>Yes (nothing created)</td>
+</tr>
+</tbody>
+</table>
+<p>Column meanings:</p>
+<ul>
+<li><strong>Reflect source change</strong>: a value changing in the provider is pulled into the
+  Secret. ESO is pull-based and does not watch providers, so only <code>Periodic</code> polls
+  (at each interval). <code>OnChange</code> re-syncs only when the <code>ExternalSecret</code> spec or
+  metadata changes, or when you set the <code>force-sync</code> annotation. <code>CreatedOnce</code> never
+  re-syncs.</li>
+<li><strong>Overwrite on ES re-create</strong>: deleting and recreating the <code>ExternalSecret</code> object
+  resets its status, so the next sync overwrites the ES-managed keys of an existing
+  target (keys owned by others are preserved). This is independent of <code>refreshPolicy</code>;
+  only <code>spec.target.immutable: true</code> prevents it.</li>
+<li><strong>Recreate if Secret deleted</strong>: you delete the target Secret while the
+  <code>ExternalSecret</code> still exists. <code>Owner</code> treats a missing Secret as invalid and
+  recreates it immediately via the Secret watch. <code>Orphan</code> treats a missing Secret as
+  valid, so it only recreates when a refresh is triggered (a <code>Periodic</code> interval);
+  under <code>CreatedOnce</code> or <code>OnChange</code> it stays deleted. <code>Merge</code> never creates.</li>
+<li><strong>Retain on ES delete</strong>: whether the target Secret survives deletion of the
+  <code>ExternalSecret</code>. Only <code>Owner</code> sets an <code>ownerReference</code>, so only <code>Owner</code> is
+  garbage-collected.</li>
+</ul>
+<p>Modifiers that cut across every row:</p>
+<ul>
+<li><strong><code>spec.target.immutable: true</code></strong>: once the target Secret exists, its data is never
+  rewritten, so "Reflect source change" and "Overwrite on ES re-create" become No. It
+  does not affect "Create if missing" or "Recreate if Secret deleted", a Secret that
+  does not exist has no data to protect, so it is created or recreated fresh.</li>
+<li><strong><code>refreshInterval: 0</code> with <code>Periodic</code></strong> behaves like <code>CreatedOnce</code>.</li>
+<li><strong><code>deletionPolicy</code></strong> (Retain, Delete, Merge) only acts when the provider returns no
+  data, which is only detected on a re-sync. So under <code>CreatedOnce</code> a provider-side
+  deletion is never detected, under <code>OnChange</code> only on an <code>ExternalSecret</code> change, and
+  under <code>Periodic</code> at the next interval.</li>
+</ul>
 
 
 
 
 
 

+ 1 - 1
main/introduction/faq/index.html

@@ -5205,7 +5205,7 @@ the <code>external-secrets.io/force-sync</code> annotation on the ClusterExterna
 <p>The interval can be changed by the <code>spec.refreshInterval</code> in the ExternalSecret. You can also control the refresh behavior by setting <code>spec.refreshPolicy</code> to one of the following options:</p>
 <p>The interval can be changed by the <code>spec.refreshInterval</code> in the ExternalSecret. You can also control the refresh behavior by setting <code>spec.refreshPolicy</code> to one of the following options:</p>
 <ul>
 <ul>
 <li><code>Periodic</code> (default): Update regularly based on refreshInterval</li>
 <li><code>Periodic</code> (default): Update regularly based on refreshInterval</li>
-<li><code>CreatedOnce</code>: Create the Secret only once and never update it afterward</li>
+<li><code>CreatedOnce</code>: Create the Secret only once per ExternalSecret object and never update it afterward (recreating the ExternalSecret re-syncs it, see the <a href="../../api/externalsecret/#createdonce">refresh policy docs</a>)</li>
 <li><code>OnChange</code>: Only update when the ExternalSecret's metadata or specification changes</li>
 <li><code>OnChange</code>: Only update when the ExternalSecret's metadata or specification changes</li>
 </ul>
 </ul>
 <h2 id="how-do-i-know-when-the-status-of-my-secret-changed-the-last-time">How do I know when the status of my secret changed the last time?</h2>
 <h2 id="how-do-i-know-when-the-status-of-my-secret-changed-the-last-time">How do I know when the status of my secret changed the last time?</h2>

File diff suppressed because it is too large
+ 0 - 0
main/search/search_index.json


Some files were not shown because too many files changed in this diff