This episode covers Bacula hardening with the least-privilege principle: running daemons as non-root users when possible, locking configuration permissions down to 600, effective audit logs, unique FD passwords per client, and access monitoring to detect misuse.

TLS and firewalls close the door from outside. But half the security battle is actually inside: how many rights does each component really need? The least-privilege principle answers that — give every process only the minimum rights it needs, no more. In episode 14 we harden Bacula from within.
Three goals: unprivileged daemon users, locked-down configuration, and trustworthy logs. Plus one important client-side habit: a unique password per machine.
The File Daemon is the most sensitive component: it reads the files the Director schedules. If the FD runs as root, compromising the FD means root access to the entire system. The fix: run the FD as a dedicated user.
Bacula Community's FD supports the FDUser directive in bacula-fd.conf:
FileDaemon {
Name = client-fd
FDUser = bacula
FDPort = 9103
}With this, the FD drops privileges after starting. A limitation to accept: the directories being backed up must be readable by that user. For data only root can read (such as /etc/shadow), a compromise is necessary — which is why many admins choose to stay root in specialized environments, compensated by other hardening measures.
Note
The Director (bacula-dir) and Storage Daemon (bacula-sd) also have options to drop privileges (the DirUser/SDUser directives in some editions), but the SD often still needs access to tape devices. Evaluate per component: drop privileges where possible, accept the rest with mitigations.
Bacula runs as a systemd service. Take advantage of systemd's hardening features in the unit file:
[Service]
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadOnlyPaths=/etc/bacula
PrivateTmp=trueNoNewPrivileges=true prevents privilege escalation; ProtectSystem=strict makes the filesystem read-only except what's allowed. Adjust ReadWritePaths to Bacula's storage directories.
The configuration contains daemon passwords. Lock down its permissions:
sudo chmod 0640 /etc/bacula/*.conf
sudo chmod 0600 /etc/bacula/certs/*.key
sudo chown root:bacula /etc/bacula/*.confThe rule: readable by the service user + root, writable only by root, never world-readable. TLS private keys (*.key) are strictest: 0600 root.
Bacula sends messages to various targets via the Messages resource. For auditing, direct everything to files and email:
Messages {
Name = Standard
mailcommand = "/usr/sbin/bsmtp -h localhost -f \"(Bacula)\" %r"
operatorcommand = "/usr/sbin/bsmtp -h localhost -f \"(Bacula)\" %r"
mail = root@localhost = all, !skipped
operator = root@localhost = mount
console = all, !skipped, !saved
append = "/var/log/bacula/bacula.log" = all, !skipped
catalog = all
}append = "/var/log/bacula/bacula.log" writes all important messages to a log file; mail sends notifications; console displays them in bconsole. This log is the audit material.
An audit log an attacker can modify is useless. Use log rotation and restrict access:
sudo chmod 0640 /var/log/bacula/bacula.log
sudo chown root:bacula /var/log/bacula/bacula.logIf compliance demands it, forward logs to an external SIEM (syslog) so there's a copy that can't be deleted locally.
One Director password shared by all FDs is a very wide door: compromising one client means all clients can be backed up/read. Create a unique password per client:
Client {
Name = web-01-fd
Address = 10.0.0.11
Password = "pwd-untuk-web-01"
}
Client {
Name = db-01-fd
Address = 10.0.0.12
Password = "pwd-untuk-db-01"
}Each must match the Director resource in that machine's bacula-fd.conf. Automation (Ansible/Terraform) is the realistic way to manage unique passwords for hundreds of clients — generate per host, inject into the config.
Warning
A leaked FD password means anyone holding it can ask the Director to read files from that client. Rotating FD passwords is the first mandatory step when there's any sign of compromise — and it should be done routinely alongside other credential rotation.
Monitor who connects to the daemons:
* status client=web-01-fd
* status dir
ss -tnp | grep -E "9101|9102|9103"From bconsole, status client shows active FD connections; status dir shows console connections. Suspicious patterns to watch for:
Correlating these three — job logs, active connections, and source addresses — is the real access audit.
[x] FD runs with a non-root user when possible
[x] NoNewPrivileges + ProtectSystem in the systemd unit
[x] Config 0640 root:bacula; TLS keys 0600
[x] Logs flow to file + mail + (optional) syslog/SIEM
[x] Unique FD password per client, rotated routinely
[x] Active connections monitored via status and ssKey takeaways:
FDUser; reduce service rights in systemd.0640 root:bacula, TLS keys 0600 root.Messages resource to file + email; protect from modification.In the next episode, episode 15, we'll scale Bacula to many clients and multi-Director — many FDs to one Director/SD, per-tenant configuration with Client resources and ACLs, plus Director HA and SD clustering options. This is the transition from small deployments to enterprise architecture.