This repository contains a tool that can pre-encrypt an Ubuntu cloud image with a key that is protected by a virtual TPM associated with a specific guest instance. Encryption of an image happens in 2 steps:
encrypt
: Perform the encryption step without protecting the key to a specific guest instance. The key is stored in cleartext inside the LUKS metadata, and can be used to create a pool of pre-encrypted images.deploy
: Take a pre-encrypted image and protect the key to a virtual TPM associated with a specific guest instance, removing the cleartext key in the process. Once this step has been performed, the image is only bootable on that specific guest instance. The deploy step does not need access to the actual TPM, but does need access to the public area of the storage primary key.
- Ubuntu environment
- root privileges (required to create NBD devices, use /dev/mapper/control and mount block devices)
- cryptsetup (>= 2.2.0)
- Available from Ubuntu archive on 20.04 LTS and later
- For Ubuntu 18.04 LTS backport is available from
sudo add-apt-repository ppa:canonical-kernel-team/azure-test
sudo apt-get update
sudo apt install cryptsetup
- qemu-utils
- cloud-guest-utils
This will create an encrypted image bound to the guest associated with the supplied storage primary key, with no PCR policy (note that this is not secure). The supplied storage primary key must be a TPM2B_PUBLIC
object in the TPM wire format. The tpm2_readpublic
command from the tpm2-tools package can create this using the -o
option.
$ sudo ./encrypt-cloud-image encrypt -o <output_path> <input_path>
$ sudo ./encrypt-cloud-image deploy --srk-pub <srkpub_path> <output_path>
It may be desirable to override an image's enabled cloud-init datasources to facilitate debugging the encrypted image in Qemu. To enable only the NoCloud datasource so that an image can be initialized with user data from a separate seed image:
$ sudo ./encrypt-cloud-image encrypt -o <output_path> --override-datasources "NoCloud" <input_path>
The --override-datasources
option takes a comma-delimited list of datasources.
Whilst cloud-init's cc_growpart module is currently not able to grow the root partition if it is backed by an encrypted volume, it is possible to grow it to fill the image during the encryption step using the --grow-root
option. This will also disable the cc_growpart module:
$ sudo ./encrypt-cloud-image encrypt -o <output_path> --grow-root <input_path>
This tool does not have access to the virtual TPM associated with a guest, and so the storage primary key (SRK) must be created by and supplied from another tool as a TPM2B_PUBLIC
structure serialized to a file in the TPM wire format, using the --srk-pub
option.
If the storage primary key is created with the standard template as defined in section 7.5.1 (Foundational Elements of the TPM Provisioning Process - Storage Hierarchy - Storage Primary Key (SRK) Templates) of the TCG TPM v2.0 Provisioning Guidance specification, then the encrypt
subcommand must be called with the --standard-srk-template
option:
$ sudo ./encrypt-cloud-image deploy --srk-pub <srkpub_path> --standard-srk-template <output_path>
If the storage primary key is not created with the standard template, then the template is inferred from a combination of the supplied SRK public area (using the --srk-pub
option) and the unique data supplied to the TPM2_CreatePrimary
command, which must be supplied to this tool as a TPMU_PUBLIC_ID
structure serialized to a file in the TPM wire format, using the --srk-template-unique-data
option:
$ sudo ./encrypt-cloud-image deploy --srk-pub <srkpub_path> --srk-template-unique-data <unique_data_path> <output_path>
Note that the format of the data supplied via the --srk-template-unique-data
option is not the same as the format supplied to the tpm2_createprimary
command via the --unique-data
option. This tool expects it to be in the TPM wire format which implies big-endian byte ordering, whereas tpm2_createprimary
requires little-endian byte ordering for this option.
If neither the --standard-srk-template
or --srk-template-unique-data
options are supplied, the template is assumed to have a unique area with zero-sized fields. This is the default when calling tpm2_createprimary
without the --unique-data
option.
The deploy
subcommand has several options for customizing the PCR policy of the TPM protected key:
--add-efi-boot-manager-profile
: Protect the key with the UEFI Boot Manager Code and Boot Attempts profile, as measured to PCR4 (see section 3.3.4.5 of the TCG PC Client Platform Firmware Profile Specification). This requires the UEFI configuration of the guest to be supplied.--add-efi-secure-boot-profile
: Protect the key with the Secure Boot Policy profile, as measured to PCR7 (see section 3.3.4.8 of the TCG PC Client Platform Firmware Profile Specification). This requires the UEFI configuration of the guest to be supplied. Note that this profile requires that secure boot is enabled.--add-ubuntu-kernel-profile
: Protect the key with the Ubuntu kernel image profile. The Ubuntu kernel measures a set of properties to PCR12. This profile is required in order to protect keys outside of the early boot environment.
By default, the deploy
subcommand will use the UEFI configuration of the host environment. The UEFI configuration of the guest can be supplied in order to override this using one of the following options:
--uefi-config
: A file containing a JSON representation of the UEFI configuration, with the following fields:PK
[base64] - The value of the PK variable.KEK
[base64] - The value of the KEK variable.db
[base64] - The value of the db variable.dbx
[base64] - The value of the dbx variable.omitsReadyToBootEvent
[bool] - Whether the firmware omits the Calling EFI Application From Boot OptionEV_EFI_ACTION
event in PCR4.
--az-disk-profile
: documentation TODO