FreeBSD runs underneath a large share of firewalls, storage appliances and network services, yet most hardening guidance and tooling is written for Linux and does not translate. FreeBSD has its own security primitives: kernel securelevels, jails, the Capsicum capability framework, the TrustedBSD MAC framework and BSM auditing. Used together they give a strong baseline, but none of them is switched on by a default install. This guide covers how identity and privilege work on FreeBSD, how to configure each control, what to log, and the misconfigurations that undo them. It is for administrators and security engineers who run FreeBSD servers or assess appliances built on it.
Key takeaways
- Raise the securelevel on production hosts: at level 1 or higher the kernel refuses to load modules or clear immutable flags, and no process can lower the level again without a reboot.
- Jails are the isolation unit, but thin and service jails share far more with the host than thick jails, so choose the type by the trust boundary you need.
- Root is still root: control it through the wheel group, sudo or doas rules, key-only SSH and named accounts, and treat every keytab and automation key as a privileged credential.
- Turn on BSM auditing (auditd) and ship trails off the host; default syslog does not record exec, file and authorisation events at the depth an investigation needs.
- Patch two layers separately: freebsd-update for the base system and pkg audit plus pkg upgrade for third-party packages, including every jail.
How identity and access work in FreeBSD
FreeBSD uses the classic Unix model: users and groups in /etc/passwd and /etc/group, with password hashes in /etc/master.passwd (built into the pwd.db and spwd.db databases). UID 0 bypasses discretionary access checks, so the hardening job is mostly about who can become UID 0, how, and what the kernel still refuses even to root.
- Login classes:
/etc/login.confsets per-class password hashing, expiry and resource limits. The Handbook gives SHA-512 as the default (:passwd_format=sha512:), expiry through:passwordtime=90d:, and process limits such as:maxproc=50:. Every change needscap_mkdb /etc/login.confto take effect, and existing hashes only change when the user next sets a password. - PAM: FreeBSD uses OpenPAM with policies in
/etc/pam.d/. Password complexity comes frompam_passwdqc.soin/etc/pam.d/passwd, which is commented out by default. See the Linux PAM Guide for PAM stacking concepts that carry over. - Account locking:
pw lock <user>locks an account, andchsh -s /usr/sbin/nologinremoves interactive login for service users. - Directory integration: the base system ships Heimdal Kerberos libraries, and OpenSSH supports
GSSAPIAuthentication yes. Central identity (LDAP or Active Directory) is added through packages rather than the base system, so check who maintains that integration and how it is patched. - Kernel-enforced limits on root: securelevel, file flags such as
schg(system immutable), MAC policies and Capsicum all constrain what a compromised root process can do. These are what make FreeBSD hardening different from simply locking down accounts.
Securelevel reference
Enable with sysrc kern_securelevel_enable="YES" and sysrc kern_securelevel=2; check with sysctl -n kern.securelevel. Any superuser process can raise the level, but no process can lower it.
| Level | Name | What the kernel enforces | Operational cost |
|---|---|---|---|
| -1 | Permanently insecure | Default initial value, no restrictions | None |
| 0 | Insecure | Immutable and append-only flags can be removed; devices follow normal permissions | None |
| 1 | Secure | System immutable and append-only flags cannot be removed; mounted disks, /dev/mem and /dev/kmem cannot be opened for writing; kernel modules cannot be loaded or unloaded; debugger entry restricted | Module loads and flag changes need single-user mode or a reboot to a lower level |
| 2 | Highly secure | Level 1 plus disks cannot be opened for writing except through mount(2), so newfs cannot run multi-user; kernel time changes clamped to one second | Disk and partition work needs a maintenance window |
| 3 | Network secure | Level 2 plus ipfw, pf and dummynet rules cannot be changed | Firewall changes require a reboot; suits fixed-purpose appliances |
Securelevel is only as strong as the boot path. If an attacker with root can edit /etc/rc.conf and reboot, the level comes back lower. Set schg on /boot/loader.conf, /etc/rc.conf, the kernel and key binaries, and make sure console and boot loader access are physically or remotely protected.
Admin roles and privileged access
FreeBSD has no built-in role model beyond root and groups, so privileged access design is a matter of convention and tooling. The principles in the Unix and Linux Privileged Access Guide apply; the FreeBSD specifics are below.
| Mechanism | Where configured | Use it for | Watch out for |
|---|---|---|---|
| wheel group and su | /etc/group, /etc/pam.d/su | Limiting who can run su to root | Shared root password, no record of who did what |
| sudo (package) | /usr/local/etc/sudoers via visudo | Command-scoped delegation with logging, e.g. user1 ALL=(ALL) /usr/sbin/service webservice * | Wildcards and NOPASSWD rules that allow shell escapes |
| doas (package) | /usr/local/etc/doas.conf | Small, simple rule sets on appliances | permit nopass rules copied from examples |
| mac_portacl | mac_portacl_load="YES", security.mac.portacl.rules | Letting a non-root service bind a port below 1024 | Running daemons as root only to bind port 80 or 443 |
| Jail root | jail.conf | Giving an application team root inside a contained environment | Allow parameters that hand back host-level power |
- Named accounts first: every administrator logs in as themselves and escalates. Keep the root password in a vault for break-glass use only, and alert when it is used.
- SSH as the front door: set
PasswordAuthentication no,PubkeyAuthentication yes, restrict withAllowUsersorAllowGroups, validate withsshd -tand apply withservice sshd reload. KeepPermitRootLogin no. See the OpenSSH Server Hardening Guide. - sudo hygiene: scope rules to commands, avoid editors, pagers and interpreters in rules, and log sudo output. The sudo and sudoers Security Guide covers rule review in depth.
- Visibility hardening: set
security.bsd.see_other_uids=0,security.bsd.see_other_gids=0andsecurity.bsd.see_jail_proc=0so ordinary users cannot enumerate other users' or jails' processes, andsecurity.bsd.unprivileged_proc_debug=0to stop non-root users attaching debuggers. The installer offers a hardening step that sets options of this kind; confirm the resulting values withsysctlrather than assuming them.
Jails, Capsicum and MAC: containing what root can reach
These three mechanisms solve different problems. Jails partition the system, Capsicum sandboxes individual programs, and MAC adds policy the owner of a file cannot override.
Jail types and their isolation
| Jail type | What it shares with the host | Isolation | Typical use |
|---|---|---|---|
| Thick (classic) | Kernel only; full copy of the base system | Highest of the jail types | Separate tenants, internet-facing services |
| Thin (ZFS clone or NullFS) | Kernel and a shared base template | Lower: a change to the template affects every jail using it | Many similar services on one host |
| Service jail (FreeBSD 15) | Host filesystem (root path /) and user accounts | No filesystem isolation; no network by default | Restricting a single rc service, not separating tenants |
| VNET (option on thick or thin) | Kernel; gets its own network stack, routes and firewall rules | Adds network separation | Jails that need their own firewall or routing |
| Linux jail | Host kernel through Linux binary compatibility | As thick or thin, plus the Linux compatibility layer's attack surface | Running Linux userland tools |
- Keep allow parameters off: each
allow.*setting (allow.raw_sockets,allow.mount,allow.mount.devfs,allow.mount.procfs,allow.mount.tmpfsand so on) gives jail root a capability it does not have by default. Grant them only per jail, with a written reason. - Restrict devices: pair
mount.devfswith a restrictivedevfs_rulesetso a jail sees only the device nodes it needs. - Clean execution: use
exec.cleanso host environment variables do not leak into jail start-up commands. - Limit resources: enable
kern.racct.enable=1in/boot/loader.conf, setrctl_enable="YES", and cap memory and processes per jail (for examplejail:classic:memoryuse:deny=2G) in/etc/rctl.confso one jail cannot starve the host. - Patch every jail: run
freebsd-update -j <name> fetch installandpkg -j <name> upgradefor thick jails, or update the shared template for NullFS thin jails. A jail's FreeBSD version cannot be newer than the host's.
Capsicum
Capsicum turns file descriptors into capabilities. A process calls cap_enter(2) to enter capability mode, after which it loses access to global namespaces such as the filesystem and PID space and can only use descriptors it already holds. cap_rights_limit(2) narrows what each descriptor allows (for example read only), process descriptors (pdfork(2), pdkill(2)) manage children without the PID namespace, and libcasper(3) provides helper services such as DNS lookups to sandboxed code. Capability mode is inherited and cannot be left. Capsicum first appeared in FreeBSD 9.0. It is a developer control: administrators cannot apply it to an arbitrary binary, but they can prefer software built with it and ask appliance vendors whether their parsers and network daemons run sandboxed.
MAC policy modules
| Module | loader.conf line | What it adds | Labels needed |
|---|---|---|---|
| mac_seeotheruids | mac_seeotheruids_load="YES" | Hides other users' processes and sockets, with an exempt group option | No |
| mac_bsdextended | mac_bsdextended_load="YES" | Firewall-style file access rules managed with ugidfw(8) | No |
| mac_portacl | mac_portacl_load="YES" | Per-user or per-group binding of local TCP and UDP ports | No |
| mac_ifoff | mac_ifoff_load="YES" | Disables network interfaces, including at boot | No |
| mac_partition | mac_partition_load="YES" | Users see only processes in their partition | Yes |
| mac_mls / mac_biba / mac_lomac | mac_mls_load="YES" and equivalents | Multilevel confidentiality or integrity policies | Yes, plus careful planning |
For most servers the label-free modules (seeotheruids, bsdextended, portacl) give real value at low cost. The labelled policies (MLS, Biba, LOMAC) need a designed label scheme and testing, and a mistake can leave a system unbootable, so trial them on a non-production host first. The Handbook describes these as loadable modules or kernel options such as options MAC_BSDEXTENDED.
Integrations, API tokens and service accounts
FreeBSD hosts rarely stand alone. Configuration management, backup agents, monitoring and directory services all hold credentials on the box, and those non-human identities are often more privileged than any human account.
- Kerberos keytabs: a host keytab (default
/etc/krb5.keytab) lets anything that can read it authenticate as the host. Keep it mode 0600 root, inventory every keytab, and rotate when a host is rebuilt. See the Linux Service Accounts and Keytab Management Guide. - Automation SSH keys: configuration management and backup tools often log in as root with a key in
authorized_keys. Restrict those keys withfrom=and forced commands, prefer a dedicated user with scoped sudo, and include them in key rotation. Unexpected additions toauthorized_keysare a known persistence method (MITRE ATT&CK T1098.004). - Service users: run each daemon as its own unprivileged user with
/usr/sbin/nologin, and use mac_portacl rather than root to bind low ports. - TLS private keys: keys generated with
openssl reqbelong in a root-only directory, not in a world-readable web root. FreeBSD 14 and later can load the OpenSSL 3 FIPS provider (openssl fipsinstall) where a FIPS module is required. - Appliance management APIs: firewall and storage products built on FreeBSD expose web and REST APIs with their own keys. Those keys are outside the operating system's account model, so govern them as you would any other API credential. See the Non-Human Identity (NHI) Guide.
Logging and detection
FreeBSD includes OpenBSM security event auditing. It is in the GENERIC kernel (custom kernels need options AUDIT) and is enabled with auditd_enable="YES" in /etc/rc.conf. Configuration lives in /etc/security/audit_control and /etc/security/audit_user, and trails go to /var/audit in binary BSM format, read with praudit and filtered with auditreduce.
| Source | Setting | What it gives you |
|---|---|---|
| BSM audit, login and authorisation | flags:lo,aa (default) | Logins, logouts and authentication or authorisation events |
| BSM audit, administrative and exec | Add ad and ex; policy:cnt,argv | Administrative actions and every execve with arguments |
| BSM audit, per user | root:lo,+ex:no in audit_user | Full command trail for root without auditing every user |
| Live stream | /dev/auditpipe | Real-time feed for a forwarder |
| Process accounting | accounting_enable=yes; read with lastcomm | Lightweight command history in /var/account |
| syslog | /var/log/auth.log, /var/log/security | sshd, su and sudo events; periodic(8) security reports |
| File integrity | mtree -c -K cksum,sha512 baseline | Detection of changed binaries and configuration |
- Rotate safely: use
audit -nor thefileszsetting, not newsyslog, and keepminfreesensible so trails do not fill the disk. - Ship off the host: an attacker with root can delete local trails. Forward from
/dev/auditpipeor syslog to a central collector. - Detections worth writing: kernel module load attempts (T1547.006), changes to
authorized_keys(T1098.004), sudo use outside change windows (T1548.003), root logins over SSH (T1021.004), changes tokern.securelevelsettings in rc.conf, and new jails or changedallow.*parameters.
Hardening baseline
There is no single official FreeBSD benchmark that every organisation uses, so most teams write their own baseline from the Handbook and security(7). A practical order of work:
- Inventory and patch: list every FreeBSD host, appliance and jail with its release and support status. Run
freebsd-update fetch installandpkg audit -F, and subscribe to FreeBSD security advisories (namedFreeBSD-SA-YY:NN.module). - Remove what you do not need: disable inetd and unused rc services, and if inetd must run, restrict it with
/etc/hosts.allow(the default allows all). - Accounts and SSH: key-only SSH, no root login, wheel restricted, sudo or doas rules reviewed, service users on nologin.
- Kernel and visibility sysctls: set the
security.bsd.*visibility and debug controls, confirm ASLR (kern.elf64.aslr.enableandkern.elf64.aslr.pie_enable) and non-executable stack settings, and leavekern.elf64.allow_wxdisabled unless an application needs it. - Auditing: enable auditd with
lo,aa,adplus exec for root, and forward logs. - Isolation: move internet-facing services into jails with no extra
allow.*rights, a restrictive devfs ruleset and rctl limits. Load mac_portacl and mac_seeotheruids where they fit. - Lock it down last: set
schgon boot and configuration files, then raise the securelevel. Test in a pilot first: once level 1 or higher is set, routine work such as loading a module needs a reboot to a lower level, so build that into change procedures. Rollback is a reboot withkern_securelevel_enabledisabled from single-user mode.
Record the baseline in configuration management, and check drift with mtree baselines and periodic security reports. Small estates can manage this by hand with a written checklist; larger estates should template jails and rc.conf through configuration management so every host starts from the same state.
Common misconfigurations
- Securelevel set but not protected: raising the level without
schgon rc.conf and loader.conf means a reboot quietly undoes it. - Thin or service jails treated as tenant boundaries: a service jail offers no filesystem isolation, and thin jails share a template. Use thick jails, or separate hosts, for untrusted tenants.
- Jails that are never patched: the host is current but jails run old packages because nobody runs
pkg -jorfreebsd-update -j. - Generous allow parameters:
allow.raw_socketsandallow.mountadded to get one tool working and left on every jail. - Appliance management planes on the internet: many FreeBSD-based firewalls and storage systems expose web consoles and SSH. Keep management interfaces on a dedicated network. See the Edge Device Security Guide.
- Audit on, nobody reading: trails accumulate in
/var/auditwithout forwarding, and fill the disk or get deleted after compromise.
Framework mapping
| Control area | FreeBSD mechanism | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | ISO/IEC 27001:2022 Annex A |
|---|---|---|---|---|
| Secure baseline | sysctls, rc.conf, securelevel, file flags | CM-2, CM-6, CM-7 | PR.PS-01 | A.8.9 |
| Least privilege | sudo or doas, mac_portacl, service users | AC-6, AC-6(5) | PR.AA-05 | A.8.2 |
| Process isolation | Jails, Capsicum, MAC | SC-39 | PR.PS-01 | A.8.9 |
| Logging | auditd, process accounting, syslog | AU-2, AU-12 | DE.CM-01 | A.8.15 |
| Patching | freebsd-update, pkg audit | SI-2 | PR.PS-02 | A.8.8 |
| Credentials | Keytabs, SSH keys, login.conf policy | IA-2, IA-5 | PR.AA-01 | A.8.5 |
Practitioner checklist
- Inventory every FreeBSD host, appliance and jail with release, support status and owner.
- Apply base updates with freebsd-update and package updates with pkg audit and pkg upgrade, inside every jail too.
- Enforce key-only SSH with root login disabled, and restrict escalation to wheel plus reviewed sudo or doas rules.
- Set the security.bsd visibility and debugging sysctls and confirm ASLR and W^X settings.
- Enable auditd with login, authorisation, administrative and root exec classes, and forward trails off the host.
- Run internet-facing services in thick or VNET jails with no unneeded allow parameters, a devfs ruleset and rctl limits.
- Load mac_portacl so no daemon runs as root just to bind a low port.
- Inventory keytabs, automation SSH keys and appliance API keys, and rotate them on a schedule.
- Set schg on boot and configuration files, raise the securelevel, and document the reboot procedure for changes.
Standards and references
- FreeBSD Handbook: Security
- FreeBSD Handbook: Jails and Containers
- FreeBSD Handbook: Mandatory Access Control
- FreeBSD Handbook: Security Event Auditing
- FreeBSD Manual Pages: security(7)
- FreeBSD Manual Pages: capsicum(4)
- NIST: SP 800-53 Rev. 5
- MITRE ATT&CK: SSH Authorized Keys
Related NHI Mgmt Group resources: Linux Server Hardening Guide · OpenSSH Server Hardening Guide · Unix and Linux Privileged Access Guide · Edge Device Security Guide