Last active
June 12, 2024 13:21
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ 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