From ef7fe7677cd5b8f9d67c3a3094735fffa6c768bf Mon Sep 17 00:00:00 2001 From: Timothy Kim Date: Wed, 18 Mar 2026 19:04:22 -0400 Subject: [PATCH] migrate bootstrap.sh from bw to bws, update docs --- ARCHITECTURE.md | 30 ++++++++++++++++-------- CLAUDE.md | 16 ++++++++----- README.md | 40 ++++++++++++++++---------------- USECASES.md | 7 +++--- scripts/bootstrap.sh | 54 ++++++++++++++++++++++++++++++-------------- 5 files changed, 92 insertions(+), 55 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4bfbfdb..4e7a282 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -21,18 +21,30 @@ A separate server running the Gitea instance. Provides: - Gitea Actions CI/CD (runner registered at site level) - Organization-level secrets and variables shared across repos -### Bitwarden (cloud) +### Bitwarden Secrets Manager (cloud) -Bitwarden free tier is used as the secret store. Stores: +Secrets are stored in Bitwarden Secrets Manager (free tier, project: `hantim`). +The `bws` CLI fetches secrets using machine account access tokens. -- `hantim-ci-registry-push` -- Gitea API token for registry access (Secure Note) -- `hantim-server-deploy` -- deploy user SSH key pair (SSH Key) -- `hantim-new-app-script` -- Gitea API token for creating repos (Secure Note) -- `hantim-vultr-api-key` -- Vultr API key for DNS management (Secure Note) -- `argento-garage` -- Garage rpc_secret, argento_node_id, S3 keys (Secure Note) +- `hantim-ci-registry-push` -- Gitea API token for registry access +- `hantim-deploy-ssh-private-key` -- deploy user SSH private key +- `hantim-deploy-ssh-public-key` -- deploy user SSH public key +- `hantim-new-app-script` -- Gitea API token for creating repos +- `hantim-vultr-api-key` -- Vultr API key for DNS management -The Bitwarden CLI (`bw`) is used in `bootstrap.sh` (on the server) and -`new-app.sh` (on dev machines) to fetch secrets at runtime. +Machine accounts: +- `hantim-server` -- used by `bootstrap.sh` and `configure.sh` on the server + (access token at `/etc/bws-token`) +- `hantim-ci` -- reserved for future CI use + +### Gitea secrets + +Workflow secrets stored in the `hantim` Gitea org. These duplicate some +Bitwarden secrets for direct use in CI workflows without installing `bws`: + +- `DEPLOY_SSH_KEY` -- deploy SSH private key +- `CI_REGISTRY_TOKEN` -- Gitea registry token +- `DEPLOY_HOST` -- server IP (variable, not secret) ## Repos diff --git a/CLAUDE.md b/CLAUDE.md index d92ff0b..9d45ed5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -31,12 +31,16 @@ Actions workflows. ## Secrets -Stored in Bitwarden (free tier), fetched via `bw` CLI: -- `hantim-ci-registry-push` -- Secure Note (Gitea registry token) -- `hantim-server-deploy` -- SSH Key (deploy user key pair) -- `hantim-new-app-script` -- Secure Note (Gitea API token for creating repos) -- `hantim-vultr-api-key` -- Secure Note (Vultr API key for DNS management) -- `argento-garage` -- Secure Note (Garage rpc_secret, argento_node_id, S3 keys) +Bitwarden Secrets Manager (project: `hantim`, fetched via `bws` CLI): +- `hantim-ci-registry-push` -- Gitea registry token (used by bootstrap.sh) +- `hantim-deploy-ssh-private-key` -- deploy user SSH private key (used by new-app.sh) +- `hantim-deploy-ssh-public-key` -- deploy user SSH public key (used by bootstrap.sh) +- `hantim-new-app-script` -- Gitea API token for creating repos (used by new-app.sh) +- `hantim-vultr-api-key` -- Vultr API key for DNS management (used by new-app.sh) + +Machine accounts: +- `hantim-server` -- access token stored at `/etc/bws-token` on hantim +- `hantim-ci` -- access token stored as Gitea secret (reserved for future use) Gitea org-level (`hantim`) secrets/variables: - `DEPLOY_HOST` -- Variable (server IP) diff --git a/README.md b/README.md index bf7e19b..4e26348 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,13 @@ bash /opt/hantim/scripts/bootstrap.sh `bootstrap.sh` runs once manually. It: -1. Installs system dependencies (jq, certbot, Node.js 20, Docker) -2. Installs and authenticates the Bitwarden CLI -3. Fetches the Docker registry token and deploy SSH public key from Bitwarden -4. Logs into the Gitea Docker registry -5. Creates the `deploy` user with restricted SSH access and sudo -6. Runs `configure.sh` (firewall, certbot, start services) +1. Installs system dependencies (jq, certbot, unzip, Docker) +2. Installs the `bws` CLI (Bitwarden Secrets Manager) +3. Prompts for a Bitwarden Secrets Manager access token (saved to `/etc/bws-token`) +4. Fetches the Docker registry token and deploy SSH public key via `bws` +5. Logs into the Gitea Docker registry +6. Creates the `deploy` user with restricted SSH access and sudo +7. Runs `configure.sh` (firewall, certbot, start services) `configure.sh` is idempotent and CI-safe. It: @@ -51,8 +52,9 @@ bash /opt/hantim/scripts/bootstrap.sh 2. Sets up certbot and issues SSL certificates for all configured domains 3. Starts all services (nginx first, then all apps) -**Prerequisites**: DNS for all configured domains must point to the server -before running bootstrap. +**Prerequisites**: +- DNS for all configured domains must point to the server +- Bitwarden Secrets Manager access token for the `hantim-server` machine account ## Adding a new app @@ -100,24 +102,22 @@ Run the same three commands as provisioning. `bootstrap.sh` is idempotent: ## Secrets -The following are stored in Bitwarden and fetched automatically by `bootstrap.sh`: +Bitwarden Secrets Manager (project: `hantim`, fetched via `bws` CLI on the server): -| Bitwarden item | Type | Purpose | +| Secret | Purpose | Used by | |---|---|---| -| `hantim-ci-registry-push` | Secure Note | Gitea token for Docker registry | -| `hantim-server-deploy` | SSH Key | Deploy user's SSH key | +| `hantim-ci-registry-push` | Gitea token for Docker registry | `bootstrap.sh` | +| `hantim-deploy-ssh-public-key` | Deploy user's SSH public key | `bootstrap.sh` | +| `hantim-deploy-ssh-private-key` | Deploy user's SSH private key | `new-app.sh` | +| `hantim-new-app-script` | Gitea API token for creating repos | `new-app.sh` | +| `hantim-vultr-api-key` | Vultr API key for DNS management | `new-app.sh` | -The following are configured in the `hantim` Gitea org settings: +Machine accounts: `hantim-server` (token at `/etc/bws-token`), `hantim-ci` (reserved). + +Gitea org-level (`hantim`) secrets/variables: | Name | Type | Purpose | |---|---|---| | `DEPLOY_HOST` | Variable | Server IP or hostname | | `DEPLOY_SSH_KEY` | Secret | SSH private key for the deploy user | | `CI_REGISTRY_TOKEN` | Secret | Gitea token for Docker registry login | - -The following are stored in Bitwarden and used by `new-app.sh`: - -| Bitwarden item | Type | Purpose | -|---|---|---| -| `hantim-new-app-script` | Secure Note | Gitea API token for creating repos | -| `hantim-vultr-api-key` | Secure Note | Vultr API key for DNS management | diff --git a/USECASES.md b/USECASES.md index cc3a350..38f3051 100644 --- a/USECASES.md +++ b/USECASES.md @@ -11,8 +11,9 @@ bash /opt/hantim/scripts/bootstrap.sh ``` **What happens:** -- Installs all dependencies (jq, certbot, Node.js 20, Docker, bw CLI) -- Fetches secrets from Bitwarden (registry token, deploy SSH key) +- Installs all dependencies (jq, certbot, unzip, Docker) +- Installs `bws` CLI, prompts for Bitwarden Secrets Manager access token +- Fetches registry token and deploy SSH public key via `bws` - Logs into Docker registry - Creates deploy user with restricted SSH + sudo - Runs `configure.sh`: @@ -22,7 +23,7 @@ bash /opt/hantim/scripts/bootstrap.sh **Prerequisites:** - DNS for all configured domains must point to the server -- Bitwarden vault must contain: `hantim-ci-registry-push`, `hantim-server-deploy` +- Bitwarden Secrets Manager access token for the `hantim-server` machine account - Docker images must exist in the Gitea registry (or apps will start on next push) ## 2. Restore from backup diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index 3e2e2f2..529d5ce 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -10,8 +10,16 @@ set -euo pipefail # 2. git clone https://git.timothykim.net/hantim/hantim-server.git /opt/hantim # 3. bash /opt/hantim/scripts/bootstrap.sh # +# Prerequisites: +# - Bitwarden Secrets Manager access token for the hantim-server machine account REPO_DIR="/opt/hantim" +BWS_TOKEN_FILE="/etc/bws-token" +BWS_VERSION="2.0.0" + +# Secret IDs (Bitwarden Secrets Manager) +SECRET_REGISTRY_TOKEN="43f4a77d-7bb4-49ad-8044-b411016c5c6e" +SECRET_DEPLOY_PUBKEY="945760dd-90e2-46e5-98ad-b411016e3f3b" # --- Prerequisites --- @@ -32,29 +40,41 @@ echo "==> Upgrading system packages..." dnf upgrade -y echo "==> Installing dependencies..." -dnf install -y jq epel-release +dnf install -y jq epel-release unzip dnf install -y certbot -dnf module reset -y nodejs -dnf module install -y nodejs:20/common -BW_CLI="$(npm config get prefix)/bin/bw" -if [ ! -x "$BW_CLI" ]; then - echo "==> Installing Bitwarden CLI..." - npm install -g @bitwarden/cli +# --- Install bws CLI --- + +if ! command -v bws &>/dev/null; then + echo "==> Installing Bitwarden Secrets Manager CLI..." + curl -sL "https://github.com/bitwarden/sdk-sm/releases/download/bws-v${BWS_VERSION}/bws-x86_64-unknown-linux-gnu-${BWS_VERSION}.zip" -o /tmp/bws.zip + unzip -o /tmp/bws.zip -d /usr/local/bin + chmod +x /usr/local/bin/bws + rm /tmp/bws.zip fi -# --- Fetch secrets from Bitwarden --- +# --- Set up access token --- -echo "==> Fetching secrets from Bitwarden..." -echo " Log in to Bitwarden when prompted." -if "$BW_CLI" status 2>/dev/null | grep -q '"status":"unauthenticated"'; then - "$BW_CLI" login +if [ ! -f "$BWS_TOKEN_FILE" ]; then + echo "==> Bitwarden Secrets Manager access token required." + echo " Generate one for the hantim-server machine account at:" + echo " https://vault.bitwarden.com/#/sm/machine-accounts" + read -rp " Paste access token: " BWS_TOKEN + if [ -z "$BWS_TOKEN" ]; then + echo "ERROR: Access token cannot be empty." + exit 1 + fi + echo "$BWS_TOKEN" > "$BWS_TOKEN_FILE" + chmod 600 "$BWS_TOKEN_FILE" fi -BW_SESSION=$("$BW_CLI" unlock --raw) -"$BW_CLI" sync --session "$BW_SESSION" -REGISTRY_TOKEN=$("$BW_CLI" get notes hantim-ci-registry-push --session "$BW_SESSION") -DEPLOY_PUBKEY=$("$BW_CLI" get item hantim-server-deploy --session "$BW_SESSION" | jq -r '.sshKey.publicKey') -"$BW_CLI" lock +export BWS_ACCESS_TOKEN +BWS_ACCESS_TOKEN=$(cat "$BWS_TOKEN_FILE") + +# --- Fetch secrets --- + +echo "==> Fetching secrets from Bitwarden Secrets Manager..." +REGISTRY_TOKEN=$(bws secret get "$SECRET_REGISTRY_TOKEN" | jq -r .value) +DEPLOY_PUBKEY=$(bws secret get "$SECRET_DEPLOY_PUBKEY" | jq -r .value) # --- Install Docker ---