{"id":2133,"date":"2026-03-31T14:03:24","date_gmt":"2026-03-31T21:03:24","guid":{"rendered":"https:\/\/wp.c9h.org\/cj\/?p=2133"},"modified":"2026-03-31T14:03:24","modified_gmt":"2026-03-31T21:03:24","slug":"finding-promoting-seabios-cloud-images-to-uefi-secure-boot-proxmox","status":"publish","type":"post","link":"https:\/\/wp.c9h.org\/cj\/?p=2133","title":{"rendered":"Finding: Promoting SeaBIOS Cloud Images to UEFI Secure Boot (Proxmox)"},"content":{"rendered":"<h2 id=\"discovery\">Discovery<\/h2>\n<p>Legacy cloud templates often lack the partitioning and bootloader<br \/>\nbinaries required for UEFI Secure Boot. Attempting to switch such a VM<br \/>\nto OVMF in Proxmox results in \u201cnot a bootable disk.\u201d We discovered that<br \/>\na surgical promotion is possible by manipulating the block device and<br \/>\nEFI variables from the hypervisor.<\/p>\n<h2 id=\"the-problem\">The Problem<\/h2>\n<ol type=\"1\">\n<li><strong>Protective MBR Flags:<\/strong> Legacy installers often set<br \/>\nthe <code>pmbr_boot<\/code> flag on the GPT\u2019s protective MBR. Strict UEFI<br \/>\nimplementations (OVMF) will ignore the GPT if this flag is present.<\/li>\n<li><strong>Missing ESP:<\/strong> Cloud images often lack a FAT32 EFI<br \/>\nSystem Partition (ESP).<\/li>\n<li><strong>Variable Store:<\/strong> A fresh Proxmox<br \/>\n<code>efidisk0<\/code> is empty and lacks both the trust certificates<br \/>\n(PK\/KEK\/db) and the BootOrder entries required for an automated<br \/>\nboot.<\/li>\n<\/ol>\n<h2 id=\"the-promotion-rule\">The \u201cPromotion\u201d Rule<\/h2>\n<p>To upgrade a SeaBIOS VM to Secure Boot without a full OS reinstall:<br \/>\n1. <strong>Surgical Partitioning:<\/strong> Map the disk on the host and<br \/>\nadd a FAT32 partition (Type <code>EF00<\/code>). Clear the<br \/>\n<code>pmbr_boot<\/code> flag from the MBR. 2. <strong>Binary<br \/>\nPreparation:<\/strong> Boot the VM in SeaBIOS mode to install<br \/>\n<code>shim<\/code> and <code>grub-efi<\/code> packages. Use<br \/>\n<code>grub2-mkconfig<\/code> to populate the new ESP. 3. <strong>Trust<br \/>\nInjection:<\/strong> Use the <code>virt-fw-vars<\/code> utility on the<br \/>\nhypervisor to programmatically enroll the Red Hat\/Microsoft CA keys and<br \/>\nany custom certificates (e.g., FreeIPA CA) into the VM\u2019s<br \/>\n<code>efidisk<\/code>. 4. <strong>Boot Pinning:<\/strong> Explicitly set<br \/>\nthe UEFI <code>BootOrder<\/code> to point to the <code>shimx64.efi<\/code><br \/>\npath via <code>virt-fw-vars --append-boot-filepath<\/code>.<\/p>\n<h2 id=\"solution-example-command-sequence\">Solution (Example Command<br \/>\nSequence)<\/h2>\n<p>On the Proxmox Host (<code>root<\/code>):<\/p>\n<div class=\"sourceCode\" id=\"cb1\">\n<pre\nclass=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=\"cb1-1\"><a href=\"#cb1-1\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># Map and Clean MBR<\/span><\/span>\n<span id=\"cb1-2\"><a href=\"#cb1-2\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"va\">DEV<\/span><span class=\"op\">=<\/span><span class=\"va\">$(<\/span><span class=\"ex\">rbd<\/span> map pool\/disk<span class=\"va\">)<\/span><\/span>\n<span id=\"cb1-3\"><a href=\"#cb1-3\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">parted<\/span> <span class=\"at\">-s<\/span> <span class=\"va\">$DEV<\/span> disk_set pmbr_boot off<\/span>\n<span id=\"cb1-4\"><a href=\"#cb1-4\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><\/span>\n<span id=\"cb1-5\"><a href=\"#cb1-5\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"co\"># Inject Trust and Boot Path (VM must be stopped)<\/span><\/span>\n<span id=\"cb1-6\"><a href=\"#cb1-6\" aria-hidden=\"true\" tabindex=\"-1\"><\/a><span class=\"ex\">virt-fw-vars<\/span> <span class=\"at\">--inplace<\/span> \/dev\/rbd\/mapped_efidisk <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb1-7\"><a href=\"#cb1-7\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--enroll-redhat<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb1-8\"><a href=\"#cb1-8\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--add-db<\/span> <span class=\"op\">&lt;<\/span>GUID<span class=\"op\">&gt;<\/span> \/path\/to\/ipa-ca.crt <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb1-9\"><a href=\"#cb1-9\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--append-boot-filepath<\/span> <span class=\"st\">&#39;\\EFI\\centos\\shimx64.efi&#39;<\/span> <span class=\"dt\">\\<\/span><\/span>\n<span id=\"cb1-10\"><a href=\"#cb1-10\" aria-hidden=\"true\" tabindex=\"-1\"><\/a>  <span class=\"at\">--sb<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>This workflow enables high-integrity Secure Boot environments using<br \/>\nexisting SeaBIOS infrastructure templates.<\/p>\n\n<div class=\"twitter-share\"><a href=\"https:\/\/twitter.com\/intent\/tweet?via=cjamescollier\" class=\"twitter-share-button\">Tweet<\/a><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Discovery Legacy cloud templates often lack the partitioning and bootloader binaries required for UEFI Secure Boot. Attempting to switch such a VM to OVMF in Proxmox results in \u201cnot a bootable disk.\u201d We discovered that a surgical promotion is possible by manipulating the block device and EFI variables from the hypervisor. The Problem Protective MBR [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[17,341,340,101,184,100],"tags":[],"class_list":["post-2133","post","type-post","status-publish","format-standard","hentry","category-debian","category-proxmox","category-secure-boot","category-security","category-virtualization","category-x509"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1YDIB-yp","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=\/wp\/v2\/posts\/2133","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2133"}],"version-history":[{"count":2,"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=\/wp\/v2\/posts\/2133\/revisions"}],"predecessor-version":[{"id":2135,"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=\/wp\/v2\/posts\/2133\/revisions\/2135"}],"wp:attachment":[{"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2133"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2133"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wp.c9h.org\/cj\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2133"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}