new guest_api working

This commit is contained in:
ghe0 2024-11-28 21:35:56 +02:00
parent e212e9a99c
commit f9781c659b
Signed by: ghe0
GPG Key ID: 451028EE56A0FBB4
9 changed files with 92 additions and 73 deletions

@ -15,8 +15,8 @@ use std::{
io::{BufReader, Read},
};
const CRT_FILE: &str = "/tmp/certs/guest_api.crt";
const KEY_FILE: &str = "/tmp/certs/guest_api.key";
const CRT_FILE: &str = "/tmp/certs/dtrfs_api.crt";
const KEY_FILE: &str = "/tmp/certs/dtrfs_api.key";
const CMDLINE_FILE: &str = "/proc/cmdline";
lazy_static! {
@ -94,8 +94,8 @@ async fn post_install_form(req: HttpRequest, form: web::Form<InstallForm>) -> Ht
return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e));
};
match os::encrypt_and_install_os(&form.url, &form.sha, &form.keyfile) {
Ok(()) => HttpResponse::Ok().body("Successfully installed OS"),
Err(e) => HttpResponse::BadRequest().body(format!("{e:?}")),
Ok(s) => HttpResponse::Ok().body(s),
Err(e) => HttpResponse::InternalServerError().body(format!("{e:?}")),
}
}
@ -179,7 +179,15 @@ fn load_rustls_config() -> rustls::ServerConfig {
#[actix_web::main]
async fn main() -> std::io::Result<()> {
os::try_hot_keyfile().unwrap();
match os::try_hot_keyfile() {
Ok(_) => {
println!("Hot decryption successful. Booting OS...");
return Ok(());
},
Err(e) => {
println!("Hot decryption failed: {e:?}");
}
}
let config = load_rustls_config();
HttpServer::new(|| {
App::new()

@ -11,10 +11,15 @@ use std::{
const SNP_KEYFILE_PATH: &str = "/tmp/detee_snp_keyfile";
const BACKUP_KEYFILE_PATH: &str = "/tmp/detee_backup_keyfile";
pub fn encrypt_and_install_os(install_url: &str, install_sha: &str, keyfile: &str) -> Result<()> {
pub fn encrypt_and_install_os(
install_url: &str,
install_sha: &str,
keyfile: &str,
) -> Result<String> {
let binary_keyfile = BASE64_URL_SAFE.decode(keyfile)?;
std::fs::write(BACKUP_KEYFILE_PATH, binary_keyfile)?;
let install_result = Command::new("install_os.sh")
// this path is hardcoded also in the initrd creation script
let install_result = Command::new("/usr/lib/dtrfs/install_os.sh")
.env("INSTALL_URL", install_url)
.env("INSTALL_SHA", install_sha)
.env("SNP_KEY_FILE", SNP_KEYFILE_PATH)
@ -23,13 +28,20 @@ pub fn encrypt_and_install_os(install_url: &str, install_sha: &str, keyfile: &st
if !install_result.status.success() {
return Err(anyhow!(
"Could not install OS.\nstdout:{:?}\nstderr:\n{:?}",
install_result.stdout,
install_result.stderr
"OS installation script failed.\nScript stdout:\n{}\nScript stderr:\n{}",
String::from_utf8(install_result.stdout)
.unwrap_or("Could not grab stdout from installation script.".to_string()),
String::from_utf8(install_result.stderr)
.unwrap_or("Could not grab stderr from installation script.".to_string()),
));
}
Ok(())
Ok(format!(
"Successfully installed OS. Script stdout:\n{}\nScript stderr:\n{}",
String::from_utf8(install_result.stdout)
.unwrap_or("Could not grab stdout from installation script.".to_string()),
String::from_utf8(install_result.stderr)
.unwrap_or("Could not grab stderr from installation script.".to_string()),
))
}
pub fn try_hot_keyfile() -> Result<()> {
@ -46,6 +58,24 @@ pub fn try_backup_keyfile(keyfile: &str) -> Result<String> {
Ok("Succesfully mounted /mnt using backup keyfile.".to_string())
}
fn decrypt_and_mount(keyfile_path: &str) -> Result<()> {
let decryption_result = Command::new("cryptsetup")
.arg("open")
.arg("--key-file")
.arg(keyfile_path)
.arg("/dev/vda1")
.arg("root")
.output()?;
if !decryption_result.status.success() {
return Err(anyhow!("Could not decrypt disk."));
}
let mount_result = Command::new("mount").arg("/dev/mapper/root").arg("/mnt").output()?;
if !mount_result.status.success() {
return Err(anyhow!("Could not mount /dev/mapper/root to /mnt"));
}
Ok(())
}
pub fn replace_hot_keyfile() -> Result<String> {
let _delete_old_keyfile = Command::new("cryptsetup")
.arg("luksKillSlot")
@ -72,24 +102,6 @@ pub fn replace_hot_keyfile() -> Result<String> {
Ok("Succesfully replaced hot keyfile using SNP KDF.".to_string())
}
fn decrypt_and_mount(keyfile_path: &str) -> Result<()> {
let decryption_result = Command::new("cryptsetup")
.arg("open")
.arg("--key-file")
.arg(keyfile_path)
.arg("/dev/vda1")
.arg("root")
.output()?;
if !decryption_result.status.success() {
return Err(anyhow!("Could not decrypt disk."));
}
let mount_result = Command::new("mount").arg("/dev/mapper/root").arg("/mnt").output()?;
if !mount_result.status.success() {
return Err(anyhow!("Could not mount /dev/mapper/root to /mnt"));
}
Ok(())
}
pub fn add_ssh_key(key: &str) -> Result<()> {
use std::os::unix::fs::PermissionsExt;
if !Path::new("/mnt/etc/os-release").try_exists().is_ok_and(|found| found == true) {

@ -23,7 +23,7 @@ install_binary $(which mkfs.ext4)
install_binary $(which fsarchiver)
install_kmod
install_busybox
install_guest_api
install_dtrfs_api
echo_cyan "Installing scripts..."
install_init_script

@ -10,9 +10,6 @@ script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
# choose a kernel if you don't want to use the active one
[[ -n "$KERNEL" ]] ||
export KERNEL="$(uname -r)"
# this is the DeTEE Guest API that allows you to control the initrd
[[ -n "$GUEST_API_URL" ]] ||
export GUEST_API_URL="https://gitea.detee.cloud/ghe0/stuff/releases/download/v0.0.0/guest_api.zst"
# this will allow you to grab modules from the machine where the installer is running
[[ -n "$GRAB_LOCAL_MODS" ]] ||
export GRAB_LOCAL_MODS="no"

@ -32,9 +32,8 @@ install_build_deps() {
create_dirs() {
rm -rf "$ROOT" 2>/dev/null
mkdir -p "${ROOT}/usr/bin/"
mkdir -p "${ROOT}/usr/bin"
mkdir -p "${ROOT}/usr/lib"
mkdir -p "${ROOT}/usr/lib/dtrfs"
mkdir -p "${ROOT}/dev"
mkdir -p "${ROOT}/etc"
mkdir -p "${ROOT}/mnt"
@ -47,9 +46,9 @@ create_dirs() {
ln -s usr/bin "${ROOT}/sbin"
ln -s usr/lib "${ROOT}/lib"
ln -s usr/lib "${ROOT}/lib64"
ln -s lib "${ROOT}/usr/lib64"
ln -s bin "${ROOT}/usr/sbin"
ln -s ../run "${ROOT}/var/run"
ln -s lib "${ROOT}/usr/lib64"
ln -s bin "${ROOT}/usr/sbin"
ln -s ../run "${ROOT}/var/run"
}
# Installs a library. Expects absolute path.
@ -116,7 +115,8 @@ install_busybox() {
install_init_script() {
cp ../init.sh "${ROOT}/init"
cp ../init_functions.sh "${ROOT}/"
cp ../init_functions.sh "${ROOT}/usr/lib/dtrfs/"
cp ../install_os.sh "${ROOT}/usr/lib/dtrfs/"
}
install_module() {
@ -182,13 +182,14 @@ scan_modules() {
done <<< "$( echo "$drivers" )"
}
install_guest_api() {
echo_cyan "Installing the guest API from https://gitea.detee.cloud/SNP/remote_decryption/"
wget -O guest_api.zst "$GUEST_API_URL" 2> /dev/null
zstd --decompress guest_api.zst
chmod +x guest_api
install_binary "$(pwd)/guest_api"
rm guest_api guest_api.zst
install_dtrfs_api() {
local my_location="$(pwd)"
cd ../../dtrfs_api && cargo build --release || {
echo_yellow "Could not build dtrfs_api. Looking for binary at $(pwd)/dtrfs_api"
}
cd "$my_location"
cp ../../dtrfs_api/target/release/dtrfs_api ./
install_binary "$(pwd)/dtrfs_api"
}
create_archive() {
@ -200,5 +201,5 @@ create_archive() {
find . | cpio -o -H newc | gzip \
> "${my_location}/detee-$(hostnamectl hostname)-${KERNEL}.cpio.gz"
cd $my_location
cd "$my_location"
}

@ -1,5 +1,5 @@
#!/bin/bash
source /init_functions.sh
source /usr/lib/dtrfs/init_functions.sh
install_url="/tmp/detee_install_url"
install_sha="/tmp/detee_install_sha"
@ -14,6 +14,7 @@ setup_network
# load this module again cause it fails the first time
modprobe sev_guest
create_certs
dtrfs_api
github_ssh_key

@ -25,25 +25,17 @@ create_mounts() {
ln -sfT /proc/self/fd/2 /dev/stderr
}
try_hot_decrypt() {
[[ -f "$snp_key_file" ]] && {
cryptsetup open --key-file $snp_key_file /dev/vda1 root || return 1
mount /dev/mapper/root /mnt || return 1
return 0
}
return 1
}
create_certs() {
cert_dir="/tmp/certs"
key="$cert_dir/guest_api.key"
cert="$cert_dir/guest_api.crt"
subject="/C=W3/O=DeTEE/OU=COCO/CN=guest-api"
key="$cert_dir/dtrfs_api.key"
cert="$cert_dir/dtrfs_api.crt"
subject="/C=W3/O=DeTEE/OU=COCO/CN=dtrfs-api"
mkdir -p "$cert_dir"
openssl genpkey -algorithm RSA -out "$key" \
-pkeyopt rsa_keygen_bits:4096 2>/dev/null
openssl req -x509 -new \
-key "$key" -out "$cert" \
-addext "subjectAltName=DNS:dtrfs-api" \
-days 365 -subj "$subject" 2>/dev/null
}

@ -2,12 +2,12 @@
# This script is called by dtrfs_api to install an OS.
[[ -z "$INSTALL_URL" ]] || {
[[ -z "$INSTALL_URL" ]] && {
echo "Did not find INSTALL_URL env variable".
exit 1
}
[[ -z "$INSTALL_URL" ]] || {
[[ -z "$INSTALL_URL" ]] && {
echo "Did not find INSTALL_SHA env variable".
exit 2
}
@ -33,23 +33,23 @@ echo === Creating partition /dev/vda1
echo w
) | fdisk /dev/vda
echo "=== Formatting /dev/vda1 using cryptsetup luksFormat and opening as root"
cryptsetup luksFormat --batch-mode -d $root_keyfile /dev/vda1
cryptsetup luksFormat --batch-mode -d $ROOT_KEYFILE /dev/vda1 || exit 5
[[ -f "$SNP_KEY_FILE" ]] && {
echo "Adding LUKS slot via SNP KDF key found at $SNP_KEY_FILE"
cryptsetup luksAddKey \
--key-file $ROOT_KEYFILE \
cryptsetup luksAddKey \
--key-file $ROOT_KEYFILE \
--new-keyfile $SNP_KEY_FILE /dev/vda1
}
cryptsetup open -d $ROOT_KEYFILE /dev/vda1 root
cryptsetup open -d $ROOT_KEYFILE /dev/vda1 root || exit 6
echo "=== Formatting /dev/mapper/root as ext4 and mounting at /mnt"
mkfs.ext4 /dev/mapper/root
mount /dev/mapper/root /mnt
mkfs.ext4 /dev/mapper/root || exit 7
mount /dev/mapper/root /mnt || exit 8
echo "=== Downloading OS template from $INSTALL_URL and verifying hash"
wget -O /mnt/template.fsa "$INSTALL_URL" || {
echo "Failed to download $INSTALL_URL"
exit 5
exit 9
}
sha256sum /mnt/template.fsa | grep $(cat ${INSTALL_SHA}) || exit 1
sha256sum /mnt/template.fsa | grep "${INSTALL_SHA}" || exit 1
echo "=== Installing OS template"
fsarchiver restdir /mnt/template.fsa /
rm /mnt/template.fsa

@ -30,8 +30,16 @@ fi
set -e
mkdir -p tmp
tar cf tmp/dtrfs.tar *.sh
# TODO: test if this works
mkdir -p tmp build
my_location="$(pwd)"
cd ../dtrfs_api && cargo build --release || {
echo Could not build dtrfs_api
exit 1
}
cd "$my_location"
cp ../dtrfs_api/target/release/dtrfs_api ./build/
tar cf tmp/dtrfs.tar *.sh build/dtrfs_api arch_guest_mods
$ssh $server rm -rf ${dir}
$ssh $server mkdir -p ${dir}
$scp tmp/dtrfs.tar ${scp_server}:${dir}