Skip to content

Instantly share code, notes, and snippets.

@marcbachmann
Last active September 19, 2021 16:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcbachmann/fb03ea3780c97d146c822c90b461400f to your computer and use it in GitHub Desktop.
Save marcbachmann/fb03ea3780c97d146c822c90b461400f to your computer and use it in GitHub Desktop.
Kubernetes create user certificate
#!/bin/bash
set -e
USERNAME=$1
if ! grep -qE '^[a-zA-Z0-9.@\-\+_]{2,100}$' <<< "$USERNAME"; then
1>&2 echo -e "❌ Username is missing or contains invalid characters
Usage: ./kubernetes-create-user.sh marc@livingdocs.io
Will create a certificate using subject '/CN=marc@livingdocs.io'
and write the credentials into the 'marc@livingdocs.io.kubeconfig' file."
exit 1
fi
CERT_KEY="$(openssl genrsa 2048 2> /dev/null)"
CERT_CSR=$(openssl req -new -subj "/CN=$USERNAME" -key /dev/stdin <<< "$CERT_KEY")
cat <<EOF | 1>/dev/null kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: $USERNAME
spec:
groups: [system:authenticated]
request: $(base64 <<< "$CERT_CSR" | tr -d "\n")
signerName: kubernetes.io/kube-apiserver-client
usages: [client auth]
EOF
1>&2 kubectl certificate approve $USERNAME > /dev/null
CERT_CRT="$(kubectl wait --for=condition=Approved=true csr/$USERNAME -o jsonpath="{.status.certificate}" | base64 -d)"
if [ "$CERT_CRT" == "" ]; then
# There is some kind of bug in kubernetes where
# the certificate is not present right after approval
# and there is no state to wait for.
sleep 1
CERT_CRT="$(kubectl wait --for=condition=Approved=true csr/$USERNAME -o jsonpath="{.status.certificate}" | base64 -d)"
if [ "$CERT_CRT" == "" ]; then
1>&2 echo "❌ Failed to extract certificate. Try again."
kubectl delete csr $USERNAME > /dev/null
exit 1
fi
fi
kubectl delete csr $USERNAME > /dev/null
CLUSTER_NAME=$(kubectl config view --minify --raw -o jsonpath="{.clusters[0].name}")
CLUSTER_CA=$(kubectl config view --minify --raw -o jsonpath="{.clusters[0].cluster['certificate-authority-data']}")
CLUSTER_SERVER=$(kubectl config view --minify --raw -o jsonpath="{.clusters[0].cluster['server']}")
cat <<EOF > $USERNAME.kubeconfig
apiVersion: v1
kind: Config
current-context: $USERNAME@$CLUSTER_NAME
clusters:
- cluster:
certificate-authority-data: $CLUSTER_CA
server: $CLUSTER_SERVER
name: $CLUSTER_NAME
contexts:
- context:
cluster: $CLUSTER_NAME
user: $USERNAME
name: $USERNAME@$CLUSTER_NAME
users:
- name: $USERNAME
user:
client-certificate-data: $(base64 <<< "$CERT_CRT")
client-key-data: $(base64 <<< "$CERT_KEY")
EOF
1>&2 echo -e "✅ Kubernetes config written to '$USERNAME.kubeconfig'.
Test it using: \033[1mKUBECONFIG=$USERNAME.kubeconfig kubectl describe nodes\033[0m
Declare \033[1mrole bindings\033[0m manually to assign permissions before using it."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment