NAME
Kubernetes::REST::Kubeconfig - Parse kubeconfig files and create Kubernetes::REST instances
VERSION
version 1.107
SYNOPSIS
use Kubernetes::REST::Kubeconfig;
# Use default kubeconfig and current context
my $kc = Kubernetes::REST::Kubeconfig->new;
my $api = $kc->api;
# Specify kubeconfig and context
my $kc = Kubernetes::REST::Kubeconfig->new(
kubeconfig_path => '/path/to/kubeconfig',
context_name => 'my-cluster',
);
# Several kubeconfigs, merged the way kubectl merges $KUBECONFIG
my $kc = Kubernetes::REST::Kubeconfig->new(
kubeconfig_path => '/etc/kube/base:/home/me/.kube/extra',
);
my $kc = Kubernetes::REST::Kubeconfig->new(
kubeconfig_path => [ '/etc/kube/base', '/home/me/.kube/extra' ],
);
# List available contexts
my $contexts = $kc->contexts;
# Get API for specific context
my $api = $kc->api('production');
# Inside a Kubernetes pod: no kubeconfig needed, auto-detects service account
my $api = Kubernetes::REST::Kubeconfig->new->api;
DESCRIPTION
Parses Kubernetes kubeconfig files (typically ~/.kube/config) and creates configured Kubernetes::REST instances.
Several kubeconfig files can be given at once - as the :-separated list kubectl expects in KUBECONFIG, or as an arrayref - and are merged into one configuration the way kubectl merges them. See "MERGING".
When no kubeconfig file is found, automatically falls back to in-cluster authentication using the pod's service account token.
Supports:
Multiple clusters and contexts
Merging several kubeconfig files,
kubectl-styleToken authentication, inline or from a
tokenFileClient certificate authentication
Inline certificate data (base64 encoded)
External certificate files
Exec-based credential plugins
In-cluster service account auto-detection
kubeconfig_path
Path to the kubeconfig file: a single path, a $Config{path_sep}-separated list of paths (: on Unix, ; on Win32), or an arrayref of paths. A list is merged as described in "MERGING"; a single path behaves exactly as it always has.
Defaults to the KUBECONFIG environment variable if it is set and not empty, otherwise to ~/.kube/config. With neither KUBECONFIG nor HOME set there is no path to guess, and the default is undef: "api" then goes straight to in-cluster authentication, and every method that needs a file croaks naming the two missing variables instead of reaching for /.kube/config.
The split list, without empty entries, is "kubeconfig_paths".
kubeconfig_paths
Arrayref of the individual kubeconfig paths "kubeconfig_path" names, in the order they are merged, with empty entries removed. Derived from kubeconfig_path and not settable on its own. Empty when neither KUBECONFIG nor HOME is set.
The paths are not checked for existence here - see "MERGING" for what happens to entries that are not there.
context_name
Optional. The context name to use. If not specified, uses the current-context from the kubeconfig.
refresh_token_files
Whether a token that comes from a file - a user's tokenFile, or the service account token of the in-cluster fallback - is re-read when the file changes. True by default; see "TOKEN FILES AND ROTATION".
Set it to false and such a token is read once, when "api" builds the client, and never again, which is what this module did before it could refresh.
my $kc = Kubernetes::REST::Kubeconfig->new(refresh_token_files => 0);
It reaches every client this object builds. A caller who wants it per client can build a second Kubernetes::REST::Kubeconfig - they are cheap, and the kubeconfig is only read when a client is actually built.
current_context_name
my $name = $kc->current_context_name;
Returns the current context name (either from context_name attribute or from the kubeconfig's current-context). With several kubeconfig files merged, current-context is the one from the first file that sets it.
contexts
my $contexts = $kc->contexts;
Returns an arrayref of all available context names from the kubeconfig, or from every merged kubeconfig.
context
my $ctx = $kc->context;
my $ctx = $kc->context('production');
Look up a context entry by name and return its context hashref (with cluster, user, and optional namespace keys). Defaults to current_context_name when $name is omitted. Croaks if the context is not found.
cluster
my $cluster = $kc->cluster('prod-cluster');
Look up a cluster entry by name and return its cluster hashref (with keys such as server, certificate-authority/certificate-authority-data, and insecure-skip-tls-verify). Croaks if the cluster is not found.
user
my $user = $kc->user('token-user');
Look up a user entry by name and return its user hashref (with keys such as token, client-certificate/client-certificate-data, client-key/client-key-data, or exec). Croaks if the user is not found.
api
my $api = $kc->api;
my $api = $kc->api('production');
Create a Kubernetes::REST instance (with a Kubernetes::REST::Server built from the cluster entry and credentials built from the user entry) configured from the kubeconfig. If $context_name is provided, uses that context; otherwise uses the current context.
Certificate and key material can come from either an inline base64 *-data field or a plain file-path field in the kubeconfig. Inline data is decoded and passed to Kubernetes::REST::Server as an in-memory PEM string (ssl_ca_pem/ssl_cert_pem/ssl_key_pem) rather than written to a temporary file, so the returned Kubernetes::REST instance keeps working after this Kubernetes::REST::Kubeconfig object is garbage-collected. A file path is passed on as ssl_ca_file/ssl_cert_file/ssl_key_file, absolute: a relative one is resolved against the directory of the kubeconfig that defined the entry, see "MERGING".
User authentication is resolved in this order: a plain token field; a tokenFile, whose content is the bearer token; an exec block (kubectl's exec-credential-plugin mechanism, used for e.g. cloud IAM auth), which runs the configured command (with args and any env entries applied to the child process) and reads status.token from its output (parsed as YAML, which also accepts the JSON that real exec plugins emit); otherwise an empty token, for setups that authenticate via client certificate alone.
That order is kubectl's. An inline token wins over a tokenFile - client-go's getUserIdentificationPartialConfig reads the file only when there is no inline token - and either of them wins over an exec block, which kubectl skips whenever a request already carries an Authorization header. An exec plugin is therefore not run at all when the user also has a token or a token file.
A tokenFile that cannot be read, or that holds nothing but whitespace, is a fatal error naming the user and the file. It is deliberately not a fall-through to the next mechanism: a kubeconfig saying where its token lives is a statement about how this user authenticates, and quietly carrying on would produce a 401 from the cluster with nothing pointing at the file. Leading and trailing whitespace is stripped - such files almost always end in a newline, and a newline in an Authorization header does not reach the server as intended.
A tokenFile is handed to Kubernetes::REST as a Kubernetes::REST::AuthTokenFile, which reads the file again when it changes, so a rotated token is picked up without rebuilding the client. The in-cluster service account token works the same way. See "TOKEN FILES AND ROTATION", and "refresh_token_files" to turn it off.
Falls back to in-cluster service account authentication when no kubeconfig file is found - none of the merged paths exists, or there is no path at all because neither KUBECONFIG nor HOME is set - and the pod has a mounted token at /var/run/secrets/kubernetes.io/serviceaccount/token. In that case the API server address comes from the KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT environment variables (defaulting to kubernetes.default.svc:443), and the cluster CA is read from /var/run/secrets/kubernetes.io/serviceaccount/ca.crt.
MERGING
KUBECONFIG is a PATH-style list of kubeconfig files, not a single path - :-separated everywhere except on Win32, where it is ;-separated, the same separator Perl reports in $Config{path_sep}. kubectl merges every file in that list into one configuration, and so does this module:
Clusters, contexts and users are unioned by name. The first file that defines a given name wins; later definitions of that same name are discarded, they do not overwrite fields.
current-contextcomes from the first file in the list that sets one, as does every other top-level key (apiVersion,kind,preferences).Entries that name a file that does not exist are skipped silently, which is what
kubectldoes - a list assembled by a shell profile or bydirenvroutinely mentions files that are not there. So are empty entries, so/a::/band a trailing:are harmless.Relative entries in the list itself are resolved against the current working directory.
If no file in the list exists, the configuration is empty and "api" falls back to in-cluster authentication exactly as it does for a single missing file.
Relative paths inside a kubeconfig
The file references an entry holds - certificate-authority on a cluster, client-certificate, client-key and tokenFile on a user - are resolved against the directory of the kubeconfig file that defines that entry, the way kubectl resolves them, and not against the current working directory.
With several files merged that directory is a property of the entry, not of the configuration: a cluster that won from /a/config resolves its CA against /a even when the current context came from /b/config. Resolution therefore happens as each file is read, before anything is merged, so what "cluster", "user" and "api" hand back are absolute paths that keep pointing at the same file after a chdir.
An absolute reference is passed through untouched, and so is the inline base64 of the *-data fields, which names no file. A leading ~ is not expanded - it is an ordinary directory name, exactly as it is for kubectl, and resolves like any other relative path. An exec plugin's command is not a file reference in this sense either: it is looked up in PATH and is left alone.
TOKEN FILES AND ROTATION
Kubernetes rotates the files a token can come from. The kubelet replaces a projected service account token well before it expires, and a client that read the file once at startup would go on sending a token that has stopped being valid while a good one sits in the file next to it.
A token that comes from a file - a user's tokenFile, or the service account token of the in-cluster fallback - is therefore not handed over as a fixed string. "api" builds a Kubernetes::REST::AuthTokenFile, which reads the file again whenever it has changed. There is no timer and no interval to configure: the trigger is the file itself, and a client picks up a new token on the first request after the rotation.
What "changed" means, and what it costs, is "token" in Kubernetes::REST::AuthTokenFile: one stat per request, comparing inode, size and modification time, so the ..data symlink swap the kubelet performs is seen as the different file it is. A read that fails after a successful one - the file gone for a moment mid-rotation - keeps the last good token rather than breaking the client. Only the first read, when the client is built, is fatal.
Set "refresh_token_files" to false to switch this off. The token is then read exactly once, when api() builds the client, and never again: no stat per request, and the client stops working when that token expires, until something builds it anew.
An inline token in the kubeconfig is unaffected either way - there is no file to watch, and it is used exactly as it is written.
SEE ALSO
Kubernetes::REST - Main API client
Kubernetes::REST::Server - Server configuration
Kubernetes::REST::AuthToken - Authentication credentials
SUPPORT
Issues
Please report bugs and feature requests on GitHub at https://github.com/pplu/kubernetes-rest/issues.
IRC
Join #kubernetes on irc.perl.org or message Getty directly.
CONTRIBUTING
Contributions are welcome! Please fork the repository and submit a pull request.
AUTHORS
Torsten Raudssus <getty@cpan.org>
Jose Luis Martinez Torres <jlmartin@cpan.org>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2019-2026 by Jose Luis Martinez Torres <jlmartin@cpan.org>.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004