When Root Meets Immutable: OpenBSD Chflags vs. Log Tampering
ISO 27001 is like that careful lawyer who never says exactly what they mean – it tells you what needs to be achieved, not how to do it. When it comes to logging, this is particularly telling: Control A.12.4.2 simply states that “logging information and logging facilities shall be protected against tampering and unauthorized access.” Period. How? That’s your problem to solve. But anyone who’s ever had to investigate a security incident knows the harsh reality: logs are only as trustworthy as their protection against post-incident tampering.
An attacker who gains root access isn’t going to politely leave their tracks in the log files – unless they physically can’t alter them anymore. Anyone who follows this blog knows I’ve been diving into VFS/FFS code lately, and during that exploration, I stumbled across SF_APPEND and SF_IMMUTABLE flags in the kernel source. “IMMUTABLE?” I thought. “What the hack, OpenBSD can do that? Must be dead code ;)”. Turns out these flags are very much alive and can be beautifully set using chflags.
I started playing around with them in /tmp, and for days afterward, I’d get a bunch of error messages on every boot because OpenBSD, as you know, cleans /tmp on startup. I left it like that for a while – just another quirky reminder of my filesystem experiments. Then a client I administrate several OpenBSD servers for asked me about ISO 27001 compliance. Suddenly, those “dead” immutable flags didn’t seem so useless anymore.
In fact, they turned out to be exactly what the standard was asking for, even if it doesn’t explicitly say so. This is where immutability becomes not just a nice-to-have, but a forensic necessity. While ISO 27001 never mentions the word “immutable”, it’s essentially describing exactly that: logs that cannot be modified after they’re written.
This isn’t security theater – it’s about maintaining the integrity of your audit trail when it matters most. But there’s a deeper motivation here beyond just checking the compliance box. If an attacker gains root privileges on your system without you knowing, you have a massive problem. Your logs might be the only evidence of what happened, when it happened, and how extensive the breach was.
If those logs can be silently modified or deleted, you’re essentially flying blind during the most critical moment of your security response. The following blog post shows one approach to having secure, root-tamper-proof logs and archiving them IMMUTABLE without any external system.
OpenBSD’s Default Logging: Simple but Effective
OpenBSD ships with a straightforward logging configuration that handles most system events out of the box. The default /etc/syslog.conf follows a clean separation of concerns:
- This configuration creates a logical hierarchy: general system messages land in /var/log/messages, while specific services get their own dedicated log files.
- Authentication attempts go to /var/log/authlog, privileged operations to /var/log/secure, and so on.
The beauty of this setup is its predictability. When you need to investigate a login issue, you know exactly where to look. Mail problems? Check /var/log/maillog. System crashes? /var/log/messages has your answers.
However, there’s also a security aspect to consider: newsyslog runs as a root cron job every hour, rotating these logs automatically. A quick look at /etc/newsyslog.conf shows the rotation schedule:
- While this prevents logs from consuming all available disk space, it also means that log files are regularly recreated, moved, and compressed.
From an attacker’s perspective, this creates windows of opportunity – not just to modify logs, but to potentially interfere with the rotation process itself. Even more concerning: any attacker with root access can simply open the log files directly and delete specific lines, modify timestamps, or insert false entries.
Solving the Problem with chflags
OpenBSD’s chflags command provides fine-grained control over file attributes at the filesystem level. According to the manpage, several flags are available, but for our log protection purposes, we’re particularly interested in:
- sappnd for active log files that need to grow
- schg for archived logs that should never change
Our strategy is simple: use sappnd for active log files that need to grow, and schg for archived logs that should never change. Let’s see this in action.
Setting up Immutable Logging
First, let’s check the current flags on a log file:
chflags -o /var/log/authlog
The -o flag shows us file flags, and we see none are set (the dash after wheel). Now let’s set the append-only flag:
chflags sappnd /var/log/authlog
Notice something interesting? We set sappnd but see uappnd. That’s because we’re running as root (the owner), so the system flag becomes a user flag from our perspective.
We could have used uappnd directly with the same result. The behaviour makes the removal of flags somewhat error-prone.
Securing the System Level
Now comes the fascinating part. Let’s try to remove this flag as root:
chflags -n /var/log/authlog sappnd
Even root can’t remove it! This is where OpenBSD’s security model shines. According to the manpage: The superuser-settable sappnd and schg flags can be set at any time, but may only be cleared when the system is running at security level 0 or -1 (insecure or permanently insecure mode, respectively).
This brings securelevel(7) into play – I think the only practical user-defined use case for OpenBSD’s securelevel(7) (All other use cases are not really useful for the end user).
Complete Setup: Immutable Logging Implementation
Now let’s put it all together into a complete, production-ready setup. Step 1: Disable the hourly newsyslog cron job – since we can’t rotate files with sappnd flags through the normal newsyslog(1) process (append-only means the file can’t be moved or renamed), we need to disable the automatic rotation:
crontab -e
Step 2: Create the log archive directory – we need a dedicated space for our immutable archived logs: mkdir /var/log/archive. If you have existing rotated logs, move them to the archive and make them permanently immutable:
mv /var/log/authlog /var/log/archive/ chflags schg /var/log/authlog
Step 3: Set append-only flag on active logs – now protect the active log files: chflags sappnd /var/log/authlog.
Step 4: Create the securelevel script – this is where the magic happens. Create /etc/rc.securelevel:
#!/bin/sh # Rotate logs into archive directory and make immutablefind /var/log/ -type f -exec chflags schg {} \; mv /var/log/authlog /var/log/archive/
echo "system: 0"
The beauty of this setup? Once the system reaches normal security level, even root cannot tamper with these logs without rebooting into single-user mode – exactly the kind of forensic integrity ISO 27001 demands.
I hope this post was helpful for anyone facing similar challenges. These flags aren’t unique to OpenBSD – you’ll find these and additional options in NetBSD and FreeBSD as well. FreeBSD probably has even cooler solutions for this problem using ZFS features, and if not, maybe this could serve as inspiration for someone.