Skip to content

Commit

Permalink
selinux: Print status and usage of RawSelinux
Browse files Browse the repository at this point in the history
The nodestatus controller didn't handle the rawselinux policy at all.
Let's handle the kind in the nodestatus and add a very basic test for
the rawselinuxprofile so that we are sure it works at all.
  • Loading branch information
jhrozek committed Feb 22, 2023
1 parent 585bbb0 commit bbd5bf4
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 14 deletions.
2 changes: 2 additions & 0 deletions internal/pkg/manager/nodestatus/nodestatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ func (r *StatusReconciler) getProfileFromStatus(
prof = &seccompprofileapi.SeccompProfile{}
case "SelinuxProfile":
prof = &selxv1alpha2.SelinuxProfile{}
case "RawSelinuxProfile":
prof = &selxv1alpha2.RawSelinuxProfile{}
default:
return nil, fmt.Errorf("getting owner profile: %w", ErrUnkownOwnerKind)
}
Expand Down
12 changes: 8 additions & 4 deletions test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,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: Metrics (update, delete)",
e.testCaseSelinuxMetrics,
Expand Down Expand Up @@ -409,19 +413,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 string, 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 string, 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
38 changes: 30 additions & 8 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 the permissive
// flag as needed.
Expand Down Expand Up @@ -125,28 +138,37 @@ spec:
)

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

func (e *e2e) testCaseRawSelinuxBaseUsage(nodes []string) {
e.selinuxBaseUsage("selinuxprofile", 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 @@ -161,7 +183,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 @@ -184,7 +206,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 @@ -229,7 +251,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
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

0 comments on commit bbd5bf4

Please sign in to comment.