Idempotent host configuration targeting Ubuntu 24.04 with ZFS on a dedicated second disk. Role-based platform-infra/ansible: - base: apt packages, timezone, unattended security upgrades. - zfs: install ZFS, create pool on a dedicated disk (guarded against wiping a non-empty disk), create platform datasets + customers parent per docs/03; docker dataset mounted at /var/lib/docker. - docker: Docker Engine + Compose plugin, daemon.json written before first start so the native zfs storage driver initializes on the ZFS data-root; per-site network address pool preconfigured. - firewall: nftables inbound default-deny in a dedicated table that never flushes Docker's rules; container outbound SMTP blocked via a DOCKER-USER jump applied by a systemd oneshot. - ssh_hardening: key-first SSH with an anti-lockout assertion, config validation gate, and the sftponly group for Phase 4 SFTP accounts. Includes ansible.cfg, requirements.yml, inventory example, group_vars with safety notes, and a run guide. Real inventory (hosts.yml) is git-ignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
56 lines
3 KiB
YAML
56 lines
3 KiB
YAML
# ─────────────────────────────────────────────────────────────────────────────
|
|
# heleos platform — host baseline variables (Phase 1)
|
|
# Edit these to match your environment before running the playbook.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
# --- General ----------------------------------------------------------------
|
|
host_timezone: "Europe/Brussels"
|
|
|
|
# --- ZFS --------------------------------------------------------------------
|
|
# The pool is created on a DEDICATED second virtual disk. Attach a disk to the
|
|
# VM first (e.g. /dev/sdb or /dev/vdb) and set it here.
|
|
#
|
|
# ⚠️ zpool create is DESTRUCTIVE to the target disk. The playbook refuses to
|
|
# touch a disk that already contains a filesystem/partition unless you set
|
|
# zfs_pool_force: true. For production prefer a stable /dev/disk/by-id/... path.
|
|
zfs_pool_name: tank
|
|
zfs_pool_disk: /dev/sdb
|
|
zfs_pool_force: false
|
|
zfs_compression: lz4 # lz4 (fast) or zstd (denser)
|
|
|
|
# Datasets created under the pool. Web roots and per-site/customer datasets are
|
|
# created later by the provisioning CLI (Phase 4); here we create the fixed
|
|
# platform datasets + the customers parent. See docs/03-naming-conventions.md.
|
|
zfs_child_datasets:
|
|
- { path: "platform" }
|
|
- { path: "platform/docker", mountpoint: "/var/lib/docker" }
|
|
- { path: "platform/mariadb" }
|
|
- { path: "platform/db-backups" }
|
|
- { path: "platform/traefik" }
|
|
- { path: "platform/forgejo" }
|
|
- { path: "platform/monitoring" }
|
|
- { path: "customers" }
|
|
|
|
# --- Docker -----------------------------------------------------------------
|
|
# Native ZFS storage driver keeps image layers as ZFS datasets under the pool
|
|
# (data-root sits on tank/platform/docker). Switch to overlay2 only if you have
|
|
# a specific reason.
|
|
docker_storage_driver: zfs
|
|
docker_data_root: /var/lib/docker
|
|
# Address pool for the many per-site bridge networks (avoids subnet exhaustion).
|
|
docker_address_pool_base: "10.201.0.0/16"
|
|
docker_address_pool_size: 24
|
|
|
|
# --- Firewall (nftables + Docker egress) ------------------------------------
|
|
ssh_port: 22
|
|
firewall_allowed_tcp_ports: [80, 443] # SSH is added automatically via ssh_port
|
|
# Outbound SMTP from containers is blocked (spam prevention from hacked sites).
|
|
smtp_blocked_ports: [25, 465, 587]
|
|
smtp_relay_host: "" # optional: allow SMTP only to this host
|
|
|
|
# --- SSH hardening ----------------------------------------------------------
|
|
# ⚠️ If ssh_disable_password_auth is true you MUST provide admin_authorized_keys
|
|
# for admin_user, or you will lock yourself out. The playbook asserts this.
|
|
admin_user: "{{ ansible_user }}"
|
|
admin_authorized_keys: [] # list of public key strings
|
|
ssh_disable_password_auth: false # flip to true once key login is verified
|