Skip to content

Commit 9d569b8

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 9d569b8

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed

mantle/kola/tests/fips/failure.go

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
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.nonppc64le",
86+
Description: "Verify cryptsetup lukscreate will fail with FIPS and incompatible crypto algorithms.",
87+
Run: runFipsFailureNonPpc64Le,
88+
ClusterSize: 0,
89+
Platforms: []string{"qemu"},
90+
Tags: []string{"ignition"},
91+
Distros: []string{"rhcos"},
92+
ExcludeArchitectures: []string{"ppc64le"},
93+
})
94+
register.RegisterTest(&register.Test{
95+
Name: "fips.failure.ppc64le",
96+
Description: "Verify cryptsetup lukscreate will fail with FIPS and incompatible crypto algorithms.",
97+
Run: runFipsFailurePpc64Le,
98+
ClusterSize: 0,
99+
Platforms: []string{"qemu"},
100+
Tags: []string{"ignition"},
101+
Distros: []string{"rhcos"},
102+
Architectures: []string{"ppc64le"},
103+
})
104+
}
105+
106+
func runFipsFailureNonPpc64Le(c cluster.TestCluster) {
107+
// Default to 4GB memery on non PPC64LE architectures for root reprovisioning
108+
if err := ignitionFailure(c, 4096); err != nil {
109+
c.Fatal(err.Error())
110+
}
111+
}
112+
113+
func runFipsFailurePpc64Le(c cluster.TestCluster) {
114+
// Default to 8GB memery on PPC64LE architecture for root reprovisioning
115+
if err := ignitionFailure(c, 8192); err != nil {
116+
c.Fatal(err.Error())
117+
}
118+
}
119+
120+
// Read file and verify if it contains a pattern
121+
// 1. Read file, make sure it exists
122+
// 2. regex for pattern
123+
func fileContainsPattern(path string, searchPattern string) (bool, error) {
124+
file, err := os.ReadFile(path)
125+
if err != nil {
126+
return false, err
127+
}
128+
// File has content, but the pattern is not present
129+
match := regexp.MustCompile(searchPattern).Match(file)
130+
if match {
131+
// Pattern found
132+
return true, nil
133+
}
134+
// Pattern not found
135+
return false, nil
136+
}
137+
138+
// Start the VM, take string and grep for it in the temporary console logs
139+
func verifyError(builder *platform.QemuBuilder, searchPattern string) error {
140+
inst, err := builder.Exec()
141+
if err != nil {
142+
return err
143+
}
144+
defer inst.Destroy()
145+
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
146+
147+
defer cancel()
148+
149+
errchan := make(chan error)
150+
go func() {
151+
resultingError := inst.WaitAll(ctx)
152+
if resultingError == nil {
153+
resultingError = fmt.Errorf("ignition unexpectedly succeeded")
154+
} else if resultingError == platform.ErrInitramfsEmergency {
155+
// Expected initramfs failure, checking the console file to ensure
156+
// that it failed the expected way
157+
found, err := fileContainsPattern(builder.ConsoleFile, searchPattern)
158+
if err != nil {
159+
resultingError = errors.Wrapf(err, "looking for pattern '%s' in file '%s' failed", searchPattern, builder.ConsoleFile)
160+
} else if !found {
161+
resultingError = fmt.Errorf("pattern '%s' in file '%s' not found", searchPattern, builder.ConsoleFile)
162+
} else {
163+
// The expected case
164+
resultingError = nil
165+
}
166+
} else {
167+
resultingError = errors.Wrapf(resultingError, "expected initramfs emergency.target error")
168+
}
169+
errchan <- resultingError
170+
}()
171+
172+
select {
173+
case <-ctx.Done():
174+
if err := inst.Kill(); err != nil {
175+
return errors.Wrapf(err, "failed to kill the vm instance")
176+
}
177+
return errors.Wrapf(ctx.Err(), "timed out waiting for initramfs error")
178+
case err := <-errchan:
179+
if err != nil {
180+
return err
181+
}
182+
return nil
183+
}
184+
}
185+
186+
func ignitionFailure(c cluster.TestCluster, memory int) error {
187+
builder := platform.NewQemuBuilder()
188+
defer builder.Close()
189+
190+
// Prepare Ingnition config
191+
failConfig, err := failConfig.Render(conf.FailWarnings)
192+
if err != nil {
193+
return errors.Wrapf(err, "creating invalid FIPS config")
194+
}
195+
196+
// Create a temporary log file
197+
consoleFile := c.H.TempFile("console-")
198+
199+
// Instruct builder to use it
200+
builder.ConsoleFile = consoleFile.Name()
201+
builder.SetConfig(failConfig)
202+
err = builder.AddBootDisk(&platform.Disk{
203+
BackingFile: kola.QEMUOptions.DiskImage,
204+
})
205+
if err != nil {
206+
return err
207+
}
208+
209+
builder.MemoryMiB = memory
210+
builder.Firmware = kola.QEMUOptions.Firmware
211+
212+
searchPattern := "Only PBKDF2 is supported in FIPS mode"
213+
if err := verifyError(builder, searchPattern); err != nil {
214+
return err
215+
}
216+
return nil
217+
}

0 commit comments

Comments
 (0)