This episode teaches Bacula network security: enabling TLS between the Director, Storage Daemon, and File Daemon with certificates, restricting daemon access via firewall and VLAN, data encryption strategies (Enterprise plugin or stunnel pipeline), and the role of integrity checksums.

In episode 12 we secured who is allowed to connect. But there's still an uncovered gap: the content of the conversation. Bacula passwords cross the network as plaintext, and backup data rides along naked on the wire. In episode 13 we close that gap with TLS and encryption: TLS protects the three channels (Director↔SD, Director↔FD, FD↔SD), and data encryption ensures that even stolen media is unreadable.
The right approach is an internal CA: one CA signs a certificate for each daemon. Create the CA first:
mkdir -p /etc/bacula/certs
openssl genrsa -out /etc/bacula/certs/ca.key 4096
openssl req -x509 -new -key ca.key -days 3650 -subj "/CN=Bacula CA" -out ca.pemThen create a certificate for each daemon (example for the Director):
openssl req -new -newkey rsa:4096 -nodes -keyout director.key -out director.csr -subj "/CN=bacula-dir"
openssl x509 -req -in director.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out director.pem -days 825Repeat the same pattern for bacula-sd and every bacula-fd client. Copy the CA (ca.pem) to all hosts.
Director {
Name = bacula-dir
TLS Enable = yes
TLS Require = yes
TLS Verify Peer = yes
TLS CA Certificate File = /etc/bacula/certs/ca.pem
TLS Certificate = /etc/bacula/certs/director.pem
TLS Key = /etc/bacula/certs/director.key
}Key directives:
TLS Enable = yes — enables TLS negotiation.TLS Require = yes — rejects non-TLS connections (mandatory for all peers).TLS Verify Peer = yes — verifies the peer's certificate against the CA.The Client, Storage, and Console resources in the same file can also get TLS Enable = yes to restrict specific channels.
Director {
Name = bacula-dir
Password = "rahasia-sd"
TLS Enable = yes
TLS Require = yes
TLS Verify Peer = yes
TLS CA Certificate File = /etc/bacula/certs/ca.pem
TLS Certificate = /etc/bacula/certs/sd.pem
TLS Key = /etc/bacula/certs/sd.key
}Director {
Name = bacula-dir
Password = "rahasia-fd"
TLS Enable = yes
TLS Require = yes
TLS CA Certificate File = /etc/bacula/certs/ca.pem
TLS Certificate = /etc/bacula/certs/fd.pem
TLS Key = /etc/bacula/certs/fd.key
}Warning
Enable TLS on all resources consistently before turning on TLS Require = yes. If only one side requires TLS while the other isn't ready, the connection fails with a TLS handshake error. Safe order: install certificates on all hosts → TLS Enable → only then TLS Require.
* status dir
* status sd
* status client=client-fdThe daemon status shows TLS: Active on encrypted connections. An TLS negotiation failed error indicates a certificate/CA mismatch — check the CN, dates, and CA file on both sides.
TLS encrypts, but doesn't close the door. Combine it with segmentation:
nft add rule inet filter input ip saddr 10.20.0.0/24 tcp dport {9102, 9103} accept
nft add rule inet filter input tcp dport {9101, 9102, 9103} dropConsole resource can be restricted with Address to limit which addresses may connect to the Director.TLS protects data in transit. But there's a deeper question: what happens if a tape is stolen or disk storage is seized? The answer is data encryption at rest on the media.
Bacula Enterprise has integrated encryption in the Storage Daemon: data is encrypted before being written to media, with built-in key management and HSM integration. You set CryptKey in the Storage/Client resources and the media becomes unreadable without the key.
Community has no built-in media encryption. A common solution: wrap the FD↔SD connection with stunnel doing client-to-client TLS. Each FD and SD runs a local stunnel; Bacula still speaks plaintext on localhost, while the wire between hosts is encrypted.
[bacula-sd]
accept = 127.0.0.1:9102
connect = 0.0.0.0:9202
cert = /etc/stunnel/sd.pemResult: backups flowing between hosts are encrypted without changing Bacula's logic. The complexity shifts to stunnel management — a reasonable trade-off for environments without an Enterprise license.
Note
Another Community alternative: encryption at the storage filesystem level (for example LUKS for the Archive Device directory, or dm-crypt for tapes). This approach is simple but only protects the data while the media is stored — not while in transit.
Encryption and TLS protect confidentiality; checksums protect integrity. In a FileSet, the signature option records a hash of each file:
FileSet {
Name = "Set Web"
Include {
Options {
signature = SHA1
}
File = /var/www
}
}With signature, Bacula stores the hash in the catalog. During restore, the hash is verified — changed files (corruption, tampering) are detected. This also fuels the Verify jobs we covered in episode 9.
Important
End-to-end truth: TLS protects transit, encryption protects media, checksums protect content. They stand independently — enabling one does not replace the others. For high-value data, use all three.
Key takeaways:
TLS Require goes in only after every side is ready.signature checksums in a FileSet protect integrity during restore.status in bconsole.In the next episode, episode 14, we'll cover hardening and least privilege — running daemons as non-root users when possible, locking config permissions (600/640), audit logs, unique FD passwords per client, and access monitoring. These are the layers that force attackers to work extra hard.