mirror of https://github.com/k3s-io/k3s
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.9 KiB
134 lines
4.9 KiB
#!/usr/bin/env bash |
|
set -e |
|
umask 027 |
|
|
|
# Example K3s self-signed CA rotation script. |
|
# |
|
# This script will generate new self-signed root CA certificates, and cross-sign them with the |
|
# current self-signed root CA certificates. It will then generate new leaf CA certificates |
|
# signed by the new self-signed/cross-signed root CAs. The resulting cluster CA bundle will |
|
# allow existing certificates to be trusted up until the original root CAs expire. |
|
# |
|
CONFIG=" |
|
[v3_ca] |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid:always,issuer:always |
|
basicConstraints=CA:true" |
|
TIMESTAMP=$(date +%s) |
|
PRODUCT="${PRODUCT:-k3s}" |
|
DATA_DIR="${DATA_DIR:-/var/lib/rancher/${PRODUCT}}" |
|
TEMP_DIR="${DATA_DIR}/server/rotate-ca" |
|
|
|
if type -t openssl-3 &>/dev/null; then |
|
OPENSSL=openssl-3 |
|
else |
|
OPENSSL=openssl |
|
fi |
|
|
|
echo "Using $(type -p ${OPENSSL}): $(${OPENSSL} version)" |
|
|
|
if ! ${OPENSSL} ecparam -name prime256v1 -genkey -out /dev/null &>/dev/null; then |
|
echo "openssl not found or missing Elliptic Curve (ecparam) support." |
|
exit 1 |
|
fi |
|
|
|
${OPENSSL} version | grep -qF 'OpenSSL 3' && OPENSSL_GENRSA_FLAGS=-traditional |
|
|
|
mkdir -p ${TEMP_DIR}/tls/etcd |
|
cd ${TEMP_DIR}/tls |
|
|
|
# Set up temporary openssl configuration |
|
mkdir -p ".ca/certs" |
|
trap "rm -rf .ca" EXIT |
|
touch .ca/index |
|
openssl rand -hex 8 > .ca/serial |
|
cat >.ca/config <<'EOF' |
|
[ca] |
|
default_ca = ca_default |
|
[ca_default] |
|
dir = ./.ca |
|
database = $dir/index |
|
serial = $dir/serial |
|
new_certs_dir = $dir/certs |
|
default_md = sha256 |
|
policy = policy_anything |
|
[policy_anything] |
|
commonName = supplied |
|
[req] |
|
distinguished_name = req_distinguished_name |
|
[req_distinguished_name] |
|
[v3_ca] |
|
subjectKeyIdentifier = hash |
|
authorityKeyIdentifier = keyid:always |
|
basicConstraints = critical, CA:true |
|
keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign |
|
EOF |
|
|
|
for TYPE in client server request-header etcd/peer etcd/server; do |
|
if [ ! -f ${DATA_DIR}/server/tls/${TYPE}-ca.crt ]; then |
|
echo "Current ${TYPE} CA cert does not exist; cannot continue" |
|
exit 1 |
|
fi |
|
|
|
if [ "$(grep -cF 'END CERTIFICATE' ${DATA_DIR}/server/tls/${TYPE}-ca.crt)" -gt "1" ]; then |
|
awk 'BEGIN { RS = "-----END CERTIFICATE-----\n" } NR==2 { print $0 RS }' ${DATA_DIR}/server/tls/${TYPE}-ca.crt > ${TYPE}-root-old.pem |
|
awk 'BEGIN { RS = "-----END EC PRIVATE KEY-----\n" } NR==2 { print $0 RS }' ${DATA_DIR}/server/tls/${TYPE}-ca.key > ${TYPE}-root-old.key |
|
else |
|
cat ${DATA_DIR}/server/tls/${TYPE}-ca.crt > ${TYPE}-root-old.pem |
|
cat ${DATA_DIR}/server/tls/${TYPE}-ca.key > ${TYPE}-root-old.key |
|
fi |
|
|
|
CERT_NAME="${PRODUCT}-$(echo ${TYPE} | tr / -)-root" |
|
echo "Generating ${CERT_NAME} root and cross-signed certificate authority key and certificates" |
|
${OPENSSL} ecparam -name prime256v1 -genkey -noout -out ${TYPE}-root.key |
|
${OPENSSL} req -x509 -new -nodes -sha256 -days 7300 \ |
|
-subj "/CN=${CERT_NAME}@${TIMESTAMP}" \ |
|
-key ${TYPE}-root.key \ |
|
-out ${TYPE}-root-ssigned.pem \ |
|
-config ./.ca/config \ |
|
-extensions v3_ca |
|
${OPENSSL} req -new -nodes \ |
|
-subj "/CN=${CERT_NAME}@${TIMESTAMP}" \ |
|
-key ${TYPE}-root.key | |
|
${OPENSSL} ca -batch -notext -days 7300 \ |
|
-in /dev/stdin \ |
|
-out ${TYPE}-root-xsigned.pem \ |
|
-keyfile ${TYPE}-root-old.key \ |
|
-cert ${TYPE}-root-old.pem \ |
|
-config ./.ca/config \ |
|
-extensions v3_ca |
|
CERT_NAME="${PRODUCT}-$(echo ${TYPE} | tr / -)-ca" |
|
echo "Generating ${CERT_NAME} intermediate certificate authority key and certificates" |
|
${OPENSSL} ecparam -name prime256v1 -genkey -noout -out ${TYPE}-ca.key |
|
${OPENSSL} req -new -nodes \ |
|
-subj "/CN=${CERT_NAME}@${TIMESTAMP}" \ |
|
-key ${TYPE}-ca.key | |
|
${OPENSSL} ca -batch -notext -days 7300 \ |
|
-in /dev/stdin \ |
|
-out ${TYPE}-ca.pem \ |
|
-keyfile ${TYPE}-root.key \ |
|
-cert ${TYPE}-root-ssigned.pem \ |
|
-config ./.ca/config \ |
|
-extensions v3_ca |
|
|
|
cat ${TYPE}-ca.pem \ |
|
${TYPE}-root-ssigned.pem \ |
|
${TYPE}-root-xsigned.pem \ |
|
${TYPE}-root-old.pem > ${TYPE}-ca.crt |
|
cat ${TYPE}-root.key >> ${TYPE}-ca.key |
|
done |
|
|
|
${OPENSSL} genrsa ${OPENSSL_GENRSA_FLAGS:-} -out service.key 2048 |
|
cat ${DATA_DIR}/server/tls/service.key >> service.key |
|
|
|
export SERVER_CA_HASH=$(${OPENSSL} x509 -noout -fingerprint -sha256 -in server-ca.pem | awk -F= '{ gsub(/:/, "", $2); print tolower($2) }') |
|
SERVER_TOKEN=$(awk -F:: '{print "K10" ENVIRON["SERVER_CA_HASH"] FS $2}' ${DATA_DIR}/server/token) |
|
AGENT_TOKEN=$(awk -F:: '{print "K10" ENVIRON["SERVER_CA_HASH"] FS $2}' ${DATA_DIR}/server/agent-token) |
|
|
|
echo |
|
echo "Cross-signed CA certs and keys now available in ${TEMP_DIR}" |
|
echo "Updated server token: ${SERVER_TOKEN}" |
|
echo "Updated agent token: ${AGENT_TOKEN}" |
|
echo |
|
echo "To update certificates, you may now run:" |
|
echo " k3s certificate rotate-ca --path=${TEMP_DIR}"
|
|
|