Kubernetes-REST
view release on metacpan or search on metacpan
lib/Kubernetes/REST/Kubeconfig.pm view on Meta::CPAN
return $item if $item->{name} eq $name;
}
return undef;
}
sub context {
my ($self, $name) = @_;
$name //= $self->current_context_name;
my $ctx = $self->_find_by_name($self->_config->{contexts}, $name)
or croak "Context not found: $name";
return $ctx->{context};
}
sub cluster {
my ($self, $name) = @_;
my $cluster = $self->_find_by_name($self->_config->{clusters}, $name)
or croak "Cluster not found: $name";
return $cluster->{cluster};
}
sub user {
my ($self, $name) = @_;
my $user = $self->_find_by_name($self->_config->{users}, $name)
or croak "User not found: $name";
return $user->{user};
}
sub _resolve_cert {
my ($self, $hash, $key) = @_;
my $data_key = "${key}-data";
if (my $data = $hash->{$data_key}) {
return (pem => decode_base64($data));
}
if (my $file = $hash->{$key}) {
return (file => $file);
}
return ();
}
sub api {
my ($self, $context_name) = @_;
# If no kubeconfig, try in-cluster
unless ($self->_config) {
return $self->_in_cluster_api
// croak "Kubeconfig not found: " . $self->kubeconfig_path
. " and not running in-cluster";
}
$context_name //= $self->current_context_name;
my $ctx = $self->context($context_name);
my $cluster = $self->cluster($ctx->{cluster});
my $user = $self->user($ctx->{user});
# Build server config
my %server = (
endpoint => $cluster->{server},
);
if (my %ca = $self->_resolve_cert($cluster, 'certificate-authority')) {
$server{ $ca{pem} ? 'ssl_ca_pem' : 'ssl_ca_file' } = $ca{pem} // $ca{file};
}
if ($cluster->{'insecure-skip-tls-verify'}) {
$server{ssl_verify_server} = 0;
} else {
$server{ssl_verify_server} = 1;
}
if (my %cert = $self->_resolve_cert($user, 'client-certificate')) {
$server{ $cert{pem} ? 'ssl_cert_pem' : 'ssl_cert_file' } = $cert{pem} // $cert{file};
}
if (my %key = $self->_resolve_cert($user, 'client-key')) {
$server{ $key{pem} ? 'ssl_key_pem' : 'ssl_key_file' } = $key{pem} // $key{file};
}
# Build credentials
my $credentials;
if (my $token = $user->{token}) {
$credentials = Kubernetes::REST::AuthToken->new(token => $token);
} elsif (my $exec = $user->{exec}) {
$credentials = $self->_exec_credential($exec);
} else {
# No token auth, might be using client certs only
$credentials = Kubernetes::REST::AuthToken->new(token => '');
}
return Kubernetes::REST->new(
server => Kubernetes::REST::Server->new(%server),
credentials => $credentials,
);
}
sub _exec_credential {
my ($self, $exec) = @_;
my $cmd = $exec->{command};
my @args = @{$exec->{args} // []};
# Set up environment
local %ENV = %ENV;
for my $env (@{$exec->{env} // []}) {
$ENV{$env->{name}} = $env->{value};
}
my $output = `$cmd @args`;
croak "exec credential command failed: $cmd" if $?;
my $cred = YAML::XS::Load($output);
my $token = $cred->{status}{token}
or croak "exec credential did not return token";
return Kubernetes::REST::AuthToken->new(token => $token);
}
my $SA_TOKEN = '/var/run/secrets/kubernetes.io/serviceaccount/token';
my $SA_CA = '/var/run/secrets/kubernetes.io/serviceaccount/ca.crt';
sub _in_cluster_api {
my ($self) = @_;
return undef unless -f $SA_TOKEN;
my $host = $ENV{KUBERNETES_SERVICE_HOST} // 'kubernetes.default.svc';
my $port = $ENV{KUBERNETES_SERVICE_PORT} // '443';
open my $fh, '<', $SA_TOKEN or croak "Cannot read $SA_TOKEN: $!";
my $token = do { local $/; <$fh> };
chomp $token;
return Kubernetes::REST->new(
server => Kubernetes::REST::Server->new(
endpoint => "https://$host:$port",
ssl_ca_file => $SA_CA,
ssl_verify_server => 1,
),
credentials => Kubernetes::REST::AuthToken->new(token => $token),
);
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Kubernetes::REST::Kubeconfig - Parse kubeconfig files and create Kubernetes::REST instances
=head1 VERSION
version 1.104
=head1 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',
);
# 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;
=head1 DESCRIPTION
Parses Kubernetes kubeconfig files (typically C<~/.kube/config>) and creates configured L<Kubernetes::REST> instances.
When no kubeconfig file is found, automatically falls back to in-cluster
authentication using the pod's service account token.
Supports:
=over 4
=item * Multiple clusters and contexts
=item * Token authentication
( run in 0.878 second using v1.01-cache-2.11-cpan-524268b4103 )