Skip to content

Commit

Permalink
upgrade cvm rewriter with plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
wenhuizhang committed Mar 6, 2024
1 parent 2e49c83 commit 9793ab6
Show file tree
Hide file tree
Showing 51 changed files with 293 additions and 271 deletions.
85 changes: 43 additions & 42 deletions src/cvm-image-rewriter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ config, OVMF firmware etc.

## 1. Overview

The confidential VM guest can be customized including follows:
The confidential VM guest can be customized as follows:

![](/docs/cvm-customizations.png)

Expand Down Expand Up @@ -37,7 +37,7 @@ framework, and the whole flow was divided into three stages:

### 2.1 Existing Plugins

There are following customization plugins in Pre-Stage providing customization to base image.
There are following customization plugins in Plugins providing customization to base image.

| Name | Descriptions | Required for CCNP deployment |
| ---- | ------------ | ------------ |
Expand All @@ -46,28 +46,29 @@ There are following customization plugins in Pre-Stage providing customization t
| 03-netplan | Customize the netplan.yaml | N |
| 04-user-authkey | Add auth key for user login instead of password | N |
| 05-readonly-data | Fix some file permission to ready-only | N |
| 07-install-mvp-guest | Install MVP TDX guest kernel | Y |
| 08-device-permission | Fix the permission for device node | Y |
| 09-ccnp-uds-directory-permission | Fix the permission for CCNP UDS directory | Y |
| 06-install-tdx-guest-kernel | Install MVP TDX guest kernel | Y |
| 07-device-permission | Fix the permission for device node | Y |
| 08-ccnp-uds-directory-permission | Fix the permission for CCNP UDS directory | Y |
| 60-initrd-update | Update the initrd image | N |
| 97-sample | plugin customization example | N |
| 98-ima-enable-simple | Enable IMA (Integrity Measurement Architecture) feature | N |

### 2.2 Design a new plugin

A plugin is put into the directory of [`pre-stage`](/src/cvm-image-rewriter/pre-stage/),
A plugin is put into the directory of [`plugins`](/tools/cvm-image-rewriter/plugins/),
with the number as directory name's prefix. So the execution of plugin will be
dispatched according to number sequence for example `99-test` is the final one.
dispatched according to number sequence for example `99-byebye` is the final one.

A plugin includes several customization approaches:

1. File override: all files under `<plugin directory>/files` will be copied the
corresponding directory in target guest image.
2. Pre-stage execution on the host: the `<plugin directory>/host_run.sh` will be
executed before cloud-init stage
3. cloud-init customization: please put the config yaml into `<plugin directory>/cloud-init/cloud-config`,
and put the scripts to `<plugin directory>/cloud-init/x-shellscript`
1. File override: all files under `<plugin directory>/files` will be copied into the
corresponding directory in the target guest image.
2. Pre-stage execution on the host: the `<plugin directory>/pre-stage/host_run.sh` will be
executed before cloud-init stage.
3. cloud-init customization: please put the config yaml in `<plugin directory>/cloud-init/cloud-config`,
and put the scripts in `<plugin directory>/cloud-init/x-shellscript`.

Please refer [the sample plugin](/src/cvm-image-rewriter/pre-stage/99-test/).
Please refer to [the sample plugin](/tools/cvm-image-rewriter/plugins/97-sample/).

## 3. How to Run the tool

Expand All @@ -76,32 +77,32 @@ Please refer [the sample plugin](/src/cvm-image-rewriter/pre-stage/99-test/).
1. This tool has been tested on `Ubuntu 22.04` and `Debian 10`. It is recommend to use
`Ubuntu 22.04`.

