#!/usr/bin/env -S nix shell nixpkgs#openssl nixpkgs#yq-go nixpkgs#sops -c bash set -o errexit set -o pipefail generate_ca() { local target_dir=$1 local ca_name=$2 local ca_days=$3 local cn=$4 mkdir -p "${target_dir}" local ca_key=${target_dir}/${ca_name}.key local ca_cert=${target_dir}/${ca_name}.crt openssl genrsa -out "${ca_key}" 2048 openssl req -x509 -new -nodes -key "${ca_key}" -days "${ca_days}" -out "${ca_cert}" -subj "/CN=${cn}" } generate_alt_names() { local hosts=("$@") local dns=0 local ip=0 local alt_names="" for host in "${hosts[@]}"; do if [[ ${host} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then alt_names="${alt_names}IP.${ip} = ${host}\n" ((ip++)) else alt_names="${alt_names}DNS.${dns} = ${host}\n" ((dns++)) fi done echo -e "${alt_names}" } generate_cnf() { local target_dir=$1 local cnf_name=$2 local cn=$3 local hosts=("${@:4}") mkdir -p "${target_dir}" local cnf_file=${target_dir}/${cnf_name}.cnf cat < "${cnf_file}" [req] prompt = no [ req_ext ] subjectAltName = @alt_names [ alt_names ] $(generate_alt_names "${hosts[@]}") [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment,digitalSignature extendedKeyUsage=serverAuth,clientAuth subjectAltName=@alt_names EOF } generate_crt() { local target_dir=$1 local cert_name=$2 local cert_days=$3 local cn=$4 local o=$5 local ca_key=$6 local ca_cert=$7 local hosts=("${@:8}") mkdir -p "${target_dir}" local cert_key=${target_dir}/${cert_name}.key local cert_csr=${target_dir}/${cert_name}.csr local cert_cert=${target_dir}/${cert_name}.crt openssl genrsa -out "${cert_key}" 2048 local subject="/CN=${cn}" if [ -n "${o}" ]; then subject="${subject}/O=${o}" fi if [ -n "${hosts}" ]; then generate_cnf "${target_dir}" "${cert_name}" "${cn}" "${hosts[@]}" openssl req -new -key "${cert_key}" -out "${cert_csr}" -subj "${subject}" -config "${target_dir}"/"${cert_name}".cnf openssl x509 -req -in "${cert_csr}" -CA "${ca_cert}" -CAkey "${ca_key}" -CAcreateserial -out "${cert_cert}" -days "${cert_days}" -extfile "${target_dir}"/"${cert_name}".cnf -extensions v3_ext else openssl req -new -key "${cert_key}" -out "${cert_csr}" -subj "${subject}" openssl x509 -req -in "${cert_csr}" -CA "${ca_cert}" -CAkey "${ca_key}" -CAcreateserial -out "${cert_cert}" -days "${cert_days}" fi } generate_key_pair() { local target_dir=$1 local key_name=$2 mkdir -p "${target_dir}" local private_key=${target_dir}/${key_name}.key local public_key=${target_dir}/${key_name}.pub openssl genrsa -out "${private_key}" 2048 openssl rsa -in "${private_key}" -pubout -out "${public_key}" } generate_auth_token() { local target_dir=$1 local token_name=$2 local user=$3 local id=$4 local groups=$5 mkdir -p "${target_dir}" local token_file="${target_dir}/${token_name}.token" local token_auth_file="${target_dir}/${token_name}.csv" token="$(head -c 16 /dev/urandom | od -An -t x | tr -d ' ')" echo "${token}" > "${token_file}" echo "${token},${user},${id},\"${groups}\"" > "${token_auth_file}" } DEFAULT_CA_DAYS=3650 if [[ -z "$SOPS_AGE_KEY_FILE" ]]; then echo "Please set the SOPS_AGE_KEY_FILE environment variable" exit 1 fi hostname=${1:-$(hostname)} if [ -z "${hostname}" ]; then echo "Usage: $0 [hostname]" exit 1 fi generate_ca out ca ${DEFAULT_CA_DAYS} kubernetes-ca "" generate_ca out/front-proxy ca ${DEFAULT_CA_DAYS} kubernetes-front-proxy-ca "" generate_ca out/etcd ca ${DEFAULT_CA_DAYS} etcd-ca "" generate_crt out/apiserver cert ${DEFAULT_CA_DAYS} kube-apiserver "" out/ca.key out/ca.crt "kubernetes" "kubernetes.default" "kubernetes.default.svc" "kubernetes.default.svc.cluster" "kubernetes.default.svc.cluster.local" "localhost" "10.0.0.1" "127.0.0.1" generate_crt out/apiserver kubelet-client ${DEFAULT_CA_DAYS} kube-apiserver-kubelet-client system:masters out/ca.key out/ca.crt "" generate_crt out/apiserver etcd-client ${DEFAULT_CA_DAYS} kube-apiserver-etcd-client "" out/etcd/ca.key out/etcd/ca.crt "" generate_crt out/front-proxy client ${DEFAULT_CA_DAYS} front-proxy-client "" out/front-proxy/ca.key out/front-proxy/ca.crt "" generate_crt out/etcd server ${DEFAULT_CA_DAYS} kube-etcd "" out/etcd/ca.key out/etcd/ca.crt "etcd.local" "etcd.cluster.local" "localhost" "127.0.0.1" generate_crt out/etcd peer ${DEFAULT_CA_DAYS} kube-etcd-peer "" out/etcd/ca.key out/etcd/ca.crt "etcd.local" "etcd.cluster.local" "localhost" "127.0.0.1" generate_key_pair out sa generate_crt out/accounts admin ${DEFAULT_CA_DAYS} kubernetes-admin system:masters out/ca.key out/ca.crt "" generate_crt out/accounts users ${DEFAULT_CA_DAYS} kubernetes-users system:masters out/ca.key out/ca.crt "" generate_crt out/accounts controller-manager ${DEFAULT_CA_DAYS} system:kube-controller-manager "" out/ca.key out/ca.crt "" generate_crt out/accounts addon-manager ${DEFAULT_CA_DAYS} system:kube-addon-manager "" out/ca.key out/ca.crt "" generate_crt out/accounts scheduler ${DEFAULT_CA_DAYS} system:kube-scheduler "" out/ca.key out/ca.crt "" generate_crt out/accounts proxy ${DEFAULT_CA_DAYS} system:kube-proxy "" out/ca.key out/ca.crt "" generate_crt out/accounts flannel ${DEFAULT_CA_DAYS} flannel-client "" out/ca.key out/ca.crt "" generate_auth_token out/accounts kubelet-bootstrap "kubelet-bootstrap" 10001 "system:bootstrappers" sops_config="../../../../../$(hostname)/secrets/sops.yaml" secrets_file="../../../../../$(hostname)/secrets/secrets.yaml" decrypted_secrets_file="../../../../../$(hostname)/secrets/.decrypted~secrets.yaml" sops -d "${secrets_file}" > "${decrypted_secrets_file}" yq -i ' del(.kubernetes) | .kubernetes.ca.crt = load_str("out/ca.crt") | .kubernetes.ca.key = load_str("out/ca.key") | .kubernetes.front-proxy.ca.crt = load_str("out/front-proxy/ca.crt") | .kubernetes.front-proxy.ca.key = load_str("out/front-proxy/ca.key") | .kubernetes.etcd.ca.crt = load_str("out/etcd/ca.crt") | .kubernetes.etcd.ca.key = load_str("out/etcd/ca.key") | .kubernetes.apiserver.cert.crt = load_str("out/apiserver/cert.crt") | .kubernetes.apiserver.cert.key = load_str("out/apiserver/cert.key") | .kubernetes.apiserver.kubelet-client.crt = load_str("out/apiserver/kubelet-client.crt") | .kubernetes.apiserver.kubelet-client.key = load_str("out/apiserver/kubelet-client.key") | .kubernetes.apiserver.etcd-client.crt = load_str("out/apiserver/etcd-client.crt") | .kubernetes.apiserver.etcd-client.key = load_str("out/apiserver/etcd-client.key") | .kubernetes.front-proxy.client.crt = load_str("out/front-proxy/client.crt") | .kubernetes.front-proxy.client.key = load_str("out/front-proxy/client.key") | .kubernetes.etcd.server.crt = load_str("out/etcd/server.crt") | .kubernetes.etcd.server.key = load_str("out/etcd/server.key") | .kubernetes.etcd.peer.crt = load_str("out/etcd/peer.crt") | .kubernetes.etcd.peer.key = load_str("out/etcd/peer.key") | .kubernetes.sa.key = load_str("out/sa.key") | .kubernetes.sa.pub = load_str("out/sa.pub") | .kubernetes.accounts.admin.crt = load_str("out/accounts/admin.crt") | .kubernetes.accounts.admin.key = load_str("out/accounts/admin.key") | .kubernetes.accounts.users.crt = load_str("out/accounts/users.crt") | .kubernetes.accounts.users.key = load_str("out/accounts/users.key") | .kubernetes.accounts.controller-manager.crt = load_str("out/accounts/controller-manager.crt") | .kubernetes.accounts.controller-manager.key = load_str("out/accounts/controller-manager.key") | .kubernetes.accounts.addon-manager.crt = load_str("out/accounts/addon-manager.crt") | .kubernetes.accounts.addon-manager.key = load_str("out/accounts/addon-manager.key") | .kubernetes.accounts.scheduler.crt = load_str("out/accounts/scheduler.crt") | .kubernetes.accounts.scheduler.key = load_str("out/accounts/scheduler.key") | .kubernetes.accounts.proxy.crt = load_str("out/accounts/proxy.crt") | .kubernetes.accounts.proxy.key = load_str("out/accounts/proxy.key") | .kubernetes.accounts.flannel.crt = load_str("out/accounts/flannel.crt") | .kubernetes.accounts.flannel.key = load_str("out/accounts/flannel.key") | .kubernetes.accounts.kubelet-bootstrap.token = load_str("out/accounts/kubelet-bootstrap.token") | .kubernetes.accounts.kubelet-bootstrap.csv = load_str("out/accounts/kubelet-bootstrap.csv") ' "${decrypted_secrets_file}" sops --config "${sops_config}" -e "${decrypted_secrets_file}" > "${secrets_file}" rm -rf out