Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

selinux: Print status and usage of RawSelinux #1496

Merged
merged 1 commit into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 8 additions & 4 deletions test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func (e *e2e) TestSecurityProfilesOperator() {
"SELinux: base case (install policy, run pod and delete)",
e.testCaseSelinuxBaseUsage,
},
{
"SELinux: base case (install policy, run pod and delete) for the raw CR",
e.testCaseRawSelinuxBaseUsage,
},
{
"SELinux: non-default template",
e.testCaseSelinuxNonDefaultTemplate,
Expand Down Expand Up @@ -430,19 +434,19 @@ func (e *e2e) writeAndDo(verb, manifest, filePattern string) func() {
return func() { os.Remove(fileName) }
}

func (e *e2e) getSELinuxPolicyName(policy string) string {
usageStr := e.getSELinuxPolicyUsage(policy)
func (e *e2e) getSELinuxPolicyName(kind, policy string) string {
usageStr := e.getSELinuxPolicyUsage(kind, policy)
// Udica (the library that helps out generate SELinux policies),
// adds .process in the end of the usage. So we need to remove it
// to get the module name
return strings.TrimSuffix(usageStr, ".process")
}

func (e *e2e) getSELinuxPolicyUsage(policy string) string {
func (e *e2e) getSELinuxPolicyUsage(kind, policy string) string {
ns := e.getCurrentContextNamespace(defaultNamespace)
// This describes the usage string, which is not necessarily
// the name of the policy in the node
return e.kubectl("get", "selinuxprofile", "-n", ns, policy, "-o", "jsonpath={.status.usage}")
return e.kubectl("get", kind, "-n", ns, policy, "-o", "jsonpath={.status.usage}")
}

func (e *e2e) sliceContainsString(slice []string, s string) bool {
Expand Down
2 changes: 1 addition & 1 deletion test/tc_metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (e *e2e) testCaseSelinuxMetrics(nodes []string) {
e.kubectl("wait", "--timeout", defaultSelinuxOpTimeout,
"--for", "condition=ready", "selinuxprofile", "errorlogger")

rawPolicyName := e.getSELinuxPolicyName("errorlogger")
rawPolicyName := e.getSELinuxPolicyName("selinuxprofile", "errorlogger")
e.logf("assert errorlogger policy is installed")
e.assertSelinuxPolicyIsInstalled(nodes, rawPolicyName, maxNodeIterations, sleepBetweenIterations)

Expand Down
46 changes: 34 additions & 12 deletions test/tc_selinux_base_usage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ spec:
- open
`

rawErrorloggerPolicy = `
apiVersion: security-profiles-operator.x-k8s.io/v1alpha2
kind: RawSelinuxProfile
metadata:
name: raw-errorlogger
spec:
policy: |
(blockinherit container)
(allow process var_log_t ( dir ( open read getattr lock search ioctl add_name remove_name write )))
(allow process var_log_t ( file ( getattr read write append ioctl lock map open create )))
(allow process var_log_t ( sock_file ( getattr read write append open )))
`

// this is the equivalent of errorloggerPolicy but with several calls removed. The idea is to
// ensure that the workload will fail if the policy in incomplete. Allows setting a parameter
// as needed.
Expand Down Expand Up @@ -139,28 +152,37 @@ spec:
)

func (e *e2e) testCaseSelinuxBaseUsage(nodes []string) {
e.selinuxBaseUsage("selinuxprofile", errorloggerPolicy, "errorlogger", nodes)
}

func (e *e2e) testCaseRawSelinuxBaseUsage(nodes []string) {
e.selinuxBaseUsage("rawselinuxprofile", rawErrorloggerPolicy, "raw-errorlogger", nodes)
}

func (e *e2e) selinuxBaseUsage(kind, policy, polName string, nodes []string) {
e.selinuxOnlyTestCase()

e.logf("The 'errorlogger' workload should be able to use SELinux policy")

e.logf("creating policy")
e.writeAndCreate(errorloggerPolicy, "errorlogger-policy.yml")
rmFn := e.writeAndCreate(policy, "errorlogger-policy.yml")
defer rmFn()

// Let's wait for the policy to be processed
e.kubectl("wait", "--timeout", defaultSelinuxOpTimeout,
"--for", "condition=ready", "selinuxprofile", "errorlogger")
"--for", "condition=ready", kind, polName)

rawPolicyName := e.getSELinuxPolicyName("errorlogger")
rawPolicyName := e.getSELinuxPolicyName(kind, polName)

e.logf("assert policy is installed")
e.assertSelinuxPolicyIsInstalled(nodes, rawPolicyName, maxNodeIterations, sleepBetweenIterations)

e.logf("creating workload")

podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage("errorlogger"))
podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage(kind, polName))
e.writeAndCreate(podWithPolicy, "pod-w-policy.yml")

e.waitFor("condition=ready", "pod", "errorlogger")
e.waitFor("condition=ready", "pod", polName)

e.logf("the workload should be running")
podWithPolicyPhase := e.kubectl(
Expand All @@ -175,7 +197,7 @@ func (e *e2e) testCaseSelinuxBaseUsage(nodes []string) {
e.kubectl("delete", "pod", "errorlogger")

e.logf("removing policy")
e.kubectl("delete", "selinuxprofile", "errorlogger")
e.kubectl("delete", kind, polName)

e.logf("assert policy was removed")
e.assertSelinuxPolicyIsRemoved(nodes, rawPolicyName, maxNodeIterations, sleepBetweenIterations)
Expand All @@ -198,7 +220,7 @@ func (e *e2e) testCaseSelinuxIncompletePolicy() {
"--for", "condition=ready", "selinuxprofile", enforcingProfileName)

e.logf("creating workload - it should become ready, but fail")
podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage(enforcingProfileName))
podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage("selinuxprofile", enforcingProfileName))
e.writeAndCreate(podWithPolicy, "pod-w-incomplete-policy.yml")

// note: this would have been much nicer with kubectl wait --jsonpath, but I found it racy incase the status
Expand Down Expand Up @@ -240,7 +262,7 @@ func (e *e2e) testCaseSelinuxNonDefaultTemplate(nodes []string) {
e.kubectl("wait", "--timeout", defaultSelinuxOpTimeout,
"--for", "condition=ready", "selinuxprofile", netContainerPolicyName)

rawPolicyName := e.getSELinuxPolicyName(netContainerPolicyName)
rawPolicyName := e.getSELinuxPolicyName("selinuxprofile", netContainerPolicyName)

e.logf("assert policy is installed")
e.assertSelinuxPolicyIsInstalled(nodes, rawPolicyName, maxNodeIterations, sleepBetweenIterations)
Expand All @@ -263,7 +285,7 @@ func (e *e2e) testCaseSelinuxIncompletePermissivePolicy() {
"--for", "condition=ready", "selinuxprofile", permissiveProfileName)

e.logf("creating workload - it should become ready, but fail")
podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage(permissiveProfileName))
podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage("selinuxprofile", permissiveProfileName))
e.writeAndCreate(podWithPolicy, "pod-w-incomplete-permissive-policy.yml")

e.waitFor("condition=ready", "pod", "errorlogger")
Expand Down Expand Up @@ -292,7 +314,7 @@ func (e *e2e) testCaseSelinuxIncompleteDisabledPolicy() {
"--for", "condition=ready=false", "selinuxprofile", disabledProfileName)

e.logf("creating workload - it should not even become ready")
podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage(disabledProfileName))
podWithPolicy := fmt.Sprintf(podWithPolicyFmt, e.getSELinuxPolicyUsage("selinuxprofile", disabledProfileName))
e.writeAndCreate(podWithPolicy, "pod-w-incomplete-disabled-policy.yml")

var exitCode string
Expand Down Expand Up @@ -332,7 +354,7 @@ func (e *e2e) assertSelinuxPolicyIsInstalled(nodes []string, policy string, node
if missingPolName != "" {
if i == nodeIterations-1 {
e.Fail(fmt.Sprintf(
"The SelinuxProfile errorlogger wasn't found in the %s node with the name %s",
"The SelinuxProfile wasn't found in the %s node with the name %s",
missingPolName, policy,
))
} else {
Expand All @@ -358,7 +380,7 @@ func (e *e2e) assertSelinuxPolicyIsRemoved(nodes []string, policy string, nodeIt
if missingPolName != "" {
if i == nodeIterations-1 {
e.Fail(fmt.Sprintf(
"The SelinuxProfile errorlogger was found in the %s node with the name %s",
"The SelinuxProfile was found in the %s node with the name %s",
missingPolName, policy,
))
} else {
Expand Down
2 changes: 1 addition & 1 deletion test/tc_selinux_profilebindings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (e *e2e) testCaseSelinuxProfileBinding() {
namespace := e.getCurrentContextNamespace(defaultNamespace)

e.logf("Getting selinux profile usage")
selinuxUsage := e.getSELinuxPolicyUsage(selinuxTestProfileName)
selinuxUsage := e.getSELinuxPolicyUsage("selinuxprofile", selinuxTestProfileName)

e.logf("Testing that pod has securityContext")
output := e.kubectl(
Expand Down