Skip to content

Instantly share code, notes, and snippets.

@hegerdes
Last active June 12, 2024 13:21
Show Gist options
  • Save hegerdes/0cee1725f000dcb244d6298b3a1d3aaa to your computer and use it in GitHub Desktop.
Save hegerdes/0cee1725f000dcb244d6298b3a1d3aaa to your computer and use it in GitHub Desktop.
Create Kubernetes client configs with X509 certificates via openssl and the certificate-api
#!/bin/bash
set -e
# Make it priiittttty
RED='\033[0;31m'
NC='\033[0m'
GRN='\033[0;32m'
# Easy config
KEY_SIZE=4096
DST_DIR="certificates"
CLIENT_VALID_DAYS="365"
CERT_FILE_EXTENTION="pem"
AUTO_APPROVE_CSR="true"
CREATE_CLUSTER_ROLE_BINDING="true"
CLUSTER_ROLE=cluster-admin
####################### CHANGEME #######################
# NOTE: Activate the kube-context you want to create users in
# Add aditional names for mor clients (seperated by space)
# Usernames must be valid characters for mail addresses.
# You may also want to change the groups for the user configs in line 75+
CLIENTS=(test1 test2 test3)
CLUSTER_NAME=CHANGE_ME
# Cert data
COUNTRY="DE"
STATE="Hamburg"
CITY="Hamburg"
ORG="Company"
ORG_UNIT="Team_1"
#Set CWD
cd "$(dirname "$0")"
#Create DST-folder
mkdir -p "$DST_DIR"
#Check commands
if ! command -v openssl &>/dev/null; then
echo -e "${RED}openssl not be found. Exit${NC}"
exit 1
fi
if ! command -v jq &>/dev/null; then
echo -e "${RED}jq not be found. Exit${NC}"
exit 1
fi
if ! command -v kubectl &>/dev/null; then
echo -e "${RED}kubectl not be found. Exit${NC}"
exit 1
fi
# Get the current k8s context
k8s_current_context=$(kubectl config current-context)
# Get the cluster of the current context
k8s_current_cluster=$(kubectl config view -o jsonpath="{.contexts[?(@.name == \"$k8s_current_context\")].context.cluster}")
# Get the server of the current cluster
k8s_current_server=$(kubectl config view -o jsonpath="{.clusters[?(@.name == \"$k8s_current_cluster\")].cluster.server}")
# Get current cluster ca
k8s_current_server_ca=$(kubectl config view --raw -o jsonpath="{.clusters[?(@.name == \"$k8s_current_cluster\")].cluster.certificate-authority-data}")
# Ceck for openssl.conf
if [ -f openssl.conf ]; then
echo "Using default values form local openssl.conf."
OPENSSL_CONF_PARAM="-config openssl.conf"
fi
# Clients
for client in ${CLIENTS[@]}; do
# Create cert if not exist
if [ ! -f "$DST_DIR/$client.csr" ] || [ ! -f "$DST_DIR/$client.key" ]; then
echo -e "${GRN}Creating ${client} key and sign request ${NC}"
openssl req -new -newkey rsa:$KEY_SIZE -nodes -keyout $DST_DIR/$client.key -days $CLIENT_VALID_DAYS $OPENSSL_CONF_PARAM -batch -out $DST_DIR/$client.csr -subj "/CN=${client}/C=${COUNTRY}/ST=${STATE}/L=${CITY}/O=${ORG}/OU=${ORG_UNIT}/emailAddress=${client}@${ORG}.${COUNTRY,,}"
fi
kube_csr="apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: $client
spec:
request: $(cat $DST_DIR/$client.csr | base64 | tr -d '\n')
signerName: kubernetes.io/kube-apiserver-client
groups:
- system:unauthenticated
- user:external-$client
- user:external
usages:
- digital signature
- key encipherment
- client auth
"
# Create csr
echo "${kube_csr}" | kubectl apply -f -
done
echo -e "${GRN}You can inspect the created CertificateSigningRequest with \"kubectl get csr\"${NC}"
echo "---"
if [ "$AUTO_APPROVE_CSR" = "true" ]; then
for client in ${CLIENTS[@]}; do
if [ $(kubectl get csr $client -o json | jq .status.certificate) = "null" ]; then
echo -e "${GRN}Approving ${client} csr ${NC}"
kubectl certificate approve $client
fi
done
fi
# Check if approved anc create kubeconf
for client in ${CLIENTS[@]}; do
if [ $(kubectl get csr $client -o json | jq .status.certificate) = "null" ]; then
echo -e "${GRN}Please approve the csr's now an run the script again ${NC}"
exit 1
fi
echo -e "${GRN}Creating kubeconf for ${client} ${NC}"
kubectl get csr $client -o json | jq -r .status.certificate | base64 -d >$DST_DIR/$client.$CERT_FILE_EXTENTION
kubectl --kubeconfig $DST_DIR/$client-kubeconf.yaml config set clusters.$CLUSTER_NAME.server $k8s_current_server
kubectl --kubeconfig $DST_DIR/$client-kubeconf.yaml config set clusters.$CLUSTER_NAME.certificate-authority-data $k8s_current_server_ca
kubectl --kubeconfig $DST_DIR/$client-kubeconf.yaml config set users.$CLUSTER_NAME-$client.client-key-data $(cat $DST_DIR/$client.key | base64 -w0)
kubectl --kubeconfig $DST_DIR/$client-kubeconf.yaml config set users.$CLUSTER_NAME-$client.client-certificate-data $(cat $DST_DIR/$client.$CERT_FILE_EXTENTION | base64 -w0)
kubectl --kubeconfig $DST_DIR/$client-kubeconf.yaml config set-context $CLUSTER_NAME --cluster $CLUSTER_NAME --user $CLUSTER_NAME-$client
kubectl --kubeconfig $DST_DIR/$client-kubeconf.yaml config use-context $CLUSTER_NAME
done
# Create CRB
if [ "$CREATE_CLUSTER_ROLE_BINDING" = "true" ]; then
for client in ${CLIENTS[@]}; do
kube_crb="
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: external-user-$client
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: $CLUSTER_ROLE
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: $client
"
echo "${kube_crb}" | kubectl apply -f -
done
else
echo -e "${GRN}Please create RBAC rules for users${NC}"
fi
# Debug helper: https://www.sslshopper.com/article-most-common-openssl-commands.html
# cat $DST_DIR/$client.$CERT_FILE_EXTENTION $DST_DIR/$CA_FILE_NAME.$CERT_FILE_EXTENTION >$DST_DIR/$client-full.$CERT_FILE_EXTENTION
# To install the CA do:
# sudo cp certificates/ca.$CERT_FILE_EXTENTION /usr/local/share/ca-certificates/my-ca-cert.crt
# sudo update-ca-certificates
# Windows import
# https://community.spiceworks.com/how_to/1839-installing-self-signed-ca-certificate-in-windows
echo -e "${GRN}Everything generated succsesfully${NC}"
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = v3_req
promt = no
# Default values can be overwirtten on CLI
[ req_distinguished_name ]
countryName = DE
stateOrProvinceName = Hamburg
localityName = Hamburg
organizationName = Company
commonName = client1
commonName_max = 64
commonName_default = client1
emailAddress = [email protected]
emailAddress_max = 64
emailAddress_default = [email protected]
#Usage and SAN
[ v3_req ]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = *.localhost
DNS.3 = *.k8s.localhost
DNS.4 = host.docker.internal
DNS.5 = gateway.docker.internal
DNS.6 = kubernetes.docker.internal
DNS.7 = *.local
DNS.8 = *.internal
DNS.9 = *.k8s.internal
IP.1 = 127.0.0.1
IP.2 = ::1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment