Skip to content

Commit f38ba6e

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 bc7e0f4 commit f38ba6e

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed

mantle/kola/tests/fips/failure.go

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
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+
coreosarch "github.com/coreos/stream-metadata-go/arch"
27+
28+
"github.com/coreos/coreos-assembler/mantle/kola"
29+
"github.com/coreos/coreos-assembler/mantle/kola/cluster"
30+
"github.com/coreos/coreos-assembler/mantle/kola/register"
31+
"github.com/coreos/coreos-assembler/mantle/platform"
32+
"github.com/coreos/coreos-assembler/mantle/platform/conf"
33+
)
34+
35+
var failConfig = conf.Ignition(`{
36+
"ignition": {
37+
"version": "3.4.0"
38+
},
39+
"storage": {
40+
"filesystems": [
41+
{
42+
"device": "/dev/mapper/root",
43+
"format": "xfs",
44+
"label": "root",
45+
"wipeFilesystem": true
46+
}
47+
],
48+
"luks": [
49+
{
50+
"clevis": {
51+
"tpm2": true
52+
},
53+
"device": "/dev/disk/by-partlabel/root",
54+
"label": "luks-root",
55+
"name": "root",
56+
"options": [
57+
"--cipher",
58+
"aes-cbc-essiv:sha256",
59+
"--pbkdf",
60+
"argon2i"
61+
],
62+
"wipeVolume": true
63+
}
64+
],
65+
"files": [
66+
{
67+
"group": {
68+
"name": "root"
69+
},
70+
"overwrite": true,
71+
"path": "/etc/ignition-machine-config-encapsulated.json",
72+
"user": {
73+
"name": "root"
74+
},
75+
"contents": {
76+
"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",
77+
"verification": {}
78+
},
79+
"mode": 420
80+
}
81+
]
82+
}
83+
}`)
84+
85+
func init() {
86+
register.RegisterTest(&register.Test{
87+
Name: "fips.failure",
88+
Description: "Verify cryptsetup lukscreate will fail with FIPS and incompatible crypto algorithms.",
89+
Run: runFipsFailure,
90+
ClusterSize: 0,
91+
Platforms: []string{"qemu"},
92+
Tags: []string{"ignition"},
93+
Distros: []string{"rhcos"},
94+
})
95+
}
96+
97+
func runFipsFailure(c cluster.TestCluster) {
98+
if err := ignitionFailure(c); err != nil {
99+
c.Fatal(err.Error())
100+
}
101+
}
102+
103+
// Read file and verify if it contains a pattern
104+
// 1. Read file, make sure it exists
105+
// 2. regex for pattern
106+
func fileContainsPattern(path string, searchPattern string) (bool, error) {
107+
file, err := os.ReadFile(path)
108+
if err != nil {
109+
return false, err
110+
}
111+
// File has content, but the pattern is not present
112+
match := regexp.MustCompile(searchPattern).Match(file)
113+
if match {
114+
// Pattern found
115+
return true, nil
116+
}
117+
// Pattern not found
118+
return false, nil
119+
}
120+
121+
// Start the VM, take string and grep for it in the temporary console logs
122+
func verifyError(builder *platform.QemuBuilder, searchPattern string) error {
123+
inst, err := builder.Exec()
124+
if err != nil {
125+
return err
126+
}
127+
defer inst.Destroy()
128+
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
129+
130+
defer cancel()
131+
132+
errchan := make(chan error)
133+
go func() {
134+
resultingError := inst.WaitAll(ctx)
135+
if resultingError == nil {
136+
resultingError = fmt.Errorf("ignition unexpectedly succeeded")
137+
} else if resultingError == platform.ErrInitramfsEmergency {
138+
// Expected initramfs failure, checking the console file to ensure
139+
// that it failed the expected way
140+
found, err := fileContainsPattern(builder.ConsoleFile, searchPattern)
141+
if err != nil {
142+
resultingError = errors.Wrapf(err, "looking for pattern '%s' in file '%s' failed", searchPattern, builder.ConsoleFile)
143+
} else if !found {
144+
resultingError = fmt.Errorf("pattern '%s' in file '%s' not found", searchPattern, builder.ConsoleFile)
145+
} else {
146+
// The expected case
147+
resultingError = nil
148+
}
149+
} else {
150+
resultingError = errors.Wrapf(resultingError, "expected initramfs emergency.target error")
151+
}
152+
errchan <- resultingError
153+
}()
154+
155+
select {
156+
case <-ctx.Done():
157+
if err := inst.Kill(); err != nil {
158+
return errors.Wrapf(err, "failed to kill the vm instance")
159+
}
160+
return errors.Wrapf(ctx.Err(), "timed out waiting for initramfs error")
161+
case err := <-errchan:
162+
if err != nil {
163+
return err
164+
}
165+
return nil
166+
}
167+
}
168+
169+
func ignitionFailure(c cluster.TestCluster) error {
170+
builder := platform.NewQemuBuilder()
171+
defer builder.Close()
172+
173+
// Prepare Ingnition config
174+
failConfig, err := failConfig.Render(conf.FailWarnings)
175+
if err != nil {
176+
return errors.Wrapf(err, "creating invalid FIPS config")
177+
}
178+
179+
// Create a temporary log file
180+
consoleFile := c.H.TempFile("console-")
181+
182+
// Instruct builder to use it
183+
builder.ConsoleFile = consoleFile.Name()
184+
builder.SetConfig(failConfig)
185+
err = builder.AddBootDisk(&platform.Disk{
186+
BackingFile: kola.QEMUOptions.DiskImage,
187+
})
188+
if err != nil {
189+
return err
190+
}
191+
192+
builder.MemoryMiB = 4096
193+
switch coreosarch.CurrentRpmArch() {
194+
case "ppc64le":
195+
builder.MemoryMiB = 8192
196+
}
197+
builder.Firmware = kola.QEMUOptions.Firmware
198+
199+
searchPattern := "Only PBKDF2 is supported in FIPS mode"
200+
if err := verifyError(builder, searchPattern); err != nil {
201+
return err
202+
}
203+
return nil
204+
}

0 commit comments

Comments
 (0)