Skip to content

Instantly share code, notes, and snippets.

@innovia
Last active January 29, 2024 23:00
Star You must be signed in to star a gist
Save innovia/fbba8259042f71db98ea8d4ad19bd708 to your computer and use it in GitHub Desktop.
Create a service account and generate a kubeconfig file for it - this will also set the default namespace for the user
#!/bin/bash
set -e
set -o pipefail
# Add user to k8s using service account, no RBAC (must create RBAC after this script)
if [[ -z "$1" ]] || [[ -z "$2" ]]; then
echo "usage: $0 <service_account_name> <namespace>"
exit 1
fi
SERVICE_ACCOUNT_NAME=$1
NAMESPACE="$2"
KUBECFG_FILE_NAME="/tmp/kube/k8s-${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-conf"
TARGET_FOLDER="/tmp/kube"
create_target_folder() {
echo -n "Creating target directory to hold files in ${TARGET_FOLDER}..."
mkdir -p "${TARGET_FOLDER}"
printf "done"
}
create_service_account() {
echo -e "\\nCreating a service account in ${NAMESPACE} namespace: ${SERVICE_ACCOUNT_NAME}"
kubectl create sa "${SERVICE_ACCOUNT_NAME}" --namespace "${NAMESPACE}"
}
get_secret_name_from_service_account() {
echo -e "\\nGetting secret of service account ${SERVICE_ACCOUNT_NAME} on ${NAMESPACE}"
SECRET_NAME=$(kubectl get sa "${SERVICE_ACCOUNT_NAME}" --namespace="${NAMESPACE}" -o json | jq -r .secrets[].name)
echo "Secret name: ${SECRET_NAME}"
}
extract_ca_crt_from_secret() {
echo -e -n "\\nExtracting ca.crt from secret..."
kubectl get secret --namespace "${NAMESPACE}" "${SECRET_NAME}" -o json | jq \
-r '.data["ca.crt"]' | base64 -D > "${TARGET_FOLDER}/ca.crt"
printf "done"
}
get_user_token_from_secret() {
echo -e -n "\\nGetting user token from secret..."
USER_TOKEN=$(kubectl get secret --namespace "${NAMESPACE}" "${SECRET_NAME}" -o json | jq -r '.data["token"]' | base64 -D)
printf "done"
}
set_kube_config_values() {
context=$(kubectl config current-context)
echo -e "\\nSetting current context to: $context"
CLUSTER_NAME=$(kubectl config get-contexts "$context" | awk '{print $3}' | tail -n 1)
echo "Cluster name: ${CLUSTER_NAME}"
ENDPOINT=$(kubectl config view \
-o jsonpath="{.clusters[?(@.name == \"${CLUSTER_NAME}\")].cluster.server}")
echo "Endpoint: ${ENDPOINT}"
# Set up the config
echo -e "\\nPreparing k8s-${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-conf"
echo -n "Setting a cluster entry in kubeconfig..."
kubectl config set-cluster "${CLUSTER_NAME}" \
--kubeconfig="${KUBECFG_FILE_NAME}" \
--server="${ENDPOINT}" \
--certificate-authority="${TARGET_FOLDER}/ca.crt" \
--embed-certs=true
echo -n "Setting token credentials entry in kubeconfig..."
kubectl config set-credentials \
"${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
--kubeconfig="${KUBECFG_FILE_NAME}" \
--token="${USER_TOKEN}"
echo -n "Setting a context entry in kubeconfig..."
kubectl config set-context \
"${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
--kubeconfig="${KUBECFG_FILE_NAME}" \
--cluster="${CLUSTER_NAME}" \
--user="${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
--namespace="${NAMESPACE}"
echo -n "Setting the current-context in the kubeconfig file..."
kubectl config use-context "${SERVICE_ACCOUNT_NAME}-${NAMESPACE}-${CLUSTER_NAME}" \
--kubeconfig="${KUBECFG_FILE_NAME}"
}
create_target_folder
create_service_account
get_secret_name_from_service_account
extract_ca_crt_from_secret
get_user_token_from_secret
set_kube_config_values
echo -e "\\nAll done! Test with:"
echo "KUBECONFIG=${KUBECFG_FILE_NAME} kubectl get pods"
echo "you should not have any permissions by default - you have just created the authentication part"
echo "You will need to create RBAC permissions"
KUBECONFIG=${KUBECFG_FILE_NAME} kubectl get pods
@heralight
Copy link

Hi, I create a complete project with a part of this wonderful script https://github.com/heralight/k8s-user-tools , don't hesitate to comment it!

Thank you

@dharmendrakariya
Copy link

It takes too much time, is it expected?

@simplenotezy
Copy link

Script almost finishes, but ends with:

Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:helm-github-actions" cannot list resource "pods" in API group "" in the namespace "default"

Specifically this command:

KUBECONFIG=${KUBECFG_FILE_NAME} kubectl get pods

@simplenotezy
Copy link

# permissions.yaml
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: deliverybot-clusterrolebinding
subjects:
  - kind: ServiceAccount
    name: deliverybot
    namespace: default
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: ""

Heres what I used to get access. You'll want to update the service account name to be whatever you used in ./setup command.

Heres how I did it. First I saved the above in a file names permissions.yaml and ran the following.

chmod +x setup.sh
./setup.sh deliverybot default
kubectl apply -f permissions.yaml 
KUBECONFIG=/tmp/kube/k8s-deliverybot-default-conf kubectl get pods

Ah - this fixed it. Thanks!

@sdarwin
Copy link

sdarwin commented Mar 13, 2023

Does this have an effect on the process?
From https://kubernetes.io/docs/concepts/security/service-accounts/

"""
Service Account Token Secrets In Kubernetes v1.24 and later, the LegacyServiceAccountTokenNoAutoGeneration feature gate prevents Kubernetes from automatically creating these tokens for ServiceAccounts. LegacyServiceAccountTokenNoAutoGeneration is enabled by default; in other words, Kubernetes does not create these tokens.
"""

Here is an updated version which creates the api token manually.
https://gist.github.com/sdarwin/ffc5fed82b6128a7549fd6d5696d98a8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment