197 lines
4.7 KiB
Bash
Executable File
197 lines
4.7 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
ROOT_DIR="$(realpath "$SCRIPT_DIR/..")"
|
|
LIB_DIR="$ROOT_DIR/scripts"
|
|
CLUSTER_ENV_WORK="${CLUSTER_ENV_WORK:-$ROOT_DIR/configs/cluster.env.work}"
|
|
|
|
KUBECTL="${KUBECTL:-kubectl}"
|
|
TTL_HOURS="${TTL_HOURS:-24}"
|
|
WAIT_SECONDS="${WAIT_SECONDS:-30}"
|
|
|
|
need() {
|
|
command -v "$1" >/dev/null 2>&1 || {
|
|
echo "missing required command: $1" >&2
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
rfc3339_after_hours() {
|
|
hours="$1"
|
|
|
|
# GNU date
|
|
if date -u -d "+${hours} hours" '+%Y-%m-%dT%H:%M:%SZ' >/dev/null 2>&1; then
|
|
date -u -d "+${hours} hours" '+%Y-%m-%dT%H:%M:%SZ'
|
|
return
|
|
fi
|
|
|
|
# BSD/macOS date
|
|
if date -u -v+"${hours}"H '+%Y-%m-%dT%H:%M:%SZ' >/dev/null 2>&1; then
|
|
date -u -v+"${hours}"H '+%Y-%m-%dT%H:%M:%SZ'
|
|
return
|
|
fi
|
|
|
|
echo "cannot compute expiration time with this date(1). Set EXPIRATION manually." >&2
|
|
exit 1
|
|
}
|
|
|
|
decode_base64_to_file() {
|
|
input="$1"
|
|
output="$2"
|
|
|
|
if printf '%s' "$input" | base64 -d >"$output" 2>/dev/null; then
|
|
return
|
|
fi
|
|
|
|
if printf '%s' "$input" | base64 -D >"$output" 2>/dev/null; then
|
|
return
|
|
fi
|
|
|
|
if printf '%s' "$input" | openssl base64 -d -A >"$output" 2>/dev/null; then
|
|
return
|
|
fi
|
|
|
|
echo "failed to decode certificate-authority-data" >&2
|
|
exit 1
|
|
}
|
|
|
|
need "$KUBECTL"
|
|
need openssl
|
|
need awk
|
|
need sed
|
|
|
|
TOKEN_ID="${TOKEN_ID:-$(openssl rand -hex 3)}"
|
|
TOKEN_SECRET="${TOKEN_SECRET:-$(openssl rand -hex 8)}"
|
|
TOKEN="${TOKEN_ID}.${TOKEN_SECRET}"
|
|
SECRET_NAME="bootstrap-token-${TOKEN_ID}"
|
|
|
|
if [ "${TTL_HOURS}" = "0" ]; then
|
|
EXPIRATION=""
|
|
else
|
|
EXPIRATION="${EXPIRATION:-$(rfc3339_after_hours "$TTL_HOURS")}"
|
|
fi
|
|
|
|
echo "Creating bootstrap token Secret: ${SECRET_NAME}" >&2
|
|
|
|
{
|
|
cat <<EOF
|
|
apiVersion: v1
|
|
kind: Secret
|
|
metadata:
|
|
name: ${SECRET_NAME}
|
|
namespace: kube-system
|
|
type: bootstrap.kubernetes.io/token
|
|
stringData:
|
|
description: "Join token created with kubectl"
|
|
token-id: "${TOKEN_ID}"
|
|
token-secret: "${TOKEN_SECRET}"
|
|
usage-bootstrap-authentication: "true"
|
|
usage-bootstrap-signing: "true"
|
|
auth-extra-groups: "system:bootstrappers:kubeadm:default-node-token"
|
|
EOF
|
|
|
|
if [ -n "$EXPIRATION" ]; then
|
|
printf ' expiration: "%s"\n' "$EXPIRATION"
|
|
fi
|
|
} | "$KUBECTL" apply -f -
|
|
|
|
TMPDIR="$(mktemp -d)"
|
|
trap 'rm -rf "$TMPDIR"' EXIT INT TERM
|
|
|
|
CA_FILE="$TMPDIR/ca.crt"
|
|
|
|
CA_DATA="$("$KUBECTL" config view --raw --minify --flatten -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')"
|
|
|
|
if [ -z "$CA_DATA" ]; then
|
|
echo "could not find certificate-authority-data in current kubeconfig" >&2
|
|
echo "token was created, but cannot print a safe kubeadm join command" >&2
|
|
echo "token: ${TOKEN}"
|
|
exit 0
|
|
fi
|
|
|
|
decode_base64_to_file "$CA_DATA" "$CA_FILE"
|
|
|
|
CA_HASH="$(
|
|
openssl x509 -in "$CA_FILE" -pubkey -noout |
|
|
openssl pkey -pubin -outform der 2>/dev/null |
|
|
openssl dgst -sha256 -hex |
|
|
awk '{print $2}'
|
|
)"
|
|
|
|
SERVER="$("$KUBECTL" config view --raw --minify -o jsonpath='{.clusters[0].cluster.server}')"
|
|
JOIN_ENDPOINT="$(printf '%s\n' "$SERVER" | sed -E 's#^https?://##')"
|
|
|
|
echo "Waiting for cluster-info signature for token ${TOKEN_ID}..." >&2
|
|
|
|
i=0
|
|
signed="false"
|
|
while [ "$i" -lt "$WAIT_SECONDS" ]; do
|
|
template="{{ index .data \"jws-kubeconfig-${TOKEN_ID}\" }}"
|
|
sig="$("$KUBECTL" -n kube-public get configmap cluster-info -o "go-template=${template}" 2>/dev/null || true)"
|
|
|
|
if [ -n "$sig" ]; then
|
|
signed="true"
|
|
break
|
|
fi
|
|
|
|
i=$((i + 1))
|
|
sleep 1
|
|
done
|
|
|
|
echo
|
|
echo "Token:"
|
|
echo " ${TOKEN}"
|
|
|
|
if [ -n "$EXPIRATION" ]; then
|
|
echo
|
|
echo "Expires:"
|
|
echo " ${EXPIRATION}"
|
|
fi
|
|
|
|
echo
|
|
echo "Join command:"
|
|
echo " kubeadm join ${JOIN_ENDPOINT} --token ${TOKEN} --discovery-token-ca-cert-hash sha256:${CA_HASH}"
|
|
|
|
TMP_ENV="$(mktemp)"
|
|
trap 'rm -f "$TMP_ENV"; rm -rf "$TMPDIR"' EXIT INT TERM
|
|
|
|
cat >"$TMP_ENV" <<EOF
|
|
MKS_API_SERVER_ENDPOINT=${JOIN_ENDPOINT}
|
|
MKS_BOOTSTRAP_TOKEN=${TOKEN}
|
|
MKS_DISCOVERY_TOKEN_CA_CERT_HASH=sha256:${CA_HASH}
|
|
EOF
|
|
|
|
echo
|
|
echo "cluster-config:"
|
|
cat "$TMP_ENV"
|
|
|
|
if [ ! -x "$LIB_DIR/merge-env.sh" ]; then
|
|
echo "merge-env.sh not found or not executable: $LIB_DIR/merge-env.sh" >&2
|
|
exit 1
|
|
fi
|
|
|
|
"$LIB_DIR/merge-env.sh" "$TMP_ENV" "$CLUSTER_ENV_WORK"
|
|
|
|
echo
|
|
echo "Merged into:"
|
|
echo " $CLUSTER_ENV_WORK"
|
|
echo
|
|
echo "Try"
|
|
cat <<EOF
|
|
make cluster-config \\
|
|
MKS_HOSTNAME=monok8s-worker \\
|
|
MKS_CLUSTER_ROLE=worker \\
|
|
MKS_INIT_CONTROL_PLANE=no \\
|
|
MKS_MGMT_ADDRESS=10.0.0.10/24 \\
|
|
MKS_APISERVER_ADVERTISE_ADDRESS=10.0.0.10 \\
|
|
MKS_CNI_PLUGIN=none
|
|
EOF
|
|
|
|
|
|
if [ "$signed" != "true" ]; then
|
|
echo >&2
|
|
echo "warning: cluster-info was not signed within ${WAIT_SECONDS}s." >&2
|
|
echo "If kubeadm join fails discovery, check that kube-controller-manager enables bootstrapsigner." >&2
|
|
fi
|