#!/usr/bin/env bash

# Fail on error
set -eo pipefail

# Script location and name
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
SCRIPT_NAME=`basename "$0"`

green() {
  echo -e "\033[0;32m$@\033[0m"
}

red() {
  echo -e "\033[0;31m$@\033[0m"
}

yellow() {
  echo -e "\033[0;33m$@\033[0m"
}

cyan() {
  echo -e "\033[0;36m$@\033[0m"
}

# Display help message
help() {
  echo "Generate a kubeconfig file for a given service account."
  echo
  echo "Usage: $SCRIPT_NAME SERVICE_ACCOUNT [kubectl options]"
  echo "Parameters:"
  echo "SERVICE_ACCOUNT     Name of the service account to generate a kubeconfig for."
  echo
}

# Check kubectl is available on system
check_kubectl() {
  if test ! command -v kubectl &>/dev/null; then
    red "kubectl was not found on your system!"
    exit 2
  fi
}

# Check authenticated user has required permissions to execute the script without error
check_permissions() {
  cyan "Checking permissions..."

  # Check permission to get service accounts
  if test ! _kubectl auth can-i get sa &>/dev/null; then
    red "You do not have the permission to get service accounts."
    exit 3
  # Check permission to get secrets
  elif test ! _kubectl auth can-i get secret &>/dev/null; then
    red "You do not have the permission to get secrets."
    exit 4
  fi
}

# Helper function to execute kubectl with parameters while passing it user-provided parameters
_kubectl() {
  kubectl $@ $KUBE_OPTS
}

# Fail if no parameters given to script
if test $# -eq 0; then
  help
  exit 1
fi

# Get user-provided parameters
SERVICE_ACCOUNT=$1
KUBE_OPTS=${@:2}

# Execute checks before executing script
check_kubectl
check_permissions


# Set namespace for the creation of the secret and generation of the kubeconfig
NAMESPACE=$(_kubectl get sa $SERVICE_ACCOUNT -o jsonpath='{.metadata.namespace}')

# Create secret for the service account w
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: $SERVICE_ACCOUNT
  namespace: $NAMESPACE
  annotations:
    kubernetes.io/service-account.name: $SERVICE_ACCOUNT
type: kubernetes.io/service-account-token
EOF

# Prepare data needed to generate kubeconfig file
TOKEN=$(kubectl -n $NAMESPACE get secret $SERVICE_ACCOUNT -o jsonpath='{.data.token}' | base64 -d)
CA_CERT=$(kubectl -n $NAMESPACE get secret $SERVICE_ACCOUNT -o jsonpath='{.data.ca\.crt}')
CONTEXT=$(kubectl config current-context)
CLUSTER=$(kubectl config view -o "jsonpath={.contexts[?(@.name==\"$CONTEXT\")].context.cluster}")
SERVER=$(kubectl config view -o "jsonpath={.clusters[?(@.name==\"$CLUSTER\")].cluster.server}")

# Generate kubeconfig from previously gathered data
KUBECONFIG=$(mktemp)
cat <<EOF > $KUBECONFIG
apiVersion: v1
kind: Config
clusters:
- name: $CLUSTER
  cluster:
    certificate-authority-data: $CA_CERT
    server: $SERVER
contexts:
- name: $CONTEXT
  context:
    cluster: $CLUSTER
    namespace: $NAMESPACE
    user: $SERVICE_ACCOUNT
current-context: $CONTEXT
users:
- name: $SERVICE_ACCOUNT
  user:
    token: $TOKEN
EOF

# Move generated kubeconfig to a file in current working directory
mv $KUBECONFIG $(pwd)/kubeconfig-$SERVICE_ACCOUNT.yaml

# Display generated kubeconfig location to user
green "Kubeconfig file successfully generated: $(pwd)/kubeconfig-$SERVICE_ACCOUNT.yaml"
