Skip to content

Commit

Permalink
Merge pull request #556 from flatcar/sayan/secureboot-implement-ci+jepio
Browse files Browse the repository at this point in the history
support testing secureboot in Qemu
  • Loading branch information
jepio authored Sep 11, 2024
2 parents aad4b72 + b496a0b commit cf464dd
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 27 deletions.
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,26 +95,31 @@ wget https://alpha.release.flatcar-linux.net/amd64-usr/current/flatcar_productio
wget https://alpha.release.flatcar-linux.net/amd64-usr/current/flatcar_production_qemu_uefi_efi_code.fd.sig
gpg --verify flatcar_production_qemu_uefi_efi_code.fd.sig

wget https://alpha.release.flatcar-linux.net/amd64-usr/current/flatcar_production_qemu_uefi_efi_vars.fd
wget https://alpha.release.flatcar-linux.net/amd64-usr/current/flatcar_production_qemu_uefi_efi_vars.fd.sig
gpg --verify flatcar_production_qemu_uefi_efi_vars.fd.sig

sudo ./bin/kola run --board amd64-usr --key ${HOME}/.ssh/id_rsa.pub -k -b cl -p qemu \
--qemu-bios flatcar_production_qemu_uefi_efi_code.fd \
--qemu-firmware flatcar_production_qemu_uefi_efi_code.fd \
--qemu-ovmf-vars flatcar_production_qemu_uefi_efi_vars.fd \
--qemu-image flatcar_production_qemu_image.img \
cl.locksmith.cluster
```

###### Run tests for ARM64
Example with the latest `alpha` release:
```shell
wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_secure_image.img
wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_secure_image.img.sig
gpg --verify flatcar_production_qemu_uefi_secure_image.img.sig
wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_image.img
wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_image.img.sig
gpg --verify flatcar_production_qemu_uefi_image.img.sig

wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_efi_code.fd
wget https://alpha.release.flatcar-linux.net/arm64-usr/current/flatcar_production_qemu_uefi_efi_code.fd.sig
gpg --verify flatcar_production_qemu_uefi_efi_code.fd.sig

