Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m34s
CD Pipeline / build-and-deploy (push) Failing after 4m30s
CD Pipeline / post-deploy-checks (push) Has been skipped
Agent Version Lifecycle Watch / version-lifecycle-watch (push) Successful in 15s
140 lines
5.2 KiB
Bash
Executable File
140 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
MODE="check"
|
|
ROTATE=0
|
|
CONTROLLER_TARGET="${AGENT99_K3S_CONTROLLER_TARGET:-wooo@192.168.0.121}"
|
|
WINDOWS_TARGET="${AGENT99_WINDOWS_TARGET:-Administrator@192.168.0.99}"
|
|
KUBECONFIG_PATH="${AGENT99_KUBECONFIG_PATH:-/etc/rancher/k3s/k3s.yaml}"
|
|
NAMESPACE="${AGENT99_K8S_NAMESPACE:-awoooi-prod}"
|
|
SECRET_NAME="${AGENT99_K8S_SECRET_NAME:-awoooi-secrets}"
|
|
K8S_TOKEN_KEY="AGENT99_SRE_ALERT_RELAY_TOKEN"
|
|
WINDOWS_TOKEN_ENV="AGENT99_SRE_RELAY_TOKEN"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: agent99-provision-completion-token.sh [--check | --apply] [--rotate]
|
|
|
|
Safely provisions the Agent99 completion callback credential to the AWOOOI
|
|
Kubernetes Secret and Windows 99 machine environment. The credential is sent
|
|
only through SSH stdin and is never printed or written to an evidence file.
|
|
|
|
Options:
|
|
--check Read presence metadata only (default).
|
|
--apply Provision when either endpoint is missing.
|
|
--rotate Replace both endpoints even when both are present.
|
|
--controller TARGET K3s controller SSH target.
|
|
--windows TARGET Windows 99 OpenSSH target.
|
|
--kubeconfig PATH Controller kubeconfig path.
|
|
--namespace NAME Kubernetes namespace.
|
|
--secret NAME Kubernetes Secret name.
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--check) MODE="check" ;;
|
|
--apply) MODE="apply" ;;
|
|
--rotate) ROTATE=1 ;;
|
|
--controller) CONTROLLER_TARGET="${2:?missing controller target}"; shift ;;
|
|
--windows) WINDOWS_TARGET="${2:?missing Windows target}"; shift ;;
|
|
--kubeconfig) KUBECONFIG_PATH="${2:?missing kubeconfig path}"; shift ;;
|
|
--namespace) NAMESPACE="${2:?missing namespace}"; shift ;;
|
|
--secret) SECRET_NAME="${2:?missing Secret name}"; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "Unknown argument: $1" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [[ ! "$CONTROLLER_TARGET" =~ ^[A-Za-z0-9_.@:-]+$ ]] ||
|
|
[[ ! "$WINDOWS_TARGET" =~ ^[A-Za-z0-9_.@:-]+$ ]] ||
|
|
[[ ! "$NAMESPACE" =~ ^[A-Za-z0-9_.-]+$ ]] ||
|
|
[[ ! "$SECRET_NAME" =~ ^[A-Za-z0-9_.-]+$ ]] ||
|
|
[[ ! "$KUBECONFIG_PATH" =~ ^/[A-Za-z0-9_./-]+$ ]]; then
|
|
echo "Unsafe provisioning target argument" >&2
|
|
exit 2
|
|
fi
|
|
|
|
for command_name in ssh openssl iconv base64; do
|
|
command -v "$command_name" >/dev/null || {
|
|
echo "Missing required command: $command_name" >&2
|
|
exit 2
|
|
}
|
|
done
|
|
|
|
encode_powershell() {
|
|
iconv -f UTF-8 -t UTF-16LE | base64 | tr -d '\r\n'
|
|
}
|
|
|
|
windows_presence_script=$(cat <<EOF
|
|
\$ProgressPreference = 'SilentlyContinue'
|
|
\$value = [Environment]::GetEnvironmentVariable('${WINDOWS_TOKEN_ENV}', 'Machine')
|
|
if ([string]::IsNullOrWhiteSpace(\$value)) { Write-Output '0' } else { Write-Output '1' }
|
|
EOF
|
|
)
|
|
windows_presence_encoded=$(printf '%s' "$windows_presence_script" | encode_powershell)
|
|
|
|
read_presence() {
|
|
local k8s_presence windows_presence
|
|
k8s_presence=$(ssh -o BatchMode=yes "$CONTROLLER_TARGET" \
|
|
"sudo kubectl --kubeconfig='$KUBECONFIG_PATH' -n '$NAMESPACE' get secret '$SECRET_NAME' -o go-template='{{if index .data \"$K8S_TOKEN_KEY\"}}1{{else}}0{{end}}'" | tr -d '\r\n')
|
|
windows_presence=$(ssh -o BatchMode=yes "$WINDOWS_TARGET" \
|
|
powershell.exe -NoProfile -NonInteractive -OutputFormat Text \
|
|
-EncodedCommand "$windows_presence_encoded" | tr -d '\r\n')
|
|
|
|
[[ "$k8s_presence" == "1" ]] || k8s_presence="0"
|
|
[[ "$windows_presence" == "1" ]] || windows_presence="0"
|
|
printf 'K8S_COMPLETION_TOKEN_PRESENT=%s\n' "$k8s_presence"
|
|
printf 'WINDOWS_COMPLETION_TOKEN_PRESENT=%s\n' "$windows_presence"
|
|
if [[ "$k8s_presence" == "1" && "$windows_presence" == "1" ]]; then
|
|
printf 'AGENT99_COMPLETION_TOKEN_READY=1\n'
|
|
return 0
|
|
fi
|
|
printf 'AGENT99_COMPLETION_TOKEN_READY=0\n'
|
|
return 1
|
|
}
|
|
|
|
if [[ "$MODE" == "check" ]]; then
|
|
read_presence
|
|
exit $?
|
|
fi
|
|
|
|
if read_presence >/dev/null 2>&1 && [[ "$ROTATE" -ne 1 ]]; then
|
|
echo "AGENT99_COMPLETION_TOKEN_ALREADY_PRESENT=1"
|
|
echo "AGENT99_COMPLETION_TOKEN_READY=1"
|
|
exit 0
|
|
fi
|
|
|
|
token="$(openssl rand -hex 32)"
|
|
trap 'unset token token_b64 patch_json windows_set_script windows_set_encoded' EXIT
|
|
if [[ ${#token} -ne 64 ]]; then
|
|
echo "Credential generation failed" >&2
|
|
exit 1
|
|
fi
|
|
|
|
token_b64=$(printf '%s' "$token" | base64 | tr -d '\r\n')
|
|
patch_json=$(printf '{"data":{"%s":"%s"}}' "$K8S_TOKEN_KEY" "$token_b64")
|
|
printf '%s' "$patch_json" | ssh -o BatchMode=yes "$CONTROLLER_TARGET" \
|
|
"sudo kubectl --kubeconfig='$KUBECONFIG_PATH' -n '$NAMESPACE' patch secret '$SECRET_NAME' --type merge --patch-file=/dev/stdin >/dev/null"
|
|
|
|
windows_set_script=$(cat <<EOF
|
|
\$ProgressPreference = 'SilentlyContinue'
|
|
\$token = [Console]::In.ReadToEnd().Trim()
|
|
if (\$token.Length -ne 64) { throw 'Invalid completion token length' }
|
|
[Environment]::SetEnvironmentVariable('${WINDOWS_TOKEN_ENV}', \$token, 'Machine')
|
|
Write-Output 'WINDOWS_COMPLETION_TOKEN_WRITTEN=1'
|
|
EOF
|
|
)
|
|
windows_set_encoded=$(printf '%s' "$windows_set_script" | encode_powershell)
|
|
printf '%s' "$token" | ssh -o BatchMode=yes "$WINDOWS_TARGET" \
|
|
powershell.exe -NoProfile -NonInteractive -OutputFormat Text \
|
|
-EncodedCommand "$windows_set_encoded" >/dev/null
|
|
|
|
unset token token_b64 patch_json
|
|
if ! read_presence; then
|
|
echo "Agent99 completion token provisioning did not pass presence readback" >&2
|
|
exit 1
|
|
fi
|
|
echo "AGENT99_COMPLETION_TOKEN_PROVISIONED=1"
|