How to create a kubectl config file for serviceaccount
Asked Answered
D

5

51

I have a kubernetes cluster on Azure and I created 2 namespaces and 2 service accounts because I have two teams deploying on the cluster. I want to give each team their own kubeconfig file for the serviceaccount I created.

I am pretty new to Kubernetes and haven't been able to find a clear instruction on the kubernetes website. How do I create a kube config file for a serviceaccount? Hopefully someone can help me out :), I rather not give the default kube config file to the teams.

With kind regards,

Bram

Dipteran answered 12/12, 2017 at 10:45 Comment(0)
H
86
# your server name goes here
server=https://localhost:8443
# the name of the secret containing the service account token goes here
name=default-token-sg96k

ca=$(kubectl get secret/$name -o jsonpath='{.data.ca\.crt}')
token=$(kubectl get secret/$name -o jsonpath='{.data.token}' | base64 --decode)
namespace=$(kubectl get secret/$name -o jsonpath='{.data.namespace}' | base64 --decode)

echo "
apiVersion: v1
kind: Config
clusters:
- name: default-cluster
  cluster:
    certificate-authority-data: ${ca}
    server: ${server}
contexts:
- name: default-context
  context:
    cluster: default-cluster
    namespace: default
    user: default-user
current-context: default-context
users:
- name: default-user
  user:
    token: ${token}
" > sa.kubeconfig
Hyehyena answered 12/12, 2017 at 15:52 Comment(7)
Commands ca=..., token=..., and namespace=... will fail if the secret resides in an namespace other than default. IMO you have to set also namespace up front instead of calculating it. And BTW here is a related, still unanswered question.Dictograph
This is what I got: base64: invalid option -- 'D' Try 'base64 --help' for more information. It's -d, not -D.Gloaming
base64 --decode is more desktop OS compatible (Debian, FreeBSD & MacOS) than -D (only MacOS?) or -d (Debian & FreeBSD, Busybox => also Alpine) (cc: @AlexGrönholm)Juryrig
The name can also be extracted using kubectl get sa -n namespace service_account_name -o jsonpath='{.secrets[0].name}'Sigismond
When I use the above yaml, I get error as below: error: unable to recognize "sa.kubeconfig": no matches for kind "Config" in version "v1"Platypus
I'm trying to do something like this, but I get error: You must be logged in to the server (Unauthorized). Isn't the config supposed to be the authorization?Cultivator
Is it just me or is the namespace shell variable not required?Tahoe
F
22

I cleaned up Jordan Liggitt's script a little.

Unfortunately I am not yet allowed to comment so this is an extra answer:

Be aware that starting with Kubernetes 1.24 you will need to create the Secret with the token yourself and reference that

# The script returns a kubeconfig for the ServiceAccount given
# you need to have kubectl on PATH with the context set to the cluster you want to create the config for

# Cosmetics for the created config
clusterName='some-cluster'
# your server address goes here get it via `kubectl cluster-info`
server='https://157.90.17.72:6443'
# the Namespace and ServiceAccount name that is used for the config
namespace='kube-system'
serviceAccount='developer'

# The following automation does not work from Kubernetes 1.24 and up.
# You might need to
# define a Secret, reference the ServiceAccount there and set the secretName by hand!
# See https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#manually-create-a-long-lived-api-token-for-a-serviceaccount for details
secretName=$(kubectl --namespace="$namespace" get serviceAccount "$serviceAccount" -o=jsonpath='{.secrets[0].name}')

######################
# actual script starts
set -o errexit


ca=$(kubectl --namespace="$namespace" get secret/"$secretName" -o=jsonpath='{.data.ca\.crt}')
token=$(kubectl --namespace="$namespace" get secret/"$secretName" -o=jsonpath='{.data.token}' | base64 --decode)

echo "
---
apiVersion: v1
kind: Config
clusters:
  - name: ${clusterName}
    cluster:
      certificate-authority-data: ${ca}
      server: ${server}
contexts:
  - name: ${serviceAccount}@${clusterName}
    context:
      cluster: ${clusterName}
      namespace: ${namespace}
      user: ${serviceAccount}
users:
  - name: ${serviceAccount}
    user:
      token: ${token}
current-context: ${serviceAccount}@${clusterName}
"
Foison answered 7/7, 2021 at 11:5 Comment(1)
For Kubernetes 1,24 and up you need to create the secret manually, ie you can then pull it from its name instead of looking it up through serviceAccount/... https://mcmap.net/q/354671/-service-account-secret-is-not-listed-how-to-fix-itOutlawry
P
5

Look to https://github.com/superbrothers/kubectl-view-serviceaccount-kubeconfig-plugin

This plugin helps to get service account config via

kubectl view-serviceaccount-kubeconfig <service_account> -n <namespace>
Pitcher answered 25/5, 2022 at 8:38 Comment(2)
It has a error: Error: serviceaccount xxx has no secrets. I use k8s 1.26Nolin
github.com/superbrothers/…Pitcher
P
4

Kubectl can be initialized to use a cluster account. To do so, get the cluster url, cluster certificate and account token.

