fix: [nomad-step-0] S0.3 — install vault + systemd auto-unseal + vault-init.sh (dev-persisted seal) (#823)
Adds the Vault half of the factory-dev-box bringup, landed but not started (per the install-but-don't-start pattern used for nomad in #822): - lib/init/nomad/install.sh — now also installs vault from the shared HashiCorp apt repo. VAULT_VERSION pinned (1.18.5). Fast-path skips apt entirely when both binaries are at their pins; partial upgrades only touch the package that drifted. - nomad/vault.hcl — single-node config: file storage backend at /var/lib/vault/data, localhost listener on :8200, ui on, mlock kept on. No TLS / HA / audit yet; those land in later steps. - lib/init/nomad/systemd-vault.sh — writes /etc/systemd/system/vault.service (Type=notify, ExecStartPost auto-unseals from /etc/vault.d/unseal.key, CAP_IPC_LOCK granted for mlock), deploys nomad/vault.hcl to /etc/vault.d/, creates /var/lib/vault/data (0700 root), enables the unit without starting it. Idempotent via content-compare. - lib/init/nomad/vault-init.sh — first-run init: spawns a temporary `vault server` if not already reachable, runs operator-init with key-shares=1/threshold=1, persists unseal.key + root.token (0400 root), unseals once in-process, shuts down the temp server. Re-run detects initialized + unseal.key present → no-op. Initialized but key missing is a hard failure (can't recover). lib/hvault.sh already defaults VAULT_TOKEN to /etc/vault.d/root.token when the env var is absent, so no change needed there. Seal model: the single unseal key lives on disk; seal-key theft equals vault theft. Factory-dev-box-acceptable tradeoff — avoids running a second Vault to auto-unseal the first. Blocks S0.4 (#824). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
75bec43c4a
commit
57bc88b9a7
6 changed files with 519 additions and 68 deletions
|
|
@ -1,27 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
# =============================================================================
|
||||
# lib/init/nomad/install.sh — Idempotent apt install of HashiCorp Nomad
|
||||
# lib/init/nomad/install.sh — Idempotent apt install of HashiCorp Nomad + Vault
|
||||
#
|
||||
# Part of the Nomad+Vault migration (S0.2, issue #822). Installs the `nomad`
|
||||
# binary from the HashiCorp apt repository. Does NOT install Vault — S0.3
|
||||
# owns that. Does NOT configure, start, or enable a systemd unit —
|
||||
# lib/init/nomad/systemd-nomad.sh owns that. Does NOT wire this script into
|
||||
# `disinto init` — S0.4 owns that.
|
||||
# Part of the Nomad+Vault migration. Installs both the `nomad` binary (S0.2,
|
||||
# issue #822) and the `vault` binary (S0.3, issue #823) from the same
|
||||
# HashiCorp apt repository. Does NOT configure, start, or enable any systemd
|
||||
# unit — lib/init/nomad/systemd-nomad.sh and lib/init/nomad/systemd-vault.sh
|
||||
# own that. Does NOT wire this script into `disinto init` — S0.4 owns that.
|
||||
#
|
||||
# Idempotency contract:
|
||||
# - Running twice back-to-back is a no-op once the target version is
|
||||
# - Running twice back-to-back is a no-op once both target versions are
|
||||
# installed and the apt source is in place.
|
||||
# - Adds the HashiCorp apt keyring only if it is absent.
|
||||
# - Adds the HashiCorp apt sources list only if it is absent.
|
||||
# - Skips `apt-get install` entirely when the installed version already
|
||||
# matches ${NOMAD_VERSION}.
|
||||
# - Skips `apt-get install` for any package whose installed version already
|
||||
# matches the pin. If both are at pin, exits before touching apt.
|
||||
#
|
||||
# Configuration:
|
||||
# NOMAD_VERSION — pinned Nomad version (default: see below). The apt
|
||||
# package name is versioned as "nomad=<version>-1".
|
||||
# NOMAD_VERSION — pinned Nomad version (default: see below). Apt package
|
||||
# name is versioned as "nomad=<version>-1".
|
||||
# VAULT_VERSION — pinned Vault version (default: see below). Apt package
|
||||
# name is versioned as "vault=<version>-1".
|
||||
#
|
||||
# Usage:
|
||||
# sudo NOMAD_VERSION=1.9.5 lib/init/nomad/install.sh
|
||||
# sudo lib/init/nomad/install.sh
|
||||
# sudo NOMAD_VERSION=1.9.5 VAULT_VERSION=1.18.5 lib/init/nomad/install.sh
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 success (installed or already present)
|
||||
|
|
@ -29,16 +32,29 @@
|
|||
# =============================================================================
|
||||
set -euo pipefail
|
||||
|
||||
# Pin to a specific Nomad 1.x release. Bump here, not at call sites.
|
||||
# Pin to specific 1.x releases. Bump here, not at call sites.
|
||||
NOMAD_VERSION="${NOMAD_VERSION:-1.9.5}"
|
||||
VAULT_VERSION="${VAULT_VERSION:-1.18.5}"
|
||||
|
||||
HASHICORP_KEYRING="/usr/share/keyrings/hashicorp-archive-keyring.gpg"
|
||||
HASHICORP_SOURCES="/etc/apt/sources.list.d/hashicorp.list"
|
||||
HASHICORP_GPG_URL="https://apt.releases.hashicorp.com/gpg"
|
||||
HASHICORP_REPO_URL="https://apt.releases.hashicorp.com"
|
||||
|
||||
log() { printf '[install-nomad] %s\n' "$*"; }
|
||||
die() { printf '[install-nomad] ERROR: %s\n' "$*" >&2; exit 1; }
|
||||
log() { printf '[install] %s\n' "$*"; }
|
||||
die() { printf '[install] ERROR: %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
# _installed_version BINARY
|
||||
# Echoes the installed semver for `nomad` or `vault` (e.g. "1.9.5").
|
||||
# Both tools print their version on the first line of `<bin> version` as
|
||||
# "<Name> v<semver>..." — the shared awk extracts $2 with the leading "v"
|
||||
# stripped. Empty string when the binary is absent or output is unexpected.
|
||||
_installed_version() {
|
||||
local bin="$1"
|
||||
command -v "$bin" >/dev/null 2>&1 || { printf ''; return 0; }
|
||||
"$bin" version 2>/dev/null \
|
||||
| awk 'NR==1 {sub(/^v/, "", $2); print $2; exit}'
|
||||
}
|
||||
|
||||
# ── Preconditions ────────────────────────────────────────────────────────────
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
|
|
@ -53,16 +69,24 @@ done
|
|||
CODENAME="$(lsb_release -cs)"
|
||||
[ -n "$CODENAME" ] || die "lsb_release returned empty codename"
|
||||
|
||||
# ── Fast-path: already at desired version? ───────────────────────────────────
|
||||
installed_version=""
|
||||
if command -v nomad >/dev/null 2>&1; then
|
||||
# `nomad version` prints e.g. "Nomad v1.9.5" on the first line.
|
||||
installed_version="$(nomad version 2>/dev/null \
|
||||
| awk 'NR==1 {sub(/^v/, "", $2); print $2; exit}')"
|
||||
# ── Fast-path: are both already at desired versions? ─────────────────────────
|
||||
nomad_installed="$(_installed_version nomad)"
|
||||
vault_installed="$(_installed_version vault)"
|
||||
|
||||
need_pkgs=()
|
||||
if [ "$nomad_installed" = "$NOMAD_VERSION" ]; then
|
||||
log "nomad ${NOMAD_VERSION} already installed"
|
||||
else
|
||||
need_pkgs+=("nomad=${NOMAD_VERSION}-1")
|
||||
fi
|
||||
if [ "$vault_installed" = "$VAULT_VERSION" ]; then
|
||||
log "vault ${VAULT_VERSION} already installed"
|
||||
else
|
||||
need_pkgs+=("vault=${VAULT_VERSION}-1")
|
||||
fi
|
||||
|
||||
if [ "$installed_version" = "$NOMAD_VERSION" ]; then
|
||||
log "nomad ${NOMAD_VERSION} already installed — nothing to do"
|
||||
if [ "${#need_pkgs[@]}" -eq 0 ]; then
|
||||
log "nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
|
|
@ -94,25 +118,26 @@ else
|
|||
apt_update_needed=0
|
||||
fi
|
||||
|
||||
# ── Install the pinned version ───────────────────────────────────────────────
|
||||
# ── Install the pinned versions ──────────────────────────────────────────────
|
||||
if [ "$apt_update_needed" -eq 1 ]; then
|
||||
log "running apt-get update"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get update -qq \
|
||||
|| die "apt-get update failed"
|
||||
fi
|
||||
|
||||
# HashiCorp apt packages use the "<version>-1" package-revision suffix.
|
||||
pkg_spec="nomad=${NOMAD_VERSION}-1"
|
||||
log "installing ${pkg_spec}"
|
||||
log "installing ${need_pkgs[*]}"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||
"$pkg_spec" \
|
||||
|| die "apt-get install ${pkg_spec} failed"
|
||||
"${need_pkgs[@]}" \
|
||||
|| die "apt-get install ${need_pkgs[*]} failed"
|
||||
|
||||
# ── Verify ───────────────────────────────────────────────────────────────────
|
||||
final_version="$(nomad version 2>/dev/null \
|
||||
| awk 'NR==1 {sub(/^v/, "", $2); print $2; exit}')"
|
||||
if [ "$final_version" != "$NOMAD_VERSION" ]; then
|
||||
die "post-install check: expected ${NOMAD_VERSION}, got '${final_version}'"
|
||||
final_nomad="$(_installed_version nomad)"
|
||||
if [ "$final_nomad" != "$NOMAD_VERSION" ]; then
|
||||
die "post-install check: expected nomad ${NOMAD_VERSION}, got '${final_nomad}'"
|
||||
fi
|
||||
final_vault="$(_installed_version vault)"
|
||||
if [ "$final_vault" != "$VAULT_VERSION" ]; then
|
||||
die "post-install check: expected vault ${VAULT_VERSION}, got '${final_vault}'"
|
||||
fi
|
||||
|
||||
log "nomad ${NOMAD_VERSION} installed successfully"
|
||||
log "nomad ${NOMAD_VERSION} + vault ${VAULT_VERSION} installed successfully"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue