152 lines
5.7 KiB
Bash
152 lines
5.7 KiB
Bash
|
|
#!/bin/bash
|
||
|
|
# setup-buildkit-client.sh — declarative apply of lian-build's mTLS identity
|
||
|
|
# at the buildkit_lite CA Issuer.
|
||
|
|
#
|
||
|
|
# Source of truth: manifests/buildkit-client-cert.yaml.tmpl (this directory).
|
||
|
|
# Reads NCL-derived config from environment OR from component.json if present.
|
||
|
|
#
|
||
|
|
# Usage:
|
||
|
|
# setup-buildkit-client.sh # apply (idempotent)
|
||
|
|
# setup-buildkit-client.sh export <dir> # apply then dump ca/tls.crt/tls.key to <dir>
|
||
|
|
# setup-buildkit-client.sh revoke # delete the Certificate (and Secret)
|
||
|
|
#
|
||
|
|
# Cluster access:
|
||
|
|
# The buildkit-ca-issuer typically lives on a remote cluster (e.g. libre-daoshi)
|
||
|
|
# whose API server is not directly reachable from the operator workstation.
|
||
|
|
# This script supports two modes:
|
||
|
|
# (1) Local kubectl — set KUBECONFIG and rely on local 'kubectl'
|
||
|
|
# (2) SSH+remote kubectl — set BUILDKIT_REMOTE_HOST=root@libre-daoshi-0 to run
|
||
|
|
# 'k0s kubectl' over ssh on the node itself
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
|
TMPL="$SCRIPT_DIR/manifests/buildkit-client-cert.yaml.tmpl"
|
||
|
|
|
||
|
|
# Cluster access wrapper. When BUILDKIT_REMOTE_HOST is set, exec kubectl through
|
||
|
|
# ssh on the node using 'k0s kubectl' (matches the daoshi single-node k0s layout).
|
||
|
|
# Both stdin (manifest piping) and stdout (json/jsonpath output) flow transparently.
|
||
|
|
BUILDKIT_REMOTE_HOST="${BUILDKIT_REMOTE_HOST:-}"
|
||
|
|
BUILDKIT_REMOTE_KCTL="${BUILDKIT_REMOTE_KCTL:-k0s kubectl}"
|
||
|
|
|
||
|
|
_kctl() {
|
||
|
|
if [ -n "$BUILDKIT_REMOTE_HOST" ]; then
|
||
|
|
# printf %q quotes each arg safely so jsonpath braces/escapes survive the
|
||
|
|
# ssh-shell pass-through (otherwise {.data.ca\.crt} gets expanded as glob).
|
||
|
|
local quoted=""
|
||
|
|
local arg
|
||
|
|
for arg in "$@"; do
|
||
|
|
quoted+=$(printf '%q ' "$arg")
|
||
|
|
done
|
||
|
|
ssh -o BatchMode=yes "$BUILDKIT_REMOTE_HOST" "$BUILDKIT_REMOTE_KCTL $quoted"
|
||
|
|
else
|
||
|
|
kubectl "$@"
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# Stdin-piping variant — for `envsubst < tmpl | _kctl_stdin apply -f -`.
|
||
|
|
_kctl_stdin() {
|
||
|
|
if [ -n "$BUILDKIT_REMOTE_HOST" ]; then
|
||
|
|
local quoted=""
|
||
|
|
local arg
|
||
|
|
for arg in "$@"; do
|
||
|
|
quoted+=$(printf '%q ' "$arg")
|
||
|
|
done
|
||
|
|
ssh -o BatchMode=yes "$BUILDKIT_REMOTE_HOST" "$BUILDKIT_REMOTE_KCTL $quoted"
|
||
|
|
else
|
||
|
|
kubectl "$@"
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# Read overrides from environment, falling back to component.json (when present)
|
||
|
|
# for the values configured via NCL.
|
||
|
|
_load_from_component_json() {
|
||
|
|
local key="$1"
|
||
|
|
local default="$2"
|
||
|
|
local f="$SCRIPT_DIR/component.json"
|
||
|
|
if [ -f "$f" ] && command -v jq >/dev/null 2>&1; then
|
||
|
|
local v
|
||
|
|
v=$(jq -r --arg k "$key" '.buildkit_client[$k] // empty' "$f" 2>/dev/null || true)
|
||
|
|
if [ -n "$v" ] && [ "$v" != "null" ]; then
|
||
|
|
printf '%s' "$v"
|
||
|
|
return
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
printf '%s' "$default"
|
||
|
|
}
|
||
|
|
|
||
|
|
BUILDKIT_CLIENT_NAME="${BUILDKIT_CLIENT_NAME:-$(_load_from_component_json client_name "lian-build")}"
|
||
|
|
BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE="${BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE:-$(_load_from_component_json ca_issuer_namespace "build-system")}"
|
||
|
|
BUILDKIT_CLIENT_CA_ISSUER_NAME="${BUILDKIT_CLIENT_CA_ISSUER_NAME:-$(_load_from_component_json ca_issuer_name "buildkit-ca-issuer")}"
|
||
|
|
BUILDKIT_CLIENT_DURATION="${BUILDKIT_CLIENT_DURATION:-$(_load_from_component_json duration "2160h")}"
|
||
|
|
BUILDKIT_CLIENT_RENEW_BEFORE="${BUILDKIT_CLIENT_RENEW_BEFORE:-$(_load_from_component_json renew_before "360h")}"
|
||
|
|
|
||
|
|
export BUILDKIT_CLIENT_NAME BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE BUILDKIT_CLIENT_CA_ISSUER_NAME \
|
||
|
|
BUILDKIT_CLIENT_DURATION BUILDKIT_CLIENT_RENEW_BEFORE
|
||
|
|
|
||
|
|
SECRET_NAME="buildkit-client-${BUILDKIT_CLIENT_NAME}-tls"
|
||
|
|
CERT_NAME="buildkit-client-${BUILDKIT_CLIENT_NAME}"
|
||
|
|
|
||
|
|
_apply() {
|
||
|
|
if [ ! -f "$TMPL" ]; then
|
||
|
|
echo "ERROR: template missing: $TMPL" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
if ! _kctl get issuer "$BUILDKIT_CLIENT_CA_ISSUER_NAME" \
|
||
|
|
--namespace "$BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" >/dev/null 2>&1; then
|
||
|
|
echo "ERROR: Issuer $BUILDKIT_CLIENT_CA_ISSUER_NAME not found in $BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" >&2
|
||
|
|
echo "Hint: enable mtls.cert_manager on buildkit_lite first" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
envsubst < "$TMPL" | _kctl_stdin apply -f -
|
||
|
|
echo "Applied Certificate $CERT_NAME in namespace $BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE"
|
||
|
|
}
|
||
|
|
|
||
|
|
_wait_for_secret() {
|
||
|
|
local timeout=60
|
||
|
|
local elapsed=0
|
||
|
|
while [ "$elapsed" -lt "$timeout" ]; do
|
||
|
|
if _kctl get secret "$SECRET_NAME" \
|
||
|
|
--namespace "$BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" >/dev/null 2>&1; then
|
||
|
|
return 0
|
||
|
|
fi
|
||
|
|
sleep 2
|
||
|
|
elapsed=$((elapsed + 2))
|
||
|
|
done
|
||
|
|
echo "ERROR: secret $SECRET_NAME not issued within ${timeout}s" >&2
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
|
||
|
|
_export() {
|
||
|
|
local out_dir="${1:-${HOME}/.lian-build/buildkit-client}"
|
||
|
|
out_dir="${out_dir/#\~/$HOME}"
|
||
|
|
mkdir -p "$out_dir"
|
||
|
|
_wait_for_secret
|
||
|
|
_kctl get secret "$SECRET_NAME" --namespace "$BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" \
|
||
|
|
-o jsonpath='{.data.ca\.crt}' | base64 -d > "$out_dir/ca.crt"
|
||
|
|
_kctl get secret "$SECRET_NAME" --namespace "$BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" \
|
||
|
|
-o jsonpath='{.data.tls\.crt}' | base64 -d > "$out_dir/tls.crt"
|
||
|
|
_kctl get secret "$SECRET_NAME" --namespace "$BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" \
|
||
|
|
-o jsonpath='{.data.tls\.key}' | base64 -d > "$out_dir/tls.key"
|
||
|
|
chmod 0600 "$out_dir/tls.key"
|
||
|
|
echo "Exported client cert material to $out_dir"
|
||
|
|
}
|
||
|
|
|
||
|
|
_revoke() {
|
||
|
|
_kctl delete certificate "$CERT_NAME" \
|
||
|
|
--namespace "$BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" --ignore-not-found
|
||
|
|
_kctl delete secret "$SECRET_NAME" \
|
||
|
|
--namespace "$BUILDKIT_CLIENT_CA_ISSUER_NAMESPACE" --ignore-not-found
|
||
|
|
echo "Revoked $CERT_NAME"
|
||
|
|
}
|
||
|
|
|
||
|
|
case "${1:-apply}" in
|
||
|
|
apply) _apply ;;
|
||
|
|
export) _apply; _export "${2:-}" ;;
|
||
|
|
export-only) _export "${2:-}" ;;
|
||
|
|
revoke) _revoke ;;
|
||
|
|
*)
|
||
|
|
echo "Usage: $(basename "$0") [apply|export <dir>|export-only <dir>|revoke]" >&2
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|