Kubernetes v1.35: Restricting executables invoked by kubeconfigs via exec plugin allowList added to kuberc
<p>Did you know that <code>kubectl</code> can run arbitrary executables, including shell scripts, with the full privileges of the invoking user, and without your knowledge? Whenever you download or auto-generate a <code>kubeconfig</code>, the <code>users[n].exec.command</code> field can specify an executable to fetch credentials on your behalf. Don't get me wrong, this is an incredible feature that allows you to authenticate to the cluster with external identity providers. Nevertheless, you probably see the problem: Do you know exactly what executables your <code>kubeconfig</code> is running on your system? Do you trust the pipeline that generated your <code>kubeconfig</code>? If there has been a supply-chain attack on the code that generates the kubeconfig, or if the generating pipeline has been compromised, an attacker might well be doing unsavory things to your machine by tricking your <code>kubeconfig</code> into running arbitrary code.</p> <p>To give the user more control over what gets run on their system, <a href="https://git.k8s.io/community/sig-auth">SIG-Auth</a> and <a href="https://git.k8s.io/community/sig-cli">SIG-CLI</a> added the credential plugin policy and allowlist as a beta feature to Kubernetes 1.35. This is available to all clients using the <code>client-go</code> library, by filling out the <a href="https://github.com/kubernetes/client-go/blob/master/tools/clientcmd/api/types.go#L290">ExecProvider.PluginPolicy</a> struct on a REST config. To broaden the impact of this change, Kubernetes v1.35 also lets you manage this without writing a line of application code. You can configure <code>kubectl</code> to enforce the policy and allowlist by adding two fields to the <code>kuberc</code> configuration file: <code>credentialPluginPolicy</code> and <code>credentialPluginAllowlist</code>. Adding one or both of these fields restricts which credential plugins <code>kubectl</code> is allowed to execute.</p> <h2 id="how-it-works">How it works</h2> <p>A full description of this functionality is available in our <a href="https://kubernetes.io/docs/reference/kubectl/kuberc/">official documentation</a> for kuberc, but this blog post will give a brief overview of the new security knobs. The new features are in beta and available without using any feature gates.</p> <p>The following example is the simplest one: simply don't specify the new fields.</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>kubectl.config.k8s.io/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Preference<span style="color:#bbb"> </span></span></span></code></pre></div><p>This will keep <code>kubectl</code> acting as it always has, and all plugins will be allowed.</p> <p>The next example is functionally identical, but it is more explicit and therefore preferred if it's actually what you want:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>kubectl.config.k8s.io/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Preference<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">credentialPluginPolicy</span>:<span style="color:#bbb"> </span>AllowAll<span style="color:#bbb"> </span></span></span></code></pre></div><p>If you <em>don't know</em> whether or not you're using exec credential plugins, try setting your policy to <code>DenyAll</code>:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>kubectl.config.k8s.io/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Preference<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">credentialPluginPolicy</span>:<span style="color:#bbb"> </span>DenyAll<span style="color:#bbb"> </span></span></span></code></pre></div><p>If you <em>are</em> using credential plugins, you'll quickly find out what <code>kubectl</code> is trying to execute. You'll get an error like the following.</p> <blockquote> <p>Unable to connect to the server: getting credentials: plugin "cloudco-login" not allowed: policy set to "DenyAll"</p> </blockquote> <p>If there is insufficient information for you to debug the issue, increase the logging verbosity when you run your next command. For example:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#080;font-style:italic"># increase or decrease verbosity if the issue is still unclear</span> </span></span><span style="display:flex;"><span>kubectl get pods --verbosity <span style="color:#666">5</span> </span></span></code></pre></div><h3 id="selectively-allowing-plugins">Selectively allowing plugins</h3> <p>What if you need the <code>cloudco-login</code> plugin to do your daily work? That is why there's a third option for your policy, <code>Allowlist</code>. To allow a specific plugin, set the policy and add the <code>credentialPluginAllowlist</code>:</p> <div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">apiVersion</span>:<span style="color:#bbb"> </span>kubectl.config.k8s.io/v1beta1<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">kind</span>:<span style="color:#bbb"> </span>Preference<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">credentialPluginPolicy</span>:<span style="color:#bbb"> </span>Allowlist<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"></span><span style="color:#008000;font-weight:bold">credentialPluginAllowlist</span>:<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#008000;font-weight:bold">name</span>:<span style="color:#bbb"> </span>/usr/local/bin/cloudco-login<span style="color:#bbb"> </span></span></span><span style="display:flex;"><span><span style="color:#bbb"> </span>- <span style="color:#008000;font-weight:bold">name</span>:<span style="color:#bbb"> </span>get-identity<span style="color:#bbb"> </span></span></span></code></pre></div><p>You'll notice that there are two entries in the allowlist. One of them is specified by full path, and the other, <code>get-identity</code> is just a basename. When you specify just the basename, the full path will be looked up using <code>exec.LookPath</code>, which does not expand globbing or handle wildcards. Globbing is not supported at this time. Both forms (basename and full path) are acceptable, but the full path is preferable because it narrows the scope of allowed binaries even further.</p> <h3 id="future-enhancements">Future enhancements</h3> <p>Currently, an allowlist entry has only one field, <code>name</code>. In the future, we (Kubernetes SIG CLI) want to see other requirements added. One idea that seems useful is checksum verification whereby, for example, a binary would only be allowed to run if it has the sha256 sum <code>b9a3fad00d848ff31960c44ebb5f8b92032dc085020f857c98e32a5d5900ff9c</code> <strong>and</strong> exists at the path <code>/usr/bin/cloudco-login</code>.</p> <p>Another possibility is only allowing binaries that have been signed by one of a set of a trusted signing keys.</p> <h2 id="get-involved">Get involved</h2> <p>The credential plugin policy is still under development and we are very interested in your feedback. We'd love to hear what you like about it and what problems you'd like to see it solve. Or, if you have the cycles to contribute one of the above enhancements, they'd be a great way to get started contributing to Kubernetes. Feel free to join in the discussion on slack:</p> <ul> <li><a href="https://kubernetes.slack.com/archives/C2GL57FJ4">#sig-cli</a>,</li> <li><a href="https://kubernetes.slack.com/archives/C0EN96KUY">#sig-auth</a>.</li> </ul>
출처
- [Kubernetes Blog](https://kubernetes.io/blog/2026/01/09/kubernetes-v1-35-kuberc-credential-plugin-allowlist/)
- 발행일시: 2026. 1. 10. 오전 3:30:00