fix: use individual admins
This commit is contained in:
parent
f9afc7285f
commit
98d5197056
3 changed files with 77 additions and 26 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
.bootstrap/
|
.bootstrap/
|
||||||
.direnv/
|
.direnv/
|
||||||
|
dump/
|
||||||
|
|
|
||||||
12
flake.nix
12
flake.nix
|
|
@ -153,13 +153,13 @@
|
||||||
type = "app";
|
type = "app";
|
||||||
program = "${pkgs.writeShellScript "bootstrap-host" (
|
program = "${pkgs.writeShellScript "bootstrap-host" (
|
||||||
builtins.replaceStrings
|
builtins.replaceStrings
|
||||||
[ "@ADMIN_KEYS@" ]
|
|
||||||
[
|
[
|
||||||
(lib.concatMapStringsSep "\n" (key: " \"${key}\"") (
|
"@ADMIN_USERS_JSON@"
|
||||||
lib.flatten (
|
"@JQ@"
|
||||||
lib.mapAttrsToList (_: userCfg: userCfg.openssh.authorizedKeys.keys or [ ]) siteConfig.adminUsers
|
]
|
||||||
)
|
[
|
||||||
))
|
(builtins.toJSON siteConfig.adminUsers)
|
||||||
|
"${pkgs.jq}/bin/jq"
|
||||||
]
|
]
|
||||||
(builtins.readFile ./scripts/bootstrap-host.sh)
|
(builtins.readFile ./scripts/bootstrap-host.sh)
|
||||||
)}";
|
)}";
|
||||||
|
|
|
||||||
|
|
@ -3,29 +3,39 @@ set -euo pipefail
|
||||||
usage() {
|
usage() {
|
||||||
cat <<'USAGE'
|
cat <<'USAGE'
|
||||||
Usage:
|
Usage:
|
||||||
nix run .#bootstrap-host -- <main-wiki|replica-wiki> <target-host> [ssh-identity-file]
|
nix run .#bootstrap-host -- [--admin <name>] <main-wiki|replica-wiki> <target-host> [ssh-identity-file]
|
||||||
nix run .#bootstrap-host -- <main-target-host> <replica-target-host> [ssh-identity-file]
|
nix run .#bootstrap-host -- [--admin <name>] <main-target-host> <replica-target-host> [ssh-identity-file]
|
||||||
|
|
||||||
Examples:
|
|
||||||
nix run .#bootstrap-host -- main-wiki root@203.0.113.10 ~/.ssh/do-bootstrap
|
|
||||||
nix run .#bootstrap-host -- root@203.0.113.10 root@203.0.113.11 ~/.ssh/do-bootstrap
|
|
||||||
USAGE
|
USAGE
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
repo_root="$(pwd)"
|
repo_root="$(pwd)"
|
||||||
if [ ! -f "$repo_root/flake.nix" ]; then
|
if [ ! -f "$repo_root/flake.nix" ]; then
|
||||||
printf 'Run bootstrap-host from the repo root\n' >&2
|
printf 'Run bootstrap-host from the repo root\n' >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
admin_users_json='@ADMIN_USERS_JSON@'
|
||||||
|
|
||||||
|
bootstrap_admin="jet"
|
||||||
ssh_identity_file=""
|
ssh_identity_file=""
|
||||||
main_target=""
|
main_target=""
|
||||||
replica_target=""
|
replica_target=""
|
||||||
|
failures=()
|
||||||
|
|
||||||
|
if [ "${1:-}" = "--admin" ]; then
|
||||||
|
if [ "$#" -lt 4 ]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
bootstrap_admin="$2"
|
||||||
|
shift 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
main-wiki|replica-wiki)
|
main-wiki|replica-wiki)
|
||||||
|
|
@ -43,8 +53,22 @@ case "$1" in
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
admin_keys() {
|
||||||
|
printf '%s' "$admin_users_json" | @JQ@ -r --arg user "$1" '.[$user].openssh.authorizedKeys.keys[]? | " \"" + . + "\""'
|
||||||
|
}
|
||||||
|
|
||||||
|
admin_exists() {
|
||||||
|
printf '%s' "$admin_users_json" | @JQ@ -e --arg user "$1" 'has($user)' >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! admin_exists "$bootstrap_admin"; then
|
||||||
|
printf 'Unknown admin user for bootstrap: %s\n' "$bootstrap_admin" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
make_host_module() {
|
make_host_module() {
|
||||||
local module_file="$1"
|
local module_file="$1"
|
||||||
|
local admin_name="$2"
|
||||||
|
|
||||||
cat > "$module_file" <<'MODULE'
|
cat > "$module_file" <<'MODULE'
|
||||||
{ ... }:
|
{ ... }:
|
||||||
|
|
@ -73,7 +97,7 @@ make_host_module() {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.jet = {
|
users.users.BOOTSTRAP_ADMIN = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
extraGroups = [ "wheel" ];
|
extraGroups = [ "wheel" ];
|
||||||
openssh.authorizedKeys.keys = [
|
openssh.authorizedKeys.keys = [
|
||||||
|
|
@ -86,6 +110,9 @@ make_host_module() {
|
||||||
services.do-agent.enable = false;
|
services.do-agent.enable = false;
|
||||||
}
|
}
|
||||||
MODULE
|
MODULE
|
||||||
|
|
||||||
|
sed -i "s/BOOTSTRAP_ADMIN/$admin_name/" "$module_file"
|
||||||
|
perl -0pi -e 's/\n@ADMIN_KEYS@/\n'"$(admin_keys "$admin_name" | sed 's/[\/&]/\\&/g')"'/g' "$module_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
run_bootstrap() {
|
run_bootstrap() {
|
||||||
|
|
@ -97,12 +124,14 @@ run_bootstrap() {
|
||||||
local try
|
local try
|
||||||
local ssh_cmd=(ssh -o StrictHostKeyChecking=accept-new)
|
local ssh_cmd=(ssh -o StrictHostKeyChecking=accept-new)
|
||||||
local scp_cmd=(scp -o StrictHostKeyChecking=accept-new)
|
local scp_cmd=(scp -o StrictHostKeyChecking=accept-new)
|
||||||
|
local admin_target
|
||||||
|
|
||||||
work_dir="$(mktemp -d)"
|
work_dir="$(mktemp -d)"
|
||||||
module_file="$work_dir/host-bootstrap.nix"
|
module_file="$work_dir/host-bootstrap.nix"
|
||||||
remote_target="$target_host:/etc/nixos/host-bootstrap.nix"
|
remote_target="$target_host:/etc/nixos/host-bootstrap.nix"
|
||||||
|
admin_target="${bootstrap_admin}@${target_host#*@}"
|
||||||
|
|
||||||
make_host_module "$module_file"
|
make_host_module "$module_file" "$bootstrap_admin"
|
||||||
|
|
||||||
if [ -n "$ssh_identity_file" ]; then
|
if [ -n "$ssh_identity_file" ]; then
|
||||||
ssh_cmd+=( -i "$ssh_identity_file" )
|
ssh_cmd+=( -i "$ssh_identity_file" )
|
||||||
|
|
@ -118,27 +147,48 @@ run_bootstrap() {
|
||||||
|
|
||||||
printf 'Waiting for %s to reboot into NixOS\n' "$host_name"
|
printf 'Waiting for %s to reboot into NixOS\n' "$host_name"
|
||||||
for try in $(seq 1 60); do
|
for try in $(seq 1 60); do
|
||||||
if "${ssh_cmd[@]}" -o ConnectTimeout=5 "$target_host" 'grep -q "^ID=nixos" /etc/os-release'; then
|
if "${ssh_cmd[@]}" -o ConnectTimeout=5 "$admin_target" 'grep -q "^ID=nixos" /etc/os-release' 2>/dev/null; then
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
sleep 5
|
sleep 5
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if ! "${ssh_cmd[@]}" -o ConnectTimeout=5 "$admin_target" 'grep -q "^ID=nixos" /etc/os-release' 2>/dev/null; then
|
||||||
|
printf 'Bootstrap failed for %s: host did not come back as NixOS with %s access\n' "$host_name" "$bootstrap_admin" >&2
|
||||||
|
failures+=( "$host_name" )
|
||||||
|
rm -rf "$work_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
printf 'Finalizing network config on %s\n' "$host_name"
|
printf 'Finalizing network config on %s\n' "$host_name"
|
||||||
"${ssh_cmd[@]}" "$target_host" '
|
"${ssh_cmd[@]}" "$admin_target" '
|
||||||
sed -i "/defaultGateway6 = {/,/};/d" /etc/nixos/networking.nix 2>/dev/null || true
|
sudo sed -i "/defaultGateway6 = {/,/};/d" /etc/nixos/networking.nix 2>/dev/null || true
|
||||||
sed -i "/ipv6.routes = \[ { address = \"\"; prefixLength = 128; } \];/d" /etc/nixos/networking.nix 2>/dev/null || true
|
sudo sed -i "/ipv6.routes = \[ { address = \"\"; prefixLength = 128; } \];/d" /etc/nixos/networking.nix 2>/dev/null || true
|
||||||
nixos-rebuild switch
|
sudo nixos-rebuild switch
|
||||||
'
|
'
|
||||||
|
|
||||||
|
if ! "${ssh_cmd[@]}" "$admin_target" 'sudo -n true >/dev/null && test "$(systemctl is-system-running || true)" = running' 2>/dev/null; then
|
||||||
|
printf 'Bootstrap verification failed for %s: host is not healthy after first switch\n' "$host_name" >&2
|
||||||
|
failures+=( "$host_name" )
|
||||||
|
rm -rf "$work_dir"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'Bootstrap verified for %s\n' "$host_name"
|
||||||
|
|
||||||
rm -rf "$work_dir"
|
rm -rf "$work_dir"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -n "${main_target:-}" ]; then
|
if [ -n "${main_target:-}" ]; then
|
||||||
run_bootstrap main-wiki "$main_target"
|
run_bootstrap main-wiki "$main_target" || true
|
||||||
fi
|
fi
|
||||||
if [ -n "${replica_target:-}" ]; then
|
if [ -n "${replica_target:-}" ]; then
|
||||||
run_bootstrap replica-wiki "$replica_target"
|
run_bootstrap replica-wiki "$replica_target" || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '\nBootstrap complete. The hosts should now be reachable as minimal NixOS systems over public SSH.\n'
|
if [ "${#failures[@]}" -ne 0 ]; then
|
||||||
|
printf '\nBootstrap failed for: %s\n' "${failures[*]}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '\nBootstrap complete. The hosts should now be reachable as NixOS systems over public SSH as %s.\n' "$bootstrap_admin"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue