From 77f2995131d2b3bf4c32c71e74c7f2fbb18f7400 Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Tue, 27 Jan 2026 07:49:12 +0300 Subject: [PATCH 01/10] CUBE-135 - Fix cloud init Signed-off-by: WashingtonKK --- hal/ubuntu/qemu.sh | 531 +++++++++++++++++---------------- hal/ubuntu/user-data-base.yaml | 112 +++++++ hal/ubuntu/user-data-tdx.yaml | 153 ++++++++++ 3 files changed, 539 insertions(+), 257 deletions(-) create mode 100644 hal/ubuntu/user-data-base.yaml create mode 100644 hal/ubuntu/user-data-tdx.yaml diff --git a/hal/ubuntu/qemu.sh b/hal/ubuntu/qemu.sh index b078516e..c0671d7c 100755 --- a/hal/ubuntu/qemu.sh +++ b/hal/ubuntu/qemu.sh @@ -1,13 +1,17 @@ #!/bin/bash # Copyright (c) Ultraviolet # SPDX-License-Identifier: Apache-2.0 +# +# QEMU launch script for Ubuntu cloud images with CVM (TDX/SNP) support +set -e + +# Default configuration BASE_IMAGE_URL="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" BASE_IMAGE="ubuntu-base.qcow2" CUSTOM_IMAGE="ubuntu-custom.qcow2" DISK_SIZE="35G" SEED_IMAGE="seed.img" -USER_DATA="user-data" META_DATA="meta-data" VM_NAME="cube-ai-vm" RAM="16384M" @@ -17,264 +21,277 @@ PASSWORD="password" QEMU_BINARY="qemu-system-x86_64" OVMF_CODE="/usr/share/OVMF/OVMF_CODE.fd" OVMF_VARS="/usr/share/OVMF/OVMF_VARS.fd" -OVMF_VARS_COPY="OVMF_VARS.fd" # Per-VM copy of OVMF vars -ENABLE_CVM="${ENABLE_CVM:-auto}" # Options: auto, tdx, none - -if ! command -v wget &> /dev/null; then - echo "wget is not installed. Please install it and try again." - exit 1 -fi - -if ! command -v cloud-localds &> /dev/null; then - echo "cloud-localds is not installed. Please install it and try again." - exit 1 -fi - -if ! command -v qemu-system-x86_64 &> /dev/null; then - echo "qemu-system-x86_64 is not installed. Please install it and try again." - exit 1 -fi - -if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root" 1>&2 - exit 1 -fi - -if [ ! -f $BASE_IMAGE ]; then - echo "Downloading base Ubuntu image..." - wget -q $BASE_IMAGE_URL -O $BASE_IMAGE -fi - -echo "Creating custom QEMU image..." -qemu-img create -f qcow2 -b $BASE_IMAGE -F qcow2 $CUSTOM_IMAGE $DISK_SIZE - -# Create a writable copy of OVMF_VARS for this VM instance -if [ ! -f $OVMF_VARS_COPY ]; then - echo "Creating OVMF vars copy..." - cp $OVMF_VARS $OVMF_VARS_COPY -fi - -# We don't upgrade the system since this changes initramfs -cat <<'EOF' > $USER_DATA -#cloud-config -package_update: true -package_upgrade: false - -users: - - name: ultraviolet - plain_text_passwd: password - lock_passwd: false - sudo: ALL=(ALL) NOPASSWD:ALL - shell: /bin/bash - - name: ollama - system: true - home: /var/lib/ollama - shell: /usr/sbin/nologin - -ssh_pwauth: true - -packages: - - curl - - git - - golang-go - - build-essential - -write_files: - - path: /etc/cube/agent.env - content: | - UV_CUBE_AGENT_LOG_LEVEL=info - UV_CUBE_AGENT_HOST=0.0.0.0 - UV_CUBE_AGENT_PORT=7001 - UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 - UV_CUBE_AGENT_TARGET_URL=http://localhost:11434 - UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt - UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key - UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt - UV_CUBE_AGENT_CA_URL=https://prism.ultraviolet.rs/am-certs - permissions: '0644' - - path: /etc/systemd/system/ollama.service - content: | - [Unit] - Description=Ollama Service - After=network-online.target - Wants=network-online.target - - [Service] - Type=simple - User=ollama - Group=ollama - Environment="OLLAMA_HOST=0.0.0.0:11434" - ExecStart=/usr/local/bin/ollama serve - Restart=always - RestartSec=3 - - [Install] - WantedBy=multi-user.target - permissions: '0644' - - path: /etc/systemd/system/cube-agent.service - content: | - [Unit] - Description=Cube Agent Service - After=network-online.target ollama.service - Wants=network-online.target - - [Service] - Type=simple - EnvironmentFile=/etc/cube/agent.env - ExecStart=/usr/local/bin/cube-agent - Restart=on-failure - RestartSec=5 - StartLimitBurst=5 - StartLimitIntervalSec=60 - - [Install] - WantedBy=multi-user.target - permissions: '0644' - - path: /usr/local/bin/pull-ollama-models.sh - content: | - #!/bin/bash - # Wait for ollama to be ready - for i in $(seq 1 60); do - if curl -s http://localhost:11434/api/version > /dev/null 2>&1; then - break - fi - sleep 2 - done - # Pull models - /usr/local/bin/ollama pull llama3.2:3b - /usr/local/bin/ollama pull starcoder2:3b - /usr/local/bin/ollama pull nomic-embed-text:v1.5 - permissions: '0755' - -runcmd: - - echo 'ultraviolet:password' | chpasswd - - | - cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' - PasswordAuthentication yes - SSHEOF - - systemctl restart sshd - - sleep 2 - - | - # Install TDX-capable kernel from Ubuntu's intel-tdx PPA - add-apt-repository -y ppa:kobuk-team/intel-tdx || echo "PPA add failed, trying canonical tdx" - apt-get update || true - apt-get install -y linux-image-generic linux-modules-extra-generic || echo "Kernel install failed" - # Try to load TDX guest module - modprobe tdx_guest 2>/dev/null || echo "tdx_guest module not yet available (may need reboot)" - # Add to modules to load at boot - mkdir -p /etc/modules-load.d - echo "tdx_guest" > /etc/modules-load.d/tdx.conf - - mkdir -p /etc/cube - - mkdir -p /etc/cube/certs - - | - # Generate CA certificate - openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" - # Generate server certificate - openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" - openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 - # Generate client certificate for mTLS - openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" - openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 - # Set permissions - chmod 600 /etc/cube/certs/*.key - chmod 644 /etc/cube/certs/*.crt - - mkdir -p /var/lib/ollama - - mkdir -p /home/ollama/.ollama - - chown -R ollama:ollama /var/lib/ollama - - chown -R ollama:ollama /home/ollama - - curl -fsSL https://ollama.com/install.sh | sh - - git clone https://github.com/ultravioletrs/cube.git /tmp/cube - - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 - - export HOME=/root - - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent - - systemctl daemon-reload - - systemctl enable ollama.service - - systemctl start ollama.service - - systemctl enable cube-agent.service - - systemctl start cube-agent.service - - nohup /usr/local/bin/pull-ollama-models.sh > /var/log/ollama-pull.log 2>&1 & - -final_message: "Cube Agent and Ollama services started." -EOF +OVMF_VARS_COPY="OVMF_VARS.fd" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# CVM mode: auto, tdx, snp, none +ENABLE_CVM="${ENABLE_CVM:-auto}" + +function check_dependencies() { + local missing=() + + if ! command -v wget &> /dev/null; then + missing+=("wget") + fi + + if ! command -v cloud-localds &> /dev/null; then + missing+=("cloud-localds (cloud-image-utils)") + fi + + if ! command -v qemu-system-x86_64 &> /dev/null; then + missing+=("qemu-system-x86_64") + fi + + if [ ${#missing[@]} -ne 0 ]; then + echo "Missing dependencies: ${missing[*]}" + echo "Please install them and try again." + exit 1 + fi +} + +function check_root() { + if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" 1>&2 + exit 1 + fi +} + +function detect_cvm_support() { + local tdx_available=false + local snp_available=false -cat < $META_DATA + # Check for TDX host support + if dmesg 2>/dev/null | grep -q "virt/tdx: module initialized"; then + tdx_available=true + echo "TDX host support detected (module initialized)" + elif grep -q tdx /proc/cpuinfo 2>/dev/null; then + tdx_available=true + echo "TDX CPU support detected" + fi + + # Check for SEV-SNP host support + if [ -e /dev/sev ]; then + snp_available=true + echo "SEV device detected" + fi + if dmesg 2>/dev/null | grep -q "SEV-SNP supported"; then + snp_available=true + echo "SEV-SNP host support detected" + elif grep -q sev /proc/cpuinfo 2>/dev/null; then + snp_available=true + echo "SEV CPU support detected" + fi + + # Return detected support + if [ "$tdx_available" = true ]; then + echo "tdx" + elif [ "$snp_available" = true ]; then + echo "snp" + else + echo "none" + fi +} + +function download_base_image() { + if [ ! -f "$BASE_IMAGE" ]; then + echo "Downloading base Ubuntu image..." + wget -q --show-progress "$BASE_IMAGE_URL" -O "$BASE_IMAGE" + else + echo "Base image already exists: $BASE_IMAGE" + fi +} + +function create_custom_image() { + echo "Creating custom QEMU image..." + qemu-img create -f qcow2 -b "$BASE_IMAGE" -F qcow2 "$CUSTOM_IMAGE" "$DISK_SIZE" +} + +function create_ovmf_vars_copy() { + if [ ! -f "$OVMF_VARS_COPY" ]; then + echo "Creating OVMF vars copy..." + cp "$OVMF_VARS" "$OVMF_VARS_COPY" + fi +} + +function create_seed_image() { + local user_data_file="$1" + + echo "Creating seed image with $user_data_file..." + + # Create meta-data + cat < "$META_DATA" instance-id: iid-${VM_NAME} local-hostname: $VM_NAME EOF -echo "Creating ubuntu seed image..." -cloud-localds $SEED_IMAGE $USER_DATA $META_DATA - -# Detect TDX support -TDX_AVAILABLE=false -if [ "$ENABLE_CVM" = "auto" ] || [ "$ENABLE_CVM" = "tdx" ]; then - # Check if TDX is initialized on the host (for creating guest VMs) - if dmesg | grep -q "virt/tdx: module initialized"; then - TDX_AVAILABLE=true - echo "TDX host support detected" - elif grep -q tdx /proc/cpuinfo; then - TDX_AVAILABLE=true - echo "TDX CPU support detected" - else - echo "TDX not available on host" - fi -fi - -# Override if explicitly set -if [ "$ENABLE_CVM" = "tdx" ]; then - TDX_AVAILABLE=true - echo "TDX mode forced via ENABLE_CVM=tdx" -elif [ "$ENABLE_CVM" = "none" ]; then - TDX_AVAILABLE=false - echo "CVM disabled via ENABLE_CVM=none" -fi - -# Build QEMU command based on TDX availability -QEMU_CMD="$QEMU_BINARY" -QEMU_OPTS="-name $VM_NAME" -QEMU_OPTS="$QEMU_OPTS -m $RAM" -QEMU_OPTS="$QEMU_OPTS -smp $CPU" -QEMU_OPTS="$QEMU_OPTS -enable-kvm" -QEMU_OPTS="$QEMU_OPTS -boot d" -QEMU_OPTS="$QEMU_OPTS -netdev user,id=vmnic,hostfwd=tcp::6190-:22,hostfwd=tcp::6191-:80,hostfwd=tcp::6192-:443,hostfwd=tcp::6193-:7001" -QEMU_OPTS="$QEMU_OPTS -nographic" -QEMU_OPTS="$QEMU_OPTS -no-reboot" -QEMU_OPTS="$QEMU_OPTS -drive file=$SEED_IMAGE,media=cdrom" -QEMU_OPTS="$QEMU_OPTS -drive file=$CUSTOM_IMAGE,if=none,id=disk0,format=qcow2" -QEMU_OPTS="$QEMU_OPTS -device virtio-scsi-pci,id=scsi,disable-legacy=on" -QEMU_OPTS="$QEMU_OPTS -device scsi-hd,drive=disk0" - -if [ "$TDX_AVAILABLE" = true ]; then - echo "Starting QEMU VM with Intel TDX (Confidential VM)..." - # Update the -name option to include process and debug-threads - QEMU_OPTS=$(echo "$QEMU_OPTS" | sed "s/-name $VM_NAME/-name $VM_NAME,process=$VM_NAME,debug-threads=on/") - # Remove -m and add memory-backend-memfd for TDX (critical!) - QEMU_OPTS=$(echo "$QEMU_OPTS" | sed "s/-m $RAM//") - QEMU_OPTS="$QEMU_OPTS -object memory-backend-memfd,id=ram1,size=$RAM,share=true,prealloc=false" - QEMU_OPTS="$QEMU_OPTS -m $RAM" - QEMU_OPTS="$QEMU_OPTS -cpu host,pmu=off" - # TDX guest object with quote generation socket - QEMU_OPTS="$QEMU_OPTS -object {\"qom-type\":\"tdx-guest\",\"id\":\"tdx0\",\"quote-generation-socket\":{\"type\":\"vsock\",\"cid\":\"2\",\"port\":\"4050\"}}" - QEMU_OPTS="$QEMU_OPTS -machine q35,confidential-guest-support=tdx0,memory-backend=ram1,kernel-irqchip=split,hpet=off" - # Use -bios for TDX boot - QEMU_OPTS="$QEMU_OPTS -bios /usr/share/ovmf/OVMF.fd" - # Disk boot (Ubuntu cloud image) - QEMU_OPTS="$QEMU_OPTS -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile=" - QEMU_OPTS="$QEMU_OPTS -nodefaults" - QEMU_OPTS="$QEMU_OPTS -nographic" - QEMU_OPTS="$QEMU_OPTS -serial mon:stdio" - QEMU_OPTS="$QEMU_OPTS -monitor pty" -else - echo "Starting QEMU VM in regular mode (no CVM)..." - QEMU_OPTS="$QEMU_OPTS -drive if=pflash,format=raw,unit=0,file=$OVMF_CODE,readonly=on" - QEMU_OPTS="$QEMU_OPTS -drive if=pflash,format=raw,unit=1,file=$OVMF_VARS_COPY" - QEMU_OPTS="$QEMU_OPTS -cpu host" - QEMU_OPTS="$QEMU_OPTS -machine q35" - QEMU_OPTS="$QEMU_OPTS -device virtio-net-pci,netdev=vmnic,romfile=" -fi - -# Execute QEMU (use eval to handle complex quoting) -echo "Full QEMU command:" -echo "$QEMU_CMD $QEMU_OPTS" -echo "" -$QEMU_CMD $QEMU_OPTS + cloud-localds "$SEED_IMAGE" "$user_data_file" "$META_DATA" +} + +function start_regular() { + echo "Starting QEMU VM in regular mode (no CVM)..." + + create_ovmf_vars_copy + create_seed_image "${SCRIPT_DIR}/user-data-tdx.yaml" + + $QEMU_BINARY \ + -name "$VM_NAME" \ + -m "$RAM" \ + -smp "$CPU" \ + -enable-kvm \ + -boot d \ + -cpu host \ + -machine q35 \ + -drive if=pflash,format=raw,unit=0,file="$OVMF_CODE",readonly=on \ + -drive if=pflash,format=raw,unit=1,file="$OVMF_VARS_COPY" \ + -netdev user,id=vmnic,hostfwd=tcp::6190-:22,hostfwd=tcp::6191-:80,hostfwd=tcp::6192-:443,hostfwd=tcp::6193-:7001 \ + -device virtio-net-pci,netdev=vmnic,romfile= \ + -nographic \ + -no-reboot \ + -drive file="$SEED_IMAGE",media=cdrom \ + -drive file="$CUSTOM_IMAGE",if=none,id=disk0,format=qcow2 \ + -device virtio-scsi-pci,id=scsi,disable-legacy=on \ + -device scsi-hd,drive=disk0 +} + +function start_tdx() { + echo "Starting QEMU VM with Intel TDX (Confidential VM)..." + + create_seed_image "${SCRIPT_DIR}/user-data-tdx.yaml" + + $QEMU_BINARY \ + -name "$VM_NAME,process=$VM_NAME,debug-threads=on" \ + -m "$RAM" \ + -smp "$CPU" \ + -enable-kvm \ + -cpu host,pmu=off \ + -object memory-backend-memfd,id=ram1,size="$RAM",share=true,prealloc=false \ + -object '{"qom-type":"tdx-guest","id":"tdx0","quote-generation-socket":{"type":"vsock","cid":"2","port":"4050"}}' \ + -machine q35,confidential-guest-support=tdx0,memory-backend=ram1,kernel-irqchip=split,hpet=off \ + -bios /usr/share/ovmf/OVMF.fd \ + -netdev user,id=vmnic,hostfwd=tcp::6190-:22,hostfwd=tcp::6191-:80,hostfwd=tcp::6192-:443,hostfwd=tcp::6193-:7001 \ + -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= \ + -nodefaults \ + -nographic \ + -serial mon:stdio \ + -monitor pty \ + -no-reboot \ + -drive file="$SEED_IMAGE",media=cdrom \ + -drive file="$CUSTOM_IMAGE",if=none,id=disk0,format=qcow2 \ + -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true \ + -device scsi-hd,drive=disk0 \ + -device vhost-vsock-pci,guest-cid=3 +} + +function start_snp() { + echo "Starting QEMU VM with AMD SEV-SNP (Confidential VM)..." + + local QEMU_OVMF_CODE="${QEMU_OVMF_CODE:-/var/cube-ai/OVMF.fd}" + + create_seed_image "${SCRIPT_DIR}/user-data-snp.yaml" + + $QEMU_BINARY \ + -name "$VM_NAME" \ + -m "$RAM" \ + -smp "$CPU" \ + -cpu EPYC-v4 \ + -machine q35 \ + -enable-kvm \ + -drive if=pflash,format=raw,unit=0,file="$QEMU_OVMF_CODE",readonly=on \ + -object memory-backend-memfd-private,id=ram1,size="$RAM",share=true \ + -machine memory-encryption=sev0,memory-backend=ram1,kvm-type=protected \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,discard=none \ + -netdev user,id=vmnic,hostfwd=tcp::6190-:22,hostfwd=tcp::6191-:80,hostfwd=tcp::6192-:443,hostfwd=tcp::6193-:7001 \ + -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= \ + -nographic \ + -no-reboot \ + -drive file="$SEED_IMAGE",media=cdrom \ + -drive file="$CUSTOM_IMAGE",if=none,id=disk0,format=qcow2 \ + -device virtio-scsi-pci,id=scsi,disable-legacy=on \ + -device scsi-hd,drive=disk0 \ + -device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=198 +} + +function print_help() { + cat < /dev/null 2>&1; then + break + fi + sleep 2 + done + # Pull models + /usr/local/bin/ollama pull tinyllama:1.1b + /usr/local/bin/ollama pull starcoder2:3b + /usr/local/bin/ollama pull nomic-embed-text:v1.5 + permissions: '0755' + - path: /usr/local/bin/setup-certs.sh + content: | + #!/bin/bash + # Generate certificates for Cube Agent mTLS + mkdir -p /etc/cube/certs + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" + # Generate server certificate + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" + openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" + openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 + # Set permissions + chmod 600 /etc/cube/certs/*.key + chmod 644 /etc/cube/certs/*.crt + permissions: '0755' diff --git a/hal/ubuntu/user-data-tdx.yaml b/hal/ubuntu/user-data-tdx.yaml new file mode 100644 index 00000000..68a99f62 --- /dev/null +++ b/hal/ubuntu/user-data-tdx.yaml @@ -0,0 +1,153 @@ +#cloud-config +# Copyright (c) Ultraviolet +# SPDX-License-Identifier: Apache-2.0 +# +# Cloud-init configuration for Intel TDX (Trust Domain Extensions) VMs +# Ubuntu 24.04+ has TDX guest support built into the kernel + +package_update: true +package_upgrade: false + +users: + - name: ultraviolet + plain_text_passwd: password + lock_passwd: false + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + - name: ollama + system: true + home: /var/lib/ollama + shell: /usr/sbin/nologin + +ssh_pwauth: true + +packages: + - curl + - git + - golang-go + - build-essential + +write_files: + - path: /etc/cube/agent.env + content: | + UV_CUBE_AGENT_LOG_LEVEL=info + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + UV_CUBE_AGENT_TARGET_URL=http://localhost:11434 + UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt + UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key + UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt + UV_CUBE_AGENT_CA_URL=https://prism.ultraviolet.rs/am-certs + # TDX-specific settings + AGENT_OS_TYPE=tdx + permissions: '0644' + - path: /etc/systemd/system/ollama.service + content: | + [Unit] + Description=Ollama Service + After=network-online.target + Wants=network-online.target + + [Service] + Type=simple + User=ollama + Group=ollama + Environment="OLLAMA_HOST=0.0.0.0:11434" + ExecStart=/usr/local/bin/ollama serve + Restart=always + RestartSec=3 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /etc/systemd/system/cube-agent.service + content: | + [Unit] + Description=Cube Agent Service + After=network-online.target ollama.service + Wants=network-online.target + + [Service] + Type=simple + EnvironmentFile=/etc/cube/agent.env + ExecStart=/usr/local/bin/cube-agent + Restart=on-failure + RestartSec=5 + StartLimitBurst=5 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /usr/local/bin/pull-ollama-models.sh + content: | + #!/bin/bash + # Wait for ollama to be ready + for i in $(seq 1 60); do + if curl -s http://localhost:11434/api/version > /dev/null 2>&1; then + break + fi + sleep 2 + done + # Pull models + /usr/local/bin/ollama pull tinyllama:1.1b + /usr/local/bin/ollama pull starcoder2:3b + /usr/local/bin/ollama pull nomic-embed-text:v1.5 + permissions: '0755' + +runcmd: + - echo 'ultraviolet:password' | chpasswd + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + - sleep 2 + # TDX Setup for Ubuntu 24.04+ + # Ubuntu 24.04 (Noble) has TDX guest support built into the kernel + # No additional kernel installation or module loading is required + # The kernel CONFIG_INTEL_TDX_GUEST is enabled by default + - | + # Verify TDX guest support + if [ -e /sys/firmware/tdx ]; then + echo "TDX: Running inside a TDX Trust Domain" + echo "TDX attestation available via /dev/tdx_guest or configfs" + elif grep -q tdx_guest /proc/modules 2>/dev/null; then + echo "TDX: Guest module loaded" + elif grep -q "tdx" /proc/cpuinfo 2>/dev/null; then + echo "TDX: CPU supports TDX" + else + echo "TDX: Not detected (may be running in non-TDX mode)" + fi + - mkdir -p /etc/cube + - mkdir -p /etc/cube/certs + - | + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" + # Generate server certificate + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" + openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" + openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 + # Set permissions + chmod 600 /etc/cube/certs/*.key + chmod 644 /etc/cube/certs/*.crt + - mkdir -p /var/lib/ollama + - mkdir -p /home/ollama/.ollama + - chown -R ollama:ollama /var/lib/ollama + - chown -R ollama:ollama /home/ollama + - curl -fsSL https://ollama.com/install.sh | sh + - git clone https://github.com/ultravioletrs/cube.git /tmp/cube + - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 + - export HOME=/root + - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - systemctl daemon-reload + - systemctl enable ollama.service + - systemctl start ollama.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + - nohup /usr/local/bin/pull-ollama-models.sh > /var/log/ollama-pull.log 2>&1 & + +final_message: "Cube Agent (TDX) and Ollama services started." From cfc9af7c90788ef2fb20f3d5eb5109d78be73b65 Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Tue, 27 Jan 2026 08:16:24 +0300 Subject: [PATCH 02/10] update docs Signed-off-by: WashingtonKK --- hal/ubuntu/README.md | 99 +++++++++++++++++++-- hal/ubuntu/user-data-snp.yaml | 162 ++++++++++++++++++++++++++++++++++ 2 files changed, 256 insertions(+), 5 deletions(-) create mode 100644 hal/ubuntu/user-data-snp.yaml diff --git a/hal/ubuntu/README.md b/hal/ubuntu/README.md index e79d7503..3c9f730a 100644 --- a/hal/ubuntu/README.md +++ b/hal/ubuntu/README.md @@ -1,11 +1,100 @@ -# Ubuntu +# Ubuntu Cloud-Init for Cube AI -This directory contains the cloud-init configuration files for Cube AI. +This directory contains cloud-init configurations and QEMU launch scripts for running Cube AI in Ubuntu-based Confidential VMs (CVMs). -## After the first boot +## Overview -For local development, replace the following IP address entries in `docker/.env` with the IP address of the qemu virtual machine as follows: +Ubuntu 24.04 (Noble) has built-in support for both Intel TDX and AMD SEV-SNP confidential computing technologies. No additional kernel modules or packages need to be installed - the guest support is enabled by default in the kernel. + +## Files + +- `qemu.sh` - Main QEMU launch script with TDX/SNP support +- `user-data-tdx.yaml` - Cloud-init configuration for Intel TDX VMs +- `user-data-snp.yaml` - Cloud-init configuration for AMD SEV-SNP VMs +- `user-data-base.yaml` - Base configuration template (reference only) + +## Usage + +### Auto-detect CVM Support + +```bash +sudo ./qemu.sh start +``` + +This will automatically detect available CVM support (TDX or SNP) and launch the VM with the appropriate configuration. + +### Force Specific CVM Mode ```bash - UV_CUBE_NEXTAUTH_URL=http://:${UI_PORT} +# Intel TDX +sudo ./qemu.sh start_tdx + +# AMD SEV-SNP +sudo ./qemu.sh start_snp + +# Regular KVM (no CVM) +sudo ./qemu.sh start_regular ``` + +### Environment Variables + +```bash +# Force specific CVM mode +ENABLE_CVM=tdx sudo ./qemu.sh start +ENABLE_CVM=snp sudo ./qemu.sh start +ENABLE_CVM=none sudo ./qemu.sh start + +# Customize VM resources +RAM=32768M CPU=16 sudo ./qemu.sh start +``` + +### Detect Available Support + +```bash +sudo ./qemu.sh detect +``` + +## CVM Support Details + +### Intel TDX (Trust Domain Extensions) + +- Ubuntu 24.04 kernel has `CONFIG_INTEL_TDX_GUEST=y` enabled by default +- Guest attestation available via `/sys/firmware/tdx` or configfs +- Quote generation via vsock (CID=2, port=4050) + +### AMD SEV-SNP (Secure Nested Paging) + +- Ubuntu 24.04 kernel has `CONFIG_SEV_GUEST=y` enabled by default +- Guest attestation available via `/dev/sev-guest` +- Modules: `sev-guest`, `ccp` (loaded automatically) + +## After First Boot + +For local development, update the following in `docker/.env`: + +```bash +UV_CUBE_NEXTAUTH_URL=http://:${UI_PORT} +``` + +Default SSH access: +- **Port**: 6190 (forwarded from guest port 22) +- **User**: ultraviolet +- **Password**: password + +## Host Requirements + +### For TDX VMs +- Intel CPU with TDX support (4th Gen Xeon Scalable or newer) +- TDX-enabled BIOS/firmware +- Host kernel with TDX module initialized + +### For SNP VMs +- AMD EPYC CPU with SEV-SNP support (Milan or newer) +- SEV-SNP enabled in BIOS +- Host kernel with SEV-SNP support +- `/dev/sev` device available + +### Common Requirements +- QEMU with confidential computing support +- OVMF firmware (for UEFI boot) +- KVM enabled diff --git a/hal/ubuntu/user-data-snp.yaml b/hal/ubuntu/user-data-snp.yaml new file mode 100644 index 00000000..0ea7f9b2 --- /dev/null +++ b/hal/ubuntu/user-data-snp.yaml @@ -0,0 +1,162 @@ +#cloud-config +# Copyright (c) Ultraviolet +# SPDX-License-Identifier: Apache-2.0 +# +# Cloud-init configuration for AMD SEV-SNP (Secure Nested Paging) VMs +# Ubuntu 24.04+ has SEV-SNP guest support built into the kernel + +package_update: true +package_upgrade: false + +users: + - name: ultraviolet + plain_text_passwd: password + lock_passwd: false + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + - name: ollama + system: true + home: /var/lib/ollama + shell: /usr/sbin/nologin + +ssh_pwauth: true + +packages: + - curl + - git + - golang-go + - build-essential + +write_files: + - path: /etc/cube/agent.env + content: | + UV_CUBE_AGENT_LOG_LEVEL=info + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + UV_CUBE_AGENT_TARGET_URL=http://localhost:11434 + UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt + UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key + UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt + UV_CUBE_AGENT_CA_URL=https://prism.ultraviolet.rs/am-certs + # SNP-specific settings + AGENT_OS_TYPE=snp + AGENT_VMPL=2 + permissions: '0644' + - path: /etc/systemd/system/ollama.service + content: | + [Unit] + Description=Ollama Service + After=network-online.target + Wants=network-online.target + + [Service] + Type=simple + User=ollama + Group=ollama + Environment="OLLAMA_HOST=0.0.0.0:11434" + ExecStart=/usr/local/bin/ollama serve + Restart=always + RestartSec=3 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /etc/systemd/system/cube-agent.service + content: | + [Unit] + Description=Cube Agent Service + After=network-online.target ollama.service + Wants=network-online.target + + [Service] + Type=simple + EnvironmentFile=/etc/cube/agent.env + ExecStart=/usr/local/bin/cube-agent + Restart=on-failure + RestartSec=5 + StartLimitBurst=5 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /usr/local/bin/pull-ollama-models.sh + content: | + #!/bin/bash + # Wait for ollama to be ready + for i in $(seq 1 60); do + if curl -s http://localhost:11434/api/version > /dev/null 2>&1; then + break + fi + sleep 2 + done + # Pull models + /usr/local/bin/ollama pull tinyllama:1.1b + /usr/local/bin/ollama pull starcoder2:3b + /usr/local/bin/ollama pull nomic-embed-text:v1.5 + permissions: '0755' + - path: /etc/modules-load.d/sev-snp.conf + content: | + # AMD SEV-SNP guest modules + sev-guest + ccp + permissions: '0644' + +runcmd: + - echo 'ultraviolet:password' | chpasswd + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + - sleep 2 + # SEV-SNP Setup for Ubuntu 24.04+ + # Ubuntu 24.04 (Noble) has SEV-SNP guest support built into the kernel + # The kernel CONFIG_SEV_GUEST is enabled by default + - | + # Load SEV-SNP guest modules + modprobe ccp 2>/dev/null || echo "CCP module not available" + modprobe sev-guest 2>/dev/null || echo "sev-guest module not available" + # Verify SEV-SNP guest support + if [ -e /dev/sev-guest ]; then + echo "SEV-SNP: Running inside an SEV-SNP protected VM" + echo "SEV-SNP attestation available via /dev/sev-guest" + elif [ -e /sys/kernel/debug/sev ]; then + echo "SEV-SNP: SEV support detected" + elif grep -q "sev" /proc/cpuinfo 2>/dev/null; then + echo "SEV-SNP: CPU supports SEV" + else + echo "SEV-SNP: Not detected (may be running in non-SEV mode)" + fi + - mkdir -p /etc/cube + - mkdir -p /etc/cube/certs + - | + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" + # Generate server certificate + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" + openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" + openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 + # Set permissions + chmod 600 /etc/cube/certs/*.key + chmod 644 /etc/cube/certs/*.crt + - mkdir -p /var/lib/ollama + - mkdir -p /home/ollama/.ollama + - chown -R ollama:ollama /var/lib/ollama + - chown -R ollama:ollama /home/ollama + - curl -fsSL https://ollama.com/install.sh | sh + - git clone https://github.com/ultravioletrs/cube.git /tmp/cube + - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 + - export HOME=/root + - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - systemctl daemon-reload + - systemctl enable ollama.service + - systemctl start ollama.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + - nohup /usr/local/bin/pull-ollama-models.sh > /var/log/ollama-pull.log 2>&1 & + +final_message: "Cube Agent (SEV-SNP) and Ollama services started." From 16c92f4eafc5e835b455b4c987e1e66a6ff0242e Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Tue, 27 Jan 2026 17:35:10 +0300 Subject: [PATCH 03/10] address comments Signed-off-by: WashingtonKK --- hal/ubuntu/README.md | 2 +- hal/ubuntu/qemu.sh | 2 +- ...-data-base.yaml => user-data-regular.yaml} | 60 +++++++++++++------ hal/ubuntu/user-data-tdx.yaml | 26 ++++---- 4 files changed, 58 insertions(+), 32 deletions(-) rename hal/ubuntu/{user-data-base.yaml => user-data-regular.yaml} (53%) diff --git a/hal/ubuntu/README.md b/hal/ubuntu/README.md index 3c9f730a..0e0e8cdd 100644 --- a/hal/ubuntu/README.md +++ b/hal/ubuntu/README.md @@ -11,7 +11,7 @@ Ubuntu 24.04 (Noble) has built-in support for both Intel TDX and AMD SEV-SNP con - `qemu.sh` - Main QEMU launch script with TDX/SNP support - `user-data-tdx.yaml` - Cloud-init configuration for Intel TDX VMs - `user-data-snp.yaml` - Cloud-init configuration for AMD SEV-SNP VMs -- `user-data-base.yaml` - Base configuration template (reference only) +- `user-data-regular.yaml` - Cloud-init configuration for regular (non-CVM) VMs ## Usage diff --git a/hal/ubuntu/qemu.sh b/hal/ubuntu/qemu.sh index c0671d7c..e07dc2dd 100755 --- a/hal/ubuntu/qemu.sh +++ b/hal/ubuntu/qemu.sh @@ -131,7 +131,7 @@ function start_regular() { echo "Starting QEMU VM in regular mode (no CVM)..." create_ovmf_vars_copy - create_seed_image "${SCRIPT_DIR}/user-data-tdx.yaml" + create_seed_image "${SCRIPT_DIR}/user-data-regular.yaml" $QEMU_BINARY \ -name "$VM_NAME" \ diff --git a/hal/ubuntu/user-data-base.yaml b/hal/ubuntu/user-data-regular.yaml similarity index 53% rename from hal/ubuntu/user-data-base.yaml rename to hal/ubuntu/user-data-regular.yaml index 41d88f48..3295201e 100644 --- a/hal/ubuntu/user-data-base.yaml +++ b/hal/ubuntu/user-data-regular.yaml @@ -2,8 +2,7 @@ # Copyright (c) Ultraviolet # SPDX-License-Identifier: Apache-2.0 # -# Base cloud-init configuration for Cube AI VMs -# This file is included by CVM-specific configurations (TDX/SNP) +# Cloud-init configuration for regular (non-CVM) VMs package_update: true package_upgrade: false @@ -93,20 +92,43 @@ write_files: /usr/local/bin/ollama pull starcoder2:3b /usr/local/bin/ollama pull nomic-embed-text:v1.5 permissions: '0755' - - path: /usr/local/bin/setup-certs.sh - content: | - #!/bin/bash - # Generate certificates for Cube Agent mTLS - mkdir -p /etc/cube/certs - # Generate CA certificate - openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" - # Generate server certificate - openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" - openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 - # Generate client certificate for mTLS - openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" - openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 - # Set permissions - chmod 600 /etc/cube/certs/*.key - chmod 644 /etc/cube/certs/*.crt - permissions: '0755' + +runcmd: + - echo 'ultraviolet:password' | chpasswd + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + - sleep 2 + - mkdir -p /etc/cube + - mkdir -p /etc/cube/certs + - | + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" + # Generate server certificate + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" + openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" + openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 + # Set permissions + chmod 600 /etc/cube/certs/*.key + chmod 644 /etc/cube/certs/*.crt + - mkdir -p /var/lib/ollama + - mkdir -p /home/ollama/.ollama + - chown -R ollama:ollama /var/lib/ollama + - chown -R ollama:ollama /home/ollama + - curl -fsSL https://ollama.com/install.sh | sh + - git clone https://github.com/ultravioletrs/cube.git /tmp/cube + - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 + - export HOME=/root + - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - systemctl daemon-reload + - systemctl enable ollama.service + - systemctl start ollama.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + - nohup /usr/local/bin/pull-ollama-models.sh > /var/log/ollama-pull.log 2>&1 & + +final_message: "Cube Agent and Ollama services started." diff --git a/hal/ubuntu/user-data-tdx.yaml b/hal/ubuntu/user-data-tdx.yaml index 68a99f62..853e5e2a 100644 --- a/hal/ubuntu/user-data-tdx.yaml +++ b/hal/ubuntu/user-data-tdx.yaml @@ -105,20 +105,24 @@ runcmd: - systemctl restart sshd - sleep 2 # TDX Setup for Ubuntu 24.04+ - # Ubuntu 24.04 (Noble) has TDX guest support built into the kernel - # No additional kernel installation or module loading is required - # The kernel CONFIG_INTEL_TDX_GUEST is enabled by default + # Install TDX kernel modules and configure module loading - | - # Verify TDX guest support - if [ -e /sys/firmware/tdx ]; then + KERNEL_VERSION=$(uname -r) + echo "Installing TDX modules for kernel ${KERNEL_VERSION}..." + apt-get update + apt-get install -y linux-modules-extra-${KERNEL_VERSION} || apt-get install -y linux-modules-extra-generic || echo "Module package install failed" + # Configure TDX module to load at boot + mkdir -p /etc/modules-load.d + echo "tdx_guest" > /etc/modules-load.d/tdx.conf + # Load TDX guest module immediately + modprobe tdx_guest 2>/dev/null || echo "tdx_guest module not available (will load after reboot)" + # Verify TDX device + if [ -e /dev/tdx_guest ]; then + echo "TDX: /dev/tdx_guest device available" + elif [ -e /sys/firmware/tdx ]; then echo "TDX: Running inside a TDX Trust Domain" - echo "TDX attestation available via /dev/tdx_guest or configfs" - elif grep -q tdx_guest /proc/modules 2>/dev/null; then - echo "TDX: Guest module loaded" - elif grep -q "tdx" /proc/cpuinfo 2>/dev/null; then - echo "TDX: CPU supports TDX" else - echo "TDX: Not detected (may be running in non-TDX mode)" + echo "TDX: Module configured, will be available after reboot" fi - mkdir -p /etc/cube - mkdir -p /etc/cube/certs From 6d0a98bdca66dcc23cb16d4f035e697c7321cb49 Mon Sep 17 00:00:00 2001 From: Washington Kigani Kamadi Date: Wed, 28 Jan 2026 11:30:42 +0300 Subject: [PATCH 04/10] add cloud-init script (#8) Signed-off-by: WashingtonKK --- hal/ubuntu/cloud/README.md | 203 ++++++++++++++ hal/ubuntu/cloud/cube-agent-config.yml | 288 ++++++++++++++++++++ hal/ubuntu/cloud/cube-agent-vllm-config.yml | 265 ++++++++++++++++++ 3 files changed, 756 insertions(+) create mode 100644 hal/ubuntu/cloud/README.md create mode 100644 hal/ubuntu/cloud/cube-agent-config.yml create mode 100644 hal/ubuntu/cloud/cube-agent-vllm-config.yml diff --git a/hal/ubuntu/cloud/README.md b/hal/ubuntu/cloud/README.md new file mode 100644 index 00000000..a3316df1 --- /dev/null +++ b/hal/ubuntu/cloud/README.md @@ -0,0 +1,203 @@ +# Cloud-Init Configuration for Cube AI + +This directory contains cloud-init configuration files for deploying Cube AI on Ubuntu-based confidential virtual machines (CVMs) on cloud providers. + +## Cloud-Init Files + +| File | Backend | Description | +|------|---------|-------------| +| `cube-agent-config.yml` | Ollama | Default configuration with Ollama for easy model management | +| `cube-agent-vllm-config.yml` | vLLM | High-performance configuration with vLLM for production workloads | + +## Choosing a Backend + +### Ollama (Recommended for Getting Started) + +Use `cube-agent-config.yml` for: + +- Quick setup and experimentation +- Running multiple models +- CPU or small GPU deployments +- Built-in quantization support (Q4_0, Q4_1, Q8_0) + +### vLLM (Recommended for Production) + +Use `cube-agent-vllm-config.yml` for: + +- Maximum inference throughput +- Large-scale production deployments +- Multi-GPU setups with tensor parallelism +- Continuous batching and PagedAttention + +## Deployment + +### Google Cloud Platform (GCP) + +```bash +# Clone infrastructure templates +git clone https://github.com/ultravioletrs/cocos-infra.git +cd cocos-infra + +# Configure terraform.tfvars +cat >> terraform.tfvars << 'EOF' +vm_name = "cube-ai-vm" +project_id = "your-gcp-project-id" +region = "us-central1" +zone = "us-central1-a" +min_cpu_platform = "AMD Milan" +confidential_instance_type = "SEV_SNP" +machine_type = "n2d-standard-4" +cloud_init_config = "/path/to/cube/hal/ubuntu/cloud/cube-agent-config.yml" +EOF + +# Deploy +cd gcp +tofu init && tofu apply -var-file="../terraform.tfvars" +``` + +### Microsoft Azure + +```bash +# Configure terraform.tfvars +cat >> terraform.tfvars << 'EOF' +vm_name = "cube-ai-vm" +resource_group_name = "cube-ai-rg" +location = "westus" +subscription_id = "your-subscription-id" +machine_type = "Standard_DC4ads_v5" +cloud_init_config = "/path/to/cube/hal/ubuntu/cloud/cube-agent-config.yml" +EOF + +# Deploy +cd azure +az login +tofu init && tofu apply -var-file="../terraform.tfvars" +``` + +## Configuration + +### Environment Variables + +Set these environment variables before deployment to customize the configuration: + +| Variable | Default | Description | +|----------|---------|-------------| +| `CUBE_MODELS` | `tinyllama:1.1b` | Comma-separated Ollama models to pull | +| `CUBE_VLLM_MODEL` | `meta-llama/Llama-2-7b-hf` | HuggingFace model ID for vLLM | +| `CUBE_VLLM_GPU_COUNT` | `1` | Number of GPUs for tensor parallelism | +| `CUBE_AGENT_VERSION` | `latest` | Cube Agent release version | +| `HF_TOKEN` | - | HuggingFace token for gated models | + +### TLS/mTLS Certificates + +For production deployments, replace the self-signed certificate generation with your own certificates: + +1. Edit the cloud-init file +2. Uncomment the certificate file sections +3. Replace placeholder content with your certificates +4. Update `/etc/cube/agent.env` to enable TLS + +### Custom Models (Ollama) + +Pull additional models by setting `CUBE_MODELS`: + +```bash +export CUBE_MODELS="llama2:7b,mistral:latest,codellama:13b" +``` + +Or create a custom Modelfile after deployment: + +```bash +ssh cubeadmin@ +cat > /tmp/Modelfile << 'EOF' +FROM llama2:7b +PARAMETER temperature 0.7 +SYSTEM You are a helpful AI assistant. +EOF +sudo -u ollama /usr/local/bin/ollama create custom-assistant -f /tmp/Modelfile +``` + +## Verification + +After deployment, verify the services are running: + +```bash +# Check cloud-init completion +ssh cubeadmin@ +cloud-init status --wait + +# Check service status +sudo systemctl status cube-agent +sudo systemctl status ollama # or vllm + +# Test health endpoint +curl http://localhost:7001/health + +# Test chat completion +curl http://:7001/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "tinyllama:1.1b", + "messages": [{"role": "user", "content": "Hello!"}] + }' +``` + +## VM Size Recommendations + +### GCP + +| Use Case | Machine Type | vCPUs | RAM | +|----------|--------------|-------|-----| +| Development | `n2d-standard-2` | 2 | 8GB | +| Production (Ollama) | `n2d-standard-4` | 4 | 16GB | +| Production (vLLM) | `n2d-standard-8` | 8 | 32GB | +| Production (vLLM + GPU) | `n1-standard-8` + T4 | 8 | 30GB | + +### Azure + +| Use Case | Machine Type | vCPUs | RAM | +|----------|--------------|-------|-----| +| Development | `Standard_DC2ads_v5` | 2 | 8GB | +| Production (Ollama) | `Standard_DC4ads_v5` | 4 | 16GB | +| Production (vLLM) | `Standard_DC8ads_v5` | 8 | 32GB | +| Production (vLLM + GPU) | `Standard_NC6s_v3` | 6 | 112GB | + +## Troubleshooting + +### Cloud-init not completing + +```bash +# Check cloud-init logs +sudo cat /var/log/cloud-init-output.log +sudo cat /var/log/cloud-init.log +``` + +### Cube Agent not starting + +```bash +# Check service logs +sudo journalctl -u cube-agent -f + +# Verify configuration +cat /etc/cube/agent.env +``` + +### Ollama not responding + +```bash +# Check service logs +sudo journalctl -u ollama -f + +# Check if models are downloaded +sudo -u ollama /usr/local/bin/ollama list +``` + +### vLLM GPU issues + +```bash +# Check NVIDIA driver +nvidia-smi + +# Check vLLM logs +sudo journalctl -u vllm -f +``` diff --git a/hal/ubuntu/cloud/cube-agent-config.yml b/hal/ubuntu/cloud/cube-agent-config.yml new file mode 100644 index 00000000..6c0dc4db --- /dev/null +++ b/hal/ubuntu/cloud/cube-agent-config.yml @@ -0,0 +1,288 @@ +#cloud-config +# Cube AI Cloud-Init Configuration +# Copyright (c) Ultraviolet +# SPDX-License-Identifier: Apache-2.0 +# +# This cloud-init configuration sets up a Cube AI agent with Ollama backend +# on Ubuntu-based confidential VMs (GCP, Azure, or QEMU with TDX/SEV-SNP). +# +# Usage: +# - GCP: Reference this file in terraform.tfvars as cloud_init_config +# - Azure: Reference this file in terraform.tfvars as cloud_init_config +# - QEMU: Use with cloud-localds to create seed image +# +# Environment Variables (set before deployment): +# CUBE_AI_BACKEND - AI backend: "ollama" (default) or "vllm" +# CUBE_MODELS - Comma-separated list of models to pull (Ollama only) +# CUBE_VLLM_MODEL - HuggingFace model ID for vLLM backend +# +# For vLLM backend, see: hal/ubuntu/cloud/cube-agent-vllm-config.yml + +package_update: true +package_upgrade: false + +users: + - name: cubeadmin + plain_text_passwd: changeme + lock_passwd: false + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + groups: [docker] + - name: ollama + system: true + home: /var/lib/ollama + shell: /usr/sbin/nologin + +ssh_pwauth: true + +packages: + - curl + - git + - golang-go + - build-essential + - ca-certificates + - jq + +write_files: + # Cube Agent environment configuration template + # Customize these values for your deployment + - path: /etc/cube/agent.env.template + content: | + # Cube Agent Configuration + # Copy to /etc/cube/agent.env and customize + + # Logging + UV_CUBE_AGENT_LOG_LEVEL=info + + # Network binding + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + + # Instance identification + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + + # AI Backend URL (Ollama default) + UV_CUBE_AGENT_TARGET_URL=http://localhost:11434 + + # TLS Configuration (optional - uncomment for production) + # UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt + # UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key + # UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt + + # Attestation Manager URL (optional) + # UV_CUBE_AGENT_CA_URL=https://cloud.prism.ultraviolet.rs/am-certs + permissions: '0644' + + # Default agent.env (minimal configuration) + - path: /etc/cube/agent.env + content: | + UV_CUBE_AGENT_LOG_LEVEL=info + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + UV_CUBE_AGENT_TARGET_URL=http://localhost:11434 + permissions: '0644' + + # Ollama systemd service + - path: /etc/systemd/system/ollama.service + content: | + [Unit] + Description=Ollama Service + After=network-online.target + Wants=network-online.target + + [Service] + Type=simple + User=ollama + Group=ollama + Environment="OLLAMA_HOST=0.0.0.0:11434" + ExecStart=/usr/local/bin/ollama serve + Restart=always + RestartSec=3 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + + # Cube Agent systemd service + - path: /etc/systemd/system/cube-agent.service + content: | + [Unit] + Description=Cube Agent Service + After=network-online.target ollama.service + Wants=network-online.target + + [Service] + Type=simple + EnvironmentFile=/etc/cube/agent.env + ExecStart=/usr/local/bin/cube-agent + Restart=on-failure + RestartSec=5 + StartLimitBurst=5 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + + # Model pull script for Ollama + - path: /usr/local/bin/pull-ollama-models.sh + content: | + #!/bin/bash + # Pull Ollama models after service is ready + # Default models: tinyllama:1.1b + # Override with CUBE_MODELS environment variable + + MODELS="${CUBE_MODELS:-tinyllama:1.1b}" + + # Wait for Ollama to be ready (max 2 minutes) + echo "Waiting for Ollama service..." + for i in $(seq 1 60); do + if curl -s http://localhost:11434/api/version > /dev/null 2>&1; then + echo "Ollama is ready" + break + fi + sleep 2 + done + + # Pull each model + IFS=',' read -ra MODEL_ARRAY <<< "$MODELS" + for model in "${MODEL_ARRAY[@]}"; do + model=$(echo "$model" | xargs) # Trim whitespace + echo "Pulling model: $model" + /usr/local/bin/ollama pull "$model" + done + + echo "Model pull complete" + permissions: '0755' + + # TLS certificate generation script (for development/testing) + - path: /usr/local/bin/generate-cube-certs.sh + content: | + #!/bin/bash + # Generate self-signed certificates for Cube Agent + # For production, replace with certificates from your CA + + CERT_DIR="/etc/cube/certs" + mkdir -p "$CERT_DIR" + + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 \ + -keyout "$CERT_DIR/ca.key" \ + -out "$CERT_DIR/ca.crt" \ + -days 365 -nodes \ + -subj "/CN=Cube-CA" + + # Generate server certificate + openssl req -newkey rsa:4096 \ + -keyout "$CERT_DIR/server.key" \ + -out "$CERT_DIR/server.csr" \ + -nodes -subj "/CN=cube-agent" + + openssl x509 -req \ + -in "$CERT_DIR/server.csr" \ + -CA "$CERT_DIR/ca.crt" \ + -CAkey "$CERT_DIR/ca.key" \ + -CAcreateserial \ + -out "$CERT_DIR/server.crt" \ + -days 365 + + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 \ + -keyout "$CERT_DIR/client.key" \ + -out "$CERT_DIR/client.csr" \ + -nodes -subj "/CN=cube-client" + + openssl x509 -req \ + -in "$CERT_DIR/client.csr" \ + -CA "$CERT_DIR/ca.crt" \ + -CAkey "$CERT_DIR/ca.key" \ + -CAcreateserial \ + -out "$CERT_DIR/client.crt" \ + -days 365 + + # Set permissions + chmod 600 "$CERT_DIR"/*.key + chmod 644 "$CERT_DIR"/*.crt + rm -f "$CERT_DIR"/*.csr + + echo "Certificates generated in $CERT_DIR" + permissions: '0755' + + # Optional: TLS certificate placeholders for production + # Uncomment and replace with your actual certificates + # + # - path: /etc/cube/certs/server.crt + # content: | + # -----BEGIN CERTIFICATE----- + # [Your server certificate here] + # -----END CERTIFICATE----- + # permissions: '0644' + # + # - path: /etc/cube/certs/server.key + # content: | + # -----BEGIN PRIVATE KEY----- + # [Your server private key here] + # -----END PRIVATE KEY----- + # permissions: '0600' + # + # - path: /etc/cube/certs/ca.crt + # content: | + # -----BEGIN CERTIFICATE----- + # [Your CA certificate here] + # -----END CERTIFICATE----- + # permissions: '0644' + +runcmd: + # Configure SSH for password authentication + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + + # Create Cube directories + - mkdir -p /etc/cube/certs + - mkdir -p /var/log/cube + + # Generate self-signed certificates (for development) + # Comment out for production if using real certificates + - /usr/local/bin/generate-cube-certs.sh + + # Set up Ollama directories + - mkdir -p /var/lib/ollama + - mkdir -p /home/ollama/.ollama + - chown -R ollama:ollama /var/lib/ollama + - chown -R ollama:ollama /home/ollama + + # Install Ollama + - curl -fsSL https://ollama.com/install.sh | sh + + # Install Cube Agent from latest release + - | + CUBE_VERSION="${CUBE_AGENT_VERSION:-latest}" + if [ "$CUBE_VERSION" = "latest" ]; then + DOWNLOAD_URL=$(curl -s https://api.github.com/repos/ultravioletrs/cube/releases/latest | jq -r '.assets[] | select(.name | contains("linux") and contains("amd64")) | .browser_download_url' | head -1) + else + DOWNLOAD_URL="https://github.com/ultravioletrs/cube/releases/download/${CUBE_VERSION}/cube-agent-linux-amd64" + fi + if [ -n "$DOWNLOAD_URL" ] && [ "$DOWNLOAD_URL" != "null" ]; then + curl -fsSL "$DOWNLOAD_URL" -o /usr/local/bin/cube-agent + chmod +x /usr/local/bin/cube-agent + else + echo "Could not find release, building from source..." + git clone https://github.com/ultravioletrs/cube.git /tmp/cube + cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + fi + + # Enable and start services + - systemctl daemon-reload + - systemctl enable ollama.service + - systemctl start ollama.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + + # Pull default models in background + - nohup /usr/local/bin/pull-ollama-models.sh > /var/log/cube/ollama-pull.log 2>&1 & + +final_message: "Cube AI deployment complete. Cube Agent running on port 7001." diff --git a/hal/ubuntu/cloud/cube-agent-vllm-config.yml b/hal/ubuntu/cloud/cube-agent-vllm-config.yml new file mode 100644 index 00000000..429ae147 --- /dev/null +++ b/hal/ubuntu/cloud/cube-agent-vllm-config.yml @@ -0,0 +1,265 @@ +#cloud-config +# Cube AI Cloud-Init Configuration - vLLM Backend +# Copyright (c) Ultraviolet +# SPDX-License-Identifier: Apache-2.0 +# +# This cloud-init configuration sets up a Cube AI agent with vLLM backend +# for high-performance inference on Ubuntu-based confidential VMs. +# +# vLLM Features: +# - Continuous batching for higher throughput +# - PagedAttention for efficient memory management +# - OpenAI-compatible API +# - Tensor parallelism for multi-GPU setups +# +# Usage: +# - GCP: Reference this file in terraform.tfvars as cloud_init_config +# - Azure: Reference this file in terraform.tfvars as cloud_init_config +# +# Recommended VM sizes: +# - GCP: n1-standard-8 with nvidia-tesla-t4 or better +# - Azure: Standard_NC6s_v3 (NVIDIA V100) or better + +package_update: true +package_upgrade: false + +users: + - name: cubeadmin + plain_text_passwd: changeme + lock_passwd: false + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + groups: [docker] + - name: vllm + system: true + home: /var/lib/vllm + shell: /usr/sbin/nologin + +ssh_pwauth: true + +packages: + - curl + - git + - python3 + - python3-pip + - python3-venv + - build-essential + - ca-certificates + - jq + - nvidia-driver-535 + - nvidia-cuda-toolkit + +write_files: + # Cube Agent environment configuration for vLLM + - path: /etc/cube/agent.env.template + content: | + # Cube Agent Configuration for vLLM Backend + # Copy to /etc/cube/agent.env and customize + + # Logging + UV_CUBE_AGENT_LOG_LEVEL=info + + # Network binding + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + + # Instance identification + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + + # vLLM Backend URL + UV_CUBE_AGENT_TARGET_URL=http://localhost:8000 + + # TLS Configuration (optional - uncomment for production) + # UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt + # UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key + # UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt + + # Attestation Manager URL (optional) + # UV_CUBE_AGENT_CA_URL=https://prism.ultraviolet.rs/am-certs + permissions: '0644' + + # Default agent.env for vLLM + - path: /etc/cube/agent.env + content: | + UV_CUBE_AGENT_LOG_LEVEL=info + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + UV_CUBE_AGENT_TARGET_URL=http://localhost:8000 + permissions: '0644' + + # vLLM environment configuration + - path: /etc/cube/vllm.env + content: | + # vLLM Configuration + # Model to serve (HuggingFace model ID) + VLLM_MODEL=${CUBE_VLLM_MODEL:-meta-llama/Llama-2-7b-hf} + + # Server configuration + VLLM_HOST=0.0.0.0 + VLLM_PORT=8000 + + # GPU configuration + VLLM_TENSOR_PARALLEL_SIZE=${CUBE_VLLM_GPU_COUNT:-1} + + # Memory configuration + VLLM_GPU_MEMORY_UTILIZATION=0.9 + + # HuggingFace token (for gated models) + # HF_TOKEN=your_token_here + permissions: '0644' + + # vLLM systemd service + - path: /etc/systemd/system/vllm.service + content: | + [Unit] + Description=vLLM Inference Server + After=network-online.target + Wants=network-online.target + + [Service] + Type=simple + User=vllm + Group=vllm + EnvironmentFile=/etc/cube/vllm.env + WorkingDirectory=/var/lib/vllm + ExecStart=/var/lib/vllm/venv/bin/python -m vllm.entrypoints.openai.api_server \ + --model ${VLLM_MODEL} \ + --host ${VLLM_HOST} \ + --port ${VLLM_PORT} \ + --tensor-parallel-size ${VLLM_TENSOR_PARALLEL_SIZE} \ + --gpu-memory-utilization ${VLLM_GPU_MEMORY_UTILIZATION} + Restart=on-failure + RestartSec=10 + StartLimitBurst=3 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + + # Cube Agent systemd service + - path: /etc/systemd/system/cube-agent.service + content: | + [Unit] + Description=Cube Agent Service + After=network-online.target vllm.service + Wants=network-online.target + + [Service] + Type=simple + EnvironmentFile=/etc/cube/agent.env + ExecStart=/usr/local/bin/cube-agent + Restart=on-failure + RestartSec=5 + StartLimitBurst=5 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + + # TLS certificate generation script + - path: /usr/local/bin/generate-cube-certs.sh + content: | + #!/bin/bash + # Generate self-signed certificates for Cube Agent + # For production, replace with certificates from your CA + + CERT_DIR="/etc/cube/certs" + mkdir -p "$CERT_DIR" + + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 \ + -keyout "$CERT_DIR/ca.key" \ + -out "$CERT_DIR/ca.crt" \ + -days 365 -nodes \ + -subj "/CN=Cube-CA" + + # Generate server certificate + openssl req -newkey rsa:4096 \ + -keyout "$CERT_DIR/server.key" \ + -out "$CERT_DIR/server.csr" \ + -nodes -subj "/CN=cube-agent" + + openssl x509 -req \ + -in "$CERT_DIR/server.csr" \ + -CA "$CERT_DIR/ca.crt" \ + -CAkey "$CERT_DIR/ca.key" \ + -CAcreateserial \ + -out "$CERT_DIR/server.crt" \ + -days 365 + + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 \ + -keyout "$CERT_DIR/client.key" \ + -out "$CERT_DIR/client.csr" \ + -nodes -subj "/CN=cube-client" + + openssl x509 -req \ + -in "$CERT_DIR/client.csr" \ + -CA "$CERT_DIR/ca.crt" \ + -CAkey "$CERT_DIR/ca.key" \ + -CAcreateserial \ + -out "$CERT_DIR/client.crt" \ + -days 365 + + # Set permissions + chmod 600 "$CERT_DIR"/*.key + chmod 644 "$CERT_DIR"/*.crt + rm -f "$CERT_DIR"/*.csr + + echo "Certificates generated in $CERT_DIR" + permissions: '0755' + +runcmd: + # Configure SSH for password authentication + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + + # Create Cube directories + - mkdir -p /etc/cube/certs + - mkdir -p /var/log/cube + - mkdir -p /var/lib/vllm + + # Generate self-signed certificates (for development) + - /usr/local/bin/generate-cube-certs.sh + + # Set up vLLM user and directories + - chown -R vllm:vllm /var/lib/vllm + + # Install vLLM in virtual environment + - | + sudo -u vllm python3 -m venv /var/lib/vllm/venv + sudo -u vllm /var/lib/vllm/venv/bin/pip install --upgrade pip + sudo -u vllm /var/lib/vllm/venv/bin/pip install vllm + + # Install Cube Agent from latest release + - | + CUBE_VERSION="${CUBE_AGENT_VERSION:-latest}" + if [ "$CUBE_VERSION" = "latest" ]; then + DOWNLOAD_URL=$(curl -s https://api.github.com/repos/ultravioletrs/cube/releases/latest | jq -r '.assets[] | select(.name | contains("linux") and contains("amd64")) | .browser_download_url' | head -1) + else + DOWNLOAD_URL="https://github.com/ultravioletrs/cube/releases/download/${CUBE_VERSION}/cube-agent-linux-amd64" + fi + if [ -n "$DOWNLOAD_URL" ] && [ "$DOWNLOAD_URL" != "null" ]; then + curl -fsSL "$DOWNLOAD_URL" -o /usr/local/bin/cube-agent + chmod +x /usr/local/bin/cube-agent + else + echo "Could not find release, building from source..." + apt-get install -y golang-go + git clone https://github.com/ultravioletrs/cube.git /tmp/cube + cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + fi + + # Enable and start services + - systemctl daemon-reload + - systemctl enable vllm.service + - systemctl start vllm.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + +final_message: "Cube AI (vLLM) deployment complete. Cube Agent running on port 7001, vLLM on port 8000." From c84f5ff8fff9d0de2085cf3b110ee1edefdc567d Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Wed, 4 Mar 2026 13:37:55 +0300 Subject: [PATCH 05/10] Enhance cloud-init and QEMU scripts for AMD SEV-SNP support Signed-off-by: WashingtonKK --- hal/ubuntu/README.md | 60 +++++++++++++++++++++++++++++++-- hal/ubuntu/qemu.sh | 63 ++++++++++++++++++++++++++--------- hal/ubuntu/user-data-snp.yaml | 21 ++++++++++++ 3 files changed, 126 insertions(+), 18 deletions(-) diff --git a/hal/ubuntu/README.md b/hal/ubuntu/README.md index 0e0e8cdd..41ed8abc 100644 --- a/hal/ubuntu/README.md +++ b/hal/ubuntu/README.md @@ -4,7 +4,7 @@ This directory contains cloud-init configurations and QEMU launch scripts for ru ## Overview -Ubuntu 24.04 (Noble) has built-in support for both Intel TDX and AMD SEV-SNP confidential computing technologies. No additional kernel modules or packages need to be installed - the guest support is enabled by default in the kernel. +Ubuntu 24.04 (Noble) has built-in support for Intel TDX confidential computing. For AMD SEV-SNP, a custom kernel is required because the host uses SVSM/Coconut — the standard Ubuntu 24.04 kernel does not support it. ## Files @@ -12,6 +12,7 @@ Ubuntu 24.04 (Noble) has built-in support for both Intel TDX and AMD SEV-SNP con - `user-data-tdx.yaml` - Cloud-init configuration for Intel TDX VMs - `user-data-snp.yaml` - Cloud-init configuration for AMD SEV-SNP VMs - `user-data-regular.yaml` - Cloud-init configuration for regular (non-CVM) VMs +- `debs/` - (Optional) Directory for custom kernel `.deb` packages, required only when the SNP host runs Coconut SVSM (see [SNP Kernel](#snp-custom-kernel)) ## Usage @@ -64,9 +65,60 @@ sudo ./qemu.sh detect ### AMD SEV-SNP (Secure Nested Paging) -- Ubuntu 24.04 kernel has `CONFIG_SEV_GUEST=y` enabled by default +- If the host runs Coconut SVSM, a custom kernel is required (see [SNP Kernel](#snp-custom-kernel)) - Guest attestation available via `/dev/sev-guest` - Modules: `sev-guest`, `ccp` (loaded automatically) +- Disk is automatically resized on first boot via `growpart` + +### SNP Custom Kernel + +A custom kernel is only required when the SNP host runs Coconut SVSM. The standard Ubuntu 24.04 kernel does not support Coconut SVSM, so a kernel built with SVSM support must be bundled into the seed image as `.deb` packages. + +**Kernel requirements:** + +The custom kernel must be built with the following options: +- `CONFIG_AMD_MEM_ENCRYPT=y` — AMD memory encryption support +- `CONFIG_SEV_GUEST=y` — SEV guest driver +- Coconut SVSM guest support patches applied + +The kernel must be packaged as `.deb` files. + +**Installing the kernel into the seed image:** + +Place the `.deb` files in a `debs/` directory next to `qemu.sh`: + +``` +hal/ubuntu/ + qemu.sh + user-data-snp.yaml + debs/ + linux-image-*.deb + linux-headers-*.deb + linux-modules-*.deb (if needed) +``` + +The `start_snp` command will automatically detect `debs/` and package the files into the seed ISO using `genisoimage`: + +```bash +genisoimage -output seed.img -volid cidata -joliet -rock cidata/ +``` + +Where the `cidata/` directory contains: +``` +cidata/ + meta-data + user-data + debs/ + *.deb +``` + +On first boot, cloud-init mounts the seed ISO, installs the `.deb` packages, runs `update-grub`, and the VM boots the new SNP-compatible kernel on next start. + +**Dependency:** + +```bash +sudo apt-get install genisoimage +``` ## After First Boot @@ -91,8 +143,10 @@ Default SSH access: ### For SNP VMs - AMD EPYC CPU with SEV-SNP support (Milan or newer) - SEV-SNP enabled in BIOS -- Host kernel with SEV-SNP support +- Host kernel with SEV-SNP/SVSM support - `/dev/sev` device available +- `genisoimage` installed (`apt-get install genisoimage`) +- If using Coconut SVSM: custom kernel `.deb` files in `debs/` (see [SNP Kernel](#snp-custom-kernel)) ### Common Requirements - QEMU with confidential computing support diff --git a/hal/ubuntu/qemu.sh b/hal/ubuntu/qemu.sh index e07dc2dd..06029d7e 100755 --- a/hal/ubuntu/qemu.sh +++ b/hal/ubuntu/qemu.sh @@ -127,6 +127,39 @@ EOF cloud-localds "$SEED_IMAGE" "$user_data_file" "$META_DATA" } +function create_seed_image_snp() { + local user_data_file="$1" + + echo "Creating SNP seed image with $user_data_file..." + + if ! command -v genisoimage &> /dev/null; then + echo "genisoimage is not installed. Please install genisoimage and try again." + exit 1 + fi + + local cidata_dir + cidata_dir="$(mktemp -d)" + trap "rm -rf $cidata_dir" RETURN + + # Write meta-data + cat < "$cidata_dir/meta-data" +instance-id: iid-${VM_NAME} +local-hostname: $VM_NAME +EOF + + # Copy user-data + cp "$user_data_file" "$cidata_dir/user-data" + + # Include kernel .deb files if present (required for SNP-compatible kernel) + if [ -d "${SCRIPT_DIR}/debs" ] && ls "${SCRIPT_DIR}/debs"/*.deb 2>/dev/null; then + mkdir -p "$cidata_dir/debs" + cp "${SCRIPT_DIR}/debs"/*.deb "$cidata_dir/debs/" + echo "Included kernel .deb files from ${SCRIPT_DIR}/debs/" + fi + + genisoimage -output "$SEED_IMAGE" -volid cidata -joliet -rock "$cidata_dir" +} + function start_regular() { echo "Starting QEMU VM in regular mode (no CVM)..." @@ -185,30 +218,30 @@ function start_tdx() { function start_snp() { echo "Starting QEMU VM with AMD SEV-SNP (Confidential VM)..." + local SNP_QEMU="/home/cocosai/bin/qemu-svsm/bin/qemu-system-x86_64" local QEMU_OVMF_CODE="${QEMU_OVMF_CODE:-/var/cube-ai/OVMF.fd}" - create_seed_image "${SCRIPT_DIR}/user-data-snp.yaml" + create_seed_image_snp "${SCRIPT_DIR}/user-data-snp.yaml" - $QEMU_BINARY \ + $SNP_QEMU \ -name "$VM_NAME" \ - -m "$RAM" \ - -smp "$CPU" \ - -cpu EPYC-v4 \ - -machine q35 \ -enable-kvm \ - -drive if=pflash,format=raw,unit=0,file="$QEMU_OVMF_CODE",readonly=on \ - -object memory-backend-memfd-private,id=ram1,size="$RAM",share=true \ - -machine memory-encryption=sev0,memory-backend=ram1,kvm-type=protected \ - -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1,discard=none \ + -machine q35,confidential-guest-support=sev0,memory-backend=ram1 \ + -cpu EPYC \ + -smp "$CPU" \ + -m "$RAM" \ + -object memory-backend-memfd,id=ram1,size="$RAM",share=true,prealloc=false \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1 \ + -bios "$QEMU_OVMF_CODE" \ -netdev user,id=vmnic,hostfwd=tcp::6190-:22,hostfwd=tcp::6191-:80,hostfwd=tcp::6192-:443,hostfwd=tcp::6193-:7001 \ - -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= \ - -nographic \ - -no-reboot \ + -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,addr=0x2,romfile= \ -drive file="$SEED_IMAGE",media=cdrom \ -drive file="$CUSTOM_IMAGE",if=none,id=disk0,format=qcow2 \ - -device virtio-scsi-pci,id=scsi,disable-legacy=on \ + -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true \ -device scsi-hd,drive=disk0 \ - -device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=198 + -nographic \ + -monitor pty \ + -no-reboot } function print_help() { diff --git a/hal/ubuntu/user-data-snp.yaml b/hal/ubuntu/user-data-snp.yaml index 0ea7f9b2..20856565 100644 --- a/hal/ubuntu/user-data-snp.yaml +++ b/hal/ubuntu/user-data-snp.yaml @@ -8,6 +8,13 @@ package_update: true package_upgrade: false +growpart: + mode: auto + devices: ["/"] + ignore_growroot_disabled: false + +resize_rootfs: true + users: - name: ultraviolet plain_text_passwd: password @@ -104,6 +111,20 @@ write_files: permissions: '0644' runcmd: + - | + # Install custom SNP-compatible kernel from seed image if present + mkdir -p /mnt/seed + dev="$(blkid -L cidata || blkid -L CIDATA || true)" + if [ -n "$dev" ]; then + mount "$dev" /mnt/seed + if ls /mnt/seed/debs/*.deb 2>/dev/null; then + cp /mnt/seed/debs/*.deb /root/ + dpkg -i /root/*.deb || apt-get -y -f install + update-grub + sync + fi + umount /mnt/seed || true + fi - echo 'ultraviolet:password' | chpasswd - | cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' From cf9ffb9cd8f5fc53a17282505650ec88af5a179d Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Wed, 4 Mar 2026 16:08:53 +0300 Subject: [PATCH 06/10] Update README and qemu.sh for AMD SEV-SNP preparation steps Signed-off-by: WashingtonKK --- hal/ubuntu/README.md | 14 ++++++++--- hal/ubuntu/qemu.sh | 58 +++++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 20 deletions(-) diff --git a/hal/ubuntu/README.md b/hal/ubuntu/README.md index 41ed8abc..599de579 100644 --- a/hal/ubuntu/README.md +++ b/hal/ubuntu/README.md @@ -30,8 +30,9 @@ This will automatically detect available CVM support (TDX or SNP) and launch the # Intel TDX sudo ./qemu.sh start_tdx -# AMD SEV-SNP -sudo ./qemu.sh start_snp +# AMD SEV-SNP (two steps required) +sudo ./qemu.sh prepare_snp # Run once: installs custom kernel via cloud-init (regular KVM) +sudo ./qemu.sh start_snp # Boot the prepared image with IGVM/SNP # Regular KVM (no CVM) sudo ./qemu.sh start_regular @@ -47,6 +48,9 @@ ENABLE_CVM=none sudo ./qemu.sh start # Customize VM resources RAM=32768M CPU=16 sudo ./qemu.sh start + +# Override IGVM file path (SNP only) +IGVM=/path/to/coconut-qemu.igvm sudo ./qemu.sh start_snp ``` ### Detect Available Support @@ -65,6 +69,8 @@ sudo ./qemu.sh detect ### AMD SEV-SNP (Secure Nested Paging) +- Boots via IGVM using the Coconut SVSM QEMU (`/home/cocosai/bin/qemu-svsm/bin/qemu-system-x86_64`) +- Requires an IGVM file (default: `/etc/cocos/coconut-qemu.igvm`) - If the host runs Coconut SVSM, a custom kernel is required (see [SNP Kernel](#snp-custom-kernel)) - Guest attestation available via `/dev/sev-guest` - Modules: `sev-guest`, `ccp` (loaded automatically) @@ -145,8 +151,10 @@ Default SSH access: - SEV-SNP enabled in BIOS - Host kernel with SEV-SNP/SVSM support - `/dev/sev` device available +- Coconut SVSM QEMU binary at `/home/cocosai/bin/qemu-svsm/bin/qemu-system-x86_64` +- IGVM file at `/etc/cocos/coconut-qemu.igvm` (or set `IGVM` env var) - `genisoimage` installed (`apt-get install genisoimage`) -- If using Coconut SVSM: custom kernel `.deb` files in `debs/` (see [SNP Kernel](#snp-custom-kernel)) +- Custom kernel `.deb` files in `debs/` (see [SNP Kernel](#snp-custom-kernel)) ### Common Requirements - QEMU with confidential computing support diff --git a/hal/ubuntu/qemu.sh b/hal/ubuntu/qemu.sh index 06029d7e..ba3efecb 100755 --- a/hal/ubuntu/qemu.sh +++ b/hal/ubuntu/qemu.sh @@ -215,33 +215,53 @@ function start_tdx() { -device vhost-vsock-pci,guest-cid=3 } -function start_snp() { - echo "Starting QEMU VM with AMD SEV-SNP (Confidential VM)..." +function prepare_snp() { + echo "Preparing SNP image via cloud-init (regular KVM, no SNP)..." + echo "This installs the custom kernel into the image. Run start_snp after this completes." local SNP_QEMU="/home/cocosai/bin/qemu-svsm/bin/qemu-system-x86_64" - local QEMU_OVMF_CODE="${QEMU_OVMF_CODE:-/var/cube-ai/OVMF.fd}" create_seed_image_snp "${SCRIPT_DIR}/user-data-snp.yaml" $SNP_QEMU \ -name "$VM_NAME" \ -enable-kvm \ - -machine q35,confidential-guest-support=sev0,memory-backend=ram1 \ - -cpu EPYC \ - -smp "$CPU" \ - -m "$RAM" \ - -object memory-backend-memfd,id=ram1,size="$RAM",share=true,prealloc=false \ - -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1 \ - -bios "$QEMU_OVMF_CODE" \ + -m 2048 \ + -smp 2 \ + -drive "file=$CUSTOM_IMAGE,if=virtio,format=qcow2" \ + -drive "file=$SEED_IMAGE,if=virtio,format=raw,readonly=on" \ + -netdev "user,id=n0,hostfwd=tcp::6190-:22" \ + -device virtio-net-pci,netdev=n0 \ + -nographic +} + +function start_snp() { + echo "Starting QEMU VM with AMD SEV-SNP (Confidential VM)..." + echo "Ensure prepare_snp has been run first to install the custom kernel." + + local SNP_QEMU="/home/cocosai/bin/qemu-svsm/bin/qemu-system-x86_64" + local IGVM="${IGVM:-/etc/cocos/coconut-qemu.igvm}" + + $SNP_QEMU \ + -name "$VM_NAME" \ + -enable-kvm \ + -cpu EPYC-v4 \ + -machine q35 \ + -smp "$CPU,sockets=1,threads=1" \ + -m "$RAM,slots=5,maxmem=40G" \ -netdev user,id=vmnic,hostfwd=tcp::6190-:22,hostfwd=tcp::6191-:80,hostfwd=tcp::6192-:443,hostfwd=tcp::6193-:7001 \ - -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,addr=0x2,romfile= \ - -drive file="$SEED_IMAGE",media=cdrom \ + -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=vmnic,romfile= \ + -machine confidential-guest-support=sev0,memory-backend=ram1,igvm-cfg=igvm0 \ + -object memory-backend-memfd,id=ram1,size="$RAM",share=true,prealloc=false,reserve=false \ + -object sev-snp-guest,id=sev0,cbitpos=51,reduced-phys-bits=1 \ + -object igvm-cfg,id=igvm0,file="$IGVM" \ -drive file="$CUSTOM_IMAGE",if=none,id=disk0,format=qcow2 \ - -device virtio-scsi-pci,id=scsi,disable-legacy=on,iommu_platform=true \ - -device scsi-hd,drive=disk0 \ + -device virtio-scsi-pci,id=scsi0,disable-legacy=on,iommu_platform=true \ + -device scsi-hd,drive=disk0,bus=scsi0.0 \ + -device vhost-vsock-pci,id=vhost-vsock-pci0,guest-cid=198 \ -nographic \ - -monitor pty \ - -no-reboot + -no-reboot \ + -monitor pty } function print_help() { @@ -251,7 +271,8 @@ Usage: $0 [command] [options] Commands: start Start the QEMU VM (auto-detect CVM support) start_tdx Start the QEMU VM with Intel TDX enabled - start_snp Start the QEMU VM with AMD SEV-SNP enabled + prepare_snp Prepare the image for SNP (run once before start_snp) + start_snp Start the QEMU VM with AMD SEV-SNP enabled (requires prepare_snp) start_regular Start the QEMU VM without CVM (regular KVM) detect Detect available CVM support on this host help Show this help message @@ -305,6 +326,9 @@ function main() { start_tdx) start_tdx ;; + prepare_snp) + prepare_snp + ;; start_snp) start_snp ;; From 402027ac97b4cf27ae0dc007fa3f2042de398774 Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Fri, 6 Mar 2026 11:06:14 +0300 Subject: [PATCH 07/10] Update README and qemu.sh for AMD SEV-SNP preparation steps Signed-off-by: WashingtonKK --- hal/ubuntu/README.md | 17 +++++++---------- hal/ubuntu/qemu.sh | 2 +- hal/ubuntu/user-data-snp.yaml | 13 ++++--------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/hal/ubuntu/README.md b/hal/ubuntu/README.md index 599de579..70d9cf4c 100644 --- a/hal/ubuntu/README.md +++ b/hal/ubuntu/README.md @@ -85,6 +85,7 @@ A custom kernel is only required when the SNP host runs Coconut SVSM. The standa The custom kernel must be built with the following options: - `CONFIG_AMD_MEM_ENCRYPT=y` — AMD memory encryption support - `CONFIG_SEV_GUEST=y` — SEV guest driver +- `CONFIG_TCG_PLATFORM=y` — required for vTPM support - Coconut SVSM guest support patches applied The kernel must be packaged as `.deb` files. @@ -103,20 +104,16 @@ hal/ubuntu/ linux-modules-*.deb (if needed) ``` -The `start_snp` command will automatically detect `debs/` and package the files into the seed ISO using `genisoimage`: +The `prepare_snp` command will automatically detect `debs/` and package them along with `user-data` and `meta-data` into the seed ISO using `genisoimage`: ```bash -genisoimage -output seed.img -volid cidata -joliet -rock cidata/ +genisoimage -output seed.img -volid cidata -rock hal/ubuntu/ ``` -Where the `cidata/` directory contains: -``` -cidata/ - meta-data - user-data - debs/ - *.deb -``` +The `hal/ubuntu/` directory must contain: +- `user-data` — the cloud-init configuration (copied from `user-data-snp.yaml`) +- `meta-data` — the VM instance metadata +- `debs/` — the custom kernel `.deb` packages On first boot, cloud-init mounts the seed ISO, installs the `.deb` packages, runs `update-grub`, and the VM boots the new SNP-compatible kernel on next start. diff --git a/hal/ubuntu/qemu.sh b/hal/ubuntu/qemu.sh index ba3efecb..819409e9 100755 --- a/hal/ubuntu/qemu.sh +++ b/hal/ubuntu/qemu.sh @@ -157,7 +157,7 @@ EOF echo "Included kernel .deb files from ${SCRIPT_DIR}/debs/" fi - genisoimage -output "$SEED_IMAGE" -volid cidata -joliet -rock "$cidata_dir" + genisoimage -output "$SEED_IMAGE" -volid cidata -rock "$cidata_dir" } function start_regular() { diff --git a/hal/ubuntu/user-data-snp.yaml b/hal/ubuntu/user-data-snp.yaml index 20856565..b67bc6ba 100644 --- a/hal/ubuntu/user-data-snp.yaml +++ b/hal/ubuntu/user-data-snp.yaml @@ -132,23 +132,18 @@ runcmd: SSHEOF - systemctl restart sshd - sleep 2 - # SEV-SNP Setup for Ubuntu 24.04+ - # Ubuntu 24.04 (Noble) has SEV-SNP guest support built into the kernel - # The kernel CONFIG_SEV_GUEST is enabled by default + # SEV-SNP Setup (local only — not needed on cloud providers like GCP/Azure + # which handle SEV-SNP at the hypervisor level) - | - # Load SEV-SNP guest modules + # Load SEV-SNP guest modules (local deployment only) modprobe ccp 2>/dev/null || echo "CCP module not available" modprobe sev-guest 2>/dev/null || echo "sev-guest module not available" # Verify SEV-SNP guest support if [ -e /dev/sev-guest ]; then echo "SEV-SNP: Running inside an SEV-SNP protected VM" echo "SEV-SNP attestation available via /dev/sev-guest" - elif [ -e /sys/kernel/debug/sev ]; then - echo "SEV-SNP: SEV support detected" - elif grep -q "sev" /proc/cpuinfo 2>/dev/null; then - echo "SEV-SNP: CPU supports SEV" else - echo "SEV-SNP: Not detected (may be running in non-SEV mode)" + echo "SEV-SNP: /dev/sev-guest not detected (expected on cloud providers)" fi - mkdir -p /etc/cube - mkdir -p /etc/cube/certs From df289cf5593b854f222ce10a70f07b034c644146 Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Fri, 6 Mar 2026 11:58:01 +0300 Subject: [PATCH 08/10] Update cloud-init YAML files for clarity and usage instructions Signed-off-by: WashingtonKK --- hal/ubuntu/README.md | 130 ++++++++++++++---------------- hal/ubuntu/user-data-regular.yaml | 3 +- hal/ubuntu/user-data-snp.yaml | 5 +- hal/ubuntu/user-data-tdx.yaml | 5 +- 4 files changed, 67 insertions(+), 76 deletions(-) diff --git a/hal/ubuntu/README.md b/hal/ubuntu/README.md index 70d9cf4c..72bd2c77 100644 --- a/hal/ubuntu/README.md +++ b/hal/ubuntu/README.md @@ -2,87 +2,91 @@ This directory contains cloud-init configurations and QEMU launch scripts for running Cube AI in Ubuntu-based Confidential VMs (CVMs). -## Overview +## Directory Structure -Ubuntu 24.04 (Noble) has built-in support for Intel TDX confidential computing. For AMD SEV-SNP, a custom kernel is required because the host uses SVSM/Coconut — the standard Ubuntu 24.04 kernel does not support it. - -## Files +``` +hal/ubuntu/ + qemu.sh # QEMU launch script (local deployment) + user-data-tdx.yaml # Cloud-init for local QEMU TDX VMs + user-data-snp.yaml # Cloud-init for local QEMU SNP VMs + user-data-regular.yaml # Cloud-init for local QEMU regular VMs + debs/ # Custom kernel .deb packages (SNP with Coconut SVSM only) These need to be added manually by the user if using SNP with Coconut SVSM locally + cloud/ # Cloud provider configs (GCP, Azure) — see cloud/README.md +``` -- `qemu.sh` - Main QEMU launch script with TDX/SNP support -- `user-data-tdx.yaml` - Cloud-init configuration for Intel TDX VMs -- `user-data-snp.yaml` - Cloud-init configuration for AMD SEV-SNP VMs -- `user-data-regular.yaml` - Cloud-init configuration for regular (non-CVM) VMs -- `debs/` - (Optional) Directory for custom kernel `.deb` packages, required only when the SNP host runs Coconut SVSM (see [SNP Kernel](#snp-custom-kernel)) +## Local Deployment (QEMU) -## Usage +All files in the root of this directory are for **local QEMU-based deployment**. Use `qemu.sh` to launch VMs directly on a host machine with KVM. -### Auto-detect CVM Support +### Quick Start ```bash +# Auto-detect CVM support (TDX or SNP) and launch sudo ./qemu.sh start -``` -This will automatically detect available CVM support (TDX or SNP) and launch the VM with the appropriate configuration. +# Or force a specific mode +sudo ./qemu.sh start_tdx # Intel TDX +sudo ./qemu.sh start_regular # Regular KVM (no CVM) +``` -### Force Specific CVM Mode +For AMD SEV-SNP, a two-step process is required: ```bash -# Intel TDX -sudo ./qemu.sh start_tdx - -# AMD SEV-SNP (two steps required) -sudo ./qemu.sh prepare_snp # Run once: installs custom kernel via cloud-init (regular KVM) -sudo ./qemu.sh start_snp # Boot the prepared image with IGVM/SNP - -# Regular KVM (no CVM) -sudo ./qemu.sh start_regular +sudo ./qemu.sh prepare_snp # Step 1: Install custom kernel via cloud-init (regular KVM) +sudo ./qemu.sh start_snp # Step 2: Boot the prepared image with IGVM/SNP ``` ### Environment Variables ```bash -# Force specific CVM mode -ENABLE_CVM=tdx sudo ./qemu.sh start -ENABLE_CVM=snp sudo ./qemu.sh start -ENABLE_CVM=none sudo ./qemu.sh start +ENABLE_CVM=tdx sudo ./qemu.sh start # Force CVM mode: auto, tdx, snp, none +RAM=32768M CPU=16 sudo ./qemu.sh start # Customize VM resources +IGVM=/path/to/coconut-qemu.igvm sudo ./qemu.sh start_snp # Override IGVM path +``` -# Customize VM resources -RAM=32768M CPU=16 sudo ./qemu.sh start +### Detect Available CVM Support -# Override IGVM file path (SNP only) -IGVM=/path/to/coconut-qemu.igvm sudo ./qemu.sh start_snp +```bash +sudo ./qemu.sh detect ``` -### Detect Available Support +### After First Boot + +Default SSH access: +- **Port**: 6190 (forwarded from guest port 22) +- **User**: ultraviolet +- **Password**: password + +For local development, update `docker/.env`: ```bash -sudo ./qemu.sh detect +UV_CUBE_NEXTAUTH_URL=http://:${UI_PORT} ``` -## CVM Support Details +## Cloud Deployment (GCP / Azure) + +For deploying on cloud providers, see [cloud/README.md](cloud/README.md). Cloud providers handle confidential computing at the hypervisor level, so no custom kernel, IGVM, or module loading is needed. -### Intel TDX (Trust Domain Extensions) +## CVM Details -- Ubuntu 24.04 kernel has `CONFIG_INTEL_TDX_GUEST=y` enabled by default -- Guest attestation available via `/sys/firmware/tdx` or configfs -- Quote generation via vsock (CID=2, port=4050) +### Intel TDX -### AMD SEV-SNP (Secure Nested Paging) +- Ubuntu 24.04 kernel has `CONFIG_INTEL_TDX_GUEST=y` enabled by default — no custom kernel needed +- **Local QEMU**: Uses `user-data-tdx.yaml` with `qemu.sh start_tdx`; loads `tdx_guest` module via modprobe +- **Cloud**: TDX module loading is handled by the cloud provider -- Boots via IGVM using the Coconut SVSM QEMU (`/home/cocosai/bin/qemu-svsm/bin/qemu-system-x86_64`) -- Requires an IGVM file (default: `/etc/cocos/coconut-qemu.igvm`) -- If the host runs Coconut SVSM, a custom kernel is required (see [SNP Kernel](#snp-custom-kernel)) -- Guest attestation available via `/dev/sev-guest` -- Modules: `sev-guest`, `ccp` (loaded automatically) -- Disk is automatically resized on first boot via `growpart` +### AMD SEV-SNP -### SNP Custom Kernel +- **Local QEMU with Coconut SVSM**: Requires a custom kernel and two-step boot process (see [SNP Custom Kernel](#snp-custom-kernel) below). Uses `user-data-snp.yaml` which loads `sev-guest` and `ccp` modules via modprobe +- **Cloud (GCP/Azure)**: SEV-SNP is enabled at the hypervisor level — no custom kernel, IGVM, or module loading needed. Use configs in `cloud/` -A custom kernel is only required when the SNP host runs Coconut SVSM. The standard Ubuntu 24.04 kernel does not support Coconut SVSM, so a kernel built with SVSM support must be bundled into the seed image as `.deb` packages. +#### SNP Custom Kernel + +A custom kernel is only required when the **local** SNP host runs Coconut SVSM. The standard Ubuntu 24.04 kernel does not support Coconut SVSM. **Kernel requirements:** -The custom kernel must be built with the following options: +The custom kernel must be built with: - `CONFIG_AMD_MEM_ENCRYPT=y` — AMD memory encryption support - `CONFIG_SEV_GUEST=y` — SEV guest driver - `CONFIG_TCG_PLATFORM=y` — required for vTPM support @@ -104,18 +108,13 @@ hal/ubuntu/ linux-modules-*.deb (if needed) ``` -The `prepare_snp` command will automatically detect `debs/` and package them along with `user-data` and `meta-data` into the seed ISO using `genisoimage`: +The `prepare_snp` command automatically packages the debs along with `user-data` and `meta-data` into the seed ISO using `genisoimage`: ```bash -genisoimage -output seed.img -volid cidata -rock hal/ubuntu/ +genisoimage -output seed.img -volid cidata -rock / ``` -The `hal/ubuntu/` directory must contain: -- `user-data` — the cloud-init configuration (copied from `user-data-snp.yaml`) -- `meta-data` — the VM instance metadata -- `debs/` — the custom kernel `.deb` packages - -On first boot, cloud-init mounts the seed ISO, installs the `.deb` packages, runs `update-grub`, and the VM boots the new SNP-compatible kernel on next start. +On first boot (`prepare_snp`), cloud-init mounts the seed ISO, installs the `.deb` packages, and runs `update-grub`. Then `start_snp` boots the prepared image with IGVM/SNP. **Dependency:** @@ -123,20 +122,9 @@ On first boot, cloud-init mounts the seed ISO, installs the `.deb` packages, run sudo apt-get install genisoimage ``` -## After First Boot - -For local development, update the following in `docker/.env`: - -```bash -UV_CUBE_NEXTAUTH_URL=http://:${UI_PORT} -``` - -Default SSH access: -- **Port**: 6190 (forwarded from guest port 22) -- **User**: ultraviolet -- **Password**: password +## Host Requirements (Local QEMU Only) -## Host Requirements +These requirements apply only to local QEMU deployment. Cloud providers manage these at the infrastructure level. ### For TDX VMs - Intel CPU with TDX support (4th Gen Xeon Scalable or newer) @@ -151,9 +139,9 @@ Default SSH access: - Coconut SVSM QEMU binary at `/home/cocosai/bin/qemu-svsm/bin/qemu-system-x86_64` - IGVM file at `/etc/cocos/coconut-qemu.igvm` (or set `IGVM` env var) - `genisoimage` installed (`apt-get install genisoimage`) -- Custom kernel `.deb` files in `debs/` (see [SNP Kernel](#snp-custom-kernel)) +- Custom kernel `.deb` files in `debs/` (see [SNP Custom Kernel](#snp-custom-kernel)) -### Common Requirements +### Common - QEMU with confidential computing support - OVMF firmware (for UEFI boot) - KVM enabled diff --git a/hal/ubuntu/user-data-regular.yaml b/hal/ubuntu/user-data-regular.yaml index 3295201e..b025893a 100644 --- a/hal/ubuntu/user-data-regular.yaml +++ b/hal/ubuntu/user-data-regular.yaml @@ -2,7 +2,8 @@ # Copyright (c) Ultraviolet # SPDX-License-Identifier: Apache-2.0 # -# Cloud-init configuration for regular (non-CVM) VMs +# Cloud-init for local QEMU regular (non-CVM) VMs +# Used by: qemu.sh start_regular package_update: true package_upgrade: false diff --git a/hal/ubuntu/user-data-snp.yaml b/hal/ubuntu/user-data-snp.yaml index b67bc6ba..db8ed0a1 100644 --- a/hal/ubuntu/user-data-snp.yaml +++ b/hal/ubuntu/user-data-snp.yaml @@ -2,8 +2,9 @@ # Copyright (c) Ultraviolet # SPDX-License-Identifier: Apache-2.0 # -# Cloud-init configuration for AMD SEV-SNP (Secure Nested Paging) VMs -# Ubuntu 24.04+ has SEV-SNP guest support built into the kernel +# Cloud-init for local QEMU AMD SEV-SNP VMs (Coconut SVSM) +# Used by: qemu.sh prepare_snp / start_snp +# For cloud deployments (GCP/Azure), see cloud/ directory instead package_update: true package_upgrade: false diff --git a/hal/ubuntu/user-data-tdx.yaml b/hal/ubuntu/user-data-tdx.yaml index 853e5e2a..42d7c58d 100644 --- a/hal/ubuntu/user-data-tdx.yaml +++ b/hal/ubuntu/user-data-tdx.yaml @@ -2,8 +2,9 @@ # Copyright (c) Ultraviolet # SPDX-License-Identifier: Apache-2.0 # -# Cloud-init configuration for Intel TDX (Trust Domain Extensions) VMs -# Ubuntu 24.04+ has TDX guest support built into the kernel +# Cloud-init for local QEMU Intel TDX VMs +# Used by: qemu.sh start_tdx +# For cloud deployments (GCP/Azure), see cloud/ directory instead package_update: true package_upgrade: false From a3070a6fd47018971d52b45b2163e06d9baa4ddf Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Fri, 6 Mar 2026 13:51:21 +0300 Subject: [PATCH 09/10] Enhance cloud-init and QEMU scripts for vLLM backend support and AMD SEV-SNP integration Signed-off-by: WashingtonKK --- hal/ubuntu/README.md | 23 ++- hal/ubuntu/cloud/README.md | 5 + hal/ubuntu/cloud/cube-agent-config.yml | 12 +- hal/ubuntu/cloud/cube-agent-vllm-config.yml | 25 +-- hal/ubuntu/qemu.sh | 4 + hal/ubuntu/user-data-regular.yaml | 10 +- hal/ubuntu/user-data-snp.yaml | 10 +- hal/ubuntu/user-data-tdx.yaml | 10 +- hal/ubuntu/user-data-vllm-regular.yaml | 143 +++++++++++++++ hal/ubuntu/user-data-vllm-snp.yaml | 187 ++++++++++++++++++++ hal/ubuntu/user-data-vllm-tdx.yaml | 162 +++++++++++++++++ 11 files changed, 559 insertions(+), 32 deletions(-) create mode 100644 hal/ubuntu/user-data-vllm-regular.yaml create mode 100644 hal/ubuntu/user-data-vllm-snp.yaml create mode 100644 hal/ubuntu/user-data-vllm-tdx.yaml diff --git a/hal/ubuntu/README.md b/hal/ubuntu/README.md index 72bd2c77..b1b1d0bd 100644 --- a/hal/ubuntu/README.md +++ b/hal/ubuntu/README.md @@ -6,14 +6,25 @@ This directory contains cloud-init configurations and QEMU launch scripts for ru ``` hal/ubuntu/ - qemu.sh # QEMU launch script (local deployment) - user-data-tdx.yaml # Cloud-init for local QEMU TDX VMs - user-data-snp.yaml # Cloud-init for local QEMU SNP VMs - user-data-regular.yaml # Cloud-init for local QEMU regular VMs - debs/ # Custom kernel .deb packages (SNP with Coconut SVSM only) These need to be added manually by the user if using SNP with Coconut SVSM locally - cloud/ # Cloud provider configs (GCP, Azure) — see cloud/README.md + qemu.sh # QEMU launch script (local deployment) + user-data-tdx.yaml # Cloud-init for local QEMU TDX VMs (Ollama backend) + user-data-snp.yaml # Cloud-init for local QEMU SNP VMs (Ollama backend) + user-data-regular.yaml # Cloud-init for local QEMU regular VMs (Ollama backend) + user-data-vllm-tdx.yaml # Cloud-init for local QEMU TDX VMs (vLLM backend) + user-data-vllm-snp.yaml # Cloud-init for local QEMU SNP VMs (vLLM backend) + user-data-vllm-regular.yaml # Cloud-init for local QEMU regular VMs (vLLM backend) + debs/ # Custom kernel .deb packages (SNP with Coconut SVSM only, added manually) + cloud/ # Cloud provider configs (GCP, Azure) — see cloud/README.md ``` +### Backend Selection + +Each CVM mode has two cloud-init variants: +- **Ollama** (default) — `user-data-{mode}.yaml` — lightweight, supports multiple models, good for development +- **vLLM** — `user-data-vllm-{mode}.yaml` — high-performance inference, OpenAI-compatible API, uses GPU if available + +The cube agent is backend-agnostic — it proxies requests to whatever `UV_CUBE_AGENT_TARGET_URL` is set to (Ollama on port 11434, vLLM on port 8000). + ## Local Deployment (QEMU) All files in the root of this directory are for **local QEMU-based deployment**. Use `qemu.sh` to launch VMs directly on a host machine with KVM. diff --git a/hal/ubuntu/cloud/README.md b/hal/ubuntu/cloud/README.md index a3316df1..181cdeae 100644 --- a/hal/ubuntu/cloud/README.md +++ b/hal/ubuntu/cloud/README.md @@ -58,6 +58,10 @@ tofu init && tofu apply -var-file="../terraform.tfvars" ### Microsoft Azure ```bash +# Clone infrastructure templates +git clone https://github.com/ultravioletrs/cocos-infra.git +cd cocos-infra + # Configure terraform.tfvars cat >> terraform.tfvars << 'EOF' vm_name = "cube-ai-vm" @@ -73,6 +77,7 @@ cd azure az login tofu init && tofu apply -var-file="../terraform.tfvars" ``` +``` ## Configuration diff --git a/hal/ubuntu/cloud/cube-agent-config.yml b/hal/ubuntu/cloud/cube-agent-config.yml index 6c0dc4db..404494ca 100644 --- a/hal/ubuntu/cloud/cube-agent-config.yml +++ b/hal/ubuntu/cloud/cube-agent-config.yml @@ -7,9 +7,10 @@ # on Ubuntu-based confidential VMs (GCP, Azure, or QEMU with TDX/SEV-SNP). # # Usage: -# - GCP: Reference this file in terraform.tfvars as cloud_init_config -# - Azure: Reference this file in terraform.tfvars as cloud_init_config -# - QEMU: Use with cloud-localds to create seed image +# Clone https://github.com/ultravioletrs/cocos-infra.git, then: +# - GCP: set cloud_init_config to this file path in terraform.tfvars +# - Azure: set cloud_init_config to this file path in terraform.tfvars +# See cloud/README.md for full deployment instructions # # Environment Variables (set before deployment): # CUBE_AI_BACKEND - AI backend: "ollama" (default) or "vllm" @@ -271,8 +272,11 @@ runcmd: chmod +x /usr/local/bin/cube-agent else echo "Could not find release, building from source..." + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz && rm /tmp/go.tar.gz git clone https://github.com/ultravioletrs/cube.git /tmp/cube - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent fi # Enable and start services diff --git a/hal/ubuntu/cloud/cube-agent-vllm-config.yml b/hal/ubuntu/cloud/cube-agent-vllm-config.yml index 429ae147..66474eaf 100644 --- a/hal/ubuntu/cloud/cube-agent-vllm-config.yml +++ b/hal/ubuntu/cloud/cube-agent-vllm-config.yml @@ -13,8 +13,10 @@ # - Tensor parallelism for multi-GPU setups # # Usage: -# - GCP: Reference this file in terraform.tfvars as cloud_init_config -# - Azure: Reference this file in terraform.tfvars as cloud_init_config +# Clone https://github.com/ultravioletrs/cocos-infra.git, then: +# - GCP: set cloud_init_config to this file path in terraform.tfvars +# - Azure: set cloud_init_config to this file path in terraform.tfvars +# See cloud/README.md for full deployment instructions # # Recommended VM sizes: # - GCP: n1-standard-8 with nvidia-tesla-t4 or better @@ -46,9 +48,6 @@ packages: - build-essential - ca-certificates - jq - - nvidia-driver-535 - - nvidia-cuda-toolkit - write_files: # Cube Agent environment configuration for vLLM - path: /etc/cube/agent.env.template @@ -99,12 +98,6 @@ write_files: VLLM_HOST=0.0.0.0 VLLM_PORT=8000 - # GPU configuration - VLLM_TENSOR_PARALLEL_SIZE=${CUBE_VLLM_GPU_COUNT:-1} - - # Memory configuration - VLLM_GPU_MEMORY_UTILIZATION=0.9 - # HuggingFace token (for gated models) # HF_TOKEN=your_token_here permissions: '0644' @@ -126,9 +119,7 @@ write_files: ExecStart=/var/lib/vllm/venv/bin/python -m vllm.entrypoints.openai.api_server \ --model ${VLLM_MODEL} \ --host ${VLLM_HOST} \ - --port ${VLLM_PORT} \ - --tensor-parallel-size ${VLLM_TENSOR_PARALLEL_SIZE} \ - --gpu-memory-utilization ${VLLM_GPU_MEMORY_UTILIZATION} + --port ${VLLM_PORT} Restart=on-failure RestartSec=10 StartLimitBurst=3 @@ -250,9 +241,11 @@ runcmd: chmod +x /usr/local/bin/cube-agent else echo "Could not find release, building from source..." - apt-get install -y golang-go + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz && rm /tmp/go.tar.gz git clone https://github.com/ultravioletrs/cube.git /tmp/cube - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent fi # Enable and start services diff --git a/hal/ubuntu/qemu.sh b/hal/ubuntu/qemu.sh index 819409e9..79ad63f9 100755 --- a/hal/ubuntu/qemu.sh +++ b/hal/ubuntu/qemu.sh @@ -283,6 +283,10 @@ Environment Variables: CPU Number of vCPUs (default: 8) DISK_SIZE Disk size (default: 35G) +Backend: + Default cloud-init configs use Ollama. For vLLM, use the + user-data-vllm-*.yaml variants (uses GPU if available). + Examples: $0 start # Auto-detect and start with best available CVM $0 start_tdx # Force TDX mode diff --git a/hal/ubuntu/user-data-regular.yaml b/hal/ubuntu/user-data-regular.yaml index b025893a..4bdf8fc9 100644 --- a/hal/ubuntu/user-data-regular.yaml +++ b/hal/ubuntu/user-data-regular.yaml @@ -24,7 +24,6 @@ ssh_pwauth: true packages: - curl - git - - golang-go - build-essential write_files: @@ -121,10 +120,17 @@ runcmd: - chown -R ollama:ollama /var/lib/ollama - chown -R ollama:ollama /home/ollama - curl -fsSL https://ollama.com/install.sh | sh + - | + # Install Go (required version from go.mod) + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go + tar -C /usr/local -xzf /tmp/go.tar.gz + rm /tmp/go.tar.gz - git clone https://github.com/ultravioletrs/cube.git /tmp/cube - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 - export HOME=/root - - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent - systemctl daemon-reload - systemctl enable ollama.service - systemctl start ollama.service diff --git a/hal/ubuntu/user-data-snp.yaml b/hal/ubuntu/user-data-snp.yaml index db8ed0a1..f1dc2368 100644 --- a/hal/ubuntu/user-data-snp.yaml +++ b/hal/ubuntu/user-data-snp.yaml @@ -32,7 +32,6 @@ ssh_pwauth: true packages: - curl - git - - golang-go - build-essential write_files: @@ -165,10 +164,17 @@ runcmd: - chown -R ollama:ollama /var/lib/ollama - chown -R ollama:ollama /home/ollama - curl -fsSL https://ollama.com/install.sh | sh + - | + # Install Go (required version from go.mod) + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go + tar -C /usr/local -xzf /tmp/go.tar.gz + rm /tmp/go.tar.gz - git clone https://github.com/ultravioletrs/cube.git /tmp/cube - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 - export HOME=/root - - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent - systemctl daemon-reload - systemctl enable ollama.service - systemctl start ollama.service diff --git a/hal/ubuntu/user-data-tdx.yaml b/hal/ubuntu/user-data-tdx.yaml index 42d7c58d..de6a52b1 100644 --- a/hal/ubuntu/user-data-tdx.yaml +++ b/hal/ubuntu/user-data-tdx.yaml @@ -25,7 +25,6 @@ ssh_pwauth: true packages: - curl - git - - golang-go - build-essential write_files: @@ -144,10 +143,17 @@ runcmd: - chown -R ollama:ollama /var/lib/ollama - chown -R ollama:ollama /home/ollama - curl -fsSL https://ollama.com/install.sh | sh + - | + # Install Go (required version from go.mod) + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go + tar -C /usr/local -xzf /tmp/go.tar.gz + rm /tmp/go.tar.gz - git clone https://github.com/ultravioletrs/cube.git /tmp/cube - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 - export HOME=/root - - cd /tmp/cube && /usr/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent - systemctl daemon-reload - systemctl enable ollama.service - systemctl start ollama.service diff --git a/hal/ubuntu/user-data-vllm-regular.yaml b/hal/ubuntu/user-data-vllm-regular.yaml new file mode 100644 index 00000000..8d649038 --- /dev/null +++ b/hal/ubuntu/user-data-vllm-regular.yaml @@ -0,0 +1,143 @@ +#cloud-config +# Copyright (c) Ultraviolet +# SPDX-License-Identifier: Apache-2.0 +# +# Cloud-init for local QEMU regular (non-CVM) VMs with vLLM backend +# Used by: qemu.sh start_regular +# vLLM will use GPU automatically if available, otherwise falls back to CPU + +package_update: true +package_upgrade: false + +users: + - name: ultraviolet + plain_text_passwd: password + lock_passwd: false + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + - name: vllm + system: true + home: /var/lib/vllm + shell: /usr/sbin/nologin + +ssh_pwauth: true + +packages: + - curl + - git + - build-essential + - python3 + - python3-pip + - python3-venv + +write_files: + - path: /etc/cube/agent.env + content: | + UV_CUBE_AGENT_LOG_LEVEL=info + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + UV_CUBE_AGENT_TARGET_URL=http://localhost:8000 + UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt + UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key + UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt + UV_CUBE_AGENT_CA_URL=https://prism.ultraviolet.rs/am-certs + permissions: '0644' + - path: /etc/cube/vllm.env + content: | + VLLM_MODEL=${CUBE_VLLM_MODEL:-meta-llama/Llama-2-7b-hf} + VLLM_HOST=0.0.0.0 + VLLM_PORT=8000 + permissions: '0644' + - path: /etc/systemd/system/vllm.service + content: | + [Unit] + Description=vLLM Inference Server + After=network-online.target + Wants=network-online.target + + [Service] + Type=simple + User=vllm + Group=vllm + EnvironmentFile=/etc/cube/vllm.env + WorkingDirectory=/var/lib/vllm + ExecStart=/var/lib/vllm/venv/bin/python -m vllm.entrypoints.openai.api_server \ + --model ${VLLM_MODEL} \ + --host ${VLLM_HOST} \ + --port ${VLLM_PORT} + Restart=on-failure + RestartSec=10 + StartLimitBurst=3 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /etc/systemd/system/cube-agent.service + content: | + [Unit] + Description=Cube Agent Service + After=network-online.target vllm.service + Wants=network-online.target + + [Service] + Type=simple + EnvironmentFile=/etc/cube/agent.env + ExecStart=/usr/local/bin/cube-agent + Restart=on-failure + RestartSec=5 + StartLimitBurst=5 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + +runcmd: + - echo 'ultraviolet:password' | chpasswd + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + - sleep 2 + - mkdir -p /etc/cube + - mkdir -p /etc/cube/certs + - | + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" + # Generate server certificate + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" + openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" + openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 + # Set permissions + chmod 600 /etc/cube/certs/*.key + chmod 644 /etc/cube/certs/*.crt + - mkdir -p /var/lib/vllm + - chown -R vllm:vllm /var/lib/vllm + - | + # Install vLLM in virtual environment + sudo -u vllm python3 -m venv /var/lib/vllm/venv + sudo -u vllm /var/lib/vllm/venv/bin/pip install --upgrade pip + sudo -u vllm /var/lib/vllm/venv/bin/pip install vllm + - | + # Install Go (required version from go.mod) + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go + tar -C /usr/local -xzf /tmp/go.tar.gz + rm /tmp/go.tar.gz + - git clone https://github.com/ultravioletrs/cube.git /tmp/cube + - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 + - export HOME=/root + - cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - systemctl daemon-reload + - systemctl enable vllm.service + - systemctl start vllm.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + +final_message: "Cube Agent (vLLM) and vLLM services started." diff --git a/hal/ubuntu/user-data-vllm-snp.yaml b/hal/ubuntu/user-data-vllm-snp.yaml new file mode 100644 index 00000000..0f26edf7 --- /dev/null +++ b/hal/ubuntu/user-data-vllm-snp.yaml @@ -0,0 +1,187 @@ +#cloud-config +# Copyright (c) Ultraviolet +# SPDX-License-Identifier: Apache-2.0 +# +# Cloud-init for local QEMU AMD SEV-SNP VMs with vLLM backend (Coconut SVSM) +# Used by: qemu.sh prepare_snp / start_snp +# vLLM will use GPU automatically if available, otherwise falls back to CPU +# For cloud deployments (GCP/Azure), see cloud/ directory instead + +package_update: true +package_upgrade: false + +growpart: + mode: auto + devices: ["/"] + ignore_growroot_disabled: false + +resize_rootfs: true + +users: + - name: ultraviolet + plain_text_passwd: password + lock_passwd: false + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + - name: vllm + system: true + home: /var/lib/vllm + shell: /usr/sbin/nologin + +ssh_pwauth: true + +packages: + - curl + - git + - build-essential + - python3 + - python3-pip + - python3-venv + +write_files: + - path: /etc/cube/agent.env + content: | + UV_CUBE_AGENT_LOG_LEVEL=info + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + UV_CUBE_AGENT_TARGET_URL=http://localhost:8000 + UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt + UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key + UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt + UV_CUBE_AGENT_CA_URL=https://prism.ultraviolet.rs/am-certs + # SNP-specific settings + AGENT_OS_TYPE=snp + AGENT_VMPL=2 + permissions: '0644' + - path: /etc/cube/vllm.env + content: | + VLLM_MODEL=${CUBE_VLLM_MODEL:-meta-llama/Llama-2-7b-hf} + VLLM_HOST=0.0.0.0 + VLLM_PORT=8000 + permissions: '0644' + - path: /etc/systemd/system/vllm.service + content: | + [Unit] + Description=vLLM Inference Server + After=network-online.target + Wants=network-online.target + + [Service] + Type=simple + User=vllm + Group=vllm + EnvironmentFile=/etc/cube/vllm.env + WorkingDirectory=/var/lib/vllm + ExecStart=/var/lib/vllm/venv/bin/python -m vllm.entrypoints.openai.api_server \ + --model ${VLLM_MODEL} \ + --host ${VLLM_HOST} \ + --port ${VLLM_PORT} + Restart=on-failure + RestartSec=10 + StartLimitBurst=3 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /etc/systemd/system/cube-agent.service + content: | + [Unit] + Description=Cube Agent Service + After=network-online.target vllm.service + Wants=network-online.target + + [Service] + Type=simple + EnvironmentFile=/etc/cube/agent.env + ExecStart=/usr/local/bin/cube-agent + Restart=on-failure + RestartSec=5 + StartLimitBurst=5 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /etc/modules-load.d/sev-snp.conf + content: | + # AMD SEV-SNP guest modules + sev-guest + ccp + permissions: '0644' + +runcmd: + - | + # Install custom SNP-compatible kernel from seed image if present + mkdir -p /mnt/seed + dev="$(blkid -L cidata || blkid -L CIDATA || true)" + if [ -n "$dev" ]; then + mount "$dev" /mnt/seed + if ls /mnt/seed/debs/*.deb 2>/dev/null; then + cp /mnt/seed/debs/*.deb /root/ + dpkg -i /root/*.deb || apt-get -y -f install + update-grub + sync + fi + umount /mnt/seed || true + fi + - echo 'ultraviolet:password' | chpasswd + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + - sleep 2 + # SEV-SNP Setup (local only — not needed on cloud providers like GCP/Azure + # which handle SEV-SNP at the hypervisor level) + - | + # Load SEV-SNP guest modules (local deployment only) + modprobe ccp 2>/dev/null || echo "CCP module not available" + modprobe sev-guest 2>/dev/null || echo "sev-guest module not available" + # Verify SEV-SNP guest support + if [ -e /dev/sev-guest ]; then + echo "SEV-SNP: Running inside an SEV-SNP protected VM" + echo "SEV-SNP attestation available via /dev/sev-guest" + else + echo "SEV-SNP: /dev/sev-guest not detected (expected on cloud providers)" + fi + - mkdir -p /etc/cube + - mkdir -p /etc/cube/certs + - | + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" + # Generate server certificate + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" + openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" + openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 + # Set permissions + chmod 600 /etc/cube/certs/*.key + chmod 644 /etc/cube/certs/*.crt + - mkdir -p /var/lib/vllm + - chown -R vllm:vllm /var/lib/vllm + - | + # Install vLLM in virtual environment + sudo -u vllm python3 -m venv /var/lib/vllm/venv + sudo -u vllm /var/lib/vllm/venv/bin/pip install --upgrade pip + sudo -u vllm /var/lib/vllm/venv/bin/pip install vllm + - | + # Install Go (required version from go.mod) + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go + tar -C /usr/local -xzf /tmp/go.tar.gz + rm /tmp/go.tar.gz + - git clone https://github.com/ultravioletrs/cube.git /tmp/cube + - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 + - export HOME=/root + - cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - systemctl daemon-reload + - systemctl enable vllm.service + - systemctl start vllm.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + +final_message: "Cube Agent (SEV-SNP + vLLM) and vLLM services started." diff --git a/hal/ubuntu/user-data-vllm-tdx.yaml b/hal/ubuntu/user-data-vllm-tdx.yaml new file mode 100644 index 00000000..9cddcd10 --- /dev/null +++ b/hal/ubuntu/user-data-vllm-tdx.yaml @@ -0,0 +1,162 @@ +#cloud-config +# Copyright (c) Ultraviolet +# SPDX-License-Identifier: Apache-2.0 +# +# Cloud-init for local QEMU Intel TDX VMs with vLLM backend +# Used by: qemu.sh start_tdx +# vLLM will use GPU automatically if available, otherwise falls back to CPU +# For cloud deployments (GCP/Azure), see cloud/ directory instead + +package_update: true +package_upgrade: false + +users: + - name: ultraviolet + plain_text_passwd: password + lock_passwd: false + sudo: ALL=(ALL) NOPASSWD:ALL + shell: /bin/bash + - name: vllm + system: true + home: /var/lib/vllm + shell: /usr/sbin/nologin + +ssh_pwauth: true + +packages: + - curl + - git + - build-essential + - python3 + - python3-pip + - python3-venv + +write_files: + - path: /etc/cube/agent.env + content: | + UV_CUBE_AGENT_LOG_LEVEL=info + UV_CUBE_AGENT_HOST=0.0.0.0 + UV_CUBE_AGENT_PORT=7001 + UV_CUBE_AGENT_INSTANCE_ID=cube-agent-01 + UV_CUBE_AGENT_TARGET_URL=http://localhost:8000 + UV_CUBE_AGENT_SERVER_CERT=/etc/cube/certs/server.crt + UV_CUBE_AGENT_SERVER_KEY=/etc/cube/certs/server.key + UV_CUBE_AGENT_SERVER_CA_CERTS=/etc/cube/certs/ca.crt + UV_CUBE_AGENT_CA_URL=https://prism.ultraviolet.rs/am-certs + # TDX-specific settings + AGENT_OS_TYPE=tdx + permissions: '0644' + - path: /etc/cube/vllm.env + content: | + VLLM_MODEL=${CUBE_VLLM_MODEL:-meta-llama/Llama-2-7b-hf} + VLLM_HOST=0.0.0.0 + VLLM_PORT=8000 + permissions: '0644' + - path: /etc/systemd/system/vllm.service + content: | + [Unit] + Description=vLLM Inference Server + After=network-online.target + Wants=network-online.target + + [Service] + Type=simple + User=vllm + Group=vllm + EnvironmentFile=/etc/cube/vllm.env + WorkingDirectory=/var/lib/vllm + ExecStart=/var/lib/vllm/venv/bin/python -m vllm.entrypoints.openai.api_server \ + --model ${VLLM_MODEL} \ + --host ${VLLM_HOST} \ + --port ${VLLM_PORT} + Restart=on-failure + RestartSec=10 + StartLimitBurst=3 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + - path: /etc/systemd/system/cube-agent.service + content: | + [Unit] + Description=Cube Agent Service + After=network-online.target vllm.service + Wants=network-online.target + + [Service] + Type=simple + EnvironmentFile=/etc/cube/agent.env + ExecStart=/usr/local/bin/cube-agent + Restart=on-failure + RestartSec=5 + StartLimitBurst=5 + StartLimitIntervalSec=60 + + [Install] + WantedBy=multi-user.target + permissions: '0644' + +runcmd: + - echo 'ultraviolet:password' | chpasswd + - | + cat > /etc/ssh/sshd_config.d/60-cloudimg-settings.conf << 'SSHEOF' + PasswordAuthentication yes + SSHEOF + - systemctl restart sshd + - sleep 2 + # TDX Setup for Ubuntu 24.04+ + - | + KERNEL_VERSION=$(uname -r) + echo "Installing TDX modules for kernel ${KERNEL_VERSION}..." + apt-get update + apt-get install -y linux-modules-extra-${KERNEL_VERSION} || apt-get install -y linux-modules-extra-generic || echo "Module package install failed" + mkdir -p /etc/modules-load.d + echo "tdx_guest" > /etc/modules-load.d/tdx.conf + modprobe tdx_guest 2>/dev/null || echo "tdx_guest module not available (will load after reboot)" + if [ -e /dev/tdx_guest ]; then + echo "TDX: /dev/tdx_guest device available" + elif [ -e /sys/firmware/tdx ]; then + echo "TDX: Running inside a TDX Trust Domain" + else + echo "TDX: Module configured, will be available after reboot" + fi + - mkdir -p /etc/cube + - mkdir -p /etc/cube/certs + - | + # Generate CA certificate + openssl req -x509 -newkey rsa:4096 -keyout /etc/cube/certs/ca.key -out /etc/cube/certs/ca.crt -days 365 -nodes -subj "/CN=Cube-CA" + # Generate server certificate + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/server.key -out /etc/cube/certs/server.csr -nodes -subj "/CN=cube-agent" + openssl x509 -req -in /etc/cube/certs/server.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/server.crt -days 365 + # Generate client certificate for mTLS + openssl req -newkey rsa:4096 -keyout /etc/cube/certs/client.key -out /etc/cube/certs/client.csr -nodes -subj "/CN=cube-client" + openssl x509 -req -in /etc/cube/certs/client.csr -CA /etc/cube/certs/ca.crt -CAkey /etc/cube/certs/ca.key -CAcreateserial -out /etc/cube/certs/client.crt -days 365 + # Set permissions + chmod 600 /etc/cube/certs/*.key + chmod 644 /etc/cube/certs/*.crt + - mkdir -p /var/lib/vllm + - chown -R vllm:vllm /var/lib/vllm + - | + # Install vLLM in virtual environment + sudo -u vllm python3 -m venv /var/lib/vllm/venv + sudo -u vllm /var/lib/vllm/venv/bin/pip install --upgrade pip + sudo -u vllm /var/lib/vllm/venv/bin/pip install vllm + - | + # Install Go (required version from go.mod) + GO_VERSION=$(curl -fsSL https://go.dev/VERSION?m=text | head -1 | sed 's/go//') + curl -fsSL https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz -o /tmp/go.tar.gz + rm -rf /usr/local/go + tar -C /usr/local -xzf /tmp/go.tar.gz + rm /tmp/go.tar.gz + - git clone https://github.com/ultravioletrs/cube.git /tmp/cube + - cd /tmp/cube && git fetch origin pull/88/head:pr-88 && git checkout pr-88 + - export HOME=/root + - cd /tmp/cube && /usr/local/go/bin/go build -ldflags="-s -w" -o /usr/local/bin/cube-agent ./cmd/agent + - systemctl daemon-reload + - systemctl enable vllm.service + - systemctl start vllm.service + - systemctl enable cube-agent.service + - systemctl start cube-agent.service + +final_message: "Cube Agent (TDX + vLLM) and vLLM services started." From fbe4c18bbc19896cb8430945febe4581edc3ac2c Mon Sep 17 00:00:00 2001 From: WashingtonKK Date: Fri, 6 Mar 2026 13:51:53 +0300 Subject: [PATCH 10/10] Refactor README and cube-agent-config.yml for clarity and consistency in deployment instructions Signed-off-by: WashingtonKK --- hal/ubuntu/cloud/README.md | 239 +++++++++---------------- hal/ubuntu/cloud/cube-agent-config.yml | 16 +- 2 files changed, 88 insertions(+), 167 deletions(-) diff --git a/hal/ubuntu/cloud/README.md b/hal/ubuntu/cloud/README.md index 181cdeae..b9a7fde9 100644 --- a/hal/ubuntu/cloud/README.md +++ b/hal/ubuntu/cloud/README.md @@ -1,208 +1,135 @@ -# Cloud-Init Configuration for Cube AI +# Cloud Deployment for Cube AI -This directory contains cloud-init configuration files for deploying Cube AI on Ubuntu-based confidential virtual machines (CVMs) on cloud providers. +This directory contains cloud-init configurations for deploying Cube AI on confidential VMs on GCP and Azure, using the [cocos-infra](https://github.com/ultravioletrs/cocos-infra) Terraform templates. -## Cloud-Init Files +## Files | File | Backend | Description | |------|---------|-------------| -| `cube-agent-config.yml` | Ollama | Default configuration with Ollama for easy model management | -| `cube-agent-vllm-config.yml` | vLLM | High-performance configuration with vLLM for production workloads | +| `cube-agent-config.yml` | Ollama | Default configuration with Ollama for model management | +| `cube-agent-vllm-config.yml` | vLLM | High-performance configuration with vLLM | -## Choosing a Backend +## Prerequisites -### Ollama (Recommended for Getting Started) - -Use `cube-agent-config.yml` for: - -- Quick setup and experimentation -- Running multiple models -- CPU or small GPU deployments -- Built-in quantization support (Q4_0, Q4_1, Q8_0) - -### vLLM (Recommended for Production) - -Use `cube-agent-vllm-config.yml` for: - -- Maximum inference throughput -- Large-scale production deployments -- Multi-GPU setups with tensor parallelism -- Continuous batching and PagedAttention - -## Deployment - -### Google Cloud Platform (GCP) +- [OpenTofu](https://opentofu.org) or Terraform installed +- GCP or Azure account with permissions to create confidential VMs +- cocos-infra repository cloned: ```bash -# Clone infrastructure templates git clone https://github.com/ultravioletrs/cocos-infra.git cd cocos-infra - -# Configure terraform.tfvars -cat >> terraform.tfvars << 'EOF' -vm_name = "cube-ai-vm" -project_id = "your-gcp-project-id" -region = "us-central1" -zone = "us-central1-a" -min_cpu_platform = "AMD Milan" -confidential_instance_type = "SEV_SNP" -machine_type = "n2d-standard-4" -cloud_init_config = "/path/to/cube/hal/ubuntu/cloud/cube-agent-config.yml" -EOF - -# Deploy -cd gcp -tofu init && tofu apply -var-file="../terraform.tfvars" ``` -### Microsoft Azure +## Deployment -```bash -# Clone infrastructure templates -git clone https://github.com/ultravioletrs/cocos-infra.git -cd cocos-infra +### Google Cloud Platform (GCP) -# Configure terraform.tfvars -cat >> terraform.tfvars << 'EOF' -vm_name = "cube-ai-vm" -resource_group_name = "cube-ai-rg" -location = "westus" -subscription_id = "your-subscription-id" -machine_type = "Standard_DC4ads_v5" -cloud_init_config = "/path/to/cube/hal/ubuntu/cloud/cube-agent-config.yml" -EOF +#### Step 1: Deploy KMS (for disk encryption) -# Deploy -cd azure -az login -tofu init && tofu apply -var-file="../terraform.tfvars" -``` +```bash +cd gcp/kms +tofu init +tofu apply -var-file="../../terraform.tfvars" ``` -## Configuration +Note the `disk_encryption_id` output — you'll need it in the next step. -### Environment Variables +#### Step 2: Configure terraform.tfvars -Set these environment variables before deployment to customize the configuration: +Create or update `terraform.tfvars` at the root of cocos-infra: -| Variable | Default | Description | -|----------|---------|-------------| -| `CUBE_MODELS` | `tinyllama:1.1b` | Comma-separated Ollama models to pull | -| `CUBE_VLLM_MODEL` | `meta-llama/Llama-2-7b-hf` | HuggingFace model ID for vLLM | -| `CUBE_VLLM_GPU_COUNT` | `1` | Number of GPUs for tensor parallelism | -| `CUBE_AGENT_VERSION` | `latest` | Cube Agent release version | -| `HF_TOKEN` | - | HuggingFace token for gated models | +```hcl +vm_name = "cube-ai-vm" +project_id = "your-gcp-project-id" +region = "us-central1" +min_cpu_platform = "AMD Milan" +confidential_instance_type = "SEV_SNP" +machine_type = "n2d-standard-4" +vm_id = "cube-vm-001" +workspace_id = "cube-workspace-001" +disk_encryption_id = "" # output from gcp/kms step above +cloud_init_config = "/path/to/cube/hal/ubuntu/cloud/cube-agent-config.yml" +``` -### TLS/mTLS Certificates +#### Step 3: Deploy the VM -For production deployments, replace the self-signed certificate generation with your own certificates: +```bash +cd gcp +tofu init +tofu apply -var-file="../terraform.tfvars" +``` -1. Edit the cloud-init file -2. Uncomment the certificate file sections -3. Replace placeholder content with your certificates -4. Update `/etc/cube/agent.env` to enable TLS +--- -### Custom Models (Ollama) +### Microsoft Azure -Pull additional models by setting `CUBE_MODELS`: +#### Step 1: Authenticate ```bash -export CUBE_MODELS="llama2:7b,mistral:latest,codellama:13b" +az login ``` -Or create a custom Modelfile after deployment: +#### Step 2: Deploy KMS (for disk encryption) ```bash -ssh cubeadmin@ -cat > /tmp/Modelfile << 'EOF' -FROM llama2:7b -PARAMETER temperature 0.7 -SYSTEM You are a helpful AI assistant. -EOF -sudo -u ollama /usr/local/bin/ollama create custom-assistant -f /tmp/Modelfile +cd azure/kms +tofu init +tofu apply -var-file="../../terraform.tfvars" ``` -## Verification - -After deployment, verify the services are running: - -```bash -# Check cloud-init completion -ssh cubeadmin@ -cloud-init status --wait - -# Check service status -sudo systemctl status cube-agent -sudo systemctl status ollama # or vllm +Note the `disk_encryption_id` output. -# Test health endpoint -curl http://localhost:7001/health +#### Step 3: Configure terraform.tfvars -# Test chat completion -curl http://:7001/v1/chat/completions \ - -H "Content-Type: application/json" \ - -d '{ - "model": "tinyllama:1.1b", - "messages": [{"role": "user", "content": "Hello!"}] - }' +```hcl +vm_name = "cube-ai-vm" +resource_group_name = "cube-ai-rg" +location = "westus" +subscription_id = "your-subscription-id" +machine_type = "Standard_DC4ads_v5" +vm_id = "cube-vm-001" +workspace_id = "cube-workspace-001" +disk_encryption_id = "" # output from azure/kms step above +cloud_init_config = "/path/to/cube/hal/ubuntu/cloud/cube-agent-config.yml" ``` -## VM Size Recommendations - -### GCP - -| Use Case | Machine Type | vCPUs | RAM | -|----------|--------------|-------|-----| -| Development | `n2d-standard-2` | 2 | 8GB | -| Production (Ollama) | `n2d-standard-4` | 4 | 16GB | -| Production (vLLM) | `n2d-standard-8` | 8 | 32GB | -| Production (vLLM + GPU) | `n1-standard-8` + T4 | 8 | 30GB | - -### Azure - -| Use Case | Machine Type | vCPUs | RAM | -|----------|--------------|-------|-----| -| Development | `Standard_DC2ads_v5` | 2 | 8GB | -| Production (Ollama) | `Standard_DC4ads_v5` | 4 | 16GB | -| Production (vLLM) | `Standard_DC8ads_v5` | 8 | 32GB | -| Production (vLLM + GPU) | `Standard_NC6s_v3` | 6 | 112GB | - -## Troubleshooting - -### Cloud-init not completing +#### Step 4: Deploy the VM ```bash -# Check cloud-init logs -sudo cat /var/log/cloud-init-output.log -sudo cat /var/log/cloud-init.log +cd azure +tofu init +tofu apply -var-file="../terraform.tfvars" ``` -### Cube Agent not starting +## Configuration -```bash -# Check service logs -sudo journalctl -u cube-agent -f +### Choosing a Backend -# Verify configuration -cat /etc/cube/agent.env -``` +- Use `cube-agent-config.yml` for Ollama — good for multi-model setups and general use +- Use `cube-agent-vllm-config.yml` for vLLM — OpenAI-compatible API, better throughput for single-model production use -### Ollama not responding +### Environment Variables -```bash -# Check service logs -sudo journalctl -u ollama -f +Set these in `vllm.env` or `agent.env` inside the VM to customize: -# Check if models are downloaded -sudo -u ollama /usr/local/bin/ollama list -``` +| Variable | Default | Description | +|----------|---------|-------------| +| `CUBE_VLLM_MODEL` | `meta-llama/Llama-2-7b-hf` | HuggingFace model ID for vLLM | +| `UV_CUBE_AGENT_LOG_LEVEL` | `info` | Agent log level | +| `UV_CUBE_AGENT_CA_URL` | `` | Attestation Manager URL | + +## After Deployment -### vLLM GPU issues +SSH into the VM and check service status: ```bash -# Check NVIDIA driver -nvidia-smi +# Check cloud-init completed +cloud-init status --wait + +# Check services +sudo systemctl status cube-agent +sudo systemctl status ollama # or vllm -# Check vLLM logs -sudo journalctl -u vllm -f +# Test agent health +curl http://localhost:7001/health ``` diff --git a/hal/ubuntu/cloud/cube-agent-config.yml b/hal/ubuntu/cloud/cube-agent-config.yml index 404494ca..8c6f260e 100644 --- a/hal/ubuntu/cloud/cube-agent-config.yml +++ b/hal/ubuntu/cloud/cube-agent-config.yml @@ -3,19 +3,13 @@ # Copyright (c) Ultraviolet # SPDX-License-Identifier: Apache-2.0 # -# This cloud-init configuration sets up a Cube AI agent with Ollama backend -# on Ubuntu-based confidential VMs (GCP, Azure, or QEMU with TDX/SEV-SNP). +# Cloud-init for Cube AI agent with Ollama backend on GCP or Azure confidential VMs. +# For local QEMU deployment, use user-data-*.yaml files in the parent directory instead. # # Usage: -# Clone https://github.com/ultravioletrs/cocos-infra.git, then: -# - GCP: set cloud_init_config to this file path in terraform.tfvars -# - Azure: set cloud_init_config to this file path in terraform.tfvars -# See cloud/README.md for full deployment instructions -# -# Environment Variables (set before deployment): -# CUBE_AI_BACKEND - AI backend: "ollama" (default) or "vllm" -# CUBE_MODELS - Comma-separated list of models to pull (Ollama only) -# CUBE_VLLM_MODEL - HuggingFace model ID for vLLM backend +# Clone https://github.com/ultravioletrs/cocos-infra.git and set +# cloud_init_config to this file path in terraform.tfvars. +# See cloud/README.md for full deployment instructions. # # For vLLM backend, see: hal/ubuntu/cloud/cube-agent-vllm-config.yml