feat(boundary): remove OS-hardening overlap; add k3s baseline workplan
Per ADR-002 (railiance-hosts/docs/adr/ADR-002-repo-boundary-hosts-vs-bootstrap.md): - ansible/harden.yml: replaced with tombstone pointing to railiance-hosts - ansible/bootstrap.yml: remove `import_playbook: harden.yml`; add pre-condition comment; OS hardening is no longer this repo's concern - docs/first_host.md: rewritten to reflect 3-step flow: converge railiance-hosts → railiance-bootstrap k3s install → smoke test - workplans/RAIL-BS-WP-0002-k3s-baseline.md: new workplan for k3s + Helm + Kubernetes platform baseline; linked to repo goal 70ab2379 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
---
|
---
|
||||||
# Stage 1: Harden the server before anything else is installed.
|
# Pre-condition: the target host must already be converged by railiance-hosts
|
||||||
- import_playbook: harden.yml
|
# (`make converge` in that repo) before running this playbook.
|
||||||
|
# OS hardening (SSH, UFW, fail2ban) is owned by railiance-hosts — see ADR-002.
|
||||||
|
|
||||||
# Stage 2: Install base packages and k3s.
|
# Install base packages and k3s.
|
||||||
- name: Railiance host bootstrap
|
- name: Railiance host bootstrap
|
||||||
hosts: all
|
hosts: all
|
||||||
become: true
|
become: true
|
||||||
|
|||||||
@@ -1,124 +1,16 @@
|
|||||||
---
|
---
|
||||||
- name: Server hardening
|
# SUPERSEDED — do not use for new work.
|
||||||
hosts: all
|
#
|
||||||
become: true
|
# OS security hardening (SSH, UFW, fail2ban, HISTCONTROL) is now owned by
|
||||||
|
# the railiance-hosts repository:
|
||||||
vars:
|
#
|
||||||
ssh_port: 22
|
# railiance-hosts/ansible/roles/base/
|
||||||
k3s_api_port: 6443
|
# railiance-hosts/spec/server-baseline.yaml ← authoritative spec
|
||||||
flannel_vxlan_port: 8472
|
# railiance-hosts/goss/baseline.yaml ← automated assertions
|
||||||
|
#
|
||||||
tasks:
|
# Run `make converge` in railiance-hosts before deploying anything from
|
||||||
# ── SSH hardening ────────────────────────────────────────────────────────
|
# this repo. See ADR-002 for the full boundary definition:
|
||||||
|
# railiance-hosts/docs/adr/ADR-002-repo-boundary-hosts-vs-bootstrap.md
|
||||||
- name: Disable root SSH login
|
#
|
||||||
lineinfile:
|
# This file is retained to avoid breaking git history references.
|
||||||
path: /etc/ssh/sshd_config
|
# It must not be imported or executed.
|
||||||
regexp: '^#?PermitRootLogin'
|
|
||||||
line: 'PermitRootLogin no'
|
|
||||||
state: present
|
|
||||||
notify: Restart sshd
|
|
||||||
|
|
||||||
- name: Disable password authentication
|
|
||||||
lineinfile:
|
|
||||||
path: /etc/ssh/sshd_config
|
|
||||||
regexp: '^#?PasswordAuthentication'
|
|
||||||
line: 'PasswordAuthentication no'
|
|
||||||
state: present
|
|
||||||
notify: Restart sshd
|
|
||||||
|
|
||||||
- name: Disable challenge-response authentication
|
|
||||||
lineinfile:
|
|
||||||
path: /etc/ssh/sshd_config
|
|
||||||
regexp: '^#?ChallengeResponseAuthentication'
|
|
||||||
line: 'ChallengeResponseAuthentication no'
|
|
||||||
state: present
|
|
||||||
notify: Restart sshd
|
|
||||||
|
|
||||||
# ── UFW firewall ─────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
- name: Install ufw
|
|
||||||
apt:
|
|
||||||
name: ufw
|
|
||||||
state: present
|
|
||||||
update_cache: yes
|
|
||||||
|
|
||||||
- name: Set UFW default inbound policy to deny
|
|
||||||
ufw:
|
|
||||||
default: deny
|
|
||||||
direction: incoming
|
|
||||||
|
|
||||||
- name: Set UFW default outbound policy to allow
|
|
||||||
ufw:
|
|
||||||
default: allow
|
|
||||||
direction: outgoing
|
|
||||||
|
|
||||||
- name: Allow SSH
|
|
||||||
ufw:
|
|
||||||
rule: allow
|
|
||||||
port: "{{ ssh_port }}"
|
|
||||||
proto: tcp
|
|
||||||
|
|
||||||
- name: Allow k3s API server
|
|
||||||
ufw:
|
|
||||||
rule: allow
|
|
||||||
port: "{{ k3s_api_port }}"
|
|
||||||
proto: tcp
|
|
||||||
|
|
||||||
- name: Allow Flannel VXLAN (inter-node)
|
|
||||||
ufw:
|
|
||||||
rule: allow
|
|
||||||
port: "{{ flannel_vxlan_port }}"
|
|
||||||
proto: udp
|
|
||||||
|
|
||||||
- name: Enable UFW
|
|
||||||
ufw:
|
|
||||||
state: enabled
|
|
||||||
|
|
||||||
# ── fail2ban ─────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
- name: Install fail2ban
|
|
||||||
apt:
|
|
||||||
name: fail2ban
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Configure fail2ban SSH jail
|
|
||||||
copy:
|
|
||||||
dest: /etc/fail2ban/jail.d/sshd.conf
|
|
||||||
content: |
|
|
||||||
[sshd]
|
|
||||||
enabled = true
|
|
||||||
port = {{ ssh_port }}
|
|
||||||
maxretry = 5
|
|
||||||
bantime = 3600
|
|
||||||
findtime = 600
|
|
||||||
mode: '0644'
|
|
||||||
notify: Restart fail2ban
|
|
||||||
|
|
||||||
- name: Enable and start fail2ban
|
|
||||||
systemd:
|
|
||||||
name: fail2ban
|
|
||||||
enabled: true
|
|
||||||
state: started
|
|
||||||
|
|
||||||
# ── Shell hygiene ─────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
- name: Set HISTCONTROL to suppress space-prefixed commands from history
|
|
||||||
copy:
|
|
||||||
dest: /etc/profile.d/histcontrol.sh
|
|
||||||
content: |
|
|
||||||
# Commands prefixed with a space are not recorded in shell history.
|
|
||||||
# Use this when typing secrets interactively.
|
|
||||||
export HISTCONTROL=ignorespace
|
|
||||||
mode: '0644'
|
|
||||||
|
|
||||||
handlers:
|
|
||||||
- name: Restart sshd
|
|
||||||
systemd:
|
|
||||||
name: sshd
|
|
||||||
state: restarted
|
|
||||||
|
|
||||||
- name: Restart fail2ban
|
|
||||||
systemd:
|
|
||||||
name: fail2ban
|
|
||||||
state: restarted
|
|
||||||
|
|||||||
@@ -1,22 +1,39 @@
|
|||||||
# First Railiance Host — Provider Guide
|
# First Railiance Host — Setup Guide
|
||||||
|
|
||||||
## 1) Generate SSH key
|
## Prerequisites
|
||||||
```
|
|
||||||
bin/railiance gen-ssh-key
|
The target server must be a converged `railiance-hosts` node before running
|
||||||
|
anything from this repo. The OS baseline (SSH hardening, UFW, fail2ban, SOPS
|
||||||
|
agent) is owned by `railiance-hosts`.
|
||||||
|
|
||||||
|
**Step 0 — Converge the host OS (railiance-hosts)**
|
||||||
|
```bash
|
||||||
|
# In railiance-hosts/
|
||||||
|
make converge # apply OS baseline roles
|
||||||
|
make verify # confirm all Goss assertions pass
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2) Choose a VM
|
See `railiance-hosts/docs/adr/ADR-002-repo-boundary-hosts-vs-bootstrap.md`
|
||||||
Ubuntu 24.04 LTS, 2 vCPU, 4–8GB RAM, 60+GB SSD, open 22/80/443.
|
for the boundary definition between the two repos.
|
||||||
|
|
||||||
## 3) Cloud-init
|
---
|
||||||
```
|
|
||||||
bin/railiance cloudinit > user-data.yaml
|
## Kubernetes bootstrap (this repo)
|
||||||
|
|
||||||
|
### 1) Inventory
|
||||||
|
|
||||||
|
Add the host to `ansible/hosts.ini` (gitignored — recreate on each machine):
|
||||||
|
```ini
|
||||||
|
[hosteurope]
|
||||||
|
92.205.62.239 ansible_user=tegwick
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4) Seed
|
### 2) Install k3s
|
||||||
Copy Spore or clone directly, then run seed script on the host.
|
```bash
|
||||||
|
ansible-playbook -i ansible/hosts.ini ansible/bootstrap.yml
|
||||||
|
```
|
||||||
|
|
||||||
## 5) Bootstrap (optional now)
|
### 3) Smoke test
|
||||||
```
|
```bash
|
||||||
ansible-playbook -i ansible/inventory/hosts.ini ansible/bootstrap.yml
|
tests/smoke_kube.sh
|
||||||
```
|
```
|
||||||
|
|||||||
169
workplans/RAIL-BS-WP-0002-k3s-baseline.md
Normal file
169
workplans/RAIL-BS-WP-0002-k3s-baseline.md
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
---
|
||||||
|
id: RAIL-BS-WP-0002
|
||||||
|
type: workplan
|
||||||
|
title: "k3s and Kubernetes Platform Baseline"
|
||||||
|
domain: railiance
|
||||||
|
repo: railiance-bootstrap
|
||||||
|
status: active
|
||||||
|
owner: railiance
|
||||||
|
topic_slug: railiance
|
||||||
|
repo_goal_id: "70ab2379-fb9d-4fec-a09d-b2a717e4ace8"
|
||||||
|
state_hub_workstream_id: "4c63dfc6-9eac-4e79-9f77-8f644ad7147d"
|
||||||
|
created: "2026-03-09"
|
||||||
|
updated: "2026-03-09"
|
||||||
|
---
|
||||||
|
|
||||||
|
# k3s and Kubernetes Platform Baseline
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Install k3s, Helm, and the baseline Kubernetes services on the converged
|
||||||
|
HostEurope node. This workplan picks up exactly where `railiance-hosts`
|
||||||
|
leaves off: a hardened, verified OS node that is ready for Kubernetes.
|
||||||
|
|
||||||
|
## Pre-condition
|
||||||
|
|
||||||
|
`railiance-hosts` converge + Goss verify must pass before any task here
|
||||||
|
is executed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In railiance-hosts/
|
||||||
|
make converge
|
||||||
|
make verify # must exit 0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Boundary
|
||||||
|
|
||||||
|
This repo owns everything from k3s upward. It must not re-configure items
|
||||||
|
defined in `railiance-hosts/spec/server-baseline.yaml`. See
|
||||||
|
`railiance-hosts/docs/adr/ADR-002-repo-boundary-hosts-vs-bootstrap.md`.
|
||||||
|
|
||||||
|
**Out of scope here:** application-layer deployments (Gitea, monitoring
|
||||||
|
stack, user-facing services). Those belong in `railiance-apps` once that
|
||||||
|
repo is established (decision pending).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
### T01 — Ansible playbook: install k3s (server mode)
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: T01
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
state_hub_task_id: "3f042630-eab0-4c6a-9167-e2b28ff20e40"
|
||||||
|
```
|
||||||
|
|
||||||
|
Harden `ansible/bootstrap.yml` to a production-ready k3s install:
|
||||||
|
|
||||||
|
- Use the official k3s install script pinned to a specific version
|
||||||
|
(`INSTALL_K3S_VERSION=vX.Y.Z+k3s1`)
|
||||||
|
- `INSTALL_K3S_EXEC="server --cluster-init --write-kubeconfig-mode=644"`
|
||||||
|
(cluster-init enables embedded etcd for future HA expansion)
|
||||||
|
- Wait for node `Ready` before proceeding:
|
||||||
|
```bash
|
||||||
|
k3s kubectl wait node --all --for=condition=Ready --timeout=120s
|
||||||
|
```
|
||||||
|
- Fetch kubeconfig to the control node as `~/.kube/config-hosteurope`
|
||||||
|
|
||||||
|
**Done when:** `k3s kubectl get nodes` returns `Ready` from both the server
|
||||||
|
and the control node (via kubeconfig).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T02 — Helm installation
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: T02
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
state_hub_task_id: "e8510646-46ed-4697-a345-f3d3009eea78"
|
||||||
|
```
|
||||||
|
|
||||||
|
Add a task (or a role `roles/helm/`) that:
|
||||||
|
|
||||||
|
1. Downloads the Helm binary (pinned version) to `/usr/local/bin/helm`
|
||||||
|
2. Verifies the checksum
|
||||||
|
3. Confirms `helm version` succeeds
|
||||||
|
|
||||||
|
**Done when:** `helm version` succeeds on the HostEurope node.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T03 — Smoke test: k3s + Helm
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: T03
|
||||||
|
status: todo
|
||||||
|
priority: high
|
||||||
|
state_hub_task_id: "dab2c07f-8aa0-4635-8df6-857e87e93fc5"
|
||||||
|
```
|
||||||
|
|
||||||
|
Extend `tests/smoke_kube.sh` to assert:
|
||||||
|
|
||||||
|
- `k3s kubectl get nodes` → node in Ready state
|
||||||
|
- `helm version` exits 0
|
||||||
|
- CoreDNS pod running in `kube-system`
|
||||||
|
- Traefik ingress controller pod running (default in k3s)
|
||||||
|
|
||||||
|
Run via:
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i ansible/hosts.ini ansible/smoke.yml
|
||||||
|
```
|
||||||
|
or directly over SSH if the kubeconfig is available locally.
|
||||||
|
|
||||||
|
**Done when:** all assertions pass and the script exits 0.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T04 — Commit kubeconfig management notes
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: T04
|
||||||
|
status: todo
|
||||||
|
priority: medium
|
||||||
|
state_hub_task_id: "5c3d40e4-239b-488e-9519-6f7a38d2325f"
|
||||||
|
```
|
||||||
|
|
||||||
|
Document in `docs/kubeconfig.md`:
|
||||||
|
|
||||||
|
- Where the kubeconfig is fetched to (`~/.kube/config-hosteurope`)
|
||||||
|
- How to merge it into `~/.kube/config`
|
||||||
|
- How to switch context: `kubectl config use-context default`
|
||||||
|
- Security note: kubeconfig is gitignored (contains cluster CA + client cert)
|
||||||
|
|
||||||
|
**Done when:** doc written and committed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T05 — Add `make k3s-install` and `make smoke` targets
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: T05
|
||||||
|
status: todo
|
||||||
|
priority: medium
|
||||||
|
state_hub_task_id: "7f9e0e58-a130-467a-a2d0-b3f2564e496f"
|
||||||
|
```
|
||||||
|
|
||||||
|
Add to Makefile (create one if none exists):
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
k3s-install: ## Install k3s and Helm on all inventory hosts
|
||||||
|
ansible-playbook -i ansible/hosts.ini ansible/bootstrap.yml
|
||||||
|
|
||||||
|
smoke: ## Run Kubernetes smoke tests
|
||||||
|
bash tests/smoke_kube.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Done when:** both targets work and are listed in `make help`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- Repo goal: `70ab2379-fb9d-4fec-a09d-b2a717e4ace8` (Install k3s and Kubernetes Baseline)
|
||||||
|
- Domain goal: `6f96c712-60e6-4ea9-ab06-168878eafbce` (Three-Phoenix Secure Kubernetes Infrastructure)
|
||||||
|
- Pre-condition: railiance-hosts WP-0001 (Secure Single-Server Bootstrap) — completed 2026-03-09
|
||||||
|
- Boundary ADR: `railiance-hosts/docs/adr/ADR-002-repo-boundary-hosts-vs-bootstrap.md`
|
||||||
|
- k3s releases: https://github.com/k3s-io/k3s/releases
|
||||||
Reference in New Issue
Block a user