10.4. Managing Container Virtual Hard Disk Encryption

Virtuozzo offers container virtual hard disk encryption capabilities based on dm-crypt and cryptsetup. The current implementation uses the AES-256 encryption algorithm. The encryption mechanism is separated from encryption key management, enabling you to use your own key management system (KMS) to issue and manage encryption keys.

Important

Only the root user must have access to encryption operations on the host.

The overall encryption procedure may be described as follows. An end user requests encryption for their container disk (create a new container with an encrypted disk, encrypt an existing disk, etc.). The KMS stores a secret encryption key and a public encryption key ID assigned to the end user. The administrator (or an automation tool) obtains the end user’s encryption key ID from the KMS and passes it to the corresponding prlctl command. The prlctl command passes the key ID to the getkey executable that accesses the KMS and returns the encryption key which is passed to cryptsetup. The cryptsetup tool issues a master key unique for the container disk, encrypts the disk contents with the master key, then encrypts the master key stored in container disk’s LUKS header with the encryption key passed from getkey.

The double encryption saves host resources in situations when the encryption key has to be changed (e.g., for key rotation purposes). In such cases, only the master key in the LUKS header has to be re-encrypted instead of the entire disk contents.

The only configuration step required to start using container disk encryption capabilities in Virtuozzo is to set up the encryption key requester as described further to be able to obtain encryption keys by their IDs for corresponding prlctl commands.

10.4.1. Setting Up Encryption Key Requester

The encryption mechanism communicates with the KMS as follows: executes the file /usr/libexec/ploop/crypt.d/getkey with the only string parameter–encryption key ID–and reads the returned encryption key value from the standard output. The getkey executable can be a script that calls the KMS binary and passes the specified encryption key ID to it.

On success, the executable is expected to exit with zero code and the key value is expected to be printed to the standard output in the binary form. On failure, the script is expected to exit with non-zero code.

Note

Key value may contain arbitrary bytes (e.g., \x00, \n, and such) that may be treated differently by various scripting languages. For example, assigning the key value to a Bash variable would strip the zero bytes from it, e.g., key_va\x00lue would become key_value.

To set up the encryption key requester on a Virtuozzo host, place the script to /usr/libexec/ploop/crypt.d/getkey and make it executable and only accessible by the root user:

# chown root:root /usr/libexec/ploop/crypt.d/getkey
# chmod 700 /usr/libexec/ploop/crypt.d/getkey

10.4.2. Encrypting and Decrypting Container Virtual Hard Disks

Following is a list of encryption-related operations you can perform on container virtual hard disks. All operations except decrypt require an encryption key ID obtained from your KMS.

Note

PFCache is disabled for encrypted disks.

  1. Create a container with an encrypted root disk.

    # prlctl create <CT_name|CT_UUID> --vmtype ct --encryption-keyid <key_id>
    
  2. Add a new encrypted disk to a container.

    # prlctl set <CT_name|CT_UUID> --device-add hdd --encryption-keyid <key_id>
    
  3. Encrypt an unencrypted disk. During this operation, a new empty encrypted disk is created, the data is moved to it from the unencrypted disk which is then securely erased with shred (unless --no-wipe is added). For this operation, the host needs free disk space equal to the size of the container disk being encrypted.

    # prlctl set <CT_name|CT_UUID> --device-set hdd0 --encrypt --encryption-keyid <key_id> \
    [--no-wipe]
    
  4. Change the encryption key ID of an encrypted disk with or without re-encrypting the entire disk contents. By default, only the LUKS header of an encrypted disk is re-encrypted to save host resources. The entire disk contents can be re-encrypted by adding --reencrypt to the command. During this operation, a new empty encrypted disk is created, the data is moved to it from the old encrypted disk which is then securely erased with shred (unless --no-wipe is added). For this operation, the host needs free disk space equal to the size of the container disk being re-encrypted.

    # prlctl set <CT_name|CT_UUID> --device-set hdd0 --encryption-keyid <key_id> [--reencrypt] \
    [--no-wipe]
    
  5. Decrypt an encrypted container disk. During this operation, a new empty unencrypted disk is created and the data is moved to it from the encrypted disk. If the operation completes successfully, the encrypted disk is deleted. If the operation fails, the partially decrypted data is securely erased with shred (unless --no-wipe is added) and the encrypted disk remains intact. For this operation, the host needs free disk space equal to the size of the container disk being decrypted.

    # prlctl set <CT_name|CT_UUID> --device-set hdd0 --decrypt [--no-wipe]
    

10.4.3. Encrypting System Swap

Even if containers are encrypted, their memory may still be swapped to an unencrypted system swap partition. On nodes intended to run encrypted containers, consider encrypting the swap partition as well.

To encrypt a swap partition with a random encryption key, do the following:

  1. Identify swap partitions in the system:

    # swapon -s
    Filename         Type            Size    Used    Priority
    /dev/<partition> partition       XXXXXXX 0       -1
    
  2. Add a swap partition’s entry to the /etc/crypttab file. For example:

    swap  /dev/<partition>  /dev/urandom   swap,noearly
    

    Once the encryption is initiated, this will map the /dev/<partition> to /dev/mapper/swap as an encrypted swap partition.

    Note

    To create an encryption key, you may use /dev/random instead of /dev/urandom. However, in this case, the system may take a long time to boot.

  3. Find out the UUID of the swap partition:

    # blkid /dev/<partition>
    /dev/<partition>: UUID="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" TYPE="swap"
    
  4. Comment the swap partition’s entry in the /etc/fstab file and add an entry for the mapped /dev/mapper/swap file. For example:

    #UUID=<partition_UUID> swap swap defaults 0 0
    /dev/mapper/swap none swap sw 0 0
    
  5. Reboot to initiate the encryption.

  6. Run the lsblk command to ensure the swap is encrypted. In the output, the swap partition’s TYPE should be crypt.

    # lsblk
    NAME                 MAJ:MIN    RM  SIZE RO TYPE  MOUNTPOINT
    ...
      └─<swap_partition>   X:X      0   XG   0  crypt [SWAP]
    ...
    

    The output of swapon -s will show a different filename:

    # swapon -s
    Filename                                Type            Size    Used    Priority
    /dev/dm-X                               partition       XXXXXXX 0       -1