Some checks failed
morphit-release / Build + publish release tarball (push) Has been cancelled
192 lines
6.7 KiB
YAML
192 lines
6.7 KiB
YAML
# Role: base
|
|
#
|
|
# OS-level prep: service user, base packages, NTP, hostname.
|
|
# Does NOT do hardening (that's the `hardening` role). Does NOT
|
|
# install Postgres or Node (those are their own roles).
|
|
#
|
|
# Reference: scripts/vps-bootstrap.sh in the morphit repo —
|
|
# this role re-implements its base-package install + service
|
|
# user creation in idempotent Ansible form.
|
|
|
|
---
|
|
# On a LOCAL install inventory_hostname is 'localhost' (the inline `-i localhost,`
|
|
# inventory), so these would rename the operator's own machine to "localhost" —
|
|
# skip them locally and leave the box's existing hostname alone. On a REMOTE
|
|
# install inventory_hostname is the real host name from the inventory, so they run.
|
|
- name: Set hostname
|
|
ansible.builtin.hostname:
|
|
name: "{{ inventory_hostname }}"
|
|
when: not (morphit_local_install | default(false) | bool)
|
|
|
|
- name: Ensure /etc/hosts has the hostname
|
|
ansible.builtin.lineinfile:
|
|
path: /etc/hosts
|
|
regexp: '^127\.0\.1\.1\s'
|
|
line: "127.0.1.1 {{ inventory_hostname }}"
|
|
when: not (morphit_local_install | default(false) | bool)
|
|
|
|
- name: Set timezone to UTC
|
|
community.general.timezone:
|
|
name: Etc/UTC
|
|
|
|
- name: Update apt cache
|
|
ansible.builtin.apt:
|
|
update_cache: true
|
|
cache_valid_time: 3600
|
|
|
|
- name: Install base packages
|
|
ansible.builtin.apt:
|
|
name:
|
|
# Core
|
|
- build-essential
|
|
- git
|
|
- curl
|
|
- wget
|
|
- ca-certificates
|
|
- gnupg
|
|
- lsb-release
|
|
- jq
|
|
# Cron — the aide + rkhunter scheduled scans (hardening role) install
|
|
# into /etc/cron.daily and /etc/cron.weekly, which the `cron` package
|
|
# owns. Near-universal, but pinned here so those dirs are guaranteed to
|
|
# exist even on a minimal box that shipped without cron.
|
|
- cron
|
|
# Time sync (auditd timestamps + chain-time skew depend on it)
|
|
- chrony
|
|
# Hardening packages (referenced by hardening role)
|
|
- ufw
|
|
- fail2ban
|
|
- auditd
|
|
- audispd-plugins
|
|
- aide
|
|
- aide-common
|
|
- apparmor
|
|
- apparmor-utils
|
|
- unattended-upgrades
|
|
- apt-listchanges
|
|
- rkhunter
|
|
- libpam-pwquality
|
|
# Backup tooling
|
|
- age
|
|
- rsync
|
|
# Postfix for outbound alerts (configured by morphit role)
|
|
- postfix
|
|
- libsasl2-modules
|
|
state: present
|
|
|
|
- name: Enable chrony for NTP
|
|
ansible.builtin.systemd:
|
|
name: chrony
|
|
enabled: true
|
|
state: started
|
|
|
|
- name: Create morphit service group
|
|
ansible.builtin.group:
|
|
name: "{{ morphit_service_group }}"
|
|
system: true
|
|
state: present
|
|
|
|
- name: Create morphit service user
|
|
ansible.builtin.user:
|
|
name: "{{ morphit_service_user }}"
|
|
group: "{{ morphit_service_group }}"
|
|
home: "{{ morphit_service_home }}"
|
|
shell: /usr/sbin/nologin
|
|
system: true
|
|
create_home: true
|
|
state: present
|
|
|
|
- name: Ensure the morphit service user owns its home (recursively)
|
|
# `create_home: true` only chowns the home when useradd CREATES it; if the dir
|
|
# pre-existed (a partial/earlier run, or a re-run on the same box) it is left
|
|
# root-owned, and then `npm exec`/`npm run` (which write $HOME/.npm) fail EACCES
|
|
# and Ansible's become-user temp dir (/var/lib/morphit/.ansible) is unwritable.
|
|
# This makes the home — and any stale root-owned dotfiles under it — the service
|
|
# user's, so those writes succeed on a fresh AND a re-used box.
|
|
ansible.builtin.file:
|
|
path: "{{ morphit_service_home }}"
|
|
state: directory
|
|
owner: "{{ morphit_service_user }}"
|
|
group: "{{ morphit_service_group }}"
|
|
recurse: true
|
|
|
|
# Part 122 cp5 F12 — the shipped morphit-relay.service specifies
|
|
# `User=morphit-relay / Group=morphit-relay`. Without this task,
|
|
# `systemctl start morphit-relay` fails with "user morphit-relay
|
|
# does not exist" on a first deploy, AND any earlier `chown
|
|
# morphit-relay:morphit-relay /var/lib/morphit-relay` step fails
|
|
# with "invalid user". Pre-cp5 the playbook would never reach
|
|
# "relay running" on a fresh box.
|
|
- name: Create morphit-relay system group
|
|
ansible.builtin.group:
|
|
name: morphit-relay
|
|
system: true
|
|
state: present
|
|
|
|
- name: Create morphit-relay system user
|
|
ansible.builtin.user:
|
|
name: morphit-relay
|
|
group: morphit-relay
|
|
# Add to morphit_service_group so the relay can read
|
|
# /etc/morphit/relay.env (chowned root:morphit_service_group
|
|
# mode 0640 by the morphit role). Without this membership
|
|
# the relay daemon can't read its own config.
|
|
groups: "{{ morphit_service_group }}"
|
|
append: true
|
|
home: /var/lib/morphit-relay
|
|
create_home: false
|
|
shell: /usr/sbin/nologin
|
|
system: true
|
|
state: present
|
|
|
|
# cp167 — MCP server (ops/systemd/morphit-mcp.service). Same shape
|
|
# as morphit-relay: dedicated system group + user, no shell, no home,
|
|
# member of morphit_service_group so it can read /etc/morphit/*.env.
|
|
# The MCP server holds no keys (it's read-only over the indexer's
|
|
# orderbook) so the user needs no privileged group memberships
|
|
# beyond config-file read access.
|
|
# NOTE: the morphit-mcp user/group is created by the `morphit` role (gated on
|
|
# morphit_mcp_enabled, home /opt/morphit-mcp, isolated — NOT in the service group),
|
|
# not here. base used to create it too, with a DIFFERENT home (/var/lib/morphit-mcp)
|
|
# and — wrongly — membership in morphit_service_group, which (a) forced a `usermod`
|
|
# on every converge as the two definitions fought, failing on a re-run/upgrade with
|
|
# "user morphit-mcp is currently used by process …" once morphit-mcp.service is up,
|
|
# and (b) broke the MCP's isolation (the whole point is morphit-mcp CANNOT read the
|
|
# main install's secrets). Single-owner now: the morphit role.
|
|
|
|
- name: Create /etc/morphit directory for env files + keystore
|
|
ansible.builtin.file:
|
|
path: /etc/morphit
|
|
state: directory
|
|
owner: root
|
|
group: "{{ morphit_service_group }}"
|
|
mode: '0750'
|
|
|
|
# cp676 — shared helper-script dir used by several roles (ddns, backup, mcp,
|
|
# ipfs). It was previously created only inside the ipfs role (which runs LATE),
|
|
# so an earlier consumer — e.g. the ddns role when DDNS is enabled — failed with
|
|
# "Destination directory /usr/local/lib/morphit does not exist". Create it here
|
|
# in base (runs before every consumer) so the install never depends on ipfs.
|
|
- name: Create /usr/local/lib/morphit shared script directory
|
|
ansible.builtin.file:
|
|
path: /usr/local/lib/morphit
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: '0755'
|
|
|
|
- name: Create /opt/morphit parent directory for the repo clone
|
|
ansible.builtin.file:
|
|
path: "{{ morphit_repo_path | dirname }}"
|
|
state: directory
|
|
owner: root
|
|
group: root
|
|
mode: '0755'
|
|
|
|
- name: Create /var/log/morphit for service logs
|
|
ansible.builtin.file:
|
|
path: /var/log/morphit
|
|
state: directory
|
|
owner: "{{ morphit_service_user }}"
|
|
group: "{{ morphit_service_group }}"
|
|
mode: '0750'
|