\label{volumeencryption}

\section{Storage Daemon Encryption}


When using the Device directive \textbf{Volume Encryption = yes}, the blocks in the
volumes are encrypted using the BLOCK\_CIPHER\_AES\_128\_XTS or
BLOCK\_CIPHER\_AES\_256\_XTS cipher algorithm. These symmetrical ciphers are
fast, and used by most applications that need to perform symmetrical encryption of
blocks.

Every block is encrypted using a *key* that is unique for the volume and an
IV (Initialization Vector) - the block number that is saved in the
block header. The XTS ciphers are specifically designed to support an IV
with a low entropy.

The first block of the volume that holds the Volume Label is not encrypted
because certain fields such as the Volume Name are required to manage the volume and
the encryption. A user has an option to obfuscate the fields that are not
required which might hold critical information, e.g. hostname.
These fields are replaced by the string "OBFUSCATED".

The header of the block is not encrypted. This 24-byte header does not hold
user information. See the content of the header:

\begin{itemize}
\item 32bit header option bit field
\item 32bit block length
\item 32bit block number
\item BB03 string
\item 32bit volume session id
\item 32bit volume session time.
\end{itemize}

The Volume session time is the time of the Storage Daemon at startup. The
Volume session id is reset to zero when the daemon starts and is incremented
at every backup by the Storage Daemon.

The 64bit XXH64 checksum is encrypted with the data. The block must be be
decrypted to verify the checksum. If the checksum matches, Bacula uses the
right encryption key and the block is not modified. It is currently not
possible to verify the integrity of the block without the encryption key.

If data spooling is enabled, the data in the data spool is not encrypted.

\textbf{Do not store the data spool on an unsafe storage.}

\subsection{Storage Daemon Directives}

There is one new directive in the Storage resource of the Storage Daemon:

\texttt{Encryption Command = <command>} The command specifies an external
   program that must provide the keys used to encrypt the volume.

There is one directive that must be added to all the devices
used to encrypt volumes:


\texttt{Volume Encryption = <no|yes|strong>}
   It allows you to enable the encryption for a given device.
   The encryption can be of 3 different types:

\begin{itemize}
   \item \texttt{no} Default, the device don't do any encryption.

   \item \texttt{yes} The device encrypts the data, but all information in the volume
   label are left in clear text.

   \item \texttt{strong} The device encrypts the data, and obfuscate any information in
   the volume label except the one that are needed for the management of the
   volume. The fields that are obfuscate are: volume name.
\end{itemize}


\subsection{Encryption Command}

The Encryption Command is called by the Storage Daemon every time
a new volume is initialized or mounted using a device with encryption enabled.
We provide a very simple example script that can be used to manage volume 
encryption keys.

Example Encryption Command setting in the Storage Daemon configuration:

\begin{bVerbatim}
   Encryption Command = "/opt/bacula/scripts/key-manager.py getkey"
\end{bVerbatim}
     
The command is limited to 127 characters. The same variable substitutions as
the Autochanger Command are available to be passed to the script.

The program can be an interface with your existing key management system or
perform the key management on its own.

The sample script called \texttt{key-manager.py} may be installed via the
bacula-storage-key-manager package. The install-key-manager.sh
script is designed to help to setup a master key:

\begin{bVerbatim}
   # sudo -u bacula /opt/bacula/scripts/install-key-manager.sh check
   # sudo -u bacula /opt/bacula/scripts/install-key-manager.sh install
\end{bVerbatim}

Example interaction using the sample key-manager.py script::

\begin{bVerbatim}
   $ OPERATION=LABEL VOLUME_NAME=Volume0001 ./key-manager.py getkey --cipher AES_128_XTS --key-dir /opt/bacula/keys 
   cipher: AES_128_XTS
   cipher_key: G6HksAYDnNGr67AAx2Lb/vecTVjZoYAqSLZ7lGMyDVE=
   volume_name: Volume0001

   $ OPERATION=READ VOLUME_NAME=Volume0001 ./key-manager.py getkey --cipher AES_128_XTS --key-dir /opt/bacula/keys 
   cipher: AES_128_XTS
   cipher_key: G6HksAYDnNGr67AAx2Lb/vecTVjZoYAqSLZ7lGMyDVE=
   volume_name: Volume0001

   $ cat /opt/bacula/keys/Volume0001
   cipher: AES_128_XTS
   cipher_key: G6HksAYDnNGr67AAx2Lb/vecTVjZoYAqSLZ7lGMyDVE=
   volume_name: Volume0001

   $ OPERATION=READ VOLUME_NAME=DontExist ./key-manager.py getkey --cipher AES_128_XTS --key-dir /opt/bacula/keys 2>/dev/null
   error: no key information for volume "DontExist"
   $ echo $?
   0

   $ OPERATION=BAD_CMD VOLUME_NAME=Volume0002 ./key-manager.py getkey --cipher AES_128_XTS --key-dir /opt/bacula/keys 2>/dev/null
   error: environment variable OPERATION invalid "BAD_CMD" for volume "Volume0002"
   $ echo $?
   0
\end{bVerbatim}

