new guest_api working

This commit is contained in:
ghe0 2024-11-28 21:35:56 +02:00
parent e212e9a99c
commit e619d73b8b
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}, io::{BufReader, Read},
}; };
const CRT_FILE: &str = "/tmp/certs/guest_api.crt"; const CRT_FILE: &str = "/tmp/certs/dtrfs_api.crt";
const KEY_FILE: &str = "/tmp/certs/guest_api.key"; const KEY_FILE: &str = "/tmp/certs/dtrfs_api.key";
const CMDLINE_FILE: &str = "/proc/cmdline"; const CMDLINE_FILE: &str = "/proc/cmdline";
lazy_static! { 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)); return HttpResponse::BadRequest().body(format!("Signature verification failed: {}", e));
}; };
match os::encrypt_and_install_os(&form.url, &form.sha, &form.keyfile) { match os::encrypt_and_install_os(&form.url, &form.sha, &form.keyfile) {
Ok(()) => HttpResponse::Ok().body("Successfully installed OS"), Ok(s) => HttpResponse::Ok().body(s),
Err(e) => HttpResponse::BadRequest().body(format!("{e:?}")), Err(e) => HttpResponse::InternalServerError().body(format!("{e:?}")),
} }
} }
@ -179,7 +179,15 @@ fn load_rustls_config() -> rustls::ServerConfig {
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { 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(); let config = load_rustls_config();
HttpServer::new(|| { HttpServer::new(|| {
App::new() App::new()

@ -11,10 +11,15 @@ use std::{
const SNP_KEYFILE_PATH: &str = "/tmp/detee_snp_keyfile"; const SNP_KEYFILE_PATH: &str = "/tmp/detee_snp_keyfile";
const BACKUP_KEYFILE_PATH: &str = "/tmp/detee_backup_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)?; let binary_keyfile = BASE64_URL_SAFE.decode(keyfile)?;
std::fs::write(BACKUP_KEYFILE_PATH, binary_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_URL", install_url)
.env("INSTALL_SHA", install_sha) .env("INSTALL_SHA", install_sha)
.env("SNP_KEY_FILE", SNP_KEYFILE_PATH) .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() { if !install_result.status.success() {
return Err(anyhow!( return Err(anyhow!(
"Could not install OS.\nstdout:{:?}\nstderr:\n{:?}", "OS installation script failed.\nScript stdout:\n{}\nScript stderr:\n{}",
install_result.stdout, String::from_utf8(install_result.stdout)
install_result.stderr .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(format!(
Ok(()) "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<()> { 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()) 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> { pub fn replace_hot_keyfile() -> Result<String> {
let _delete_old_keyfile = Command::new("cryptsetup") let _delete_old_keyfile = Command::new("cryptsetup")
.arg("luksKillSlot") .arg("luksKillSlot")
@ -72,24 +102,6 @@ pub fn replace_hot_keyfile() -> Result<String> {
Ok("Succesfully replaced hot keyfile using SNP KDF.".to_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<()> { pub fn add_ssh_key(key: &str) -> Result<()> {
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
if !Path::new("/mnt/etc/os-release").try_exists().is_ok_and(|found| found == true) { 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_binary $(which fsarchiver)
install_kmod install_kmod
install_busybox install_busybox
install_guest_api install_dtrfs_api
echo_cyan "Installing scripts..." echo_cyan "Installing scripts..."
install_init_script 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 # choose a kernel if you don't want to use the active one
[[ -n "$KERNEL" ]] || [[ -n "$KERNEL" ]] ||
export KERNEL="$(uname -r)" 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 # this will allow you to grab modules from the machine where the installer is running
[[ -n "$GRAB_LOCAL_MODS" ]] || [[ -n "$GRAB_LOCAL_MODS" ]] ||
export GRAB_LOCAL_MODS="no" export GRAB_LOCAL_MODS="no"

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

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

@ -25,25 +25,17 @@ create_mounts() {
ln -sfT /proc/self/fd/2 /dev/stderr 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() { create_certs() {
cert_dir="/tmp/certs" cert_dir="/tmp/certs"
key="$cert_dir/guest_api.key" key="$cert_dir/dtrfs_api.key"
cert="$cert_dir/guest_api.crt" cert="$cert_dir/dtrfs_api.crt"
subject="/C=W3/O=DeTEE/OU=COCO/CN=guest-api" subject="/C=W3/O=DeTEE/OU=COCO/CN=dtrfs-api"
mkdir -p "$cert_dir" mkdir -p "$cert_dir"
openssl genpkey -algorithm RSA -out "$key" \ openssl genpkey -algorithm RSA -out "$key" \
-pkeyopt rsa_keygen_bits:4096 2>/dev/null -pkeyopt rsa_keygen_bits:4096 2>/dev/null
openssl req -x509 -new \ openssl req -x509 -new \
-key "$key" -out "$cert" \ -key "$key" -out "$cert" \
-addext "subjectAltName=DNS:dtrfs-api" \
-days 365 -subj "$subject" 2>/dev/null -days 365 -subj "$subject" 2>/dev/null
} }

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

@ -30,8 +30,16 @@ fi
set -e set -e
mkdir -p tmp # TODO: test if this works
tar cf tmp/dtrfs.tar *.sh 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 rm -rf ${dir}
$ssh $server mkdir -p ${dir} $ssh $server mkdir -p ${dir}
$scp tmp/dtrfs.tar ${scp_server}:${dir} $scp tmp/dtrfs.tar ${scp_server}:${dir}