<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Finalizers on inetshell</title><link>https://inet.sh/en/tags/finalizers/</link><description>Recent content in Finalizers on inetshell</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sat, 26 Sep 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://inet.sh/en/tags/finalizers/index.xml" rel="self" type="application/rss+xml"/><item><title>Removing Rancher from a cluster: cattle-system stuck Terminating, clusters that will not delete, the webhook that blocks everything, and getting the admin back</title><link>https://inet.sh/en/posts/kubernetes/rancher-cleanup-cattle-system-namespaces-terminating/</link><pubDate>Sat, 26 Sep 2026 00:00:00 +0000</pubDate><guid>https://inet.sh/en/posts/kubernetes/rancher-cleanup-cattle-system-namespaces-terminating/</guid><description>After uninstalling Rancher (or after it breaks), cattle-system and cattle-fleet-system stay in Terminating because of the controller.cattle.io/namespace-auth finalizer, Cluster objects refuse to delete, and the rancher.cattle.io webhooks reject every change because the pod serving them is gone. The official rancher-cleanup job to wipe everything at once, the manual surgery when you only want to fix one thing, and reset-password / ensure-default-admin when the problem is that you cannot log in.</description><content:encoded><![CDATA[<h2 id="tldr">TL;DR</h2>
<p>To <strong>remove Rancher completely</strong> from a cluster where it was installed (irreversible, backup taken):</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl create -f https://raw.githubusercontent.com/rancher/rancher-cleanup/main/deploy/rancher-cleanup.yaml
</span></span><span class="line"><span class="cl">kubectl -n kube-system logs -l job-name<span class="o">=</span>cleanup-job -f
</span></span><span class="line"><span class="cl">kubectl create -f https://raw.githubusercontent.com/rancher/rancher-cleanup/main/deploy/verify.yaml
</span></span><span class="line"><span class="cl">kubectl -n kube-system logs -l job-name<span class="o">=</span>verify-job -f      <span class="c1"># should print nothing</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>To <strong>fix a single thing</strong> without razing everything, read on.</p>
<h2 id="namespace-stuck-in-terminating">Namespace stuck in Terminating</h2>
<p><code>cattle-system</code>, <code>cattle-fleet-system</code>, <code>cattle-impersonation-system</code>, <code>local</code>, the <code>cluster-fleet-*</code> ones, or any namespace Rancher created, stay in <code>Terminating</code> forever:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl get ns cattle-system -o <span class="nv">jsonpath</span><span class="o">=</span><span class="s1">&#39;{.metadata.finalizers}{&#34;\n&#34;}{.spec.finalizers}{&#34;\n&#34;}{.status.conditions}{&#34;\n&#34;}&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Two different cases:</p>
<ol>
<li>
<p><strong><code>metadata.finalizers</code> contains <code>controller.cattle.io/namespace-auth</code></strong> (or any <code>*.cattle.io</code>). Rancher put it there and only Rancher removes it; if Rancher is gone, nobody will. Remove it yourself:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl patch ns cattle-system --type<span class="o">=</span>merge -p <span class="s1">&#39;{&#34;metadata&#34;:{&#34;finalizers&#34;:[]}}&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div></li>
<li>
<p><strong><code>spec.finalizers</code> contains <code>kubernetes</code> and <code>status.conditions</code> says <code>SomeResourcesRemain</code> or <code>DiscoveryFailed</code></strong>. The API server will not delete the namespace because resources remain inside, almost always CRs of an API group whose service disappeared (a Rancher <code>apiservice</code>). Before forcing, look at what it is:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl api-resources --verbs<span class="o">=</span>list --namespaced -o name <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> xargs -n1 kubectl -n cattle-system get --ignore-not-found --show-kind 2&gt;/dev/null
</span></span><span class="line"><span class="cl">kubectl get apiservice <span class="p">|</span> grep -v True        <span class="c1"># dead APIs that break discovery</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Delete the dead <code>apiservice</code> or the CRs with finalizers, and the namespace goes away on its own. Forcing <code>spec.finalizers</code> to empty is the last resort and leaves orphans behind:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl get ns cattle-system -o json <span class="p">|</span> jq <span class="s1">&#39;.spec.finalizers=[]&#39;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl"><span class="se"></span>  <span class="p">|</span> kubectl replace --raw /api/v1/namespaces/cattle-system/finalize -f -
</span></span></code></pre></td></tr></table>
</div>
</div></li>
</ol>
<h2 id="cluster-that-cannot-be-deleted">Cluster that cannot be deleted</h2>
<p>An imported cluster that no longer exists stays in <em>Removing</em> in the UI, or <code>kubectl delete</code> never finishes. There are two objects with finalizers, one per API:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl -n fleet-default get clusters.provisioning.cattle.io
</span></span><span class="line"><span class="cl">kubectl -n fleet-default patch clusters.provisioning.cattle.io my-cluster --type<span class="o">=</span>merge -p <span class="s1">&#39;{&#34;metadata&#34;:{&#34;finalizers&#34;:[]}}&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">kubectl get clusters.management.cattle.io          <span class="c1"># c-m-xxxxxxxx (v2.6+) or c-xxxxx</span>
</span></span><span class="line"><span class="cl">kubectl patch clusters.management.cattle.io c-m-xxxxxxxx --type<span class="o">=</span>merge -p <span class="s1">&#39;{&#34;metadata&#34;:{&#34;finalizers&#34;:[]}}&#39;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Then clean up the <code>cluster-fleet-default-&lt;name&gt;-&lt;hash&gt;</code> namespace and whatever <code>clusters.fleet.cattle.io</code> remain in <code>fleet-default</code>.</p>
<h2 id="the-webhook-that-rejects-everything">The webhook that rejects everything</h2>
<p><code>rancher-webhook</code> validates and mutates <code>*.cattle.io</code> resources (and some core ones, such as namespaces and ServiceAccounts on managed clusters). If the pod is gone or broken, every change fails with:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Error from server (InternalError): Internal error occurred: failed calling webhook &#34;rancher.cattle.io&#34;: … connect: connection refused
</span></span></code></pre></td></tr></table>
</div>
</div><p>Export the configurations, delete them, let the pod come back healthy, and restore them:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl get validatingwebhookconfiguration rancher.cattle.io -o yaml &gt; vwc-rancher.yaml
</span></span><span class="line"><span class="cl">kubectl get mutatingwebhookconfiguration rancher.cattle.io -o yaml &gt; mwc-rancher.yaml
</span></span><span class="line"><span class="cl">kubectl delete validatingwebhookconfiguration rancher.cattle.io
</span></span><span class="line"><span class="cl">kubectl delete mutatingwebhookconfiguration rancher.cattle.io
</span></span><span class="line"><span class="cl"><span class="c1"># … fix rancher-webhook (kubectl -n cattle-system rollout restart deploy/rancher-webhook) …</span>
</span></span><span class="line"><span class="cl">kubectl apply -f vwc-rancher.yaml -f mwc-rancher.yaml
</span></span></code></pre></td></tr></table>
</div>
</div><p>If you are uninstalling, do not restore them: they are the first thing to remove so the rest of the deletion can proceed.</p>
<h2 id="getting-access-back">Getting access back</h2>
<p>Lost admin password, or the admin user disabled by mistake:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl">kubectl -n cattle-system <span class="nb">exec</span> -it deploy/rancher -- reset-password
</span></span><span class="line"><span class="cl"><span class="c1"># New password for default administrator (user-xxxxx): …</span>
</span></span><span class="line"><span class="cl">kubectl -n cattle-system <span class="nb">exec</span> -it deploy/rancher -- ensure-default-admin
</span></span></code></pre></td></tr></table>
</div>
</div><p><code>ensure-default-admin</code> re-enables the user and gives the administrator role back; <code>reset-password</code> only changes the password.</p>
<h2 id="traps">Traps</h2>
<ul>
<li><strong><code>rancher-cleanup</code> deletes the downstream cluster objects</strong> (the clusters keep running, but are no longer registered) and everything Rancher installed: monitoring, logging, Gatekeeper. Longhorn stays. Do not run it on the Rancher cluster you want to keep.</li>
<li><strong>Backup first</strong>: <code>kubectl get -A -o yaml</code> of the <code>*.cattle.io</code> resources you care about, or Rancher&rsquo;s backup-operator. Finalizers go away in a second; what was behind them does not come back.</li>
<li><strong><code>kubectl delete ns --force --grace-period=0</code> does nothing</strong> for a namespace in Terminating: the block is in the finalizers, not in the grace period.</li>
<li><strong>Rancher puts the finalizers back</strong> while it is alive: if you are cleaning a cluster still connected to a Rancher, disconnect it first (delete the <code>cattle-cluster-agent</code>) or your patches undo themselves.</li>
<li><strong>The <code>*.cattle.io</code> CRDs survive</strong> a Helm uninstall; <code>rancher-cleanup</code> removes them, a manual uninstall does not.</li>
</ul>
<h2 id="see-also">See also</h2>
<ul>
<li><a href="/en/posts/k3s/cluster-reset-lost-quorum/">k3s: cluster reset after losing quorum</a> — the other cluster surgery worth keeping at hand.</li>
<li><a href="https://github.com/rancher/rancher-cleanup">rancher-cleanup</a> and the <a href="https://ranchermanager.docs.rancher.com/faq/technical-items">Rancher technical FAQ</a>.</li>
</ul>
]]></content:encoded></item></channel></rss>