Skip to content

Create Service Account

There is currently a problem in our Kubernetes Management with the persistence of useraccounts created through the portal. This Page is dedicated to this problem with an workaround to create a service-accounts that are persistent.

Get Admin-Config from Portal

Log into the Cloud-Portal and go into your Kubernetes Dashboard.
If you already have an Kubernetes you are able to download the Kubeconfig for this Cluster. image
Click on Download Kubeconfig

image
Then click on Download Admin Kubeconfig

Download and Install Kubectl

Download kubectl from K8s.io

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"

make kubectl usable

sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl    

Copy Admin Config to .kube/config

To access the cluster with kubectl you need to create a .kube Dir in your home and paste your config into it.

cd ~
mkdir .kube
cp admin-kube.yml .kube/config

Example with Bash Script

save bash script into addUser.sh

bash addUser.sh --user testuser --role cluster-admin
save output to your .kube/admin

Example Output from Script:

## KUBECONFIG generated on Wed Feb  5 09:10:03 CET 2025
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: XXXXXXXXXXX=
    server: https://api.kube5.ewt9qdm.gardener.stage.ewcs.ch
name: garden-414d97167c7345de93300fd42872e325--<clustername>-external
contexts:
- context:
    cluster: garden-414d97167c7345de93300fd42872e325--<clustername>-external
    user: <username>-garden-414d97167c7345de93300fd42872e325--<clustername>-external
name: garden-414d97167c7345de93300fd42872e325--<clustername>-external
current-context: garden-414d97167c7345de93300fd42872e325--<clustername>-external
kind: Config
preferences: {}
users:
- name: <username>-garden-414d97167c7345de93300fd42872e325--<clustername>-external
user:
    token: XXXXXX

Bash Script

Download addUser.sh

Please install jq Package for the bash script

sudo apt install jq

#!/bin/bash

KUBECTL="/usr/local/bin/kubectl"

usage() {
    echo "Usage: $0 --user USERNAME [--role ROLE] [--delete]"
    exit 1
}

SERVICE_ACC_NAME=""
ROLE_NAME="view"
DELETE_IT=false

while [[ $# -gt 0 ]]; do
    case "$1" in
        --user)
            SERVICE_ACC_NAME="$2"
            shift 2
            ;;
        --role)
            ROLE_NAME="$2"
            shift 2
            ;;
        --delete)
            DELETE_IT=true
            shift
            ;;
        *)
            usage
            ;;
    esac
done

if [ -z "$SERVICE_ACC_NAME" ]; then
    usage
fi

if $DELETE_IT; then
    $KUBECTL delete serviceaccount "$SERVICE_ACC_NAME"
    $KUBECTL delete secret "$SERVICE_ACC_NAME-secret"
    $KUBECTL delete clusterrolebinding "view-$SERVICE_ACC_NAME-global"
    exit 0
fi

$KUBECTL create serviceaccount "$SERVICE_ACC_NAME" -n default -o json

cat <<EOF | $KUBECTL create -n default -o json -f -
apiVersion: v1
kind: Secret
metadata:
  name: $SERVICE_ACC_NAME-secret
  annotations:
    kubernetes.io/service-account.name: $SERVICE_ACC_NAME
type: kubernetes.io/service-account-token
EOF

SECRET_JSON=$($KUBECTL get secret "$SERVICE_ACC_NAME-secret" -o json)
CA_CRT=$(echo "$SECRET_JSON" | jq -r '.data["ca.crt"]')
USER_TOKEN=$(echo "$SECRET_JSON" | jq -r '.data.token | @base64d')

KUBECONFIG_JSON=$($KUBECTL config view --minify -o json)
CLUSTER_API=$(echo "$KUBECONFIG_JSON" | jq -r '.clusters[0].cluster.server')
CLUSTER_NAME=$(echo "$KUBECONFIG_JSON" | jq -r '.clusters[0].name')

cat <<EOF | $KUBECTL create -n default -o json -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: view-$SERVICE_ACC_NAME-global
subjects:
- kind: ServiceAccount
  name: $SERVICE_ACC_NAME
  namespace: default
roleRef:
  kind: ClusterRole
  name: $ROLE_NAME
  apiGroup: rbac.authorization.k8s.io
EOF

echo "## KUBECONFIG generated on $(date)"
cat <<EOF
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: $CA_CRT
    server: $CLUSTER_API
  name: $CLUSTER_NAME
contexts:
- context:
    cluster: $CLUSTER_NAME
    user: $SERVICE_ACC_NAME-$CLUSTER_NAME
  name: $CLUSTER_NAME
current-context: $CLUSTER_NAME
kind: Config
preferences: {}
users:
- name: $SERVICE_ACC_NAME-$CLUSTER_NAME
  user:
    token: $USER_TOKEN
EOF

Python Script

import sys
import json
import subprocess
import base64
from datetime import datetime

def exec_command(args, std_input=None):
    print("# " + " ".join(args))
    result = subprocess.run(args, input=std_input, text=True, capture_output=True)
    if result.returncode == 0:
        try:
            return json.loads(result.stdout)
        except json.JSONDecodeError:
            return result.stdout.strip()
    else:
        print(result.stderr, file=sys.stderr)
        sys.exit(1)

KUBECTL = "/usr/bin/kubectl"

if len(sys.argv) < 2 or sys.argv[1] == "--delete":
    print("please provide username as an argument, for example: python script.py USER_NAME [--delete]")
    sys.exit(1)

service_acc_name = sys.argv[1]
role_name = sys.argv[2] if len(sys.argv) > 2 else "view"
delete_it = len(sys.argv) > 3 and sys.argv[3] == "--delete"

if delete_it:
    exec_command([KUBECTL, "delete", "serviceaccount", service_acc_name])
    exec_command([KUBECTL, "delete", "secret", f"{service_acc_name}-secret"])
    exec_command([KUBECTL, "delete", "clusterrolebinding", f"view-{service_acc_name}-global"])
    sys.exit(0)

exec_command([KUBECTL, "create", "serviceaccount", service_acc_name, "-o", "json"])
exec_command([KUBECTL, "create", "-o", "json", "-f", "-"], f"""apiVersion: v1
kind: Secret
metadata:
  name: {service_acc_name}-secret
  annotations:
    kubernetes.io/service-account.name: {service_acc_name}
type: kubernetes.io/service-account-token""")

secret = exec_command([KUBECTL, "get", "secret", f"{service_acc_name}-secret", "-o", "json"])
ca_crt = secret["data"]["ca.crt"]
user_token = base64.b64decode(secret["data"]["token"]).decode()

kube_config = exec_command([KUBECTL, "config", "view", "--minify", "-o", "json"])
cluster_api = kube_config["clusters"][0]["cluster"]["server"]
cluster_name = kube_config["clusters"][0]["name"]

exec_command([KUBECTL, "create", "-o", "json", "-f", "-"], f"""apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name:  {role_name}-{service_acc_name}-global
subjects:
- kind: ServiceAccount
  name: {service_acc_name}
  namespace: default
roleRef:
  kind: ClusterRole
  name: {role_name}
  apiGroup: rbac.authorization.k8s.io""")

kubeconfig_output = f"""
## KUBECONFIG generated on {datetime.now()}
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: {ca_crt}
    server: {cluster_api}
  name: {cluster_name}
contexts:
- context:
    cluster: {cluster_name}
    user: {service_acc_name}-{cluster_name}
  name: {cluster_name}
current-context: {cluster_name}
kind: Config
preferences: {}
users:
- name: {service_acc_name}-{cluster_name}
  user:
    token: {user_token}
"""

print(kubeconfig_output)