-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathMakefile
More file actions
162 lines (152 loc) · 7.2 KB
/
Copy pathMakefile
File metadata and controls
162 lines (152 loc) · 7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
.PHONY: help build clean freeze-requirements extract-uki extract-boot-artifacts
# Image version - can be overridden via IMAGE_VERSION=x.y.z, defaults to mkosi.conf
IMAGE_VERSION ?= $(shell grep '^ImageVersion=' mkosi.conf | cut -d= -f2)
# Output files (mkosi adds version suffix from ImageVersion in mkosi.conf)
DISK_IMAGE_RAW=confer-image_$(IMAGE_VERSION).raw
DISK_IMAGE=confer-image_$(IMAGE_VERSION).qcow2
UKI_IMAGE=confer-image_$(IMAGE_VERSION).efi
KERNEL_IMAGE=confer-image_$(IMAGE_VERSION).vmlinuz
INITRD_IMAGE=confer-image_$(IMAGE_VERSION).initrd
CMDLINE_FILE=confer-image_$(IMAGE_VERSION).cmdline
# Default target
help:
@echo "Confer Confidential VM Image Builder"
@echo "====================================="
@echo ""
@echo "Targets:"
@echo " make build - Build confidential VM disk image (TDX/SEV-SNP)"
@echo " make clean - Remove build artifacts"
@echo " make freeze-requirements - Generate locked Python requirements"
@echo " make extract-uki - Extract UKI from disk image ESP"
@echo " make extract-boot-artifacts - Extract kernel, initrd, cmdline for direct boot"
@echo ""
@echo "Output (for direct kernel boot):"
@echo " $(DISK_IMAGE) - Rootfs disk image with dm-verity"
@echo " $(KERNEL_IMAGE) - Linux kernel for -kernel flag"
@echo " $(INITRD_IMAGE) - Initrd for -initrd flag"
@echo " $(CMDLINE_FILE) - Base kernel cmdline (add proxy-hash at runtime)"
@echo ""
@echo "Prerequisites:"
@echo " 1. Install Nix: https://nixos.org/download.html"
@echo " 2. Enable flakes: https://nixos.wiki/wiki/Flakes"
@echo " 3. Run: nix develop"
@echo ""
# Build the VM disk image and generate measurements
build: mkosi.extra/requirements-vllm.lock mkosi.extra/requirements-attestation.lock
@echo "Building confidential VM disk image with dm-verity..."
@echo "Image version: $(IMAGE_VERSION)"
@# Detect skeleton/config changes to decide if incremental cache should be cleared
@SKELETON_HASH=$$(find mkosi.skeleton mkosi.conf -type f -exec sha256sum {} \; 2>/dev/null | sort | sha256sum | cut -d' ' -f1); \
if [ "$$SKELETON_HASH" != "$$(cat .skeleton-hash 2>/dev/null)" ]; then \
echo "Skeleton/config changed, clearing incremental cache..."; \
sudo $$(which mkosi) --force --force --image-version=$(IMAGE_VERSION); \
echo "$$SKELETON_HASH" > .skeleton-hash; \
else \
echo "Skeleton unchanged, using incremental cache..."; \
sudo $$(which mkosi) --force --image-version=$(IMAGE_VERSION); \
fi
@echo ""
@echo "Extracting boot artifacts for direct kernel boot..."
@$(MAKE) extract-boot-artifacts
@echo ""
@echo "Converting to compressed qcow2..."
@qemu-img convert -f raw -O qcow2 -c -o compression_type=zstd -W -m 16 \
$(DISK_IMAGE_RAW) $(DISK_IMAGE)
@echo "✓ Converted to $(DISK_IMAGE) ($$(du -h $(DISK_IMAGE) | cut -f1))"
@echo ""
@echo "=== Build Complete ==="
@echo "Output files for direct kernel boot:"
@echo " $(KERNEL_IMAGE) - Use with QEMU -kernel"
@echo " $(INITRD_IMAGE) - Use with QEMU -initrd"
@echo " $(DISK_IMAGE) - Use with QEMU -drive"
@echo " $(CMDLINE_FILE) - Base cmdline (append proxy-hash=<hash> at runtime)"
@echo ""
# Extract UKI from disk image ESP partition
extract-uki:
@echo "Extracting UKI from ESP partition..."
@if [ ! -f $(DISK_IMAGE_RAW) ]; then \
echo "Error: Disk image not found. Run 'make build' first."; \
exit 1; \
fi
@# Find ESP partition offset (partition type C12A7328-F81F-11D2-BA4B-00A0C93EC93B)
@ESP_START=$$(sfdisk -J $(DISK_IMAGE_RAW) | python3 -c "import json,sys; parts=json.load(sys.stdin)['partitiontable']['partitions']; print(next(p['start'] for p in parts if p.get('type','').upper() == 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B'))") && \
ESP_SIZE=$$(sfdisk -J $(DISK_IMAGE_RAW) | python3 -c "import json,sys; parts=json.load(sys.stdin)['partitiontable']['partitions']; print(next(p['size'] for p in parts if p.get('type','').upper() == 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B'))") && \
echo " ESP at sector $$ESP_START, size $$ESP_SIZE sectors" && \
rm -rf .esp-mount && mkdir -p .esp-mount && \
sudo mount -o loop,offset=$$((ESP_START * 512)),sizelimit=$$((ESP_SIZE * 512)),ro $(DISK_IMAGE_RAW) .esp-mount && \
echo " ESP contents:" && \
find .esp-mount -type f | head -20 && \
UKI_PATH=$$(find .esp-mount -name '*.efi' -path '*/EFI/Linux/*' | head -1) && \
if [ -z "$$UKI_PATH" ]; then \
UKI_PATH=$$(find .esp-mount -name '*.efi' -path '*/EFI/*' | head -1); \
fi && \
if [ -z "$$UKI_PATH" ]; then \
echo "Error: Could not find UKI in ESP"; \
sudo umount .esp-mount; \
exit 1; \
fi && \
echo " Found UKI at: $$UKI_PATH" && \
sudo cp "$$UKI_PATH" $(UKI_IMAGE) && \
sudo chown $$(id -u):$$(id -g) $(UKI_IMAGE) && \
sudo umount .esp-mount && \
rm -rf .esp-mount && \
echo "✓ UKI extracted to $(UKI_IMAGE)"
# Extract kernel, initrd, cmdline from UKI for direct kernel boot
extract-boot-artifacts: extract-uki
@echo "Extracting boot artifacts from UKI..."
@if [ ! -f $(UKI_IMAGE) ]; then \
echo "Error: UKI $(UKI_IMAGE) not found."; \
exit 1; \
fi
@# Extract kernel, initrd, and cmdline sections from UKI PE binary
objcopy --dump-section .linux=$(KERNEL_IMAGE) \
--dump-section .initrd=$(INITRD_IMAGE) \
--dump-section .cmdline=.cmdline.raw \
$(UKI_IMAGE)
@# Clean up cmdline (remove null bytes) and save
@cat .cmdline.raw | tr -d '\0' > $(CMDLINE_FILE)
@rm -f .cmdline.raw
@echo "✓ Kernel extracted to $(KERNEL_IMAGE) ($$(du -h $(KERNEL_IMAGE) | cut -f1))"
@echo "✓ Initrd extracted to $(INITRD_IMAGE) ($$(du -h $(INITRD_IMAGE) | cut -f1))"
@echo "✓ Cmdline saved to $(CMDLINE_FILE)"
@echo " $$(cat $(CMDLINE_FILE))"
# Copy requirements lock files
mkosi.extra/requirements-vllm.lock: requirements-vllm.lock
@mkdir -p mkosi.extra
@cp requirements-vllm.lock mkosi.extra/
mkosi.extra/requirements-attestation.lock: requirements-attestation.lock
@mkdir -p mkosi.extra
@cp requirements-attestation.lock mkosi.extra/
# Generate frozen Python requirements (run this once to create lock files)
# vLLM and the attestation SDK are installed separately due to dependency conflicts
freeze-requirements:
@echo "Generating frozen Python requirements..."
@echo ""
@echo "==> Freezing vLLM dependencies..."
@rm -rf /tmp/vllm-freeze
@python3.12 -m venv /tmp/vllm-freeze
@/tmp/vllm-freeze/bin/pip install --upgrade pip
@/tmp/vllm-freeze/bin/pip install vllm==0.17.0
@/tmp/vllm-freeze/bin/pip freeze > requirements-vllm.lock
@rm -rf /tmp/vllm-freeze
@echo "Created requirements-vllm.lock with $$(wc -l < requirements-vllm.lock) pinned packages"
@echo ""
@echo "==> Freezing attestation SDK dependencies..."
@rm -rf /tmp/attestation-freeze
@python3.12 -m venv /tmp/attestation-freeze
@/tmp/attestation-freeze/bin/pip install --upgrade pip
@/tmp/attestation-freeze/bin/pip install nv-attestation-sdk
@/tmp/attestation-freeze/bin/pip freeze > requirements-attestation.lock
@rm -rf /tmp/attestation-freeze
@echo "Created requirements-attestation.lock with $$(wc -l < requirements-attestation.lock) pinned packages"
# Clean build artifacts
clean:
@echo "Cleaning build artifacts..."
@rm -rf mkosi.output/
@rm -rf mkosi.cache/
@rm -rf mkosi.extra/
@rm -rf .esp-mount/
@rm -f $(DISK_IMAGE)
@rm -f $(UKI_IMAGE)
@rm -f $(KERNEL_IMAGE) $(INITRD_IMAGE) $(CMDLINE_FILE)
@echo "Clean complete"