Zum Inhalt

Service-Account erstellen

Derzeit gibt es in unserem Kubernetes Management ein Problem mit der Persistenz von Admin-Konfigs die über das Dashboard erstellt werden.. Diese Seite nimmt sich diesem Problems an und bietet einen Workaround zur Erstellung von Service-Accounts in Kubernetes, die persistent sind.

Admin-Konfiguration vom Portal

Melden Sie sich im Cloud-Portal an und navigieren Sie zu Ihrem Kubernetes Dashboard.
Wenn Sie bereits einen Kubernetes-Cluster haben, können Sie die Kubeconfig für ihren Cluster herunterladen. image
Klicken Sie auf Download Kubeconfig

image
Klicken Sie dann auf Download Admin Kubeconfig

Kubectl herunterladen und installieren

Kubectl von K8s.io herunterladen

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

kubectl benutzbar machen

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

Admin-Konfiguration nach .kube/config kopieren

Um Zugriff auf ihr Kubernetes per kubectl zu erhalten müssen sie das .kube-Verzeichnis in Ihrem Home erstellen und die Konfiguration hinein kopieren.

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

Beispiel mit Bash-Skript

Bash-Skript in addUser.sh speichern

bash addUser.sh --user testuser --role cluster-admin
Speichern Sie die Ausgabe in Ihrer .kube/admin

Beispielausgabe des Skripts:

## 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-Skript

Bitte installieren Sie das jq-Paket für das Bash-Skript

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-Skript

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)