Why ISO 27001 Demands Immutable Logs (Without Actually Saying So) #
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:
*.notice;auth,authpriv,cron,ftp,kern,lpr,mail,user.none /var/log/messages
kern.debug;syslog,user.info /var/log/messages
auth.info /var/log/authlog
authpriv.debug /var/log/secure
cron.info /var/cron/log
daemon.info /var/log/daemon
ftp.info /var/log/xferlog
lpr.debug /var/log/lpd-errs
mail.info /var/log/maillog
# ....
#!doas
#*.* /var/log/doas
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.
But here’s where it gets interesting from a security perspective: newsyslog
runs as a root cron job every hour, rotating these logs automatically. A quick
look at /etc/newsyslog.conf
shows the rotation schedule:
/var/cron/log root:wheel 600 3 10 * Z
/var/log/authlog root:wheel 640 7 * 168 Z
/var/log/daemon 640 5 300 * Z
/var/log/lpd-errs 640 7 10 * Z
/var/log/maillog 640 7 * 24 Z
/var/log/messages 644 5 300 * Z
/var/log/secure 600 7 * 168 Z
/var/log/wtmp 644 7 * $M1D4 B ""
/var/log/xferlog 640 7 250 * Z
/var/log/pflog 600 3 250 * ZB "pkill -HUP -u root -U root -t - -x pflogd"
/var/www/logs/access.log 644 4 * $W0 Z "pkill -USR1 -u root -U root -x httpd"
/var/www/logs/error.log 644 7 250 * Z "pkill -USR1 -u root -U root -x httpd"
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. There’s nothing stopping rm /var/log/authlog
or a quick sed -i '/failed login/d' /var/log/secure
to clean up those failed authentication
attempts.
This is exactly where the default setup meets its limitations for ISO 27001 compliance. Those hourly rotations and the fact that everything runs as root means our logs are only as secure as our root access control. And if root is compromised, well… that’s precisely when we need our logs to be most trustworthy.
Understanding chflags: System-Level Immutability #
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 - set the system append-only flag (superuser only)
- schg - set the system immutable flag (superuser only)
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. First, let’s check the current flags on a log file:
$ ls -lo /var/log/secure
-rw------- 1 root wheel - 748935 Jul 16 19:11 /var/log/secure
^^^
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/secure
# ls -lo /var/log/secure
-rw------- 1 root wheel uappnd 748935 Jul 16 19:11 /var/log/secure
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.
Now comes the fascinating part. Let’s try to remove this flag as root:
# chflags nosappnd /var/log/secure
chflags: /var/log/secure: Operation not permitted
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). For more information on setting the system security level, see securelevel(7).
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). We can only modify these flags in 0 Insecure mode
where “system file flags may be cleared with chflags(2)”.
Of course, we don’t want to manually boot into single-user mode every time we
need to manage log rotation or we have to remove/modify chflags. Fortunately,
OpenBSD provides /etc/rc.securelevel
– commands that run before the security
level changes. This is exactly what we need to automate flag management during
the boot process.
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:
# Comment out or remove newsyslog from root's crontab
# 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/secure.0.* /var/log/archive/
# chflags -R schg /var/log/archive/
If schg
is set on these archived files, they become completely immutable -
perfect for long-term forensic preservation.
Step 3: Set append-only flag on active logs #
Now protect the active log files:
# chflags sappnd /var/log/secure
# chflags sappnd /var/log/authlog
# chflags sappnd /var/log/messages
# ....
Step 4: Create the securelevel script #
This is where the magic happens. Create /etc/rc.securelevel:
# touch /etc/rc.securelevel && chmod 700 /etc/rc.securelevel
Write your management script. Here is an example for /var/log/archive
.
#!/bin/sh
# Remove append-only and immutable flags
chflags nosappnd /var/log/secure /var/log/authlog /var/log/messages
chflags -R noschg /var/log/archive
# Run newsyslog and force log rotation regardless of size/age
newsyslog -F -a /var/log/archive
# Restore append-only and immutable flags
chflags sappnd /var/log/secure /var/log/authlog /var/log/messages
chflags -R schg /var/log/archive
This script runs during boot before the security level increases, giving us a brief window to manage our immutable files. It rotates logs into the archive directory and immediately makes them immutable again.
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.
return 0; #
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.
On that note, I’d like to thank the BSDNow podcast (which I discovered during workouts at the gym) for reading my last blog post on their show. Thank you!
This implementation provides filesystem-level log protection that satisfies ISO 27001 requirements while leveraging OpenBSD’s built-in security features. No additional software, no network dependencies – just the kernel enforcing immutability where it matters most.