In the command above, notice that the keys are kept in one
directory /opt/bacula/keys, and the arguments are passed using the environment variables.

Bacula passes the following variables via the environment:

\begin{itemize}
\item[OPERATION]  This is LABEL when the volume is labeled. In this case
   the script should generate a new key or this can be READ when
   the volume already has a label and the Storage Daemon needs the already
   existing key to read or append data to the volume

 \item[VOLUME\_NAME]  This is the name of the volume.

\end{itemize}

Some variables already exist to support a *Master Key* in the future.
This feature is not yet supported, but will come later:

\begin{itemize}
\item[ENC\_CIPHER\_KEY] This is a base64 encoded version of the key encrypted by
   the master key.

\item[MASTER\_KEYID] This is a base64 encoded version of the key ID of 
   the master key that was used to encrypt the ENC\_CIPHER\_KEY above.
\end{itemize}

Bacula expects some values in return:

\begin{itemize}
\item[volumename] This is a repetition of the name of the volume that is
   given to the script. This field is optional and ignored by Bacula.

 \item [cipher] This is the cipher that Bacula must use. 
   Bacula knows the following ciphers: AES\_128\_XTS and AES\_256\_XTS.
   Of course, the key lengths varies depending on the cipher used.

 \item [cipher\_key]  This is a symmetric key in base 64 format.

 \item  [comment] This is a single line of text that is optional and ignored by Bacula.

 \item  [error] This is a single line error message.
   This is optional, but when provided, Bacula considers that the script
   returned an error and displays this error in the job log.

Bacula expects an exit code of 0. If the script exits with a different
error code, any output is ignored and Bacula displays a generic message
with the exit code in the job log.

To return an error to Bacula, the script must use the *error* field
and return an error code of 0.


\subsection{Compatibility between Volumes Using the BB02 and BB03 Formats}

Any volume initialized using Bacula version 13.0 or prior versions can be read and appended in version 15 and above.
Volumes that have been initialized or simply appended using version 15.0 and after cannot be read with version 13.0 or prior versions.


\subsection{Interoperability between Encrypted and Unencrypted Volumes}

The volume has a flag in the header of the first block which indicated whether the volume is encrypted or not.
The field VolEncrypted in the Catalog reflects this state. Bacula does not mix encrypted and unencrypted data inside a volume.

Volumes that have been labeled or re-labeled on a Device with the directive VolumeEncryption are
encrypted volumes. Other volumes, including volumes which have been initialized
with a BB02 format using version 13.0 or older, are seen as unencrypted volumes.

You can change the value of the directive VolumeEncryption to Yes or Strong at any time.
Volumes that are not encrypted can be read on this device but cannot be appended until they are recycled.
Switching between Yes and Strong is fine, because the difference is only in the unencrypted label
and not in the blocks that come after the label.

Changing the value of the directive back to No will deactivate the encryption
and make all encrypted volumes unreadable and useless on this device until they are recycled.


\subsection{Using a Master Key}

Bacula uses symmetric keys to encrypt the volumes.
This means that the same key is used to encrypt and also to decrypt the volume content.
To improve security, each volume is expected to be encrypted using a different key.
The task of the key manager is to provide these keys to the Storage Daemon.
When needed, these keys must be generated for a new volume or when the volume is recycled.
This can result in a large amount of key files to handle, which must also be backed up or kept in a safe place.

The master key is implemented using a public/private key pair.
The public key is kept on the Storage Daemon to generate the encrypted version of the
symmetric keys while the private key may be kept somewhere else.

The master key is designed to provide two advantages:

\begin{itemize}
\item To be able to decrypt multiple volumes using one, or a set of master keys
\item When the **stealth** mode is used, the symmetric key is never stored on disk,
  which makes any restore impossible without the private key.
  If your server is hacked or stolen, nobody is able to restore your data.
\end{itemize}

\subsection{How the Master Key Is Implemented}

The master key is implemented using a public/private key pair.
The public key is stored on the Storage Daemon and is
used to encrypt the automatically generated symmetrical keys.
The private key does not need to be stored on the Storage Daemon to run backups.

The encrypted key and a unique identifier for the master key
are stored into the label of the volume.
At restore time, these two pieces of information, and the volume name are
provided to the key manager that must provide the correct symmetrical key.

There are a few scenarios to consider:

\begin{itemize}
\item  You don't use the stealth mode, and the key-manager can use the
  passphrase of the private key that you have provided in the
  configuration file to decrypt the symmetrical key coming from the
  volume *or use the clear version of the symmetrical key stored locally.

\item You use the stealth mode, and the key-manager asks GnuPG
  to decrypt the symmetrical key coming from the volume.
  There are two possibilities here:

\item The passphrase of the private key has been preset, or is still in
    the cache of the *gpg* agent and *gpg* can decrypt the symmetrical key

  \item Bacula waits until the user provides the passphrase
\end{itemize}
    
The key-manager provided with Bacula uses GnuPG to manage the
public/private key.

\subsection{Format of the key-manager.conf File}

When using the master key feature, you can set up your master keys
in the key-manager.conf file that is stored in /opt/bacula/etc.
This file is automatically populated with one master-key at installation time.
This file is not required if you don't use a master-key.

