-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Frieder Paape
committed
Nov 15, 2024
1 parent
c999955
commit 9f55786
Showing
4 changed files
with
515 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,42 @@ | ||
# flashbox :zap: :package: | ||
|
||
flashbox is an opinionated Confidential VM (CVM) base image designed to run podman pod payloads. It provides a simple way to deploy containerized applications in a secure environment. | ||
flashbox is an opinionated Confidential VM (CVM) base image built for podman pod payloads. With a focus on security balanced against TCB size, designed to give developers the simplest path to TDX VMs. | ||
|
||
## Why flashbox? | ||
|
||
One command, `./zap` - and you've got yourself a TDX box. | ||
|
||
⚠️ **IMPORTANT**: This is an early development release and is not production-ready software. Use with caution. | ||
|
||
## Quick Start | ||
|
||
1. Deploy the flashbox VM image | ||
- [Bare Metal non-TDX](#bare-metal-non-tdx) | ||
- [Bare Metal TDX](#bare-metal-tdx) | ||
- [Azure Deployment](#azure-deployment) | ||
- [GCP Deployment](#gcp-deployment) | ||
1. Download the latest VM image from the releases page | ||
|
||
2. Deploy the flashbox VM: | ||
```bash | ||
# Local deployment (non-TDX) | ||
./zap --mode normal --image flashbox.raw | ||
|
||
# Local deployment (TDX) | ||
./zap --mode tdx --image flashbox.raw | ||
|
||
# Azure deployment | ||
./zap azure myvm eastus flashbox.azure.vhd | ||
|
||
2. Provision and start your containers: | ||
# GCP deployment | ||
./zap gcp myvm us-east4 flashbox.tar.gz | ||
``` | ||
|
||
### Known Issues | ||
|
||
- Azure deployments may encounter an issue with the `--security-type` parameter. See [Azure CLI Issue #29207](https://github.com/Azure/azure-cli/issues/29207#issuecomment-2479343290) for the workaround. | ||
|
||
### Considerations | ||
|
||
⚠️ **WARNING**: Debug releases come with SSH enabled and a root user without password. Always use the `--ssh-source-ip` option to restrict SSH access in cloud deployments. | ||
⚠️ **IMPORTANT**: If you want to run TDX VMs on bare metal you need to first setup your host environment properly. For this, follow the instructions in the [canonical/tdx](https://github.com/canonical/tdx) repo. | ||
|
||
3. Provision and start your containers: | ||
```bash | ||
# Upload pod configuration and environment variables | ||
curl -X POST -F "[email protected]" -F "env=@env" http://flashbox:24070/upload | ||
|
@@ -22,16 +47,14 @@ curl -X POST http://flashbox:24070/start | |
|
||
## Pod Configuration | ||
|
||
### Docker Compose Users | ||
|
||
If you're coming from Docker Compose, you can convert your existing configurations to podman pod format. The pod configuration format is similar to Kubernetes manifests (YAML manifests). | ||
### Docker Compose Migration | ||
|
||
To convert a Docker Compose file to a podman pod configuration: | ||
If you're coming from Docker Compose, you can convert your existing configurations: | ||
```bash | ||
podman-compose generate-k8s docker-compose.yml > pod.yaml | ||
``` | ||
|
||
See the [official documentation on differences between Docker Compose and Podman](https://docs.podman.io/en/latest/markdown/podman-compose.1.html) for more details on migration. | ||
See the [official documentation on differences between Docker Compose and Podman](https://docs.podman.io/en/latest/markdown/podman-compose.1.html) for migration details. | ||
|
||
### Example Configuration | ||
|
||
|
@@ -49,17 +72,12 @@ spec: | |
- name: web-container | ||
image: nginx:latest | ||
env: | ||
- name: DB_HOST | ||
value: "localhost" | ||
- name: API_PORT | ||
value: "3000" | ||
- name: DATABASE_URL | ||
value: "${DATABASE_URL}" | ||
ports: | ||
- containerPort: 80 | ||
hostPort: 8080 | ||
``` | ||
### Non-Attestable Variable Configuration | ||
flashbox allows you to provision secrets and configuration variables that should remain outside the attestation flow. This is done through a separate `env` file that is processed independently of the pod configuration. | ||
|
@@ -80,36 +98,3 @@ env: | |
``` | ||
|
||
Variables in the env file will be substituted into the pod configuration at runtime, keeping them separate from the attestation process. This is useful for both secrets and configuration that may vary between deployments. | ||
|
||
## Deployment Options | ||
|
||
### Bare Metal non-TDX | ||
[TO BE FILLED: Bare metal non-TDX deployment instructions] | ||
|
||
### Bare Metal TDX | ||
[TO BE FILLED: Bare metal TDX deployment instructions] | ||
|
||
### Azure Deployment | ||
[TO BE FILLED: Azure deployment instructions] | ||
|
||
### GCP Deployment | ||
[TO BE FILLED: GCP deployment instructions] | ||
|
||
## Security Considerations | ||
|
||
- flashbox runs in a Confidential VM environment, providing enhanced security for your workloads | ||
- Configuration variables can be separated from pod configurations using the env file | ||
- The env file contents are not included in the attestation flow, providing flexibility for deployment-specific configurations | ||
|
||
## API Endpoints | ||
|
||
- `POST http://flashbox:24070/upload`: Upload pod configuration and environment files | ||
- `POST http://flashbox:24070/start`: Start the configured containers | ||
|
||
## Contributing | ||
|
||
[TO BE FILLED: Contributing guidelines] | ||
|
||
## License | ||
|
||
[TO BE FILLED: License information] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
#!/bin/bash | ||
|
||
usage() { | ||
echo "Usage: $0 [options]" | ||
echo "Options:" | ||
echo " --mode <normal|tdx> VM mode (default: normal)" | ||
echo " --image PATH Path to VM image (required)" | ||
echo " --ram SIZE RAM size in GB (default: 32)" | ||
echo " --cpus NUMBER Number of CPUs (default: 16)" | ||
echo " --ssh-port PORT SSH port forwarding (default: 10022)" | ||
echo " --ports PORTS Additional ports to open, comma-separated" | ||
echo " --name STRING Process name (default: qemu-vm)" | ||
echo " --log PATH Log file path (default: /tmp/qemu-guest.log)" | ||
echo " --ovmf PATH Path to OVMF firmware (default: /usr/share/ovmf/OVMF.fd)" | ||
echo " --help Show this help message" | ||
exit 1 | ||
} | ||
|
||
cleanup() { | ||
rm -f /tmp/qemu-guest*.log &> /dev/null | ||
rm -f /tmp/qemu-*-monitor.sock &> /dev/null | ||
|
||
PID_QEMU=$(cat /tmp/qemu-pid.pid 2> /dev/null) | ||
[ ! -z "$PID_QEMU" ] && echo "Cleanup, kill VM with PID: ${PID_QEMU}" && kill -TERM ${PID_QEMU} &> /dev/null | ||
sleep 3 | ||
} | ||
|
||
# Default values | ||
MODE="normal" | ||
RAM_SIZE="32" | ||
CPUS="16" | ||
SSH_PORT="10022" | ||
ADDITIONAL_PORTS="" | ||
PROCESS_NAME="qemu-vm" | ||
LOGFILE="/tmp/qemu-guest.log" | ||
OVMF_PATH="/usr/share/ovmf/OVMF.fd" | ||
|
||
# Parse command line arguments | ||
while [[ $# -gt 0 ]]; do | ||
case $1 in | ||
--mode) | ||
MODE="$2" | ||
shift 2 | ||
;; | ||
--image) | ||
VM_IMG="$2" | ||
shift 2 | ||
;; | ||
--ram) | ||
RAM_SIZE="$2" | ||
shift 2 | ||
;; | ||
--cpus) | ||
CPUS="$2" | ||
shift 2 | ||
;; | ||
--ssh-port) | ||
SSH_PORT="$2" | ||
shift 2 | ||
;; | ||
--ports) | ||
ADDITIONAL_PORTS="$2" | ||
shift 2 | ||
;; | ||
--name) | ||
PROCESS_NAME="$2" | ||
shift 2 | ||
;; | ||
--log) | ||
LOGFILE="$2" | ||
shift 2 | ||
;; | ||
--ovmf) | ||
OVMF_PATH="$2" | ||
shift 2 | ||
;; | ||
--help) | ||
usage | ||
;; | ||
*) | ||
echo "Unknown option: $1" | ||
usage | ||
;; | ||
esac | ||
done | ||
|
||
# Check required parameters | ||
if [ -z "$VM_IMG" ]; then | ||
echo "Error: VM image path is required" | ||
usage | ||
fi | ||
|
||
# Verify mode | ||
if [ "$MODE" != "normal" ] && [ "$MODE" != "tdx" ]; then | ||
echo "Error: Invalid mode. Must be 'normal' or 'tdx'" | ||
usage | ||
fi | ||
|
||
# Check KVM group membership | ||
if ! groups | grep -qw "kvm"; then | ||
echo "Please add user $USER to kvm group to run this script (usermod -aG kvm $USER and then log in again)." | ||
exit 1 | ||
fi | ||
|
||
# Clean up any existing instances | ||
cleanup | ||
if [ "$1" = "clean" ]; then | ||
exit 0 | ||
fi | ||
|
||
# Prepare port forwarding string | ||
PORT_FORWARDS="-device virtio-net-pci,netdev=nic0 -netdev user,id=nic0,hostfwd=tcp::${SSH_PORT}-:22" | ||
|
||
# Add default flashbox ports | ||
PORT_FORWARDS="${PORT_FORWARDS},hostfwd=tcp::24070-:24070,hostfwd=tcp::24071-:24071" | ||
|
||
# Add additional ports if specified | ||
if [ ! -z "$ADDITIONAL_PORTS" ]; then | ||
IFS=',' read -ra PORTS <<< "$ADDITIONAL_PORTS" | ||
for port in "${PORTS[@]}"; do | ||
PORT_FORWARDS="${PORT_FORWARDS},hostfwd=tcp::${port}-:${port}" | ||
done | ||
fi | ||
|
||
# Base QEMU command | ||
QEMU_CMD="qemu-system-x86_64 -D $LOGFILE \ | ||
-accel kvm \ | ||
-m ${RAM_SIZE}G -smp $CPUS \ | ||
-name ${PROCESS_NAME},process=${PROCESS_NAME},debug-threads=on \ | ||
-cpu host \ | ||
-nographic \ | ||
-nodefaults \ | ||
${PORT_FORWARDS} \ | ||
-drive file=${VM_IMG},if=none,id=virtio-disk0 \ | ||
-device virtio-blk-pci,drive=virtio-disk0 \ | ||
-bios ${OVMF_PATH} \ | ||
-chardev stdio,id=char0,mux=on,signal=off \ | ||
-mon chardev=char0 \ | ||
-serial chardev:char0 \ | ||
-pidfile /tmp/qemu-pid.pid" | ||
|
||
# Add TDX-specific parameters if mode is tdx | ||
if [ "$MODE" = "tdx" ]; then | ||
QEMU_CMD="$QEMU_CMD \ | ||
-object '{\"qom-type\":\"tdx-guest\",\"id\":\"tdx\",\"quote-generation-socket\":{\"type\": \"vsock\", \"cid\":\"2\",\"port\":\"4050\"}}' \ | ||
-machine q35,kernel_irqchip=split,confidential-guest-support=tdx,hpet=off \ | ||
-device vhost-vsock-pci,guest-cid=4" | ||
else | ||
QEMU_CMD="$QEMU_CMD \ | ||
-machine q35" | ||
fi | ||
|
||
# Execute QEMU command | ||
eval $QEMU_CMD | ||
|
||
ret=$? | ||
if [ $ret -ne 0 ]; then | ||
echo "Error: Failed to create VM. Please check logfile \"$LOGFILE\" for more information." | ||
exit $ret | ||
fi | ||
|
||
PID_QEMU=$(cat /tmp/qemu-pid.pid) | ||
|
||
echo "VM started in $MODE mode with PID: ${PID_QEMU}" | ||
echo "To login via SSH: ssh -p $SSH_PORT root@localhost" |
Oops, something went wrong.