--- id: RAIL-BS-WP-0002 type: workplan title: "Secure Single-Server Bootstrap at HostEurope" domain: railiance repo: railiance-bootstrap status: active owner: railiance topic_slug: railiance repo_goal_id: d7092599-927b-4796-b52e-8be833301478 state_hub_workstream_id: "bf40b47e-be5b-4930-a7d2-362e76b943bb" created: "2026-03-08" updated: "2026-03-08" handoff_note: "T01-T03 done locally (WSL, no ansible). T04+T05 require ansible on a Linux box with network access to 92.205.62.239. hosts.ini created with the IP (gitignored — recreate on new box). Run: ansible -i ansible/hosts.ini hosteurope -m ping, then ansible-playbook -i ansible/hosts.ini -l hosteurope ansible/bootstrap.yml" --- # Secure Single-Server Bootstrap at HostEurope ## Goal Bootstrap a new HostEurope server securely so that it can function as the second Kubernetes host in the ThreePhoenix cluster. The bare Ubuntu server is provisioned manually by Bernd. This workplan covers everything from first SSH contact through a verified, hardened k3s node — all services secured from the start, no shortcuts. Scope is deliberately narrow: one server, secure from day one. Automated provisioning of additional server resources (railiance-hosts) and the full three-node setup are deferred. ## Boundary conditions - Ubuntu 24.04 LTS server at HostEurope, manually provisioned - SSH access established using existing private credentials - All remote access must be key-based only (no password auth) - Firewall active before k3s is installed - No credentials committed to the repo --- ## Tasks ### T01 — Add HostEurope host to inventory ```task id: RAIL-BS-WP-0002-T01 status: done completed: "2026-03-08" priority: high state_hub_task_id: "d41e1f8e-1dc2-41e9-bf83-521c99908e18" ``` Add the HostEurope host to `ansible/hosts.ini` (create from `hosts.ini.example` if not present). Place it in a `[hosteurope]` group so it can be targeted independently from other nodes. Verify Ansible can reach the host: ```bash ansible -i ansible/hosts.ini hosteurope -m ping ``` **Done when:** ping succeeds from local control node. --- ### T02 — Create server hardening playbook ```task id: RAIL-BS-WP-0002-T02 status: done completed: "2026-03-08" priority: high state_hub_task_id: "e8abc64b-d74c-4718-9859-96d53551c654" ``` Create `ansible/harden.yml` (or a `roles/harden/` role called from `bootstrap.yml`) covering: - Disable root SSH login (`PermitRootLogin no`) - Disable password authentication (`PasswordAuthentication no`) - Enable and configure UFW: deny all inbound by default, allow SSH (22), k3s API (6443), and Flannel VXLAN (8472/UDP) — add others as needed - Install and enable `fail2ban` with SSH jail - Set `HISTCONTROL=ignorespace` in `/etc/profile.d/` to allow secret-safe shell usage **Done when:** `ansible-lint ansible/harden.yml` passes and a dry-run (`--check`) against the HostEurope host produces no errors. --- ### T03 — Integrate hardening into bootstrap sequence ```task id: RAIL-BS-WP-0002-T03 status: done completed: "2026-03-08" priority: high state_hub_task_id: "bf991fa3-a870-4c80-8d9e-91f96b97eb7c" ``` Ensure `ansible/bootstrap.yml` runs hardening **before** k3s installation. Either import `harden.yml` as a play or invoke the role inline. Order must be: 1. Harden (T02) 2. Install base packages 3. Install k3s Update `QUICKSTART.md` step 6 to note that hardening runs automatically as part of bootstrap. **Done when:** `bootstrap.yml` task list reflects the correct order and the QUICKSTART reflects it. --- ### T04 — Run bootstrap on the HostEurope host ```task id: RAIL-BS-WP-0002-T04 status: todo priority: high state_hub_task_id: "f62896f2-6fed-4512-a41b-3f5b9a1ca311" ``` Execute the full bootstrap playbook against the HostEurope host: ```bash ansible-playbook -i ansible/hosts.ini -l hosteurope ansible/bootstrap.yml ``` **Done when:** - Playbook completes with no failed tasks - `k3s kubectl get nodes` shows the host in `Ready` state - UFW is active and SSH still works after the run --- ### T05 — Smoke test and record ```task id: RAIL-BS-WP-0002-T05 status: todo priority: medium state_hub_task_id: "9e92effe-3531-4675-8bc8-7b2bc2c04877" ``` Run the existing smoke test: ```bash tests/smoke_kube.sh ``` If the smoke test is not yet parameterized for a remote host, extend it or run the equivalent `kubectl get nodes` via `ansible -m shell`. Add a brief note to `docs/` (or a new `docs/hosteurope-bootstrap.md`) recording: - Server specs (vCPU, RAM, disk) - IP / hostname (public, non-sensitive — no credentials) - Date bootstrapped - k3s version installed Call `add_progress_event()` in the State Hub to close out the workstream. **Done when:** smoke test passes and the progress event is logged. --- ## References - Repo goal: `d7092599-927b-4796-b52e-8be833301478` - ThreePhoenix workstream: `9e208376-23f1-40c7-9813-fac1f7d6ad3b` - Safety Net workstream: `7e8b0c20-51eb-40c9-9e3b-85dd380d7625` (safety net passed green 2026-02-27 — safe to proceed with cluster work) - Existing playbook: `ansible/bootstrap.yml` - Inventory template: `ansible/hosts.ini.example`