Add bootstrap scripts and restructure runbook
- scripts/run-bootstrap.sh: copies and runs the deploy user bootstrap on a fresh server, verifies SSH login, checks vault as a preflight step - scripts/bootstrap-deploy-user.sh: runs on the server as root, accepts the SSH public key as an argument (read from keys/ by run-bootstrap.sh) - scripts/check-vault.sh: decrypts vault.yml and verifies all 11 required secrets are present and non-empty - docs/runbook.md: restructured into correct order (collections → DNS → vault → bootstrap → playbook), added scripts reference table, moved first-run notes for Gitea/Keycloak/registry into their own section - README.md: added scripts/ to repo layout
This commit is contained in:
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run once as root on a fresh server to create the deploy user Ansible connects as.
|
||||
# Usage: bash bootstrap-deploy-user.sh <ssh-public-key>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SSH_PUBKEY="${1:?Usage: bootstrap-deploy-user.sh <ssh-public-key>}"
|
||||
DEPLOY_USER="deploy"
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "ERROR: must be run as root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Creating user '${DEPLOY_USER}'"
|
||||
if id "${DEPLOY_USER}" &>/dev/null; then
|
||||
echo " user already exists, skipping"
|
||||
else
|
||||
adduser --disabled-password --gecos "" "${DEPLOY_USER}"
|
||||
fi
|
||||
|
||||
echo "==> Adding '${DEPLOY_USER}' to sudo group"
|
||||
usermod -aG sudo "${DEPLOY_USER}"
|
||||
|
||||
echo "==> Installing SSH authorized key"
|
||||
SSH_DIR="/home/${DEPLOY_USER}/.ssh"
|
||||
AUTH_KEYS="${SSH_DIR}/authorized_keys"
|
||||
mkdir -p "${SSH_DIR}"
|
||||
if grep -qF "${SSH_PUBKEY}" "${AUTH_KEYS}" 2>/dev/null; then
|
||||
echo " key already present, skipping"
|
||||
else
|
||||
echo "${SSH_PUBKEY}" >> "${AUTH_KEYS}"
|
||||
fi
|
||||
chown -R "${DEPLOY_USER}:${DEPLOY_USER}" "${SSH_DIR}"
|
||||
chmod 700 "${SSH_DIR}"
|
||||
chmod 600 "${AUTH_KEYS}"
|
||||
|
||||
echo ""
|
||||
echo "Done."
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# Decrypts ansible/group_vars/vault.yml and checks all required secrets are present
|
||||
# and non-empty. Exits non-zero if any are missing.
|
||||
# Usage: bash scripts/check-vault.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
VAULT_FILE="${REPO_ROOT}/ansible/group_vars/vault.yml"
|
||||
|
||||
REQUIRED_KEYS=(
|
||||
traefik_dashboard_users
|
||||
gitea_db_password
|
||||
gitea_secret_key
|
||||
gitea_internal_token
|
||||
keycloak_db_password
|
||||
keycloak_admin_password
|
||||
nextcloud_db_password
|
||||
nextcloud_admin_password
|
||||
roundcube_db_password
|
||||
roundcube_des_key
|
||||
registry_htpasswd
|
||||
)
|
||||
|
||||
if [ ! -f "${VAULT_FILE}" ]; then
|
||||
echo "ERROR: vault file not found at ${VAULT_FILE}" >&2
|
||||
echo " Create it with: ansible-vault create ansible/group_vars/vault.yml" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v ansible-vault &>/dev/null; then
|
||||
echo "ERROR: ansible-vault not found — install with: pip install ansible" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Decrypting vault (you will be prompted for the vault password)"
|
||||
VAULT_CONTENT=$(ansible-vault view "${VAULT_FILE}")
|
||||
|
||||
MISSING=()
|
||||
for key in "${REQUIRED_KEYS[@]}"; do
|
||||
# Match lines like: key: "value" or key: value — but not key: "" or key: '' or missing
|
||||
if ! echo "${VAULT_CONTENT}" | grep -qE "^${key}:[[:space:]]+[^'\"[:space:]]|^${key}:[[:space:]]+['\"].+['\"]"; then
|
||||
MISSING+=("${key}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#MISSING[@]} -gt 0 ]; then
|
||||
echo "" >&2
|
||||
echo "ERROR: the following secrets are missing or empty in vault.yml:" >&2
|
||||
for key in "${MISSING[@]}"; do
|
||||
echo " - ${key}" >&2
|
||||
done
|
||||
echo "" >&2
|
||||
echo "Edit the vault with: ansible-vault edit ansible/group_vars/vault.yml" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo " OK — all required secrets are present"
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copies bootstrap-deploy-user.sh to the server and runs it as root.
|
||||
# Run from the repo root: bash scripts/run-bootstrap.sh
|
||||
#
|
||||
# Requires: ssh access to the server as root via keys/root_cloud_ladkau_de
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
SERVER="217.154.207.148"
|
||||
ROOT_KEY="${REPO_ROOT}/keys/root_cloud_ladkau_de"
|
||||
DEPLOY_KEY="${REPO_ROOT}/keys/notroot_cloud_ladkau_de"
|
||||
DEPLOY_PUBKEY="${REPO_ROOT}/keys/notroot_cloud_ladkau_de.pub"
|
||||
BOOTSTRAP_SCRIPT="${SCRIPT_DIR}/bootstrap-deploy-user.sh"
|
||||
|
||||
# --- Preflight checks ---
|
||||
|
||||
if [ ! -f "${ROOT_KEY}" ]; then
|
||||
echo "ERROR: root SSH key not found at ${ROOT_KEY}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${DEPLOY_KEY}" ]; then
|
||||
echo "ERROR: deploy SSH key not found at ${DEPLOY_KEY}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${DEPLOY_PUBKEY}" ]; then
|
||||
echo "ERROR: deploy public key not found at ${DEPLOY_PUBKEY}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${BOOTSTRAP_SCRIPT}" ]; then
|
||||
echo "ERROR: bootstrap script not found at ${BOOTSTRAP_SCRIPT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Vault check ---
|
||||
|
||||
bash "${SCRIPT_DIR}/check-vault.sh"
|
||||
|
||||
SSH_OPTS="-o StrictHostKeyChecking=accept-new -o ConnectTimeout=10"
|
||||
|
||||
# --- Verify root access ---
|
||||
|
||||
echo "==> Verifying root SSH access to ${SERVER}"
|
||||
if ! ssh ${SSH_OPTS} -i "${ROOT_KEY}" "root@${SERVER}" "echo ok" &>/dev/null; then
|
||||
echo "ERROR: cannot connect as root to ${SERVER}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Copy and run the bootstrap script ---
|
||||
|
||||
echo "==> Copying bootstrap script to server"
|
||||
scp ${SSH_OPTS} -i "${ROOT_KEY}" "${BOOTSTRAP_SCRIPT}" "root@${SERVER}:/root/bootstrap-deploy-user.sh"
|
||||
|
||||
echo "==> Running bootstrap script on server"
|
||||
SSH_PUBKEY="$(cat "${DEPLOY_PUBKEY}")"
|
||||
ssh ${SSH_OPTS} -i "${ROOT_KEY}" "root@${SERVER}" "bash /root/bootstrap-deploy-user.sh '${SSH_PUBKEY}'"
|
||||
|
||||
# --- Verify deploy user access ---
|
||||
|
||||
echo ""
|
||||
echo "==> Verifying deploy user SSH access"
|
||||
if ssh ${SSH_OPTS} -i "${DEPLOY_KEY}" "deploy@${SERVER}" "echo ok" &>/dev/null; then
|
||||
echo " OK — deploy user can log in"
|
||||
else
|
||||
echo "ERROR: deploy user login failed — check the bootstrap output above" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Bootstrap complete. Next step:"
|
||||
echo " ansible-playbook -i ansible/inventory.ini ansible/site.yml --ask-vault-pass"
|
||||
Reference in New Issue
Block a user