mirror of
https://github.com/siderolabs/talos.git
synced 2025-12-10 03:51:14 +01:00
Support passing uki profiles from imager. Part-of: #10190 Signed-off-by: Noel Georgi <git@frezbo.dev>
227 lines
5.8 KiB
Go
227 lines
5.8 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
// Package uki creates the UKI file out of the sd-stub and other sections.
|
|
package uki
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"github.com/siderolabs/talos/internal/pkg/measure"
|
|
"github.com/siderolabs/talos/internal/pkg/secureboot/pesign"
|
|
"github.com/siderolabs/talos/internal/pkg/uki/internal/pe"
|
|
"github.com/siderolabs/talos/pkg/imager/utils"
|
|
)
|
|
|
|
// Section is a name of a PE file section (UEFI binary).
|
|
type Section string
|
|
|
|
// List of well-known section names.
|
|
const (
|
|
SectionLinux Section = ".linux"
|
|
SectionOSRel Section = ".osrel"
|
|
SectionCmdline Section = ".cmdline"
|
|
SectionInitrd Section = ".initrd"
|
|
SectionUcode Section = ".ucode"
|
|
SectionSplash Section = ".splash"
|
|
SectionDTB Section = ".dtb"
|
|
SectionUname Section = ".uname"
|
|
SectionSBAT Section = ".sbat"
|
|
SectionPCRSig Section = ".pcrsig"
|
|
SectionPCRPKey Section = ".pcrpkey"
|
|
SectionProfile Section = ".profile"
|
|
SectionDTBAuto Section = ".dtbauto"
|
|
SectionHWIDS Section = ".hwids"
|
|
)
|
|
|
|
// String returns the string representation of the section.
|
|
func (s Section) String() string {
|
|
return string(s)
|
|
}
|
|
|
|
type section = pe.Section
|
|
|
|
// Builder is a UKI file builder.
|
|
type Builder struct {
|
|
// Source options.
|
|
//
|
|
// Arch of the UKI file.
|
|
Arch string
|
|
// Version of Talos.
|
|
Version string
|
|
// Path to the sd-stub.
|
|
SdStubPath string
|
|
// Path to the sd-boot.
|
|
SdBootPath string
|
|
// Path to the kernel image.
|
|
KernelPath string
|
|
// Path to the initrd image.
|
|
InitrdPath string
|
|
// Kernel cmdline.
|
|
Cmdline string
|
|
// SecureBoot certificate and signer.
|
|
SecureBootSigner pesign.CertificateSigner
|
|
// PCR signer.
|
|
PCRSigner measure.RSAKey
|
|
// Profiles to include in the UKI.
|
|
Profiles []Profile
|
|
|
|
// Output options:
|
|
//
|
|
// Path to the signed sd-boot.
|
|
OutSdBootPath string
|
|
// Path to the output UKI file.
|
|
OutUKIPath string
|
|
|
|
// fields initialized during build
|
|
sections []section
|
|
scratchDir string
|
|
peSigner *pesign.Signer
|
|
unsignedUKIPath string
|
|
}
|
|
|
|
// Profile is a UKI Profile.
|
|
// For now only cmdline is supported.
|
|
type Profile struct {
|
|
ID string
|
|
Title string
|
|
|
|
Cmdline string
|
|
}
|
|
|
|
// String returns the string representation of the profile that gets adds to the `.profile` section.
|
|
func (p Profile) String() string {
|
|
s := fmt.Sprintf("ID=%s", p.ID)
|
|
|
|
if p.Title != "" {
|
|
s += fmt.Sprintf("\nTITLE=%s", p.Title)
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
// Build the unsigned UKI file.
|
|
//
|
|
// Build process is as follows:
|
|
// - build ephemeral sections (uname, os-release), and other proposed sections
|
|
// - assemble the final UKI file starting from sd-stub and appending generated section.
|
|
func (builder *Builder) Build(printf func(string, ...any)) error {
|
|
var err error
|
|
|
|
builder.scratchDir, err = os.MkdirTemp("", "talos-uki")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
if err = os.RemoveAll(builder.scratchDir); err != nil {
|
|
log.Printf("failed to remove scratch dir: %v", err)
|
|
}
|
|
}()
|
|
|
|
if err := utils.CopyFiles(printf, utils.SourceDestination(builder.SdBootPath, builder.OutSdBootPath)); err != nil {
|
|
return err
|
|
}
|
|
|
|
printf("generating UKI sections")
|
|
|
|
// generate and build list of all sections
|
|
for _, generateSection := range []func() error{
|
|
builder.generateSBAT,
|
|
builder.generateOSRel,
|
|
builder.generateCmdline,
|
|
builder.generateUname,
|
|
builder.generateSplash,
|
|
builder.generateKernel,
|
|
builder.generateInitrd,
|
|
builder.generateProfiles,
|
|
} {
|
|
if err = generateSection(); err != nil {
|
|
return fmt.Errorf("error generating sections: %w", err)
|
|
}
|
|
}
|
|
|
|
printf("assembling UKI")
|
|
|
|
// assemble the final UKI file
|
|
if err = builder.assemble(); err != nil {
|
|
return fmt.Errorf("error assembling UKI: %w", err)
|
|
}
|
|
|
|
return utils.CopyFiles(printf, utils.SourceDestination(builder.unsignedUKIPath, builder.OutUKIPath))
|
|
}
|
|
|
|
// BuildSigned the UKI file.
|
|
//
|
|
// BuildSigned process is as follows:
|
|
// - sign the sd-boot EFI binary, and write it to the OutSdBootPath
|
|
// - build ephemeral sections (uname, os-release), and other proposed sections
|
|
// - measure sections, generate signature, and append to the list of sections
|
|
// - assemble the final UKI file starting from sd-stub and appending generated section.
|
|
func (builder *Builder) BuildSigned(printf func(string, ...any)) error {
|
|
var err error
|
|
|
|
builder.scratchDir, err = os.MkdirTemp("", "talos-uki")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
defer func() {
|
|
if err = os.RemoveAll(builder.scratchDir); err != nil {
|
|
log.Printf("failed to remove scratch dir: %v", err)
|
|
}
|
|
}()
|
|
|
|
printf("signing systemd-boot")
|
|
|
|
builder.peSigner, err = pesign.NewSigner(builder.SecureBootSigner)
|
|
if err != nil {
|
|
return fmt.Errorf("error initializing signer: %w", err)
|
|
}
|
|
|
|
// sign sd-boot
|
|
if err = builder.peSigner.Sign(builder.SdBootPath, builder.OutSdBootPath); err != nil {
|
|
return fmt.Errorf("error signing sd-boot: %w", err)
|
|
}
|
|
|
|
printf("generating UKI sections")
|
|
|
|
// generate and build list of all sections
|
|
for _, generateSection := range []func() error{
|
|
builder.generateSBAT,
|
|
builder.generateOSRel,
|
|
builder.generateCmdline,
|
|
builder.generateUname,
|
|
builder.generateSplash,
|
|
builder.generatePCRPublicKey,
|
|
builder.generateKernel,
|
|
builder.generateInitrd,
|
|
builder.generateProfiles,
|
|
builder.generatePCRSig,
|
|
} {
|
|
if err = generateSection(); err != nil {
|
|
return fmt.Errorf("error generating sections: %w", err)
|
|
}
|
|
}
|
|
|
|
printf("assembling UKI")
|
|
|
|
// assemble the final UKI file
|
|
if err = builder.assemble(); err != nil {
|
|
return fmt.Errorf("error assembling UKI: %w", err)
|
|
}
|
|
|
|
printf("signing UKI")
|
|
|
|
// sign the UKI file
|
|
return builder.peSigner.Sign(builder.unsignedUKIPath, builder.OutUKIPath)
|
|
}
|
|
|
|
// Extract extracts the kernel, initrd, and cmdline from the UKI file.
|
|
func Extract(ukiPath string) (asset pe.AssetInfo, err error) {
|
|
return pe.Extract(ukiPath)
|
|
}
|