\begin{bVerbatim}

	[default]
	gnupghome="/opt/bacula/etc/gnupg"

	[0378FB9C839FF9F207834D89DB856A1A513B7AB4]
	#volume_regex=Volume[0-9]+|TestVolume[0-9]+
	uid=bacula@localhost
	passphrase=xm3ynBi7MfHTUovls4QV8OtBT5rfAnXwT8Wb7wjVRyCT
	stealth=off

\end{bVerbatim}

The supported fields are:

\begin{itemize}
\item [gnupghome] This is where GnuPG stores your keys
\item [volume\_regrex] A regex that is used by the key manager to
  know if this master key must be used with one volume
\item [uid] The uid helps you to identify the key
\item [passphrase] This is the passphrase of the key
\item [stealth] When stealth is used, the key manager does not store
  the symmetrical keys in the KEYDIR directory.
\end{itemize}

The default gnupghome directory is in /opt/bacula/etc/gnupg.
When using GnuPG, you must use the --homedir option like: \texttt{--homedir /opt/bacula/etc/gnupg},
or set the GNUPGHOME environment variable::

\begin{bVerbatim}
	export GNUPGHOME="/opt/bacula/etc/gnupg"
\end{bVerbatim}

You must define a section for every master key you want to use.
The name of the section is the Key-ID of your public/private key.
You can get the Key-ID when listing your keys::

\begin{bVerbatim}
	bacula $ GNUPGHOME=/opt/bacula/etc/gnupg gpg -k
	/opt/bacula/etc/gnupg/pubring.kbx
	-----------------------------------------------------
	pub   rsa3072 2023-01-11 [SC]
		  0378FB9C839FF9F207834D89DB856A1A513B7AB4
	uid           [ultimate] Bacula <bacula@localhost>
	sub   rsa3072 2023-01-11 [E]
\end{bVerbatim}

Notice that the public key has a sub key that allows encryption.
This is the [E] in the last line. If your public/private key does not 
own such a key, you cannot use it with the key manager.

The volume\_regex are checked sequentially. The first regex
that matches the volume name submitted to the key manager will
be used even if another volume\_regex matches the name of the volume.
By default the volume\_regex is commented out to not activate the
master key feature.

The uid is only informative, and is not used by the key manager.

When stealth is set to \texttt{on} the key manager does not keep the
symmetrical keys in clear text in the KEYDIR directory.
When \texttt{on}, you must also not specify a passphrase.

When the passphrase of the public/private key is not set,
but required by the key manager, it relies on the gpg-agent
to provide the key.

\subsection{Backup Your Keys}

In case of losing your symmetrical keys and/or your master key(s), your data is not recoverable.
Therefore, it is important to backup your keys.

Your symmetrical keys are stored in the /opt/bacula/etc/keydir
directory by default. This directory may be modified with the
--key-dir option in the command line that is configured
with the Encryption Command directive defined above.
This directory must be backed up regularly.

Your master keys are stored in the /opt/bacula/etc/gnupg
directory by default. This directory is defined in the
key manager configuration file (by default /opt/bacula/etc/key-manager.conf)
in the [default] section under the gnupghome directive as
seen above. The key-manager.conf file can be relocated with the
--config option in the command defined in Encryption Command
directive defined above. The default passphrase is stored in
the key-manager.conf. You just need to backup the key-manager.conf*
file, and the /opt/bacula/etc/gnupg directory.

You can export your default private key using the command::

\begin{bVerbatim}
   # gpg --homedir /opt/bacula/etc/gnupg --output private.pgp --armor --export-secret-key bacula@localhost
\end{bVerbatim}

It asks you for the passphrase that is saved in you key-manager.conf file.
This exports an ASCII armored version of your private key
into the file private.pgp. You can print it and/or save it on USB drive or elsewhere.


\subsection{What Is Encrypted and What Is Not}

The main goal of encryption is to prevent outsiders without the volume key to
read the volume's data. Bacula does this well, but encryption alone cannot
protect against volume modifications.

The first block of the volume is the volume label and it is not encrypted.
Some information is required for the management of the volume itself.
The only data in the volume label coming from the user are: the hostname,
volumename, poolname. The hostname can be obfuscated using
the STRONG mode of encryption, the poolname and the volumename
could be made useless to an attacker by using a generic name like PoolAlpha or
Volume12345.

Data in your catalog database, for example the directories, filenames, and
               the JobLog are not encrypted.

An attacker can also make some undetected modifications to the volumes.
The easiest way is to remove one block inside the volume.
Other verifications inside Bacula could detect such a modification and
the attacker must be meticulous, but it is a possibility.

The XXH64 checksum inside each volume is encrypted using the encryption key.
This is not as strong as using a certified signature, but it provides
substantial confidence that the block cannot be modified easily.

To summarize, with volume encryption enabled, you can be confident that:

\begin{itemize}
\item An attacker can not read any of your data: Very Strong.
\item An attacker can not substitute the volume with another one: Strong.
\item An attacker can not modify the contents of the volume: Good.
\end{itemize}
