Skip to content

Commit 2caee56

Browse files
committed
e2e:must-gather: test gather_selinux
add an e2e to validate script collection format and collected data integrety. Signed-off-by: Talor Itzhak <[email protected]>
1 parent 0a04128 commit 2caee56

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+6111
-0
lines changed

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ require (
3939
sigs.k8s.io/yaml v1.4.0
4040
)
4141

42+
require github.com/opencontainers/selinux v1.13.1
43+
4244
require (
4345
github.com/OneOfOne/xxhash v1.2.9-0.20201014161131-8506fca4db5e // indirect
4446
github.com/StackExchange/wmi v1.2.1 // indirect
@@ -49,6 +51,7 @@ require (
4951
github.com/coreos/go-semver v0.3.1 // indirect
5052
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
5153
github.com/coreos/vcontext v0.0.0-20231102161604-685dc7299dc5 // indirect
54+
github.com/cyphar/filepath-securejoin v0.5.1 // indirect
5255
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
5356
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
5457
github.com/evanphx/json-patch v5.9.0+incompatible // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ github.com/coreos/vcontext v0.0.0-20231102161604-685dc7299dc5 h1:sMZSC2BW5LKCdvN
2525
github.com/coreos/vcontext v0.0.0-20231102161604-685dc7299dc5/go.mod h1:Salmysdw7DAVuobBW/LwsKKgpyCPHUhjyJoMJD+ZJiI=
2626
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
2727
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
28+
github.com/cyphar/filepath-securejoin v0.5.1 h1:eYgfMq5yryL4fbWfkLpFFy2ukSELzaJOTaUTuh+oF48=
29+
github.com/cyphar/filepath-securejoin v0.5.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
2830
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2931
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3032
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@@ -140,6 +142,8 @@ github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg
140142
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
141143
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
142144
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
145+
github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE=
146+
github.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg=
143147
github.com/openshift-kni/debug-tools v0.2.5 h1:YDHniE7pvEnveQPXPP2TOHcWbPzfpbcPsMJ2wu4vAEk=
144148
github.com/openshift-kni/debug-tools v0.2.5/go.mod h1:kBoANbhBO3X7qXwrve0dcEtAM97Enrm7mF58p8RLLJI=
145149
github.com/openshift/api v0.0.0-20250305013520-e7f23be12279 h1:eYvpiSNyNl7P7kmtNH0d6zAMLlrziyz370m0q1tggJE=

test/e2e/must-gather/must_gather_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ import (
2424
"os/exec"
2525
"path/filepath"
2626
"regexp"
27+
"strings"
2728
"time"
2829

30+
"github.com/opencontainers/selinux/go-selinux"
31+
2932
corev1 "k8s.io/api/core/v1"
3033
"k8s.io/klog/v2"
3134

@@ -184,6 +187,93 @@ var _ = Describe("[must-gather] NRO data collected", func() {
184187
Expect(podFolderNames).To(ContainElement(MatchRegexp("^secondary-scheduler*")))
185188
}
186189
})
190+
191+
It("check SELinux data files have been collected", func(ctx context.Context) {
192+
destDirContent, err := os.ReadDir(destDir)
193+
Expect(err).NotTo(HaveOccurred(), "unable to read contents from destDir:%s. error: %w", destDir, err)
194+
195+
for _, content := range destDirContent {
196+
if !content.IsDir() {
197+
continue
198+
}
199+
mgContentFolder := filepath.Join(destDir, content.Name())
200+
201+
By(fmt.Sprintf("Checking Folder: %q", mgContentFolder))
202+
By("Looking for SELinux info directory")
203+
204+
selinuxInfoFolder := filepath.Join(mgContentFolder, "selinux_info")
205+
_, err = os.Stat(selinuxInfoFolder)
206+
Expect(err).ToNot(HaveOccurred(), "selinux_info directory should exist")
207+
208+
selinuxDirContent, err := os.ReadDir(selinuxInfoFolder)
209+
Expect(err).NotTo(HaveOccurred())
210+
Expect(selinuxDirContent).ToNot(BeEmpty(), "selinux_info directory should contain node directories")
211+
212+
// Check each node directory
213+
for _, nodeDir := range selinuxDirContent {
214+
if !nodeDir.IsDir() {
215+
// We expect only directories in selinux_info, but check defensively
216+
By(fmt.Sprintf("Warning: unexpected non-directory item in selinux_info: %s", nodeDir.Name()))
217+
continue
218+
}
219+
220+
nodeName := nodeDir.Name()
221+
nodeSelinuxFolder := filepath.Join(selinuxInfoFolder, nodeName)
222+
By(fmt.Sprintf("Checking SELinux data for node: %s", nodeName))
223+
224+
// Check required files exist
225+
requiredFiles := []string{
226+
"contexts",
227+
"kubelet.service",
228+
"audit_selinux.log",
229+
"audit_podresources.log",
230+
}
231+
err = checkfilesExist(requiredFiles, nodeSelinuxFolder)
232+
Expect(err).ToNot(HaveOccurred(), "required SELinux files should exist for node %s", nodeName)
233+
234+
// Verify contexts file contains kubelet.sock SELinux context
235+
By(fmt.Sprintf("Verifying kubelet.sock SELinux context for node: %s", nodeName))
236+
contextsFile := filepath.Join(nodeSelinuxFolder, "contexts")
237+
contextsData, err := os.ReadFile(contextsFile)
238+
Expect(err).ToNot(HaveOccurred())
239+
240+
contextsContent := string(contextsData)
241+
242+
// Parse SELinux context from the kubelet.sock line using official selinux package
243+
By(fmt.Sprintf("Parsing SELinux context for kubelet.sock on node: %s", nodeName))
244+
found := false
245+
for _, line := range strings.Split(contextsContent, "\n") {
246+
if strings.Contains(line, "/var/lib/kubelet/pod-resources/kubelet.sock") {
247+
// Extract SELinux context from ls -Z output (format: "context filename")
248+
parts := strings.Fields(line)
249+
if len(parts) >= 2 {
250+
selinuxLabel := parts[0]
251+
context, err := selinux.NewContext(selinuxLabel)
252+
Expect(err).ToNot(HaveOccurred(), "should parse SELinux context: %s", selinuxLabel)
253+
254+
// Check that the type field contains kubelet_var_lib_t
255+
contextType := context["type"]
256+
Expect(contextType).To(Equal("kubelet_var_lib_t"), "kubelet.sock should have kubelet_var_lib_t SELinux context type, got: %s", contextType)
257+
258+
By(fmt.Sprintf("Found valid SELinux context for kubelet.sock: %s (type: %s)", selinuxLabel, contextType))
259+
found = true
260+
break
261+
}
262+
}
263+
}
264+
Expect(found).To(BeTrue(), "should find kubelet.sock with valid SELinux context in contexts file")
265+
266+
// Verify kubelet.service file has content
267+
By(fmt.Sprintf("Verifying kubelet.service content for node: %s", nodeName))
268+
kubeletServiceFile := filepath.Join(nodeSelinuxFolder, "kubelet.service")
269+
kubeletServiceData, err := os.ReadFile(kubeletServiceFile)
270+
Expect(err).ToNot(HaveOccurred())
271+
272+
kubeletServiceContent := string(kubeletServiceData)
273+
Expect(kubeletServiceContent).To(ContainSubstring("/usr/sbin/restorecon"), "kubelet.service should contain restorecon command in ExecStartPre")
274+
}
275+
}
276+
})
187277
})
188278
})
189279

0 commit comments

Comments
 (0)