sudo ./bin/kola run --board arm64-usr --key ${HOME}/.ssh/id_rsa.pub -k -b cl -p qemu \
--qemu-bios flatcar_production_qemu_uefi_efi_code.fd \
--qemu-image flatcar_production_qemu_uefi_secure_image.bin \
--qemu-firmware flatcar_production_qemu_uefi_efi_code.fd \
--qemu-image flatcar_production_qemu_uefi_image.img \
cl.etcd-member.discovery
```

Expand Down
15 changes: 11 additions & 4 deletions cmd/kola/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ var (
"rhcos": "v3",
}

kolaDefaultBIOS = map[string]string{
kolaDefaultFirmware = map[string]string{
"amd64-usr": "bios-256k.bin",
"arm64-usr": sdk.BuildRoot() + "/images/arm64-usr/latest/flatcar_production_qemu_uefi_efi_code.fd",
}
Expand Down Expand Up @@ -87,6 +87,7 @@ func init() {
sv(&kola.UpdatePayloadFile, "update-payload", "", "Path to an update payload that should be made available to tests")
bv(&kola.ForceFlatcarKey, "force-flatcar-key", false, "Use the Flatcar production key to verify update payload")
sv(&kola.Options.IgnitionVersion, "ignition-version", "", "Ignition version override: v2, v3")
bv(&kola.Options.EnableSecureboot, "enable-secureboot", false, "Instantiate a Secureboot Machine")
iv(&kola.Options.SSHRetries, "ssh-retries", kolaSSHRetries, "Number of retries with the SSH timeout when starting the machine")
dv(&kola.Options.SSHTimeout, "ssh-timeout", kolaSSHTimeout, "A timeout for a single try of establishing an SSH connection when starting the machine")

Expand Down Expand Up @@ -222,8 +223,11 @@ func init() {
// QEMU-specific options
sv(&kola.QEMUOptions.Board, "board", defaultTargetBoard, "target board")
sv(&kola.QEMUOptions.DiskImage, "qemu-image", "", "path to CoreOS disk image")
sv(&kola.QEMUOptions.BIOSImage, "qemu-bios", "", "BIOS to use for QEMU vm")
sv(&kola.QEMUOptions.Firmware, "qemu-bios", "", "bios to use for QEMU vm")
root.PersistentFlags().MarkDeprecated("qemu-bios", "use --qemu-firmware")
sv(&kola.QEMUOptions.Firmware, "qemu-firmware", "", "firmware image to use for QEMU vm")
sv(&kola.QEMUOptions.VNC, "qemu-vnc", "", "VNC port (0 for 5900, 1 for 5901, etc.)")
sv(&kola.QEMUOptions.OVMFVars, "qemu-ovmf-vars", "", "OVMF vars file to use for QEMU vm")
bv(&kola.QEMUOptions.UseVanillaImage, "qemu-skip-mangle", false, "don't modify CL disk image to capture console log")
sv(&kola.QEMUOptions.ExtraBaseDiskSize, "qemu-grow-base-disk-by", "", "grow base disk by the given size in bytes, following optional 1024-based suffixes are allowed: b (ignored), k, K, M, G, T")
bv(&kola.QEMUOptions.EnableTPM, "qemu-tpm", false, "enable TPM device in QEMU. Requires installing swtpm. Use only with 'kola spawn', test cases are responsible for creating a VM with TPM explicitly.")
Expand Down Expand Up @@ -310,8 +314,11 @@ func syncOptions() error {
kola.QEMUOptions.DiskImage = image
}

if kola.QEMUOptions.BIOSImage == "" {
kola.QEMUOptions.BIOSImage = kolaDefaultBIOS[kola.QEMUOptions.Board]
if kola.QEMUOptions.Firmware == "" {
kola.QEMUOptions.Firmware = kolaDefaultFirmware[kola.QEMUOptions.Board]
}
if kola.QEMUOptions.EnableSecureboot && kola.QEMUOptions.OVMFVars == "" {
return fmt.Errorf("Secureboot requires OVMF vars file")
}
units, _ := root.PersistentFlags().GetStringSlice("debug-systemd-units")
for _, unit := range units {
Expand Down
4 changes: 4 additions & 0 deletions kola/harness.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ var (
}
)

func SkipSecureboot(_ semver.Version, channel, arch, platform string) bool {
return Options.EnableSecureboot
}

// NativeRunner is a closure passed to all kola test functions and used
// to run native go functions directly on kola machines. It is necessary
// glue until kola does introspection.
Expand Down
4 changes: 3 additions & 1 deletion kola/tests/misc/falco.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package misc

import (
"github.com/flatcar/mantle/kola"
"github.com/flatcar/mantle/kola/cluster"
"github.com/flatcar/mantle/kola/register"
)
Expand All @@ -16,7 +17,8 @@ func init() {
// falco builder container can't handle our arm64 config (yet)
Architectures: []string{"amd64"},
// selinux blocks insmod from within container
Flags: []register.Flag{register.NoEnableSelinux},
Flags: []register.Flag{register.NoEnableSelinux},
SkipFunc: kola.SkipSecureboot,
})
}

Expand Down
11 changes: 8 additions & 3 deletions kola/tests/sysext/zfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"

"github.com/coreos/go-semver/semver"
"github.com/flatcar/mantle/kola"
"github.com/flatcar/mantle/kola/cluster"
"github.com/flatcar/mantle/kola/register"
"github.com/flatcar/mantle/platform"
Expand Down Expand Up @@ -133,7 +134,7 @@ func init() {
// This test is normally not related to the cloud environment
Platforms: []string{"qemu", "qemu-unpriv"},
MinVersion: semver.Version{Major: 3902},
SkipFunc: skipOnGha,
SkipFunc: skipZfs,
})

register.Register(&register.Test{
Expand All @@ -144,7 +145,7 @@ func init() {
// This test is normally not related to the cloud environment
Platforms: []string{"qemu", "qemu-unpriv"},
MinVersion: semver.Version{Major: 3902},
SkipFunc: skipOnGha,
SkipFunc: skipZfs,
})

register.Register(&register.Test{
Expand All @@ -155,10 +156,14 @@ func init() {
// This test is normally not related to the cloud environment
Platforms: []string{"qemu", "qemu-unpriv"},
MinVersion: semver.Version{Major: 3902},
SkipFunc: skipOnGha,
SkipFunc: skipZfs,
})
}

func skipZfs(version semver.Version, channel, arch, platform string) bool {
return kola.SkipSecureboot(version, channel, arch, platform) || skipOnGha(version, channel, arch, platform)
}

func skipOnGha(version semver.Version, channel, arch, platform string) bool {
// Skip for release tests as we don't yet have a sysext signed with the
// prod key, nor is it on the release server.
Expand Down
22 changes: 18 additions & 4 deletions platform/machine/qemu/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package qemu
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
"sync"
Expand Down Expand Up @@ -133,11 +134,24 @@ ExecStartPost=/usr/bin/ln -fs /run/metadata/flatcar /run/metadata/coreos

// This uses path arguments with path values being
// relative to the folder created for this machine
biosImage, err := filepath.Abs(qc.flight.opts.BIOSImage)
firmware, err := filepath.Abs(qc.flight.opts.Firmware)
if err != nil {
return nil, fmt.Errorf("failed to canonicalize bios path: %v", err)
return nil, fmt.Errorf("failed to canonicalize firmware path: %v", err)
}
qmCmd, extraFiles, err := platform.CreateQEMUCommand(qc.flight.opts.Board, qm.id, biosImage, qm.consolePath, confPath, qc.flight.diskImagePath, conf.IsIgnition(), options)
ovmfVars := ""
if qc.flight.opts.OVMFVars != "" {
ovmfVars, err = platform.CreateOvmfVarsCopy(qm.subDir, qc.flight.opts.OVMFVars)
if err != nil {
return nil, err
}
defer func() {
if ovmfVars != "" {
os.Remove(path.Join(qm.subDir, ovmfVars))
}
}()
}

qmCmd, extraFiles, err := platform.CreateQEMUCommand(qc.flight.opts.Board, qm.id, firmware, ovmfVars, qm.consolePath, confPath, qc.flight.diskImagePath, qc.flight.opts.EnableSecureboot, conf.IsIgnition(), options)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -181,7 +195,7 @@ ExecStartPost=/usr/bin/ln -fs /run/metadata/flatcar /run/metadata/coreos

// from this point on Destroy() is responsible for cleaning up swtpm
qm.swtpm, swtpm = swtpm, nil

qm.ovmfVars, ovmfVars = ovmfVars, ""
plog.Debugf("qemu PID (manual cleanup needed if --remove=false): %v", qm.qemu.Pid())

if err := platform.StartMachine(qm, qm.journal); err != nil {
Expand Down
7 changes: 5 additions & 2 deletions platform/machine/qemu/flight.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,12 @@ type Options struct {
// DiskImage is the full path to the disk image to boot in QEMU.
DiskImage string

// BIOSImage is name of the BIOS file to pass to QEMU.
// Firmware is name of the Firmware file to pass to QEMU.
// It can be a plain name, or a full path.
BIOSImage string
Firmware string

// OMVF Vars file to pass to QEMU UEFI
OVMFVars string

// Don't modify CL disk images to add console logging
UseVanillaImage bool
Expand Down
9 changes: 9 additions & 0 deletions platform/machine/qemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package qemu

import (
"io/ioutil"
"os"
"path"
"path/filepath"

"golang.org/x/crypto/ssh"
Expand All @@ -33,6 +35,7 @@ type machine struct {
journal *platform.Journal
consolePath string
console string
ovmfVars string
subDir string
swtpm *local.SoftwareTPM
}
Expand Down Expand Up @@ -76,6 +79,12 @@ func (m *machine) Destroy() {
if m.swtpm != nil {
m.swtpm.Stop()
}
if m.ovmfVars != "" {
err := os.Remove(path.Join(m.subDir, m.ovmfVars))
if err != nil {
plog.Errorf("Error removing OVMF vars: %v", err)
}
}
m.journal.Destroy()

if buf, err := ioutil.ReadFile(filepath.Join(m.subDir, m.consolePath)); err == nil {
Expand Down
21 changes: 18 additions & 3 deletions platform/machine/unprivqemu/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"io/ioutil"
"net"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
Expand Down Expand Up @@ -143,13 +144,26 @@ LinkLocalAddressing=no
}
}()
}

ovmfVars := ""
if qc.flight.opts.OVMFVars != "" {
ovmfVars, err = platform.CreateOvmfVarsCopy(qm.subDir, qc.flight.opts.OVMFVars)
if err != nil {
return nil, err
}
defer func() {
if ovmfVars != "" {
os.Remove(path.Join(qm.subDir, ovmfVars))
}
}()
}
// This uses path arguments with path values being
// relative to the folder created for this machine
biosImage, err := filepath.Abs(qc.flight.opts.BIOSImage)
firmware, err := filepath.Abs(qc.flight.opts.Firmware)
if err != nil {
return nil, fmt.Errorf("failed to canonicalize bios path: %v", err)
return nil, fmt.Errorf("failed to canonicalize firmware path: %v", err)
}
qmCmd, extraFiles, err := platform.CreateQEMUCommand(qc.flight.opts.Board, qm.id, biosImage, qm.consolePath, confPath, qc.flight.diskImagePath, conf.IsIgnition(), options)
qmCmd, extraFiles, err := platform.CreateQEMUCommand(qc.flight.opts.Board, qm.id, firmware, ovmfVars, qm.consolePath, confPath, qc.flight.diskImagePath, qc.flight.opts.EnableSecureboot, conf.IsIgnition(), options)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -182,6 +196,7 @@ LinkLocalAddressing=no

// from this point on Destroy() is responsible for cleaning up swtpm
qm.swtpm, swtpm = swtpm, nil
qm.ovmfVars, ovmfVars = ovmfVars, ""
plog.Debugf("qemu PID (manual cleanup needed if --remove=false): %v", qm.qemu.Pid())

pid := strconv.Itoa(qm.qemu.Pid())
Expand Down
9 changes: 9 additions & 0 deletions platform/machine/unprivqemu/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package unprivqemu

import (
"io/ioutil"
"os"
"path"
"path/filepath"

"golang.org/x/crypto/ssh"
Expand All @@ -32,6 +34,7 @@ type machine struct {
journal *platform.Journal
consolePath string
console string
ovmfVars string
subDir string
swtpm *local.SoftwareTPM
ip string
Expand Down Expand Up @@ -78,6 +81,12 @@ func (m *machine) Destroy() {
if m.swtpm != nil {
m.swtpm.Stop()
}
if m.ovmfVars != "" {
err := os.Remove(path.Join(m.subDir, m.ovmfVars))
if err != nil {
plog.Errorf("Error removing OVMF vars: %v", err)
}
}
m.journal.Destroy()

if buf, err := ioutil.ReadFile(filepath.Join(m.subDir, m.consolePath)); err == nil {
Expand Down
3 changes: 3 additions & 0 deletions platform/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ type Options struct {
// Board is the board used by the image
Board string

// Toggle to instantiate a secureboot instance.
EnableSecureboot bool

// How many times to retry establishing an SSH connection when
// creating a journal or when doing a machine check.
SSHRetries int
Expand Down
Loading

0 comments on commit cf464dd

Please sign in to comment.