2. This tool can run on bare metal or virtual machine (with nest VM like `Intel VT-x`, detailed in [Section 3.4](#3.4-Run-in-Nested-VM-(Optional)))
2. This tool can run on bare metal or within a virtual machine using nesting as detailed in [Section 3.4](#3.4-Run-in-Nested-VM-(Optional)).

3. Please install following packages on Ubuntu/Debian:
3. Please install the following packages on Ubuntu/Debian.

```
sudo apt install qemu-utils guestfs-tools virtinst genisoimage libvirt-daemon-system libvirt-daemon
```
If `guestfs-tools` is not available in your distribution, you may need to install some additional packages on Debian:
If `guestfs-tools` is not available in your distribution, you may need to install some additional packages on Debian.
```
sudo apt-get install guestfsd libguestfs-tools
```
5. Ensure current login user is in the group of libvirt
4. Ensure current login user is in the group of libvirt.
```
sudo usermod -aG libvirt $USER
```
6. Ensure read permission on `/boot/vmlinuz-$(uname-r)`.
5. Ensure read permission on `/boot/vmlinuz-$(uname-r)`.
```
sudo chmod o+r /boot/vmlinuz-*
```
7. The version of cloud-init is required > 23.0, so if the host distro could not
6. The version of cloud-init is required > 23.0, so if the host distro could not
provide such cloud-init tool, you have to install it manually. For example, on a
debian 10 system, the version of default cloud-init is 20.0. Please do following
steps:
Expand All @@ -110,12 +111,12 @@ steps:
sudo dpkg -i cloud-init_23.3.1-1_all.deb
```
8. If it is running with `libvirt/virt-daemon` hypervisor, then:
7. If it is running with `libvirt/virt-daemon` hypervisor, then:
- In file `/etc/libvirt/qemu.conf`, make sure `user` and `group` is `root` or
current user.
- If need customize the connection URL, you can specify via `-s` like `-s /var/run/libvirt/libvirt-sock`,
please make sure current user belong to libvirt group via following commands:
please make sure the current user belongs to the libvirt group via the following commands:
```
sudo usermod -aG libvirt $USER
sudo systemctl daemon-reload
Expand All @@ -132,23 +133,26 @@ steps:
The tool provides several plugins to customize the initial image. It will generate an `output.qcow2` under current directory.
Before running the tool, please choose the plugins that are needed.You can skip any plugin by creating a file "NOT_RUN" under the plugin directory.
Before running the tool, please choose the plugins that are needed.You can skip any plugin by creating a file "NOT_RUN" under the current directory.
For example:
```
touch pre-stage/01-resize-image/NOT_RUN
touch plugins/01-resize-image/NOT_RUN
```
If the guest image is used for CCNP deployment, it's recommended to run below plugin combination according to different initial guest image type.
If the guest image is used for CCNP deployment, it's recommended to run the below plugin combination depending on which guest image type is used.
Others are not required by CCNP and can be skipped.
| Base image | 01 | 02 | 03 | 04 | 05 | 07 | 08 | 09 | 60 | 98 |
| Base image | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 60 | 98 |
|---|---|---|---|---|---|---|---|---|---|---|
| Ubuntu base image | | | | | Y| | Y| Y| | |
| Ubuntu base image | | | | | | Y| Y| Y| | |
| TD enlightened image | | | | | | | Y| Y| | |
**NOTE:**
- TD enlightened image means the image already has TDX kernel. If not, plugin 05 is needed to install TDX kernel.
- Plugin 08 and 09 prepares device permission for CCNP deployment.
- All plugins need to be executed in numerical order.
- TD enlightened image means the image already has a TDX kernel. If not, plugin 06 is required to install a TDX kernel.
- Plugin 7 and Plugin 8 need to be executed before deploying CCNP to provide device permissions for CCNP.
- Plugin 60 requires copying or generating all files to the root directory first. When users customize plugins, please ensure that the plugin number with this requirement is placed before 60.
- Plugin 98 needs to be executed after all other plugins have completed. The number of the user-customized plugin must be before 98.
- Other plugins are optional for CCNP deployment.
The tool supports parameters as below.
Expand All @@ -160,10 +164,10 @@ Required
Optional
-t <number of minutes> Specify the timeout of rewriting, 3 minutes default,
If enabling IMA, recommend timeout >6 minutes
-s <connection socket> Default is connection URI is qemu:///system,
-s <connection socket> Default connection URI is qemu:///system,
if install libvirt, you can specify to "/var/run/libvirt/libvirt-sock"
then the corresponding URI is "qemu+unix:///system?socket=/var/run/libvirt/libvirt-sock"
-n Silence running for virt-install, no output
-n Silent running for virt-install with no output
-h Show usage
```
Expand All @@ -175,7 +179,7 @@ $ ./run.sh -i <initial guest image> -t 10
### 3.3 Boot a VM
After above tool is running successfully, you can boot a VM using the generated `output.qcow2` using `qemu-test.sh` or `virt-test.sh`.
After above tool is running successfully, you can boot a VM using the generated `output.qcow2` using `qemu-test.sh` or `start-virt.sh`.
- Boot TD or normal VM using `qemu-test.sh`.
```
Expand All @@ -187,20 +191,17 @@ After above tool is running successfully, you can boot a VM using the generated
For example:
```
# Boot a TDVM with TDX 1.0 Stack
$ sudo ./qemu-test.sh -i output.qcow2 -t td-1.0 -p <qemu monitor port> -f <ssh_forward port>

# Boot a TDVM with TDX 1.5 Stack
$ sudo ./qemu-test.sh -i output.qcow2 -t td-1.5 -p <qemu monitor port> -f <ssh_forward port>
# Boot a TD
$ sudo ./qemu-test.sh -i output.qcow2 -t td -p <qemu monitor port> -f <ssh_forward port>

# Boot a normal VM
$ sudo ./qemu-test.sh -i output.qcow2 -t legacy -p <qemu monitor port> -f <ssh_forward port>
$ sudo ./qemu-test.sh -i output.qcow2 -p <qemu monitor port> -f <ssh_forward port>
```
- Boot TD using `virt-test.sh`.
- Boot TD using `start-virt.sh`.
```
$ sudo ./virt-test.sh -h
Usage: virt-test.sh [OPTION]...
$ sudo ./start-virt.sh -h
Usage: start-virt.sh [OPTION]...
-i <guest image file> Default is tdx-guest-ubuntu22.04.qcow2 under current directory
-n <guest name> Name of TD guest
-t <template file> Default is ./tdx-libvirt-ubuntu-host.xml.template
Expand All @@ -224,7 +225,7 @@ This tool can also be run in a guest VM on the host, in case that users need to
Given that some plugins will consume more time in a low-performance guest VM, it is recommended to enable nested virtualization feature on the host.
Firstly, check if the nested virtualization is enabled. If the file `/sys/module/kvm_intel/parameters/nested` show `Y` or `1`, it indicates that the feature is enabled.
First, check if the nested virtualization is enabled. If the file `/sys/module/kvm_intel/parameters/nested` show `Y` or `1`, it indicates that the feature is enabled.
```
cat /sys/module/kvm_intel/parameters/nested
Expand Down
9 changes: 9 additions & 0 deletions src/cvm-image-rewriter/plugins/01-resize-image/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Resize the image

This plugin is used to extend the guest image size to given value from the
environment variable `${GUEST_SIZE}`.

If `${GUEST_SIZE}` is not specified like below, then this plugin will be skipped.
```
export GUEST_SIZE=50G
```
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#!/bin/bash

CURR_DIR=$(dirname "$(readlink -f "$0")")

TOP_DIR="${CURR_DIR}/../../../"
SCRIPTS_DIR="${TOP_DIR}/scripts"
# shellcheck disable=SC1091
source "${CURR_DIR}/../../scripts/common.sh"
source "${SCRIPTS_DIR}/common.sh"

info "Guest Image is at ${GUEST_IMG}..."

Expand Down
3 changes: 3 additions & 0 deletions src/cvm-image-rewriter/plugins/02-motd-welcome/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Motd welcome

This plugin is used to set the information in `/etc/motd`, which will be displayed after successful login. Users can customize the welcome information by updating the content of `files/etc/motd`.
3 changes: 3 additions & 0 deletions src/cvm-image-rewriter/plugins/03-netplan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Netplan

This plugin is used to add network configuration file `netplan.yaml` in the `/etc/netplan/` directory, which will configure the network for the guest image. Users can customize `netplan.yaml` by updating the contents of `files/etc/netplan/netplan.yaml`
14 changes: 14 additions & 0 deletions src/cvm-image-rewriter/plugins/04-user-authkey/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# User authkey

This plugin is used to set the SSH login user and public key using environment variables `${CVM_USER}` and `${CVM_AUTH_KEY}`.

The default value of `${CVM_USER}` is "cvm", and users can customize it as shown below.
```
export CVM_USER=<user>
```

The `${CVM_AUTH_KEY}` has no default value, users need to set it themselves. If `${CVM_AUTH_KEY}` is not specified like below, this plugin will be skipped.

```
export CVM_AUTH_KEY=<ssh public key>
```
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

DIR=$(dirname "$(readlink -f "$0")")
CLD_DIR="$DIR/cloud-init"
CLD_DIR="$DIR/../cloud-init"

if [[ -d "$CLD_DIR" ]]; then
rm -rf "$CLD_DIR"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
pushd "$(dirname "$(readlink -f "$0")")" || exit 0

# shellcheck disable=SC1091
source ../../scripts/common.sh
source ../../../scripts/common.sh

# Check CVM_USER, CVM_AUTH_KEY
CVM_USER="${CVM_USER:-cvm}"
info "Config user: $CVM_USER"

if [[ -z "$CVM_AUTH_KEY" ]]; then
warn "CVM_AUTH_KEY is not set, skip"
warn "SKIP: CVM_AUTH_KEY is not defined via environment variable 'CVM_AUTH_KEY'"
exit 0
fi
info "ssh pubkey: $CVM_AUTH_KEY"

# Generate cloud-config
mkdir -p cloud-init/cloud-config/
cat > cloud-init/cloud-config/04-user-authkey.yaml << EOL
mkdir -p ../cloud-init/cloud-config/
cat > ../cloud-init/cloud-config/04-user-authkey.yaml << EOL
#cloud-config
merge_how:
- name: list
Expand Down
3 changes: 3 additions & 0 deletions src/cvm-image-rewriter/plugins/05-readonly-data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Readonly data

This plugin is used to fix some file permissions to read-only. Users can specify the names of files and directories that need to be fixed in the `pre-stage/file_list`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

DIR=$(dirname "$(readlink -f "$0")")
CLD_DIR="$DIR/../cloud-init"

if [[ -d "$CLD_DIR" ]]; then
rm -rf "$CLD_DIR"
fi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
DIR=$(dirname "$(readlink -f "$0")")
FILE_LIST="$DIR/file_list"
CLD_SH_READONLY_FILE="01-file-readonly.sh"
CLD_SH="$DIR/cloud-init/x-shellscript/$CLD_SH_READONLY_FILE"
CLD_SH="$DIR/../cloud-init/x-shellscript/$CLD_SH_READONLY_FILE"
CLD_SH_TEMPLATE=""
injects=""

Expand All @@ -25,6 +25,6 @@ while IFS= read -r line || [ -n "$line" ]; do
fi
done <"$FILE_LIST"

mkdir -p "$DIR/cloud-init/x-shellscript"
mkdir -p "$DIR/../cloud-init/x-shellscript"
# shellcheck disable=SC2001
echo "$CLD_SH_TEMPLATE" | sed -e "s@PLACEHOLDER@$injects@g" > "$CLD_SH"
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Install TDX guest kernel

This plugin is used to install a TDX guest kernel from a given local repository.

# Prerequisite

Prepare the local repository and confirm that there are Debian packages related to the TDX kernel in the `/jammy/amd64/` directory of this repository. It is recommended to place this local repository in the `pre-stage/artifacts/` directory.
```
mkdir -p ./pre-stage/artifacts
mv <your guest repo> ./pre-stage/artifacts/
```

Set `${CVM_TDX_GUEST_REPO}` to the repository absolute path, or this plugin will be skipped.
```
export CVM_TDX_GUEST_REPO=$(pwd)/pre-stage/artifacts/<your guest repo>
# Or
export CVM_TDX_GUEST_REPO=<your local guest repo>
```


_NOTE: IF the original image is smaller than 1.5G, please set the environment variable GUEST\_SIZE to a larger value, as this will result in the execution of plugin 01._
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

DIR=$(dirname "$(readlink -f "$0")")
CLD_DIR="$DIR/../cloud-init"

if [[ -d "$CLD_DIR" ]]; then
rm -rf "$CLD_DIR"
fi
Loading

0 comments on commit 9793ab6

Please sign in to comment.