diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index 0e7769a8b..c81eab970 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -40,13 +40,32 @@ jobs: build-args: | "ASTER_RUST_VERSION=${{ steps.fetch-versions.outputs.rust_version }}" + - name: Generate OSDK Dockerfile + run: | + python3 ./osdk/tools/docker/gen_dockerfile.py + - name: Build and push OSDK test image uses: docker/build-push-action@v4 with: context: . - file: ./osdk/tools/Dockerfile.ubuntu22.04 + file: ./osdk/tools/docker/Dockerfile platforms: linux/amd64 push: true tags: asterinas/osdk:${{ steps.fetch-versions.outputs.aster_version }} build-args: | "ASTER_RUST_VERSION=${{ steps.fetch-versions.outputs.rust_version }}" + + - name: Generate OSDK Dockerfile for Intel TDX + run: | + python3 ./osdk/tools/docker/gen_dockerfile.py --intel-tdx + + - name: Build and push OSDK test image for Intel TDX + uses: docker/build-push-action@v4 + with: + context: . + file: ./osdk/tools/docker/Dockerfile + platforms: linux/amd64 + push: true + tags: asterinas/osdk:${{ steps.fetch-versions.outputs.aster_version }}-tdx + build-args: | + "ASTER_RUST_VERSION=${{ steps.fetch-versions.outputs.rust_version }}" diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index c14bdf60f..2712d2888 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -24,6 +24,8 @@ * [Creating an OS Project](osdk/guide/create-project.md) * [Testing or Running an OS Project](osdk/guide/run-project.md) * [Working in a Workspace](osdk/guide/work-in-workspace.md) + * Advanced Topics + * [Intel TDX](osdk/guide/intel-tdx.md) * [OSDK User Reference](osdk/reference/README.md) * [Commands](osdk/reference/commands/README.md) * [cargo osdk new](osdk/reference/commands/new.md) diff --git a/docs/src/osdk/guide/intel-tdx.md b/docs/src/osdk/guide/intel-tdx.md new file mode 100644 index 000000000..98a770e46 --- /dev/null +++ b/docs/src/osdk/guide/intel-tdx.md @@ -0,0 +1,81 @@ +# Running an OS in Intel TDX env + +OSDK supports running your OS in an [Intel TDX](https://www.intel.com/content/www/us/en/developer/tools/trust-domain-extensions/overview.html) environment conveniently. +Intel TDX can provide a more secure environment for your OS. + +## Prepare the Intel TDX Environment + +Please make sure your server supports Intel TDX. + +See [this guide](https://github.com/canonical/tdx/tree/noble-24.04?tab=readme-ov-file#4-setup-host-os) +or other materials to enable Intel TDX in host OS. + +To verify the TDX host status, you can type: + +```bash +dmesg | grep "TDX module initialized" +``` + +The following result is an example: + +```bash +[ 20.507296] tdx: TDX module initialized. +``` + +If you see the message "TDX module initialized", +it means the TDX module has loaded successfully. + +The Intel TDX environment requires TDX-enhanced versions of QEMU, KVM, GRUB, +and other essential software for running an OS. +Therefore, it is recommended to use a Docker image to deploy the environment. + +Run a TDX Docker container: + +```bash +docker run -it --privileged --network=host --device=/dev/kvm asterinas/osdk-tdx:0.4.2 +``` + +## Edit `OSDK.toml` for Intel TDX support + +As Intel TDX has extra requirements or restrictions for VMs, +it demands adjusting the OSDK configurations accordingly. +This can be easily achieved with the `scheme` feature of OSDK, +which provides a convenient way to override the default OSDK configurations +for a specific environment. + +For example, you can append the following TDX-specific scheme to your `OSDK.toml` file. + +```toml +[scheme."tdx"] +supported_archs = ["x86_64"] +boot.method = "grub-qcow2" +grub.mkrescue_path = "~/tdx-tools/grub" +grub.protocol = "linux" +qemu.args = """\ + -accel kvm \ + -name process=tdxvm,debug-threads=on \ + -m 6G \ + -vga none \ + -monitor pty \ + -no-hpet \ + -nodefaults \ + -drive file=target/osdk/asterinas/asterinas.qcow2,if=virtio,format=qcow2 \ + -monitor telnet:127.0.0.1:9001,server,nowait \ + -bios /usr/share/qemu/OVMF.fd \ + -object tdx-guest,sept-ve-disable=on,id=tdx,quote-generation-service=vsock:2:4050 \ + -object memory-backend-memfd-private,id=ram1,size=2G \ + -cpu host,-kvm-steal-time,pmu=off,tsc-freq=1000000000 \ + -machine q35,kernel_irqchip=split,confidential-guest-support=tdx,memory-backend=ram1 \ + -smp 1 \ + -nographic \ +""" +``` + +To choose the configurations specified by the TDX scheme over the default ones, +add the `--scheme` argument to the build, run, or test command. + +```bash +cargo osdk build --scheme tdx +cargo osdk run --scheme tdx +cargo osdk test --scheme tdx +``` diff --git a/osdk/tools/Dockerfile.ubuntu22.04 b/osdk/tools/Dockerfile.ubuntu22.04 deleted file mode 100644 index a7e0c62d3..000000000 --- a/osdk/tools/Dockerfile.ubuntu22.04 +++ /dev/null @@ -1,50 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 - -# This image is for the OSDK GitHub CI. -# The environment is consistent with the one -# described in the OSDK User Guide section of the Asterinas Book. -# -# TODO: We should build the Asterinas image based on the OSDK image -# since Asterinas is managed by OSDK itself. -# However, currently, these two images have different contents. -# The main distinction is that -# QEMU, grub, and OVMF in the OSDK image are installed via apt, -# while these tools in the Asterinas image are built from source. -# Some boot methods in Asterinas only function properly -# when using the tools that are built from source. - -FROM ubuntu:22.04 - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt update \ - && apt install -y \ - build-essential \ - curl \ - gdb \ - grub-efi-amd64 \ - grub2-common \ - libpixman-1-dev `# running dependency for QEMU` \ - mtools `# used by grub-mkrescue` \ - ovmf \ - qemu-system-x86 \ - xorriso \ - && apt clean \ - && rm -rf /var/lib/apt/lists/* - -# Install Rust of both nightly and stable channel -ENV PATH="/root/.cargo/bin:${PATH}" -ARG ASTER_RUST_VERSION -RUN curl https://sh.rustup.rs -sSf | \ - sh -s -- --default-toolchain ${ASTER_RUST_VERSION} -y \ - && rustup toolchain install stable \ - && rm -rf /root/.cargo/registry && rm -rf /root/.cargo/git \ - && cargo -V \ - && rustup component add rust-src rustc-dev llvm-tools-preview - -# Install cargo-binutils -RUN cargo install cargo-binutils - -VOLUME [ "/root/asterinas" ] - -WORKDIR /root/asterinas diff --git a/osdk/tools/docker/.gitignore b/osdk/tools/docker/.gitignore new file mode 100644 index 000000000..5a044a197 --- /dev/null +++ b/osdk/tools/docker/.gitignore @@ -0,0 +1 @@ +**/Dockerfile \ No newline at end of file diff --git a/osdk/tools/docker/Dockerfile.template b/osdk/tools/docker/Dockerfile.template new file mode 100644 index 000000000..39d4aef34 --- /dev/null +++ b/osdk/tools/docker/Dockerfile.template @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: MPL-2.0 + +FROM {% base_image %} + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt update \ + && apt install -y \ + build-essential \ + curl \ + gdb \ + grub-efi-amd64 \ + grub2-common \ + libpixman-1-dev `# running dependency for QEMU` \ + mtools `# used by grub-mkrescue` \ + xorriso \ + {% qemu_ovmf_installation %} \ + && apt clean \ + && rm -rf /var/lib/apt/lists/* + +# Install Rust of both nightly and stable channel +ENV PATH="/root/.cargo/bin:${PATH}" +ARG ASTER_RUST_VERSION +RUN curl https://sh.rustup.rs -sSf | \ + sh -s -- --default-toolchain ${ASTER_RUST_VERSION} -y \ + && rustup toolchain install stable \ + && rm -rf /root/.cargo/registry && rm -rf /root/.cargo/git \ + && cargo -V \ + && rustup component add rust-src rustc-dev llvm-tools-preview + +# Install cargo-binutils +RUN cargo install cargo-binutils + +VOLUME [ "/root/asterinas" ] + +WORKDIR /root/asterinas diff --git a/osdk/tools/build_image.sh b/osdk/tools/docker/build_image.sh similarity index 59% rename from osdk/tools/build_image.sh rename to osdk/tools/docker/build_image.sh index 259f12220..40e797d0a 100755 --- a/osdk/tools/build_image.sh +++ b/osdk/tools/docker/build_image.sh @@ -5,11 +5,18 @@ set -e SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) -ASTER_ROOT_DIR=${SCRIPT_DIR}/../.. +ASTER_ROOT_DIR=${SCRIPT_DIR}/../../.. ASTER_RUST_VERSION=$( grep -m1 -o 'nightly-[0-9]\+-[0-9]\+-[0-9]\+' ${ASTER_ROOT_DIR}/rust-toolchain.toml ) VERSION=$( cat ${ASTER_ROOT_DIR}/VERSION ) -IMAGE_NAME=asterinas/osdk:${VERSION} -DOCKERFILE=${SCRIPT_DIR}/Dockerfile.ubuntu22.04 +DOCKERFILE=${SCRIPT_DIR}/Dockerfile + +if [ "$1" = "intel-tdx" ]; then + IMAGE_NAME="asterinas/osdk:${VERSION}-tdx" + python3 gen_dockerfile.py --intel-tdx +else + IMAGE_NAME="asterinas/osdk:${VERSION}" + python3 gen_dockerfile.py +fi docker build \ -t ${IMAGE_NAME} \ diff --git a/osdk/tools/docker/gen_dockerfile.py b/osdk/tools/docker/gen_dockerfile.py new file mode 100644 index 000000000..6d604b58e --- /dev/null +++ b/osdk/tools/docker/gen_dockerfile.py @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: MPL-2.0 + +import re +import argparse +import os +import sys +import logging + +# Setup logging +logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + +def parse_arguments(): + parser = argparse.ArgumentParser(description='The Dockerfile generator for OSDK.') + parser.add_argument('--intel-tdx', action='store_true', help='Include Intel TDX support') + parser.add_argument( + '--out-dir', + type=str, + default='.', + help='Output the Dockerfile under this directory. \ + By default, the output directory is the current working directory.' + ) + return parser.parse_args() + +def validate_out_dir(out_dir): + if os.path.isabs(out_dir): + print("Error: The --out-dir argument must be a relative path.") + sys.exit(1) + +def setup_output_directory(out_dir): + template_dir = os.path.dirname(os.path.abspath(__file__)) + if out_dir == '.': + return template_dir + output_directory_path = os.path.join(template_dir, out_dir) + if not os.path.exists(output_directory_path): + os.makedirs(output_directory_path) + return output_directory_path + +def load_template(template_dir): + template_file = os.path.join(template_dir, 'Dockerfile.template') + if not os.path.isfile(template_file): + logging.error(f"Template file {template_file} does not exist.") + sys.exit(1) + with open(template_file, 'r') as file: + return file.read() + +def generate_dockerfile_content(variables, template_content): + for var_name, var_value in variables.items(): + template_content = re.sub(r'{%\s*' + var_name + r'\s*%}', var_value, template_content) + return template_content + +def write_dockerfile(output_directory, content): + output_path = os.path.join(output_directory, 'Dockerfile') + with open(output_path, 'w') as file: + file.write(content) + logging.info(f'Dockerfile has been generated at {output_path}.') + +def main(): + args = parse_arguments() + validate_out_dir(args.out_dir) + + variables = { + 'base_image': r'ubuntu:22.04', + 'qemu_ovmf_installation': r"""ovmf \ + qemu-system-x86""", + } + + if args.intel_tdx: + variables['base_image'] = r'intelcczoo/tdvm:ubuntu22.04-mvp_2023ww15' + variables['qemu_ovmf_installation'] = r'' + + template_dir = os.path.dirname(os.path.abspath(__file__)) + output_directory = setup_output_directory(args.out_dir) + template_content = load_template(template_dir) + dockerfile_content = generate_dockerfile_content(variables, template_content) + write_dockerfile(output_directory, dockerfile_content) + +if __name__ == '__main__': + main() diff --git a/osdk/tools/run_container.sh b/osdk/tools/docker/run_container.sh similarity index 66% rename from osdk/tools/run_container.sh rename to osdk/tools/docker/run_container.sh index c2f2ad0be..3591a216e 100755 --- a/osdk/tools/run_container.sh +++ b/osdk/tools/docker/run_container.sh @@ -7,6 +7,11 @@ set -e SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) ASTER_ROOT_DIR=${SCRIPT_DIR}/../.. VERSION=$( cat ${ASTER_ROOT_DIR}/VERSION ) -IMAGE_NAME=asterinas/osdk:${VERSION} + +if [ "$1" = "intel-tdx" ]; then + IMAGE_NAME="asterinas/osdk:${VERSION}-tdx" +else + IMAGE_NAME="asterinas/osdk:${VERSION}" +fi docker run -it -v ${ASTER_ROOT_DIR}:/root/asterinas ${IMAGE_NAME}