From bfcdc47e46a27e4927e6cbd75ee163b5c2d543d6 Mon Sep 17 00:00:00 2001 From: boxswapper Date: Sun, 13 Sep 2026 13:33:53 -0600 Subject: [PATCH] installed firewalld and selinux permissions --- .../ses_f63e23ebcffe7Q6sJKCl9W8sFt.json | 4 +-- README.md | 30 ++++++++++++++++++- group_vars/all/vars.yml | 8 +++++ roles/stoat/tasks/harden.yml | 7 +++++ roles/stoat/tasks/podman.yml | 30 +++++++++++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/.omo/run-continuation/ses_f63e23ebcffe7Q6sJKCl9W8sFt.json b/.omo/run-continuation/ses_f63e23ebcffe7Q6sJKCl9W8sFt.json index e161aac..ce2a133 100644 --- a/.omo/run-continuation/ses_f63e23ebcffe7Q6sJKCl9W8sFt.json +++ b/.omo/run-continuation/ses_f63e23ebcffe7Q6sJKCl9W8sFt.json @@ -1,10 +1,10 @@ { "sessionID": "ses_f63e23ebcffe7Q6sJKCl9W8sFt", - "updatedAt": "2026-09-13T19:25:59.636Z", + "updatedAt": "2026-09-13T19:33:29.129Z", "sources": { "background-task": { "state": "idle", - "updatedAt": "2026-09-13T19:25:59.636Z" + "updatedAt": "2026-09-13T19:33:29.129Z" } } } \ No newline at end of file diff --git a/README.md b/README.md index c6a8549..8aa5aef 100644 --- a/README.md +++ b/README.md @@ -56,11 +56,12 @@ Ansible automation that **hardens a Fedora 44 server**, installs **rootless Podm | Stage | Actions | |---|---| | **System** | `dnf update` all packages; install `git`, `curl`, `openssl` | -| **Firewall** | firewalld default-deny; allow `ssh`, `http`, `https`, `7881/tcp`, `50000-50100/udp` (LiveKit voice) | +| **Firewall** | installs + starts firewalld (native/minimal Fedora may not ship it); default-deny; allow `ssh`, `http`, `https`, `7881/tcp`, `50000-50100/udp` (LiveKit voice) | | **Fail2Ban** | `sshd` jail (3 retries → 1 h ban, incremental for repeat offenders) | | **Auto-updates** | `dnf5-plugin-automatic`, security-only, `apply_updates = yes`, started timer | | **Logs** | logrotate rule for fail2ban logs (daily, 7 rotations, compressed) | | **Podman** | rootless engine + `podman-compose` + `podman-docker`; `net.ipv4.ip_unprivileged_port_start=80` so Caddy can bind 80/443; dedicated `stoat` service user with lingering enabled | +| **SELinux** | keeps mode enforcing; installs `container-selinux` (container policy) + `policycoreutils-python-utils` / `setools-console` (`semanage`, `audit2why`) | | **Stoat** | clone `stoatchat/self-hosted` to `/opt/stoat/self-hosted`; run `generate_config.sh ` (answers: built-in Caddy, video enabled); start stack under `podman-compose-stoat.service` | --- @@ -87,6 +88,7 @@ Ansible automation that **hardens a Fedora 44 server**, installs **rootless Podm | `stoat_video` | `true` | enable camera/screen sharing (LiveKit) | | `stoat_service_user` | `stoat` | unprivileged user running rootless podman | | `podman_unprivileged_port_start` | `80` | lowest port rootless containers may bind | +| `selinux_mode` | `enforcing` | SELinux mode the role enforces (config + setenforce) | | `fail2ban_port` / `fail2ban_maxretry` / `fail2ban_bantime` | `22` / `3` / `3600` | sshd jail tuning | | `firewall_services` / `firewall_ports` | ssh,http,https / 7881, UDP range | firewalld allow rules | @@ -138,6 +140,32 @@ sudo firewall-cmd --list-all --- +## SELinux notes + +Fedora 44 ships SELinux **enforcing**; the role pins that mode. The stack runs in **rootless** podman, where containers run in the user's own SELinux domain and can read/write the `stoat` user's files — bind mounts under `/opt/stoat/self-hosted/data` generally need no relabeling or `:Z` flags. + +If a service misbehaves, check for denials before anything else: + +```bash +sudo ausearch -m avc -ts recent | grep -i stoat # recent denials +# or find the exact rule suggestion: +sudo grep "denied" /var/log/audit/audit.log | tail -20 | audit2why +``` + +Common knobs if a denial shows up (only set what the denial actually requires): + +```bash +# containers connecting to non-default ports on the host +sudo setsebool -P container_connect_any 1 +# container needs to manage cgroups (systemd inside a container) +sudo setsebool -P container_manage_cgroup 1 +# give a specific bind-mounted volume its container context (last resort, +# only if audit2why points at file labeling): +sudo chcon -R -t container_file_t /opt/stoat/self-hosted/data +``` + +--- + ## Caveats & notes - **First start pulls ~2 GB of images** and initializes MongoDB — allow a few minutes; the systemd unit tolerates up to 15 min (`TimeoutStartSec=900`). diff --git a/group_vars/all/vars.yml b/group_vars/all/vars.yml index 22ebcb8..f1af6aa 100644 --- a/group_vars/all/vars.yml +++ b/group_vars/all/vars.yml @@ -67,6 +67,14 @@ sshd_password_authentication: yes # out. Leave false unless you know what you are doing. sshd_mfa_required: false +# ------------------------------------------------------------ +# Hardening - SELinux +# ------------------------------------------------------------ +# Native Fedora 44 ships SELinux enforcing; the role keeps it in +# this mode and installs container-selinux + policycoreutils +# (semanage / audit2why) for diagnosing container denials. +selinux_mode: enforcing + # ------------------------------------------------------------ # Hardening - firewall (firewalld, default deny) # ------------------------------------------------------------ diff --git a/roles/stoat/tasks/harden.yml b/roles/stoat/tasks/harden.yml index becea6e..c89760d 100644 --- a/roles/stoat/tasks/harden.yml +++ b/roles/stoat/tasks/harden.yml @@ -1,7 +1,14 @@ --- # ------------------------------------------------------------ # Firewall (firewalld) - default deny, allow only what is needed +# Native/minimal Fedora installs may not ship firewalld, so +# install it explicitly before starting it. # ------------------------------------------------------------ +- name: Install firewalld + ansible.builtin.dnf: + name: firewalld + state: present + - name: Start and enable firewalld ansible.builtin.systemd: name: firewalld diff --git a/roles/stoat/tasks/podman.yml b/roles/stoat/tasks/podman.yml index 935a925..85108f6 100644 --- a/roles/stoat/tasks/podman.yml +++ b/roles/stoat/tasks/podman.yml @@ -30,4 +30,34 @@ # on boot without an interactive login. - name: Enable lingering for the service user ansible.builtin.command: "loginctl enable-linger {{ stoat_service_user }}" + changed_when: false + +# ------------------------------------------------------------ +# SELinux - keep enforcing, ensure the container policy and +# diagnostic tools are present for resolving any denials. +# ------------------------------------------------------------ +- name: Install SELinux container policy and diagnostics tools + ansible.builtin.dnf: + name: + - container-selinux + - policycoreutils-python-utils + - setools-console + state: present + +- name: Check current SELinux mode + ansible.builtin.command: getenforce + register: selinux_current_mode + changed_when: false + +- name: Configure SELinux mode in /etc/selinux/config + ansible.builtin.lineinfile: + path: /etc/selinux/config + regexp: '^SELINUX=' + line: 'SELINUX={{ selinux_mode }}' + +- name: Apply SELinux mode now + ansible.builtin.command: "setenforce {{ selinux_mode }}" + when: + - selinux_mode | lower == "enforcing" + - selinux_current_mode.stdout | lower != "enforcing" changed_when: false \ No newline at end of file