129 lines
4.4 KiB
Markdown
129 lines
4.4 KiB
Markdown
|
|
# Hardening Reference
|
||
|
|
|
||
|
|
What veilor-os locks down and why. Each item is applied by either the
|
||
|
|
kickstart `%post` or the overlay tree shipped in `/etc`.
|
||
|
|
|
||
|
|
## Boot chain
|
||
|
|
|
||
|
|
| Item | State | Source |
|
||
|
|
|------|-------|--------|
|
||
|
|
| Secure Boot | Required (bootloader signed) | `bootloader` kickstart line |
|
||
|
|
| Kernel lockdown | `lockdown=integrity` | bootloader kernel args |
|
||
|
|
| Slab hardening | `slab_nomerge`, `init_on_alloc=1`, `init_on_free=1` | bootloader |
|
||
|
|
| Stack offset | `randomize_kstack_offset=on` | bootloader |
|
||
|
|
| vsyscall | `vsyscall=none` | bootloader |
|
||
|
|
| LUKS2 | aes-xts-plain64 / argon2id, mem=1GB, time=9 | `part pv.veilor` |
|
||
|
|
| Module loading | Locked 30s after graphical boot | `veilor-modules-lock.service` |
|
||
|
|
|
||
|
|
## Kernel sysctl
|
||
|
|
|
||
|
|
`/etc/sysctl.d/99-veilor-hardening.conf`:
|
||
|
|
|
||
|
|
| Key | Value | Why |
|
||
|
|
|-----|-------|-----|
|
||
|
|
| `kernel.kptr_restrict` | 2 | hide kernel pointers from /proc |
|
||
|
|
| `kernel.dmesg_restrict` | 1 | dmesg root-only |
|
||
|
|
| `kernel.yama.ptrace_scope` | 2 | ptrace = parent only |
|
||
|
|
| `kernel.perf_event_paranoid` | 3 | unprivileged perf disabled |
|
||
|
|
| `net.core.bpf_jit_harden` | 2 | BPF JIT constant blinding |
|
||
|
|
| `kernel.randomize_va_space` | 2 | full ASLR |
|
||
|
|
| `fs.suid_dumpable` | 0 | no SUID core dumps |
|
||
|
|
| `dev.tty.ldisc_autoload` | 0 | block tty LPE vector |
|
||
|
|
| `net.ipv4.tcp_syncookies` | 1 | SYN flood mitigation |
|
||
|
|
| `net.ipv4.conf.all.rp_filter` | 1 | reverse-path filter |
|
||
|
|
| `accept_source_route` | 0 (v4+v6) | ignore source routing |
|
||
|
|
| `accept_redirects` | 0 (v4+v6) | ignore ICMP redirects |
|
||
|
|
|
||
|
|
## SELinux
|
||
|
|
|
||
|
|
- Enforcing, targeted policy.
|
||
|
|
- Custom module `veilor-systemd` grants `systemd_modules_load_t` the
|
||
|
|
`sys_admin` and `perfmon` capabilities required by the modules-lock
|
||
|
|
service. Source: `scripts/selinux/veilor-systemd.te`.
|
||
|
|
|
||
|
|
## Network surface
|
||
|
|
|
||
|
|
- **firewalld** default zone = `drop`.
|
||
|
|
- **Inbound:** ssh only.
|
||
|
|
- **systemd-resolved:** LLMNR off, DNSSEC `allow-downgrade`,
|
||
|
|
DNS-over-TLS opportunistic. Resolvers: Cloudflare (1.1.1.1, 1.0.0.1),
|
||
|
|
fallback Quad9 (9.9.9.9, 149.112.112.112).
|
||
|
|
- **chrony:** NTS-authenticated time from `time.cloudflare.com` and
|
||
|
|
`nts.sth1/2.ntp.se`. Pool fallback only.
|
||
|
|
|
||
|
|
## SSH
|
||
|
|
|
||
|
|
`/etc/ssh/sshd_config.d/10-veilor-hardening.conf`:
|
||
|
|
|
||
|
|
- `PasswordAuthentication no`
|
||
|
|
- `PermitRootLogin no`
|
||
|
|
- `AllowUsers admin`
|
||
|
|
- `X11Forwarding no`
|
||
|
|
- `MaxAuthTries 3`
|
||
|
|
- `ClientAliveInterval 300`
|
||
|
|
- `LogLevel VERBOSE`
|
||
|
|
|
||
|
|
## Auth / accounts
|
||
|
|
|
||
|
|
- Root account **locked** (`passwd -l root`). No interactive root login.
|
||
|
|
- Single `admin` user, `wheel` group, full sudo.
|
||
|
|
- `pwquality.conf`: minlen=14, 4 character classes required, dictcheck.
|
||
|
|
- **First-boot password flow:** `chage -d 0 admin` expires the empty
|
||
|
|
password immediately. `veilor-firstboot.service` runs on TTY1 before
|
||
|
|
SDDM, prompts for new password, then starts the graphical session.
|
||
|
|
|
||
|
|
## Audit
|
||
|
|
|
||
|
|
`/etc/audit/rules.d/99-veilor-hardening.rules` watches:
|
||
|
|
|
||
|
|
- `/etc/passwd`, `/etc/shadow`, `/etc/group`, `/etc/gshadow`
|
||
|
|
- `/etc/sudoers`, `/etc/sudoers.d/`
|
||
|
|
- `/etc/ssh/sshd_config*`, `/etc/selinux/`, `/etc/firewalld/`
|
||
|
|
- `/etc/cron.*`, `/var/spool/cron/`
|
||
|
|
- `/etc/sysctl.*`, `/etc/systemd/system/`, `/usr/lib/systemd/system/`
|
||
|
|
- All privileged binaries (sudo, su, passwd, mount, pkexec, etc.)
|
||
|
|
- Kernel module load/unload syscalls
|
||
|
|
- Permission/ownership changes by uid≥1000
|
||
|
|
|
||
|
|
## Intrusion detection
|
||
|
|
|
||
|
|
`fail2ban` jails:
|
||
|
|
|
||
|
|
- `sshd` — aggressive mode, 3 retries, 24h ban
|
||
|
|
- `pam-generic` — 5 retries, 1h ban (catches XDM, su, sudo failures)
|
||
|
|
|
||
|
|
Backend: systemd journal. Action: firewalld rich rules.
|
||
|
|
|
||
|
|
## USB
|
||
|
|
|
||
|
|
`USBGuard` daemon, `ImplicitPolicyTarget=block`.
|
||
|
|
|
||
|
|
Ships with **empty allowlist**. On first boot, admin runs:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sudo usbguard generate-policy > /etc/usbguard/rules.conf
|
||
|
|
sudo systemctl restart usbguard
|
||
|
|
```
|
||
|
|
|
||
|
|
This snapshots all currently-connected devices into the allowlist.
|
||
|
|
Anything plugged in afterward is blocked unless explicitly allowed:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
sudo usbguard list-devices
|
||
|
|
sudo usbguard allow-device <id>
|
||
|
|
```
|
||
|
|
|
||
|
|
## Disabled services
|
||
|
|
|
||
|
|
`abrt*`, `cups`, `cups-browsed`, `geoclue`, `avahi-daemon`,
|
||
|
|
`bluetooth`, `ModemManager`, `gssproxy`, `atd`, `pcscd.socket`,
|
||
|
|
`pcscd.service`, `kdeconnectd` (removed at package level).
|
||
|
|
|
||
|
|
## What's *not* enabled by default
|
||
|
|
|
||
|
|
- **Disk swap** — replaced by zram (RAM-only, no key leak risk).
|
||
|
|
- **Bluetooth** — disabled. Enable with `systemctl enable --now bluetooth`.
|
||
|
|
- **Printing** — CUPS removed. Reinstall if needed: `dnf install cups`.
|
||
|
|
- **Snapd, Flatpak** — not installed (Flatpak optional add-on).
|
||
|
|
- **PackageKit** — removed; updates manual via `dnf`.
|