KUBE_API_EP='URL+PORT'
KUBE_API_TOKEN='TOKEN'
KUBE_CERT='REDACTED'

echo $KUBE_CERT >deploy.crt
kubectl config set-cluster k8s --server=https://$KUBE_API_EP \ 
    --certificate-authority=deploy.crt  \
    --embed-certs=true
kubectl config set-credentials gitlab-deployer --token=$KUBE_API_TOKEN
kubectl config set-context k8s --cluster k8s --user gitlab-deployer
kubectl config use-context k8s

The cluster file is stored under: ~/.kube/config. Now the cluster can be accessed using:

kubectl --context=k8s get pods -n test-namespace

add this flag --insecure-skip-tls-verify if you are using self signed certificate.

Pushy answered 10/2, 2020 at 12:58 Comment(0)
A
2

Revisiting this as I was looking for a way to create a serviceaccount from the command line instead of repetitive point/click tasks through Lens IDE. I came across this thread and took the original authors ideas and expanded on the capabilities as well as supporting serviceaccount creations for Kubernetes 1.24+

#!/bin/sh

# This shell script is intended for Kubernetes clusters running 1.24+ as secrets are no longer auto-generated with serviceaccount creations
# The script does a few things: creates a serviceaccount, creates a secret for that serviceaccount (and annotates accordingly), creates a clusterrolebinding or rolebinding
# provides a kubeconfig output to the screen as well as writing to a file that can be included in the KUBECONFIG or PATH

# Feed variables to kubectl commands (modify as needed).  crb and rb can not both be true
# ------------------------------------------- #
clustername=some_cluster
name=some_user
ns=some_ns # namespace
server=https://some.server.com:6443
crb=false # clusterrolebinding
crb_name=some_binding # clusterrolebindingname_name
rb=true # rolebinding
rb_name=some_binding # rolebinding_name
# ------------------------------------------- #

# Check for existing serviceaccount first
sa_precheck=$(kubectl get sa $name -o jsonpath='{.metadata.name}' -n $ns) > /dev/null 2>&1

if [ -z "$sa_precheck" ]
then 
    kubectl create serviceaccount $name -n $ns
else
    echo "serviceacccount/"$sa_precheck" already exists"  
fi

sa_name=$(kubectl get sa $name -o jsonpath='{.metadata.name}' -n $ns)
sa_uid=$(kubectl get sa $name -o jsonpath='{.metadata.uid}' -n $ns)

# Check for existing secret/service-account-token, if one does not exist create one but do not output to external file
secret_precheck=$(kubectl get secret $sa_name-token-$sa_uid -o jsonpath='{.metadata.name}' -n $ns) > /dev/null 2>&1

if [ -z "$secret_precheck" ]
then 
    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Secret
    type: kubernetes.io/service-account-token
    metadata:
      name: $sa_name-token-$sa_uid
      namespace: $ns
      annotations:
        kubernetes.io/service-account.name: $sa_name
EOF
else
    echo "secret/"$secret_precheck" already exists"
fi

# Check for adding clusterrolebinding or rolebinding (both can not be true)
if [ "$crb" = "true" ] && [ "$rb" = "true" ] 
then
    echo "Both clusterrolebinding and rolebinding can not be true, please fix"
    exit

elif [ "$crb" = "true" ]
then
    crb_test=$(kubectl get clusterrolebinding $crb_name -o jsonpath='{.metadata.name}') > /dev/null 2>&1
    if [ "$crb_name" = "$crb_test" ]
    then
        kubectl patch clusterrolebinding $crb_name --type='json' -p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": '$sa_name', "namespace": '$ns' } }]'
    else
        echo "clusterrolebinding/"$crb_name" does not exist, please fix"
        exit    
    fi

elif [ "$rb" = "true" ]
then
    rb_test=$(kubectl get rolebinding $rb_name -n $ns -o jsonpath='{.metadata.name}' -n $ns) > /dev/null 2>&1
    if [ "$rb_name" = "$rb_test" ]
    then
        kubectl patch rolebinding $rb_name -n $ns --type='json' -p='[{"op": "add", "path": "/subjects/-", "value": {"kind": "ServiceAccount", "name": '$sa_name', "namespace": '$ns' } }]'
    else 
        echo "rolebinding/"$rb_name" does not exist in "$ns" namespace, please fix"
        exit
    fi
fi

# Create Kube Config and output to config file
ca=$(kubectl get secret $sa_name-token-$sa_uid -o jsonpath='{.data.ca\.crt}' -n $ns)
token=$(kubectl get secret $sa_name-token-$sa_uid -o jsonpath='{.data.token}' -n $ns | base64 --decode)

echo "
apiVersion: v1
kind: Config
clusters:
  - name: ${clustername}
    cluster:
      certificate-authority-data: ${ca}
      server: ${server}
contexts:
  - name: ${sa_name}@${clustername}
    context:
      cluster: ${clustername}
      namespace: ${ns}
      user: ${sa_name}
users:
  - name: ${sa_name}
    user:
      token: ${token}
current-context: ${sa_name}@${clustername}
" | tee $sa_name@${clustername}
Aleman answered 9/7, 2022 at 2:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.