Files
nixos-servers/hosts/template2/bootstrap.nix
Torjus Håkestad f5904738b0
Some checks failed
Run nix flake check / flake-check (push) Has been cancelled
Run nix flake check / flake-check (pull_request) Successful in 2m30s
vault: implement bootstrap integration
2026-02-03 01:09:43 +01:00

121 lines
4.5 KiB
Nix

{ pkgs, config, lib, ... }:
let
bootstrap-script = pkgs.writeShellApplication {
name = "nixos-bootstrap";
runtimeInputs = with pkgs; [ systemd curl nixos-rebuild jq git ];
text = ''
set -euo pipefail
# Read hostname set by cloud-init (from Terraform VM name via user-data)
# Cloud-init sets the system hostname from user-data.txt, so we read it from hostnamectl
HOSTNAME=$(hostnamectl hostname)
echo "DEBUG: Hostname from hostnamectl: '$HOSTNAME'"
echo "Starting NixOS bootstrap for host: $HOSTNAME"
echo "Waiting for network connectivity..."
# Verify we can reach the git server via HTTPS (doesn't respond to ping)
if ! curl -s --connect-timeout 5 --max-time 10 https://git.t-juice.club >/dev/null 2>&1; then
echo "ERROR: Cannot reach git.t-juice.club via HTTPS"
echo "Check network configuration and DNS settings"
exit 1
fi
echo "Network connectivity confirmed"
# Unwrap Vault token and store AppRole credentials (if provided)
if [ -n "''${VAULT_WRAPPED_TOKEN:-}" ]; then
echo "Unwrapping Vault token to get AppRole credentials..."
VAULT_ADDR="''${VAULT_ADDR:-https://vault01.home.2rjus.net:8200}"
# Unwrap the token to get role_id and secret_id
UNWRAP_RESPONSE=$(curl -sk -X POST \
-H "X-Vault-Token: $VAULT_WRAPPED_TOKEN" \
"$VAULT_ADDR/v1/sys/wrapping/unwrap") || {
echo "WARNING: Failed to unwrap Vault token (network error)"
echo "Vault secrets will not be available, but continuing bootstrap..."
}
# Check if unwrap was successful
if [ -n "$UNWRAP_RESPONSE" ] && echo "$UNWRAP_RESPONSE" | jq -e '.data' >/dev/null 2>&1; then
ROLE_ID=$(echo "$UNWRAP_RESPONSE" | jq -r '.data.role_id')
SECRET_ID=$(echo "$UNWRAP_RESPONSE" | jq -r '.data.secret_id')
# Store credentials
mkdir -p /var/lib/vault/approle
echo "$ROLE_ID" > /var/lib/vault/approle/role-id
echo "$SECRET_ID" > /var/lib/vault/approle/secret-id
chmod 600 /var/lib/vault/approle/role-id
chmod 600 /var/lib/vault/approle/secret-id
echo "Vault credentials unwrapped and stored successfully"
else
echo "WARNING: Failed to unwrap Vault token"
if [ -n "$UNWRAP_RESPONSE" ]; then
echo "Response: $UNWRAP_RESPONSE"
fi
echo "Possible causes:"
echo " - Token already used (wrapped tokens are single-use)"
echo " - Token expired (24h TTL)"
echo " - Invalid token"
echo ""
echo "To regenerate token, run: create-host --hostname $HOSTNAME --force"
echo ""
echo "Vault secrets will not be available, but continuing bootstrap..."
fi
else
echo "No Vault wrapped token provided (VAULT_WRAPPED_TOKEN not set)"
echo "Skipping Vault credential setup"
fi
echo "Fetching and building NixOS configuration from flake..."
# Read git branch from environment, default to master
BRANCH="''${NIXOS_FLAKE_BRANCH:-master}"
echo "Using git branch: $BRANCH"
# Build and activate the host-specific configuration
FLAKE_URL="git+https://git.t-juice.club/torjus/nixos-servers.git?ref=$BRANCH#''${HOSTNAME}"
if nixos-rebuild boot --flake "$FLAKE_URL"; then
echo "Successfully built configuration for $HOSTNAME"
echo "Rebooting into new configuration..."
sleep 2
systemctl reboot
else
echo "ERROR: nixos-rebuild failed for $HOSTNAME"
echo "Check that flake has configuration for this hostname"
echo "Manual intervention required - system will not reboot"
exit 1
fi
'';
};
in
{
systemd.services."nixos-bootstrap" = {
description = "Bootstrap NixOS configuration from flake on first boot";
# Wait for cloud-init to finish setting hostname and network to be online
after = [ "cloud-config.service" "network-online.target" ];
wants = [ "network-online.target" ];
requires = [ "cloud-config.service" ];
# Run on boot
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${bootstrap-script}/bin/nixos-bootstrap";
# Read environment variables from cloud-init (set by cloud-init write_files)
EnvironmentFile = "-/run/cloud-init-env";
# Logging to journald
StandardOutput = "journal+console";
StandardError = "journal+console";
};
};
}