diff --git a/internal/pkg/translator/obj2cil.go b/internal/pkg/translator/obj2cil.go index 0dea33b54b..01d1c8b3bc 100644 --- a/internal/pkg/translator/obj2cil.go +++ b/internal/pkg/translator/obj2cil.go @@ -27,7 +27,8 @@ import ( ) const ( - typePermissive = "(typepermissive process)" + typePermissive = "(typepermissive process)" + systemContainerInherit = "container" ) func Object2CIL( @@ -37,7 +38,17 @@ func Object2CIL( ) string { cilbuilder := strings.Builder{} cilbuilder.WriteString(getCILStart(sp)) + + // all templates must inherit from the system container. Without explicitly + // inheriting from the system container, the policy will not be loaded + // if it uses e.g. net_container or any other template because only the + // container template includes a "process" definition + cilbuilder.WriteString(getCILInheritline(systemContainerInherit)) for _, inherit := range systemInherits { + if inherit == systemContainerInherit { + // already appended above + continue + } cilbuilder.WriteString(getCILInheritline(inherit)) } for _, inherit := range objInherits { diff --git a/internal/pkg/translator/obj2cil_test.go b/internal/pkg/translator/obj2cil_test.go index 21578c558f..31d8beb4c2 100644 --- a/internal/pkg/translator/obj2cil_test.go +++ b/internal/pkg/translator/obj2cil_test.go @@ -259,6 +259,48 @@ func TestObject2CIL(t *testing.T) { "container", }, }, + { + name: "Test translation with another template than container", + profile: &selxv1alpha2.SelinuxProfile{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + }, + Spec: selxv1alpha2.SelinuxProfileSpec{ + Inherit: []selxv1alpha2.PolicyRef{ + { + Name: "net_container", + }, + }, + Allow: selxv1alpha2.Allow{ + "var_log_t": { + "dir": []string{ + "open", + }, + "file": []string{ + "getattr", + }, + "sock_file": []string{ + "getattr", + }, + }, + }, + }, + }, + wantMatches: []string{ + "\\(block foo_bar", + "\\(blockinherit container\\)", + "\\(blockinherit net_container\\)", + // We match on several lines since we don't care about the order + "\\(allow process var_log_t \\( dir \\(.*open.*\\)\\)\\)\n", + "\\(allow process var_log_t \\( file \\(.*getattr.*\\)\\)\\)\n", + "\\(allow process var_log_t \\( sock_file \\(.*getattr.*\\)\\)\\)\n", + }, + inheritsys: []string{ + "container", + "net_container", + }, + }, } for _, tt := range tests { tt := tt diff --git a/test/e2e_test.go b/test/e2e_test.go index 73f0abf467..f5ec05b053 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -96,6 +96,10 @@ func (e *e2e) TestSecurityProfilesOperator() { "SELinux: base case (install policy, run pod and delete)", e.testCaseSelinuxBaseUsage, }, + { + "SELinux: non-default template", + e.testCaseSelinuxNonDefaultTemplate, + }, { "SELinux: Metrics (update, delete)", e.testCaseSelinuxMetrics, diff --git a/test/suite_test.go b/test/suite_test.go index 457ba20165..f4d0b17b14 100644 --- a/test/suite_test.go +++ b/test/suite_test.go @@ -665,6 +665,9 @@ func (e *e2e) enableSelinuxInSpod() { if !strings.Contains(selinuxEnabledInSPODDS, "--with-selinux=true") { e.logf("Enable selinux in SPOD") e.kubectlOperatorNS("patch", "spod", "spod", "-p", `{"spec":{"enableSelinux": true}}`, "--type=merge") + e.kubectlOperatorNS("patch", "spod", "spod", "-p", + `{"spec":{"selinuxOptions":{"allowedSystemProfiles":["container","net_container"]}}}`, + "--type=merge") time.Sleep(defaultWaitTime) e.waitInOperatorNSFor("condition=ready", "spod", "spod") diff --git a/test/tc_selinux_base_usage_test.go b/test/tc_selinux_base_usage_test.go index 61f41caab0..edfe07f0ca 100644 --- a/test/tc_selinux_base_usage_test.go +++ b/test/tc_selinux_base_usage_test.go @@ -97,6 +97,20 @@ spec: - open ` + netContainerPolicy = ` +apiVersion: security-profiles-operator.x-k8s.io/v1alpha2 +kind: SelinuxProfile +metadata: + name: net-container-policy +spec: + inherit: + - name: net_container + allow: + var_run_t: + sock_file: + - write +` + //nolint:lll // full yaml podWithPolicyFmt = ` apiVersion: v1 @@ -212,6 +226,26 @@ func (e *e2e) testCaseSelinuxIncompletePolicy() { e.kubectl("delete", "selinuxprofile", enforcingProfileName) } +func (e *e2e) testCaseSelinuxNonDefaultTemplate(nodes []string) { + const netContainerPolicyName = "net-container-policy" + + e.selinuxOnlyTestCase() + + e.logf("Should be able to install a policy using a different template than container") + e.logf("creating policy") + + rmFn := e.writeAndCreate(netContainerPolicy, "net-container-policy.yml") + defer rmFn() + + e.kubectl("wait", "--timeout", defaultSelinuxOpTimeout, + "--for", "condition=ready", "selinuxprofile", netContainerPolicyName) + + rawPolicyName := e.getSELinuxPolicyName(netContainerPolicyName) + + e.logf("assert policy is installed") + e.assertSelinuxPolicyIsInstalled(nodes, rawPolicyName, maxNodeIterations, sleepBetweenIterations) +} + func (e *e2e) testCaseSelinuxIncompletePermissivePolicy() { e.selinuxOnlyTestCase() permissiveProfileName := "errorlogger-incomplete-permissive"