Skip to content

Commit 58b2d02

Browse files
committed
kola/tests: Add failing test for FIPS & LUKS
Ensure that setting up a LUKS device with FIPS incompatible algorithms will fail when FIPS mode is enabled. Only run this on QEMU as it should behave the same way on all platforms.
1 parent 78a253b commit 58b2d02

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed

mantle/kola/tests/fips/failure.go

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
// Copyright 2025 Red Hat, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package fips
16+
17+
import (
18+
"context"
19+
"fmt"
20+
"os"
21+
"regexp"
22+
"time"
23+
24+
"github.com/pkg/errors"
25+
26+
"github.com/coreos/coreos-assembler/mantle/kola"
27+
"github.com/coreos/coreos-assembler/mantle/kola/cluster"
28+
"github.com/coreos/coreos-assembler/mantle/kola/register"
29+
"github.com/coreos/coreos-assembler/mantle/platform"
30+
"github.com/coreos/coreos-assembler/mantle/platform/conf"
31+
)
32+
33+
var failConfig = conf.Ignition(`{
34+
"ignition": {
35+
"version": "3.4.0"
36+
},
37+
"storage": {
38+
"filesystems": [
39+
{
40+
"device": "/dev/mapper/root",
41+
"format": "xfs",
42+
"label": "root",
43+
"wipeFilesystem": true
44+
}
45+
],
46+
"luks": [
47+
{
48+
"clevis": {
49+
"tpm2": true
50+
},
51+
"device": "/dev/disk/by-partlabel/root",
52+
"label": "luks-root",
53+
"name": "root",
54+
"options": [
55+
"--cipher",
56+
"aes-cbc-essiv:sha256",
57+
"--pbkdf",
58+
"argon2i"
59+
],
60+
"wipeVolume": true
61+
}
62+
],
63+
"files": [
64+
{
65+
"group": {
66+
"name": "root"
67+
},
68+
"overwrite": true,
69+
"path": "/etc/ignition-machine-config-encapsulated.json",
70+
"user": {
71+
"name": "root"
72+
},
73+
"contents": {
74+
"source": "data:,%7B%22metadata%22%3A%7B%22name%22%3A%22rendered-worker-1cc576110e0cf8396831ce4016f63900%22%2C%22selfLink%22%3A%22%2Fapis%2Fmachineconfiguration.openshift.io%2Fv1%2Fmachineconfigs%2Frendered-worker-1cc576110e0cf8396831ce4016f63900%22%2C%22uid%22%3A%2248871c03-899d-4332-a5f5-bef94e54b23f%22%2C%22resourceVersion%22%3A%224168%22%2C%22generation%22%3A1%2C%22creationTimestamp%22%3A%222019-11-04T15%3A54%3A08Z%22%2C%22annotations%22%3A%7B%22machineconfiguration.openshift.io%2Fgenerated-by-controller-version%22%3A%22bd846958bc95d049547164046a962054fca093df%22%7D%2C%22ownerReferences%22%3A%5B%7B%22apiVersion%22%3A%22machineconfiguration.openshift.io%2Fv1%22%2C%22kind%22%3A%22MachineConfigPool%22%2C%22name%22%3A%22worker%22%2C%22uid%22%3A%223d0dee9e-c9d6-4656-a4a9-81785b9ab01a%22%2C%22controller%22%3Atrue%2C%22blockOwnerDeletion%22%3Atrue%7D%5D%7D%2C%22spec%22%3A%7B%22osImageURL%22%3A%22registry.svc.ci.openshift.org%2Focp%2F4.3-2019-11-04-125204%40sha256%3A8a344c5b157bd01c3ca1abfcef0004fc39f5d69cac1cdaad0fd8dd332ad8e272%22%2C%22config%22%3A%7B%22ignition%22%3A%7B%22config%22%3A%7B%7D%2C%22security%22%3A%7B%22tls%22%3A%7B%7D%7D%2C%22timeouts%22%3A%7B%7D%2C%22version%22%3A%223.0.0%22%7D%2C%22networkd%22%3A%7B%7D%2C%22passwd%22%3A%7B%7D%2C%22storage%22%3A%7B%7D%2C%22systemd%22%3A%7B%7D%7D%2C%22kernelArguments%22%3A%5B%5D%2C%22fips%22%3Atrue%7D%7D",
75+
"verification": {}
76+
},
77+
"mode": 420
78+
}
79+
]
80+
}
81+
}`)
82+
83+
func init() {
84+
register.RegisterTest(&register.Test{
85+
Name: "fips.failure",
86+
Description: "Verify cryptsetup lukscreate will fail with FIPS and incompatible crypto algorithms.",
87+
Run: runFipsFailure,
88+
ClusterSize: 0,
89+
Platforms: []string{"qemu"},
90+
Tags: []string{"ignition"},
91+
Distros: []string{"rhcos"},
92+
})
93+
}
94+
95+
func runFipsFailure(c cluster.TestCluster) {
96+
if err := ignitionFailure(c); err != nil {
97+
c.Fatal(err.Error())
98+
}
99+
}
100+
101+
// Read file and verify if it contains a pattern
102+
// 1. Read file, make sure it exists
103+
// 2. regex for pattern
104+
func fileContainsPattern(path string, searchPattern string) (bool, error) {
105+
file, err := os.ReadFile(path)
106+
if err != nil {
107+
return false, err
108+
}
109+
// File has content, but the pattern is not present
110+
match := regexp.MustCompile(searchPattern).Match(file)
111+
if match {
112+
// Pattern found
113+
return true, nil
114+
}
115+
// Pattern not found
116+
return false, nil
117+
}
118+
119+
// Start the VM, take string and grep for it in the temporary console logs
120+
func verifyError(builder *platform.QemuBuilder, searchPattern string) error {
121+
inst, err := builder.Exec()
122+
if err != nil {
123+
return err
124+
}
125+
defer inst.Destroy()
126+
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
127+
128+
defer cancel()
129+
130+
errchan := make(chan error)
131+
go func() {
132+
resultingError := inst.WaitAll(ctx)
133+
if resultingError == nil {
134+
resultingError = fmt.Errorf("ignition unexpectedly succeeded")
135+
} else if resultingError == platform.ErrInitramfsEmergency {
136+
// Expected initramfs failure, checking the console file to ensure
137+
// that it failed the expected way
138+
found, err := fileContainsPattern(builder.ConsoleFile, searchPattern)
139+
if err != nil {
140+
resultingError = errors.Wrapf(err, "looking for pattern '%s' in file '%s' failed", searchPattern, builder.ConsoleFile)
141+
} else if !found {
142+
resultingError = fmt.Errorf("pattern '%s' in file '%s' not found", searchPattern, builder.ConsoleFile)
143+
} else {
144+
// The expected case
145+
resultingError = nil
146+
}
147+
} else {
148+
resultingError = errors.Wrapf(resultingError, "expected initramfs emergency.target error")
149+
}
150+
errchan <- resultingError
151+
}()
152+
153+
select {
154+
case <-ctx.Done():
155+
if err := inst.Kill(); err != nil {
156+
return errors.Wrapf(err, "failed to kill the vm instance")
157+
}
158+
return errors.Wrapf(ctx.Err(), "timed out waiting for initramfs error")
159+
case err := <-errchan:
160+
if err != nil {
161+
return err
162+
}
163+
return nil
164+
}
165+
}
166+
167+
func ignitionFailure(c cluster.TestCluster) error {
168+
builder := platform.NewQemuBuilder()
169+
defer builder.Close()
170+
171+
// Prepare Ingnition config
172+
failConfig, err := failConfig.Render(conf.FailWarnings)
173+
if err != nil {
174+
return errors.Wrapf(err, "creating empty config")
175+
}
176+
177+
// Create a temporary log file
178+
consoleFile := c.H.TempFile("console-")
179+
180+
// Instruct builder to use it
181+
builder.ConsoleFile = consoleFile.Name()
182+
builder.SetConfig(failConfig)
183+
err = builder.AddBootDisk(&platform.Disk{
184+
BackingFile: kola.QEMUOptions.DiskImage,
185+
})
186+
if err != nil {
187+
return err
188+
}
189+
190+
builder.MemoryMiB = 4096
191+
builder.Firmware = kola.QEMUOptions.Firmware
192+
193+
searchPattern := "Only PBKDF2 is supported in FIPS mode"
194+
if err := verifyError(builder, searchPattern); err != nil {
195+
return err
196+
}
197+
return nil
198+
}

0 commit comments

Comments
 (0)