Repository: kubernetes-sigs/security-profiles-operator
Pull request #214 (2021-01-20 14:11:49)

Take selinuxd into use
Changes SELinux integration by ditching the intermediate configMaps 
previously used by the CM reconcile loop of the selinux controller. 
Instead, the daemon running in the DS now takes an boolean argument that 
signifies if the SELinux feature should be enabled. This is false by 
default.

If true, the DS deploys an additional container running selinuxd which 
listens to any files under /etc/selinux.d and can be queried for status 
over a UNIX socket mounted under /var/run/selinuxd. Both the socket 
directory and the drop-in directory are EmptyDirs shared between selinuxd
and the controller.

In addition, the operator receives a --with-selinux=true flag, which makes
the operator create an additional manager that listens for the 
selinuxpolicy API object. Contents of those objects are reconciled to the
/etc/selinux.d drop-in directory and then the controller queries the state
of selinuxd to make sure the policy was indeed added or removed.

### Release note
```release-note
The  selinux component can now be enabled or disabled through the  CongfiMap named  config by toggling a boolean option called EnableSelinux
 
Since not all Linux distributions support SeLinux, its support is disabled by default.
```

TODO:
   - [ ] The SELinux controller should be on by default for OpenShift
         through kustomize
   - [ ] optimize writing the policy files to write only if the file
          content differs when selinux'd `/ready` endpoint merges
   - [ ] take errors from selinuxd into use, extend the status to present them and add a test to exercise a failing selinux policy
   - [ ] the selinuxd container currently sets no resource requests/limits
   - [ ] make the selinuxd container read-only, needs to mount the selinuxd database in a separate volume
   - [ ] open a ticket to consider adding events

/kind feature

k8s-ci-robot: @jhrozek: Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our [release note process](https://git.k8s.io/community/contributors/guide/release-notes.md) to remove it.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
k8s-ci-robot: Hi @jhrozek. Thanks for your PR.

I'm waiting for a [kubernetes-sigs](https://github.com/orgs/kubernetes-sigs/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#" title="Author self-approved">jhrozek</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **saschagrunert** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @saschagrunert` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["saschagrunert"]} -->
JAORMX: /ok-to-test
JAORMX: @jhrozek can you add a release note about the flag to enable/disable SELinux?
k8s-ci-robot: @jhrozek: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-build-image | ee8fe517ac4409bf9ca809b8736465c71eee75b9 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1351895445537820672) | `/test pull-security-profiles-operator-build-image`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-build-image | ee8fe517ac4409bf9ca809b8736465c71eee75b9 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1351895445537820672) | `/test pull-security-profiles-operator-build-image`
pull-security-profiles-operator-test-e2e | ee8fe517ac4409bf9ca809b8736465c71eee75b9 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1351895445575569408) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#" title="Author self-approved">jhrozek</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#pullrequestreview-573072132" title="Approved">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/master/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
saschagrunert: Unfortunately this now needs a rebase after the merge of https://github.com/kubernetes-sigs/security-profiles-operator/pull/179 
k8s-ci-robot: @jhrozek: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
k8s-ci-robot: @jhrozek: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-unit | a4f2037b6e77d987b2e3e25cdb72ceeb7a220f61 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-unit/1352579689905917952) | `/test pull-security-profiles-operator-test-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-unit | a4f2037b6e77d987b2e3e25cdb72ceeb7a220f61 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-unit/1352579689905917952) | `/test pull-security-profiles-operator-test-unit`
pull-security-profiles-operator-test-e2e | a4f2037b6e77d987b2e3e25cdb72ceeb7a220f61 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352579689973026816) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | a4f2037b6e77d987b2e3e25cdb72ceeb7a220f61 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352579689973026816) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 6bfce88a11ecd94e82e15cebbbe0469afd3db426 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352582670873268224) | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | a4f2037b6e77d987b2e3e25cdb72ceeb7a220f61 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352579689973026816) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | b702546269dc3962d1d620efc7cf72642008ac28 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352583883157147648) | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | a4f2037b6e77d987b2e3e25cdb72ceeb7a220f61 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352579689973026816) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 565430a797b2a53a5cf3b2901cbe6e9d50bfc7a3 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352584863881891840) | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 4acf122aecf0dc5bdcf897dddf61df3e713c5122 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352585473301680128) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
JAORMX: /retest
k8s-ci-robot: @jhrozek: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 4acf122aecf0dc5bdcf897dddf61df3e713c5122 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352596804222324736) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352602704194572288) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352602704194572288) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352602704093908992) | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352602704194572288) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352602704093908992) | `/test pull-security-profiles-operator-verify`
pull-security-profiles-operator-build-image | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1352603354374606848) | `/test pull-security-profiles-operator-build-image`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352602704194572288) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352602704093908992) | `/test pull-security-profiles-operator-verify`
pull-security-profiles-operator-build-image | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1352603354374606848) | `/test pull-security-profiles-operator-build-image`
pull-security-profiles-operator-test-unit | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-unit/1352603354328469504) | `/test pull-security-profiles-operator-test-unit`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352602704194572288) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352602704093908992) | `/test pull-security-profiles-operator-verify`
pull-security-profiles-operator-build-image | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1352603354374606848) | `/test pull-security-profiles-operator-build-image`
pull-security-profiles-operator-test-unit | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-unit/1352603354328469504) | `/test pull-security-profiles-operator-test-unit`
pull-security-profiles-operator-build | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build/1352603354269749248) | `/test pull-security-profiles-operator-build`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-verify | 5e8294534c32b3015a54cb8be1c5fc27537ef1a5 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352602704093908992) | `/test pull-security-profiles-operator-verify`
pull-security-profiles-operator-build-image | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1352603354374606848) | `/test pull-security-profiles-operator-build-image`
pull-security-profiles-operator-test-unit | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-unit/1352603354328469504) | `/test pull-security-profiles-operator-test-unit`
pull-security-profiles-operator-build | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build/1352603354269749248) | `/test pull-security-profiles-operator-build`
pull-security-profiles-operator-test-e2e | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352603354408161280) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-build-image | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1352603354374606848) | `/test pull-security-profiles-operator-build-image`
pull-security-profiles-operator-test-unit | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-unit/1352603354328469504) | `/test pull-security-profiles-operator-test-unit`
pull-security-profiles-operator-build | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build/1352603354269749248) | `/test pull-security-profiles-operator-build`
pull-security-profiles-operator-test-e2e | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352603354408161280) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352603354299109376) | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-build-image | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1352603354374606848) | `/test pull-security-profiles-operator-build-image`
pull-security-profiles-operator-test-unit | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-unit/1352603354328469504) | `/test pull-security-profiles-operator-test-unit`
pull-security-profiles-operator-build | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build/1352603354269749248) | `/test pull-security-profiles-operator-build`
pull-security-profiles-operator-verify | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352603354299109376) | `/test pull-security-profiles-operator-verify`
pull-security-profiles-operator-test-e2e | a860a00fd66e6aa100ff7ea115f425b30fcb60f3 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352603644767244288) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-build-image | 922ed07afd55530c31bd812e93d039f1d6e12a7f | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-build-image/1352603354374606848) | `/test pull-security-profiles-operator-build-image`
pull-security-profiles-operator-test-e2e | a860a00fd66e6aa100ff7ea115f425b30fcb60f3 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352603644767244288) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | a860a00fd66e6aa100ff7ea115f425b30fcb60f3 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352603644666580992) | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | a860a00fd66e6aa100ff7ea115f425b30fcb60f3 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352603644767244288) | `/test pull-security-profiles-operator-test-e2e`
pull-security-profiles-operator-verify | 8c9aac5bb25cbf94bb597f786ee949ad3e4fb243 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352604310898216960) | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-verify | 8c9aac5bb25cbf94bb597f786ee949ad3e4fb243 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-verify/1352604310898216960) | `/test pull-security-profiles-operator-verify`
pull-security-profiles-operator-test-e2e | 8c9aac5bb25cbf94bb597f786ee949ad3e4fb243 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352604310982103040) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @jhrozek: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | f11e6e6c9ced461969e480c1a9969bbb0dc36450 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/214/pull-security-profiles-operator-test-e2e/1352605812001869824) | `/test pull-security-profiles-operator-test-e2e`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=214). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Ajhrozek). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/security-profiles-operator/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#pullrequestreview-574261566" title="Approved">JAORMX</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#" title="Author self-approved">jhrozek</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#pullrequestreview-573072132" title="Approved">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/master/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#pullrequestreview-574261566" title="Approved">JAORMX</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#" title="Author self-approved">jhrozek</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/214#pullrequestreview-574273790" title="LGTM">saschagrunert</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fsecurity-profiles-operator).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/security-profiles-operator/blob/master/OWNERS)~~ [saschagrunert]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/cmd/security-profiles-operator/main.go b/cmd/security-profiles-operator/main.go
index 00d9e0181..cabf9a29c 100644
--- a/cmd/security-profiles-operator/main.go
+++ b/cmd/security-profiles-operator/main.go
@@ -17,15 +17,18 @@ limitations under the License.
 package main
 
 import (
+	"context"
 	"fmt"
 	"os"
 	"time"
 
+	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
 	"github.com/urfave/cli/v2"
 	"k8s.io/klog/v2/klogr"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/manager"
+	"sigs.k8s.io/controller-runtime/pkg/scheme"
 
 	profilebindingv1alpha1 "sigs.k8s.io/security-profiles-operator/api/profilebinding/v1alpha1"
 	seccompprofilev1alpha1 "sigs.k8s.io/security-profiles-operator/api/seccompprofile/v1alpha1"
@@ -40,8 +43,10 @@ import (
 
 const (
 	jsonFlag               string = "json"
+	selinuxFlag            string = "with-selinux"
 	operatorImageKey       string = "RELATED_IMAGE_OPERATOR"
 	nonRootEnablerImageKey string = "RELATED_IMAGE_NON_ROOT_ENABLER"
+	selinuxdImageKey       string = "RELATED_IMAGE_SELINUXD"
 	defaultPort            int    = 9443
 )
 
@@ -104,6 +109,13 @@ func main() {
 			Aliases: []string{"d"},
 			Usage:   "run the security-profiles-operator daemon",
 			Action:  runDaemon,
+			Flags: []cli.Flag{
+				&cli.BoolFlag{
+					Name:  selinuxFlag,
+					Usage: "Listen for SELinux API resources",
+					Value: false,
+				},
+			},
 		},
 	}
 
@@ -158,9 +170,6 @@ func runManager(ctx *cli.Context) error {
 		return errors.Wrap(err, "create cluster manager")
 	}
 
-	if err := selinuxpolicyv1alpha1.AddToScheme(mgr.GetScheme()); err != nil {
-		return errors.Wrap(err, "add core operator APIs to scheme")
-	}
 	if err := profilebindingv1alpha1.AddToScheme(mgr.GetScheme()); err != nil {
 		return errors.Wrap(err, "add profilebinding API to scheme")
 	}
@@ -168,11 +177,7 @@ func runManager(ctx *cli.Context) error {
 		return errors.Wrap(err, "add seccompprofile API to scheme")
 	}
 
-	if err := selinuxpolicy.Setup(ctx.Context, mgr, ctrl.Log.WithName("selinuxpolicy")); err != nil {
-		return errors.Wrap(err, "setup profile controller")
-	}
-
-	if err := spod.Setup(ctx.Context, mgr, dt, ctrl.Log.WithName("spod-config")); err != nil {
+	if err := spod.Setup(ctx.Context, mgr, &dt, ctrl.Log.WithName("spod-config")); err != nil {
 		return errors.Wrap(err, "setup profile controller")
 	}
 
@@ -204,12 +209,54 @@ func getTunables() (dt spod.DaemonTunables, err error) {
 	}
 	dt.NonRootEnablerImage = nonRootEnableImage
 
+	selinuxdImage := os.Getenv(selinuxdImageKey)
+	if selinuxdImage == "" {
+		return dt, errors.New("invalid selinuxd image")
+	}
+	dt.SelinuxdImage = selinuxdImage
+
 	return dt, nil
 }
 
+// TODO(jhrozek): the type seems out of place here, maybe we should move it to a file under internal/pkg/controllers
+// that would just define the type and nothing else.
+type daemonSetupFunc func(ctx context.Context, mgr ctrl.Manager, l logr.Logger) error
+
+type controllerSettings struct {
+	name          string
+	setupFn       daemonSetupFunc
+	schemaBuilder *scheme.Builder
+}
+
+func getEnabledControllers(ctx *cli.Context) []*controllerSettings {
+	enabledSettings := make([]*controllerSettings, 0, 2)
+
+	enabledSettings = append(enabledSettings, &controllerSettings{
+		name:          "seccomp-spod",
+		setupFn:       profile.Setup,
+		schemaBuilder: seccompprofilev1alpha1.SchemeBuilder,
+	})
+
+	if ctx.Bool(selinuxFlag) {
+		enabledSettings = append(enabledSettings, &controllerSettings{
+			name:          "selinux-spod",
+			setupFn:       selinuxpolicy.Setup,
+			schemaBuilder: selinuxpolicyv1alpha1.SchemeBuilder,
+		})
+	}
+
+	return enabledSettings
+}
+
 func runDaemon(ctx *cli.Context) error {
 	// security-profiles-operator-daemon
 	printInfo("spod")
+
+	enabledControllers := getEnabledControllers(ctx)
+	if len(enabledControllers) == 0 {
+		return errors.New("no controllers enabled")
+	}
+
 	cfg, err := ctrl.GetConfig()
 	if err != nil {
 		return errors.Wrap(err, "get config")
@@ -230,12 +277,9 @@ func runDaemon(ctx *cli.Context) error {
 		return errors.Wrap(err, "create manager")
 	}
 
-	if err := seccompprofilev1alpha1.AddToScheme(mgr.GetScheme()); err != nil {
-		return errors.Wrap(err, "add core operator APIs to scheme")
-	}
-
-	if err := profile.Setup(ctx.Context, mgr, ctrl.Log.WithName("profile")); err != nil {
-		return errors.Wrap(err, "setup profile controller")
+	err = setupEnabledControllers(ctx.Context, enabledControllers, mgr)
+	if err != nil {
+		return errors.Wrap(err, "enable controllers")
 	}
 
 	setupLog.Info("starting daemon")
@@ -246,3 +290,17 @@ func runDaemon(ctx *cli.Context) error {
 	setupLog.Info("ending daemon")
 	return nil
 }
+
+func setupEnabledControllers(ctx context.Context, enabledControllers []*controllerSettings, mgr ctrl.Manager) error {
+	for _, enableCtrl := range enabledControllers {
+		if err := enableCtrl.schemaBuilder.AddToScheme(mgr.GetScheme()); err != nil {
+			return errors.Wrap(err, "add core operator APIs to scheme")
+		}
+
+		if err := enableCtrl.setupFn(ctx, mgr, ctrl.Log.WithName(enableCtrl.name)); err != nil {
+			return errors.Wrapf(err, "setup %s controller", enableCtrl.name)
+		}
+	}
+
+	return nil
+}
diff --git a/deploy/base/config.yaml b/deploy/base/config.yaml
index e614899c7..9c0352d3f 100644
--- a/deploy/base/config.yaml
+++ b/deploy/base/config.yaml
@@ -7,3 +7,4 @@ metadata:
     security-profiles-operator/config: ""
 data:
   SPOdImagePullPolicy: Always
+  EnableSelinux: "false"
diff --git a/deploy/base/kustomization.yaml b/deploy/base/kustomization.yaml
index ab1c39fee..32109c1b0 100644
--- a/deploy/base/kustomization.yaml
+++ b/deploy/base/kustomization.yaml
@@ -27,6 +27,8 @@ patchesStrategicMerge:
                 value: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
               - name: RELATED_IMAGE_NON_ROOT_ENABLER
                 value: bash:5.0
+              - name: RELATED_IMAGE_SELINUXD
+                value: quay.io/jaosorior/selinuxd
 
 commonLabels:
   app: security-profiles-operator
diff --git a/deploy/base/operator.yaml b/deploy/base/operator.yaml
index b8001d105..d934d1c4c 100644
--- a/deploy/base/operator.yaml
+++ b/deploy/base/operator.yaml
@@ -31,6 +31,8 @@ spec:
               value: security-profiles-operator
             - name: RELATED_IMAGE_NON_ROOT_ENABLER
               value: non-root-enabler
+            - name: RELATED_IMAGE_SELINUXD
+              value: quay.io/jaosorior/selinuxd
           volumeMounts:
           - name: cert
             mountPath: /tmp/k8s-webhook-server/serving-certs
diff --git a/deploy/namespace-operator.yaml b/deploy/namespace-operator.yaml
index 23428a768..7002ca07e 100644
--- a/deploy/namespace-operator.yaml
+++ b/deploy/namespace-operator.yaml
@@ -664,6 +664,8 @@ spec:
           value: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
         - name: RELATED_IMAGE_NON_ROOT_ENABLER
           value: bash:5.0
+        - name: RELATED_IMAGE_SELINUXD
+          value: quay.io/jaosorior/selinuxd
         image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
         imagePullPolicy: Always
         name: security-profiles-operator
@@ -699,6 +701,7 @@ spec:
 ---
 apiVersion: v1
 data:
+  EnableSelinux: "false"
   SPOdImagePullPolicy: Always
 kind: ConfigMap
 metadata:
diff --git a/deploy/operator.yaml b/deploy/operator.yaml
index 160184689..5d17eeb78 100644
--- a/deploy/operator.yaml
+++ b/deploy/operator.yaml
@@ -662,6 +662,8 @@ spec:
           value: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
         - name: RELATED_IMAGE_NON_ROOT_ENABLER
           value: bash:5.0
+        - name: RELATED_IMAGE_SELINUXD
+          value: quay.io/jaosorior/selinuxd
         image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
         imagePullPolicy: Always
         name: security-profiles-operator
@@ -697,6 +699,7 @@ spec:
 ---
 apiVersion: v1
 data:
+  EnableSelinux: "false"
   SPOdImagePullPolicy: Always
 kind: ConfigMap
 metadata:
diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go
index b8601b912..6306552fc 100644
--- a/internal/pkg/config/config.go
+++ b/internal/pkg/config/config.go
@@ -37,6 +37,16 @@ const (
 	RestrictNamespaceEnvKey = "RESTRICT_TO_NAMESPACE"
 )
 
+// Controller configMap keys.
+const (
+	SPOcEnableSelinux = "EnableSelinux"
+)
+
+// DaemonSet configMap keys.
+const (
+	SPOdImagePullPolicy = "SPOdImagePullPolicy"
+)
+
 // GetOperatorNamespace gets the namespace that the operator is currently running on.
 func GetOperatorNamespace() string {
 	// TODO(jaosorior): Get a method to return the current operator
diff --git a/internal/pkg/controllers/selinuxpolicy/configmap_controller.go b/internal/pkg/controllers/selinuxpolicy/configmap_controller.go
deleted file mode 100644
index 09285af62..000000000
--- a/internal/pkg/controllers/selinuxpolicy/configmap_controller.go
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package selinuxpolicy
-
-import (
-	"context"
-	"fmt"
-	"time"
-
-	rcommonv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
-	"github.com/crossplane/crossplane-runtime/pkg/event"
-	"github.com/go-logr/logr"
-	"github.com/pkg/errors"
-	corev1 "k8s.io/api/core/v1"
-	kerrors "k8s.io/apimachinery/pkg/api/errors"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/types"
-	"sigs.k8s.io/controller-runtime/pkg/client"
-	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
-	"sigs.k8s.io/controller-runtime/pkg/reconcile"
-
-	spov1alpha1 "sigs.k8s.io/security-profiles-operator/api/selinuxpolicy/v1alpha1"
-	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
-)
-
-// blank assignment to verify that ReconcileConfigMap implements `reconcile.Reconciler`.
-var _ reconcile.Reconciler = &ReconcileConfigMap{}
-
-const defaultRequeueTime = 5 * time.Second
-
-// ReconcileConfigMap reconciles a ConfigMap object.
-type ReconcileConfigMap struct {
-	// This client, initialized using mgr.Client() above, is a split client
-	// that reads objects from the cache and writes to the apiserver
-	client client.Client
-	scheme *runtime.Scheme
-	record event.Recorder
-}
-
-// Reconcile reads that state of the cluster for a ConfigMap object and makes changes based on the state read
-// and what is in the `ConfigMap.Spec`.
-func (r *ReconcileConfigMap) Reconcile(request reconcile.Request) (reconcile.Result, error) {
-	// Fetch the ConfigMap instance
-	cminstance := &corev1.ConfigMap{}
-	if err := r.client.Get(context.TODO(), request.NamespacedName, cminstance); err != nil {
-		return reconcile.Result{}, IgnoreNotFound(err)
-	}
-	policyName, ok := cminstance.Labels["appName"]
-	if !ok {
-		return reconcile.Result{}, nil
-	}
-	policyNamespace, ok := cminstance.Labels["appNamespace"]
-	if !ok {
-		return reconcile.Result{}, nil
-	}
-
-	reqLogger := log.WithValues("SelinuxPolicy.Name", policyName, "SelinuxPolicy.Namespace", policyNamespace)
-
-	policyObjKey := types.NamespacedName{Name: policyName, Namespace: policyNamespace}
-	policy := &spov1alpha1.SelinuxPolicy{}
-	if err := r.client.Get(context.TODO(), policyObjKey, policy); err != nil {
-		return reconcile.Result{}, IgnoreNotFound(err)
-	}
-
-	if policy.Status.State == "" || policy.Status.State == spov1alpha1.PolicyStatePending {
-		policyCopy := policy.DeepCopy()
-		policyCopy.Status.State = spov1alpha1.PolicyStateInProgress
-		policyCopy.Status.SetConditions(rcommonv1.Creating())
-		if err := r.client.Status().Update(context.TODO(), policyCopy); err != nil {
-			return reconcile.Result{}, errors.Wrap(err, "Updating policy without status")
-		}
-		return reconcile.Result{Requeue: true}, nil
-	}
-
-	// object is not being deleted
-	if cminstance.ObjectMeta.DeletionTimestamp.IsZero() {
-		return r.reconcileInstallerPods(policy, cminstance, reqLogger)
-	}
-	return reconcile.Result{}, nil
-}
-
-func (r *ReconcileConfigMap) reconcileInstallerPods(policy *spov1alpha1.SelinuxPolicy, cm *corev1.ConfigMap,
-	logger logr.Logger) (reconcile.Result, error) {
-	var done bool
-	logger.Info("Reconciling pods for policy")
-
-	nodesList := &corev1.NodeList{}
-	if err := r.client.List(context.TODO(), nodesList); err != nil {
-		return reconcile.Result{}, errors.Wrap(err, "Getting node list")
-	}
-	for nodeidx := range nodesList.Items {
-		// Define a new Pod object
-		pod := newPodForPolicy(policy.GetName(), policy.GetNamespace(), &nodesList.Items[nodeidx])
-		if err := controllerutil.SetControllerReference(cm, pod, r.scheme); err != nil {
-			log.Error(err, "Failed to set pod ownership", "pod", pod)
-			return reconcile.Result{}, errors.Wrap(err, "Setting controller reference for SELinux installer pod")
-		}
-
-		// Check if this Pod already exists
-		found := &corev1.Pod{}
-		err := r.client.Get(context.TODO(), types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace}, found)
-		if err != nil && kerrors.IsNotFound(err) {
-			logger.Info("Creating a new Pod", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name)
-			if err = r.client.Create(context.TODO(), pod); err != nil {
-				return reconcile.Result{}, IgnoreAlreadyExists(err)
-			}
-			// NOTE(jaosorior): We expedite the creation of all
-			// these pods...
-			continue
-		} else if err != nil {
-			return reconcile.Result{}, errors.Wrap(err, "Gettting selinux installer Pod")
-		}
-
-		exitCode, gotCode := r.getInstallerContainerExitCode(found)
-		// Pod is still running - requeue
-		if !gotCode {
-			logger.Info("Pod still running", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name)
-			return reconcile.Result{Requeue: true, RequeueAfter: defaultRequeueTime}, nil
-		}
-		if exitCode != 0 {
-			logger.Info("Pod failed", "Pod.Namespace", pod.Namespace, "Pod.Name", pod.Name, "exit-code", exitCode)
-			policyCopy := policy.DeepCopy()
-			policyCopy.Status.State = spov1alpha1.PolicyStateError
-			policyCopy.Status.SetConditions(rcommonv1.Unavailable())
-			if err := r.client.Status().Update(context.TODO(), policyCopy); err != nil {
-				return reconcile.Result{}, errors.Wrap(err, "Updating SELinux policy with install error")
-			}
-			return reconcile.Result{}, nil
-		}
-		done = true
-	}
-
-	if done {
-		policyCopy := policy.DeepCopy()
-		policyCopy.Status.State = spov1alpha1.PolicyStateInstalled
-		policyCopy.Status.SetConditions(rcommonv1.Available())
-		if err := r.client.Status().Update(context.TODO(), policyCopy); err != nil {
-			return reconcile.Result{}, errors.Wrap(err, "Updating SELinux policy with installation success")
-		}
-	}
-	return reconcile.Result{}, nil
-}
-
-func (r *ReconcileConfigMap) getInstallerContainerExitCode(pod *corev1.Pod) (int32, bool) {
-	for idx := range pod.Status.ContainerStatuses {
-		containerStatus := &pod.Status.ContainerStatuses[idx]
-		if containerStatus.Name == "policy-installer" {
-			if containerStatus.State.Terminated != nil {
-				termState := containerStatus.State.Terminated
-				return termState.ExitCode, true
-			}
-		}
-	}
-	return -1, false
-}
-
-// newPodForPolicy returns a busybox pod with the same name/namespace as the cr.
-func newPodForPolicy(name, ns string, node *corev1.Node) *corev1.Pod {
-	labels := map[string]string{
-		"appName":      name,
-		"appNamespace": ns,
-	}
-	trueVal := true
-	hostVolTypeDir := corev1.HostPathDirectory
-	return &corev1.Pod{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      GetInstallerPodName(name, ns, node),
-			Namespace: config.GetOperatorNamespace(),
-			Labels:    labels,
-		},
-		Spec: corev1.PodSpec{
-			Containers: []corev1.Container{
-				{
-					Name: "policy-installer",
-					// TODO(jaosorior): Add udica image or equivalent to a
-					// more formal registry
-					Image:   "quay.io/jaosorior/udica",
-					Command: []string{"/bin/sh"},
-					Args:    []string{"-c", "semodule -vi /tmp/policy/*.cil /usr/share/udica/templates/*cil;"},
-					SecurityContext: &corev1.SecurityContext{
-						Privileged: &trueVal,
-					},
-					VolumeMounts: []corev1.VolumeMount{
-						{
-							Name:      "fsselinux",
-							MountPath: "/sys/fs/selinux",
-						},
-						{
-							Name:      "etcselinux",
-							MountPath: "/etc/selinux",
-						},
-						{
-							Name:      "varlibselinux",
-							MountPath: "/var/lib/selinux",
-						},
-						{
-							Name:      "policyvolume",
-							MountPath: "/tmp/policy",
-						},
-					},
-				},
-				// This container needs to keep running so we can run the uninstall script.
-				{
-					Name: "policy-uninstaller",
-					// NOTE(jaosorior): Add udica image or equivalent to a
-					// more formal registry
-					Image:   "quay.io/jaosorior/udica",
-					Command: []string{"/bin/sh"},
-					Args:    []string{"-c", "trap 'exit 0' SIGINT SIGTERM; while true; do sleep infinity; done;"},
-					Lifecycle: &corev1.Lifecycle{
-						PreStop: &corev1.Handler{
-							Exec: &corev1.ExecAction{
-								Command: []string{"/bin/sh", "-c", fmt.Sprintf("semodule -vr '%s'", GetPolicyName(name, ns))},
-							},
-						},
-					},
-					SecurityContext: &corev1.SecurityContext{
-						Privileged: &trueVal,
-					},
-					VolumeMounts: []corev1.VolumeMount{
-						{
-							Name:      "fsselinux",
-							MountPath: "/sys/fs/selinux",
-						},
-						{
-							Name:      "etcselinux",
-							MountPath: "/etc/selinux",
-						},
-						{
-							Name:      "varlibselinux",
-							MountPath: "/var/lib/selinux",
-						},
-						{
-							Name:      "policyvolume",
-							MountPath: "/tmp/policy",
-						},
-					},
-				},
-			},
-			// NOTE(jaosorior): use another service account
-			ServiceAccountName: "security-profiles-operator",
-			RestartPolicy:      corev1.RestartPolicyNever,
-			NodeName:           node.Name,
-			Volumes: []corev1.Volume{
-				{
-					Name: "fsselinux",
-					VolumeSource: corev1.VolumeSource{
-						HostPath: &corev1.HostPathVolumeSource{
-							Path: "/sys/fs/selinux",
-							Type: &hostVolTypeDir,
-						},
-					},
-				},
-				{
-					Name: "etcselinux",
-					VolumeSource: corev1.VolumeSource{
-						HostPath: &corev1.HostPathVolumeSource{
-							Path: "/etc/selinux",
-							Type: &hostVolTypeDir,
-						},
-					},
-				},
-				{
-					Name: "varlibselinux",
-					VolumeSource: corev1.VolumeSource{
-						HostPath: &corev1.HostPathVolumeSource{
-							Path: "/var/lib/selinux",
-							Type: &hostVolTypeDir,
-						},
-					},
-				},
-				{
-					Name: "policyvolume",
-					VolumeSource: corev1.VolumeSource{
-						ConfigMap: &corev1.ConfigMapVolumeSource{
-							LocalObjectReference: corev1.LocalObjectReference{
-								Name: GetPolicyConfigMapName(name, ns),
-							},
-						},
-					},
-				},
-			},
-			Tolerations: []corev1.Toleration{
-				{
-					Key:      "node-role.kubernetes.io/master",
-					Operator: "Exists",
-					Effect:   "NoSchedule",
-				},
-				{
-					Key:      "node-role.kubernetes.io/control-plane",
-					Operator: "Exists",
-					Effect:   "NoSchedule",
-				},
-			},
-		},
-	}
-}
diff --git a/internal/pkg/controllers/selinuxpolicy/selinuxpolicy_controller.go b/internal/pkg/controllers/selinuxpolicy/selinuxpolicy_controller.go
index 80f77468a..a8df96c59 100644
--- a/internal/pkg/controllers/selinuxpolicy/selinuxpolicy_controller.go
+++ b/internal/pkg/controllers/selinuxpolicy/selinuxpolicy_controller.go
@@ -19,23 +19,27 @@ package selinuxpolicy
 import (
 	"bytes"
 	"context"
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net"
+	"net/http"
+	"os"
+	"path"
 	"strings"
 	"text/template"
+	"time"
 
 	rcommonv1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
 	"github.com/crossplane/crossplane-runtime/pkg/event"
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
-	corev1 "k8s.io/api/core/v1"
-	kerrors "k8s.io/apimachinery/pkg/api/errors"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/types"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 
 	spov1alpha1 "sigs.k8s.io/security-profiles-operator/api/selinuxpolicy/v1alpha1"
-	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
+	"sigs.k8s.io/security-profiles-operator/internal/pkg/controllers/spod/bindata"
 )
 
 // The underscore is not a valid character in a pod, so we can
@@ -46,6 +50,23 @@ const policyWrapper = `(block {{.Name}}_{{.Namespace}}
 
 const selinuxFinalizerName = "selinuxpolicy.finalizers.selinuxpolicy.k8s.io"
 
+const (
+	selinuxdPoliciesBaseURL = "http://unix/policies/"
+	selinuxdSocketTimeout   = 5 * time.Second
+)
+
+type sePolStatusType string
+
+const (
+	installedStatus sePolStatusType = "Installed"
+	failedStatus    sePolStatusType = "Failed"
+)
+
+type sePolStatus struct {
+	Msg    string
+	Status sePolStatusType
+}
+
 // blank assignment to verify that ReconcileSelinuxPolicy implements `reconcile.Reconciler`.
 var _ reconcile.Reconciler = &ReconcileSP{}
 
@@ -106,7 +127,7 @@ func (r *ReconcileSP) Reconcile(request reconcile.Request) (reconcile.Result, er
 		if !SliceContainsString(instance.ObjectMeta.Finalizers, selinuxFinalizerName) {
 			return r.addFinalizer(instance)
 		}
-		return r.reconcileConfigMap(instance, reqLogger)
+		return r.reconcilePolicy(instance, reqLogger)
 	}
 
 	// The object is being deleted
@@ -122,7 +143,7 @@ func (r *ReconcileSP) Reconcile(request reconcile.Request) (reconcile.Result, er
 	}
 
 	if SliceContainsString(instance.ObjectMeta.Finalizers, selinuxFinalizerName) {
-		res, err := r.reconcileDeleteConfigMap(instance, reqLogger)
+		res, err := r.reconcileDeletePolicy(instance, reqLogger)
 		if res.Requeue || err != nil {
 			return res, err
 		}
@@ -161,63 +182,115 @@ func (r *ReconcileSP) removeFinalizer(sp *spov1alpha1.SelinuxPolicy) (reconcile.
 	return reconcile.Result{}, nil
 }
 
-func (r *ReconcileSP) reconcileConfigMap(sp *spov1alpha1.SelinuxPolicy, l logr.Logger) (reconcile.Result, error) {
-	// Define a new ConfigMap object
-	cm := r.newConfigMapForPolicy(sp)
-
-	// Check if this cm already exists
-	foundCM := &corev1.ConfigMap{}
-	err := r.client.Get(context.TODO(), types.NamespacedName{Name: cm.Name, Namespace: cm.Namespace}, foundCM)
-	if err != nil && kerrors.IsNotFound(err) {
-		l.Info("Creating a new ConfigMap", "ConfigMap.Namespace", cm.Namespace, "ConfigMap.Name", cm.Name)
-		if err = r.client.Create(context.TODO(), cm); err != nil {
-			return reconcile.Result{}, IgnoreAlreadyExists(err)
+func (r *ReconcileSP) reconcilePolicy(sp *spov1alpha1.SelinuxPolicy, l logr.Logger) (reconcile.Result, error) {
+	err := r.reconcilePolicyFile(sp, l)
+	if err != nil {
+		return reconcile.Result{}, errors.Wrap(err, "Creating policy file")
+	}
+
+	l.Info("Checking if policy is installed", "policyName", sp.Name)
+	polStatus, err := r.getPolicyStatus(sp)
+	if err != nil {
+		return reconcile.Result{}, errors.Wrap(err, "Looking up policy status")
+	}
+
+	if polStatus == nil {
+		l.Info("Policy still missing, requeue")
+		policyCopy := sp.DeepCopy()
+		policyCopy.Status.State = spov1alpha1.PolicyStateInProgress
+		policyCopy.Status.SetConditions(rcommonv1.Creating())
+		if err := r.client.Status().Update(context.TODO(), policyCopy); err != nil {
+			return reconcile.Result{}, errors.Wrap(err, "Updating SELinux policy with installation in progress")
 		}
+		return reconcile.Result{Requeue: true}, nil
+	}
 
-		// CM created successfully - don't requeue
-		return reconcile.Result{}, nil
-	} else if err != nil {
-		return reconcile.Result{}, errors.Wrap(err, "Getting SelinuxPolicy ConfigMap")
+	l.Info("Policy installed")
+	policyCopy := sp.DeepCopy()
+
+	switch polStatus.Status {
+	case installedStatus:
+		policyCopy.Status.State = spov1alpha1.PolicyStateInstalled
+		policyCopy.Status.SetConditions(rcommonv1.Available())
+	case failedStatus:
+		policyCopy.Status.State = spov1alpha1.PolicyStateError
+		policyCopy.Status.SetConditions(rcommonv1.Unavailable())
+	}
+
+	if err := r.client.Status().Update(context.TODO(), policyCopy); err != nil {
+		return reconcile.Result{}, errors.Wrap(err, "Updating SELinux policy with installation success")
 	}
+
 	return reconcile.Result{}, nil
 }
 
-func (r *ReconcileSP) reconcileDeleteConfigMap(sp *spov1alpha1.SelinuxPolicy, l logr.Logger) (reconcile.Result, error) {
-	// Define a new ConfigMap object
-	cm := r.newConfigMapForPolicy(sp)
-	key := types.NamespacedName{Name: cm.Name, Namespace: cm.Namespace}
-	l.Info("Deleting ConfigMap", "ConfigMap.Namespace", cm.Namespace, "ConfigMap.Name", cm.Name)
-	if getErr := r.client.Get(context.TODO(), key, cm); getErr != nil {
-		if kerrors.IsNotFound(getErr) {
-			// this is good. Nothing to do.
+func (r *ReconcileSP) reconcilePolicyFile(sp *spov1alpha1.SelinuxPolicy, l logr.Logger) error {
+	policyPath := path.Join(bindata.SelinuxDropDirectory, GetPolicyName(sp.Name, sp.Namespace)+".cil")
+	policyContent := []byte(r.wrapPolicy(sp))
+
+	l.Info("Writing to policy file", "policyPath", policyPath)
+	err := ioutil.WriteFile(policyPath, policyContent, 0600)
+	if err != nil {
+		return errors.Wrap(err, "Writing policy file")
+	}
+
+	return nil
+}
+
+func (r *ReconcileSP) reconcileDeletePolicy(sp *spov1alpha1.SelinuxPolicy, l logr.Logger) (reconcile.Result, error) {
+	res, err := r.reconcileDeletePolicyFile(sp, l)
+	if res.Requeue || err != nil {
+		return res, err
+	}
+
+	l.Info("Checking if policy is removed", "policyName", sp.Name)
+	polStatus, err := r.getPolicyStatus(sp)
+	if err != nil {
+		return reconcile.Result{}, errors.Wrap(err, "Looking up policy status")
+	}
+
+	if polStatus != nil {
+		switch polStatus.Status {
+		case installedStatus:
+			l.Info("Policy still installed, requeue")
+			return reconcile.Result{Requeue: true}, nil
+		case failedStatus:
+			policyCopy := sp.DeepCopy()
+			policyCopy.Status.State = spov1alpha1.PolicyStateError
+			policyCopy.Status.SetConditions(rcommonv1.Unavailable())
+			if err := r.client.Status().Update(context.TODO(), policyCopy); err != nil {
+				return reconcile.Result{}, errors.Wrap(err, "Updating SELinux policy with installation success")
+			}
+
 			return reconcile.Result{}, nil
 		}
 	}
-	// We still need to delete this
-	return reconcile.Result{Requeue: true}, IgnoreNotFound(r.client.Delete(context.TODO(), cm))
+
+	l.Info("Policy removed")
+	return reconcile.Result{}, nil
 }
 
-func (r *ReconcileSP) newConfigMapForPolicy(cr *spov1alpha1.SelinuxPolicy) *corev1.ConfigMap {
-	labels := map[string]string{
-		// TODO(jaosorior): Use constant
-		cmIsSelinuxPolicy: "true",
-		"appName":         cr.Name,
-		"appNamespace":    cr.Namespace,
-	}
-
-	return &corev1.ConfigMap{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      GetPolicyConfigMapName(cr.Name, cr.Namespace),
-			Namespace: config.GetOperatorNamespace(),
-			Labels:    labels,
-			Finalizers: []string{
-				metav1.FinalizerDeleteDependents,
-			},
-		},
-		Data: map[string]string{
-			GetPolicyName(cr.Name, cr.Namespace) + ".cil": r.wrapPolicy(cr),
-		},
+func (r *ReconcileSP) reconcileDeletePolicyFile(sp *spov1alpha1.SelinuxPolicy,
+	l logr.Logger) (reconcile.Result, error) {
+	policyPath := path.Join(bindata.SelinuxDropDirectory, GetPolicyName(sp.Name, sp.Namespace)+".cil")
+
+	l.Info("Removing policy file", "policyPath", policyPath)
+	err := os.Remove(policyPath)
+	if err == nil {
+		// Reconcile again to make sure the file is gone
+		return reconcile.Result{Requeue: true}, nil
 	}
+
+	var osPathErr *os.PathError
+	if errors.As(err, &osPathErr) {
+		if errors.Is(osPathErr.Err, os.ErrNotExist) {
+			// The file is gone, stop requeuing
+			return reconcile.Result{}, nil
+		}
+	}
+
+	// Retry on a generic error
+	return reconcile.Result{Requeue: true}, errors.Wrap(err, "error removing policy file")
 }
 
 func (r *ReconcileSP) wrapPolicy(cr *spov1alpha1.SelinuxPolicy) string {
@@ -241,3 +314,47 @@ func (r *ReconcileSP) wrapPolicy(cr *spov1alpha1.SelinuxPolicy) string {
 	}
 	return result.String()
 }
+
+func (r *ReconcileSP) getPolicyStatus(sp *spov1alpha1.SelinuxPolicy) (*sePolStatus, error) {
+	ctx, cancel := context.WithTimeout(context.Background(), selinuxdSocketTimeout)
+	defer cancel()
+
+	httpc := http.Client{
+		Transport: &http.Transport{
+			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
+				return net.Dial("unix", bindata.SelinuxdSocketPath)
+			},
+		},
+	}
+
+	polURL := selinuxdPoliciesBaseURL + GetPolicyName(sp.Name, sp.Namespace)
+	req, err := http.NewRequestWithContext(ctx, "GET", polURL, nil)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to create a request to selinuxd")
+	}
+
+	response, err := httpc.Do(req)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to send a request to selinuxd")
+	}
+	defer response.Body.Close()
+
+	if response.StatusCode == http.StatusNotFound {
+		return nil, nil
+	} else if response.StatusCode != http.StatusOK {
+		return nil, errors.New("unexpected HTTP error code " + fmt.Sprint(response.StatusCode))
+	}
+
+	var status sePolStatus
+	err = json.NewDecoder(response.Body).Decode(&status)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to decode response from selinuxd")
+	}
+
+	switch status.Status {
+	case installedStatus, failedStatus:
+		return &status, nil
+	}
+
+	return nil, errors.New("invalid sePolStatus value")
+}
diff --git a/internal/pkg/controllers/selinuxpolicy/setup.go b/internal/pkg/controllers/selinuxpolicy/setup.go
index e6fc4bf50..b24fee577 100644
--- a/internal/pkg/controllers/selinuxpolicy/setup.go
+++ b/internal/pkg/controllers/selinuxpolicy/setup.go
@@ -21,38 +21,18 @@ import (
 	"text/template"
 
 	"github.com/crossplane/crossplane-runtime/pkg/event"
-	"github.com/crossplane/crossplane-runtime/pkg/resource"
 	"github.com/go-logr/logr"
 	"github.com/pkg/errors"
-	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/runtime"
 	ctrl "sigs.k8s.io/controller-runtime"
 	logf "sigs.k8s.io/controller-runtime/pkg/log"
 
 	spov1alpha1 "sigs.k8s.io/security-profiles-operator/api/selinuxpolicy/v1alpha1"
-	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
 )
 
 var log = logf.Log.WithName("selinuxpolicy")
 
-// TODO(jaosorior): Use better method than a label constant.
-const cmIsSelinuxPolicy = "is-selinux-policy"
-
 // Setup adds a controller that reconciles seccomp profiles.
 func Setup(ctx context.Context, mgr ctrl.Manager, l logr.Logger) error {
-	if err := ctrl.NewControllerManagedBy(mgr).
-		Named("configmaps").
-		For(&corev1.ConfigMap{}).
-		WithEventFilter(resource.NewPredicates(hasSELinuxLabel)).
-		Owns(&corev1.Pod{}).
-		Complete(&ReconcileConfigMap{
-			client: mgr.GetClient(),
-			scheme: mgr.GetScheme(),
-			record: event.NewAPIRecorder(mgr.GetEventRecorderFor("configmaps")),
-		}); err != nil {
-		return errors.Wrap(err, "creating configmap controller")
-	}
-
 	// Create template to wrap policies
 	tmpl, err := template.New("policyWrapper").Parse(policyWrapper)
 	if err != nil {
@@ -69,23 +49,3 @@ func Setup(ctx context.Context, mgr ctrl.Manager, l logr.Logger) error {
 			record:         event.NewAPIRecorder(mgr.GetEventRecorderFor("selinuxpolicy")),
 		})
 }
-
-func hasSELinuxLabel(obj runtime.Object) bool {
-	cm, ok := obj.(*corev1.ConfigMap)
-	if !ok {
-		return false
-	}
-	// we only care about this namespace
-	if cm.GetNamespace() != config.GetOperatorNamespace() {
-		return false
-	}
-	labels := cm.GetLabels()
-	if labels == nil {
-		return false
-	}
-	val, ok := labels[cmIsSelinuxPolicy]
-	if !ok {
-		return false
-	}
-	return val == "true"
-}
diff --git a/internal/pkg/controllers/spod/bindata/spod.go b/internal/pkg/controllers/spod/bindata/spod.go
index 976dc786a..f3e2460b1 100644
--- a/internal/pkg/controllers/spod/bindata/spod.go
+++ b/internal/pkg/controllers/spod/bindata/spod.go
@@ -34,7 +34,12 @@ var (
 	hostPathDirectoryOrCreate       = v1.HostPathDirectoryOrCreate
 )
 
-const operatorRoot = "/var/lib/security-profiles-operator"
+const (
+	operatorRoot         = "/var/lib/security-profiles-operator"
+	SelinuxDropDirectory = "/etc/selinux.d"
+	SelinuxdSocketDir    = "/var/run/selinuxd"
+	SelinuxdSocketPath   = SelinuxdSocketDir + "/selinuxd.sock"
+)
 
 var Manifest = &appsv1.DaemonSet{
 	ObjectMeta: metav1.ObjectMeta{
@@ -58,14 +63,15 @@ var Manifest = &appsv1.DaemonSet{
 			},
 			Spec: v1.PodSpec{
 				ServiceAccountName: config.OperatorName,
-				InitContainers: []v1.Container{{
-					Name: "non-root-enabler",
-					// Creates directory /var/lib/security-profiles-operator,
-					// sets 2000:2000 as its owner and symlink it to
-					// /var/lib/kubelet/seccomp/operator. This is required
-					// to allow the main container to run as non-root.
-					Command: []string{"bash", "-c"},
-					Args: []string{`
+				InitContainers: []v1.Container{
+					{
+						Name: "non-root-enabler",
+						// Creates directory /var/lib/security-profiles-operator,
+						// sets 2000:2000 as its owner and symlink it to
+						// /var/lib/kubelet/seccomp/operator. This is required
+						// to allow the main container to run as non-root.
+						Command: []string{"bash", "-c"},
+						Args: []string{`
 						set -euo pipefail
 
 						if [ ! -d ` + config.KubeletSeccompRootPath + ` ]; then
@@ -82,89 +88,216 @@ var Manifest = &appsv1.DaemonSet{
 						/bin/chown -R 2000:2000 ` + operatorRoot + `
 						cp -f -v /opt/seccomp-profiles/* ` + config.KubeletSeccompRootPath + `
 					`},
-					VolumeMounts: []v1.VolumeMount{
-						{
-							Name:      "host-varlib-volume",
-							MountPath: "/var/lib",
+						VolumeMounts: []v1.VolumeMount{
+							{
+								Name:      "host-varlib-volume",
+								MountPath: "/var/lib",
+							},
+							{
+								Name:      "profile-configmap-volume",
+								MountPath: "/opt/seccomp-profiles",
+								ReadOnly:  true,
+							},
 						},
-						{
-							Name:      "profile-configmap-volume",
-							MountPath: "/opt/seccomp-profiles",
-							ReadOnly:  true,
+						SecurityContext: &v1.SecurityContext{
+							AllowPrivilegeEscalation: &falsely,
+							ReadOnlyRootFilesystem:   &truly,
+							Capabilities: &v1.Capabilities{
+								Drop: []v1.Capability{"ALL"},
+								Add:  []v1.Capability{"CHOWN", "FOWNER", "FSETID", "DAC_OVERRIDE"},
+							},
+							RunAsUser: &userRoot,
+							SELinuxOptions: &v1.SELinuxOptions{
+								// TODO(jaosorior): Use a more restricted selinux type
+								Type: "spc_t",
+							},
 						},
-					},
-					SecurityContext: &v1.SecurityContext{
-						AllowPrivilegeEscalation: &falsely,
-						ReadOnlyRootFilesystem:   &truly,
-						Capabilities: &v1.Capabilities{
-							Drop: []v1.Capability{"ALL"},
-							Add:  []v1.Capability{"CHOWN", "FOWNER", "FSETID", "DAC_OVERRIDE"},
-						},
-						RunAsUser: &userRoot,
-						SELinuxOptions: &v1.SELinuxOptions{
-							// TODO(jaosorior): Use a more restricted selinux type
-							Type: "spc_t",
+						Resources: v1.ResourceRequirements{
+							Requests: v1.ResourceList{
+								v1.ResourceMemory:           resource.MustParse("32Mi"),
+								v1.ResourceCPU:              resource.MustParse("100m"),
+								v1.ResourceEphemeralStorage: resource.MustParse("10Mi"),
+							},
+							Limits: v1.ResourceList{
+								v1.ResourceMemory:           resource.MustParse("64Mi"),
+								v1.ResourceCPU:              resource.MustParse("250m"),
+								v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+							},
 						},
 					},
-					Resources: v1.ResourceRequirements{
-						Requests: v1.ResourceList{
-							v1.ResourceMemory:           resource.MustParse("32Mi"),
-							v1.ResourceCPU:              resource.MustParse("100m"),
-							v1.ResourceEphemeralStorage: resource.MustParse("10Mi"),
+					{
+						Name:  "selinux-shared-policies-copier",
+						Image: "quay.io/jaosorior/selinuxd",
+						// Primes the volume mount under /etc/selinux.d with the
+						// shared policies shipped by selinuxd and makes sure the volume mount
+						// is writable by 2000 in order for the controller to be able to
+						// write the policy files. In the future, the policy files should
+						// be shipped by selinuxd directly.
+						//
+						// The directory is writable by 2000 (the operator writes to this dir) and
+						// readable by root (selinuxd reads the policies and runs as root).
+						// Explicitly allowing root makes sure no dac_override audit messages
+						// are logged even in absence of CAP_DAC_OVERRIDE.
+						//
+						// If, in the future we wanted to make the DS more compact, we could move
+						// the chown+chmod to the previous init container and move the copying of
+						// the files into a lifecycle handler of selinuxd.
+						Command: []string{"bash", "-c"},
+						Args: []string{`
+						set -x
+
+						chown 2000:0 /etc/selinux.d
+						chmod 750 /etc/selinux.d
+						cp /usr/share/udica/templates/* /etc/selinux.d
+					`},
+						VolumeMounts: []v1.VolumeMount{
+							{
+								Name:      "selinux-drop-dir",
+								MountPath: SelinuxDropDirectory,
+							},
 						},
-						Limits: v1.ResourceList{
-							v1.ResourceMemory:           resource.MustParse("64Mi"),
-							v1.ResourceCPU:              resource.MustParse("250m"),
-							v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+						SecurityContext: &v1.SecurityContext{
+							AllowPrivilegeEscalation: &falsely,
+							ReadOnlyRootFilesystem:   &truly,
+							Capabilities: &v1.Capabilities{
+								Drop: []v1.Capability{"ALL"},
+								Add:  []v1.Capability{"CHOWN", "FOWNER", "FSETID", "DAC_OVERRIDE"},
+							},
+							RunAsUser: &userRoot,
+							SELinuxOptions: &v1.SELinuxOptions{
+								// TODO(jaosorior): Use a more restricted selinux type
+								Type: "spc_t",
+							},
 						},
-					},
-				}},
-				Containers: []v1.Container{{
-					Name:            config.OperatorName,
-					Args:            []string{"daemon"},
-					ImagePullPolicy: v1.PullAlways,
-					VolumeMounts: []v1.VolumeMount{
-						{
-							Name:      "host-operator-volume",
-							MountPath: config.ProfilesRootPath,
+						Resources: v1.ResourceRequirements{
+							Requests: v1.ResourceList{
+								v1.ResourceMemory:           resource.MustParse("32Mi"),
+								v1.ResourceCPU:              resource.MustParse("100m"),
+								v1.ResourceEphemeralStorage: resource.MustParse("10Mi"),
+							},
+							Limits: v1.ResourceList{
+								v1.ResourceMemory:           resource.MustParse("64Mi"),
+								v1.ResourceCPU:              resource.MustParse("250m"),
+								v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+							},
 						},
 					},
-					SecurityContext: &v1.SecurityContext{
-						AllowPrivilegeEscalation: &falsely,
-						ReadOnlyRootFilesystem:   &truly,
-						Capabilities: &v1.Capabilities{
-							Drop: []v1.Capability{"ALL"},
-						},
-						RunAsUser:  &userRootless,
-						RunAsGroup: &userRootless,
-						SELinuxOptions: &v1.SELinuxOptions{
-							// TODO(jaosorior): Use a more restricted selinux type
-							Type: "spc_t",
+				},
+				Containers: []v1.Container{
+					{
+						Name:            config.OperatorName,
+						Args:            []string{"daemon"},
+						ImagePullPolicy: v1.PullAlways,
+						VolumeMounts: []v1.VolumeMount{
+							{
+								Name:      "host-operator-volume",
+								MountPath: config.ProfilesRootPath,
+							},
+							{
+								Name:      "selinux-drop-dir",
+								MountPath: SelinuxDropDirectory,
+							},
+							{
+								Name:      "selinuxd-socket-volume",
+								MountPath: SelinuxdSocketDir,
+							},
 						},
-					},
-					Resources: v1.ResourceRequirements{
-						Requests: v1.ResourceList{
-							v1.ResourceMemory:           resource.MustParse("64Mi"),
-							v1.ResourceCPU:              resource.MustParse("100m"),
-							v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+						SecurityContext: &v1.SecurityContext{
+							AllowPrivilegeEscalation: &falsely,
+							ReadOnlyRootFilesystem:   &truly,
+							Capabilities: &v1.Capabilities{
+								Drop: []v1.Capability{"ALL"},
+							},
+							RunAsUser:  &userRootless,
+							RunAsGroup: &userRootless,
+							SELinuxOptions: &v1.SELinuxOptions{
+								// TODO(jaosorior): Use a more restricted selinux type
+								Type: "spc_t",
+							},
 						},
-						Limits: v1.ResourceList{
-							v1.ResourceMemory:           resource.MustParse("128Mi"),
-							v1.ResourceCPU:              resource.MustParse("300m"),
-							v1.ResourceEphemeralStorage: resource.MustParse("200Mi"),
+						Resources: v1.ResourceRequirements{
+							Requests: v1.ResourceList{
+								v1.ResourceMemory:           resource.MustParse("64Mi"),
+								v1.ResourceCPU:              resource.MustParse("100m"),
+								v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+							},
+							Limits: v1.ResourceList{
+								v1.ResourceMemory:           resource.MustParse("128Mi"),
+								v1.ResourceCPU:              resource.MustParse("300m"),
+								v1.ResourceEphemeralStorage: resource.MustParse("200Mi"),
+							},
 						},
-					},
-					Env: []v1.EnvVar{
-						{
-							Name: config.NodeNameEnvKey,
-							ValueFrom: &v1.EnvVarSource{
-								FieldRef: &v1.ObjectFieldSelector{
-									FieldPath: "spec.nodeName",
+						Env: []v1.EnvVar{
+							{
+								Name: config.NodeNameEnvKey,
+								ValueFrom: &v1.EnvVarSource{
+									FieldRef: &v1.ObjectFieldSelector{
+										FieldPath: "spec.nodeName",
+									},
 								},
 							},
 						},
 					},
-				}},
+					{
+						Name:  "selinuxd",
+						Image: "quay.io/jaosorior/selinuxd",
+						Args: []string{
+							"daemon",
+							"--socket-path", SelinuxdSocketPath,
+							"--socket-uid", "0",
+							"--socket-gid", "2000",
+						},
+						ImagePullPolicy: v1.PullAlways,
+						VolumeMounts: []v1.VolumeMount{
+							{
+								Name:      "selinux-drop-dir",
+								MountPath: SelinuxDropDirectory,
+							},
+							{
+								Name:      "selinuxd-socket-volume",
+								MountPath: SelinuxdSocketDir,
+							},
+							{
+								Name:      "host-fsselinux-volume",
+								MountPath: "/sys/fs/selinux",
+							},
+							{
+								Name:      "host-etcselinux-volume",
+								MountPath: "/etc/selinux",
+							},
+							{
+								Name:      "host-varlibselinux-volume",
+								MountPath: "/var/lib/selinux",
+							},
+						},
+						SecurityContext: &v1.SecurityContext{
+							// TODO(jhrozek): If we wanted RO fs, we would need to mount
+							// the selinuxd db elsewhere than /var/run/selinuxd.db
+							// ReadOnlyRootFilesystem:   &truly,
+							RunAsUser:  &userRoot,
+							RunAsGroup: &userRoot,
+							SELinuxOptions: &v1.SELinuxOptions{
+								// TODO(jaosorior): Use a more restricted selinux type
+								Type: "spc_t",
+							},
+							/* TODO(jhrozek) is this really needed? */
+							Privileged: &truly,
+						},
+						// selinuxd seems to be resource hungry, set later
+						// Resources: v1.ResourceRequirements{
+						//	Requests: v1.ResourceList{
+						//		v1.ResourceMemory:           resource.MustParse("128Mi"),
+						//		v1.ResourceCPU:              resource.MustParse("300m"),
+						//		v1.ResourceEphemeralStorage: resource.MustParse("200Mi"),
+						//	},
+						//	Limits: v1.ResourceList{
+						//		v1.ResourceMemory:           resource.MustParse("256Mi"),
+						//		v1.ResourceCPU:              resource.MustParse("600m"),
+						//		v1.ResourceEphemeralStorage: resource.MustParse("400Mi"),
+						//	},
+						// },
+					},
+				},
 				Volumes: []v1.Volume{
 					// /var/lib is used as symlinks cannot be created across
 					// different volumes
@@ -196,6 +329,52 @@ var Manifest = &appsv1.DaemonSet{
 							},
 						},
 					},
+					// Ephemeral emptyDirs for the selinuxd socket and the policies.
+					// As the policies are loaded based on API objects and contents of
+					// the init container and loaded on selinuxd start, we don't need
+					// to persist them
+					{
+						Name: "selinux-drop-dir",
+						VolumeSource: v1.VolumeSource{
+							EmptyDir: &v1.EmptyDirVolumeSource{},
+						},
+					},
+					{
+						Name: "selinuxd-socket-volume",
+						VolumeSource: v1.VolumeSource{
+							EmptyDir: &v1.EmptyDirVolumeSource{},
+						},
+					},
+					// The following host mounts only make sense on a SELinux enabled
+					// system. But if SELinux is not configured, then they wouldn't be
+					// used by any container, so it's OK to define them unconditionally
+					{
+						Name: "host-fsselinux-volume",
+						VolumeSource: v1.VolumeSource{
+							HostPath: &v1.HostPathVolumeSource{
+								Path: "/sys/fs/selinux",
+								Type: &hostPathDirectory,
+							},
+						},
+					},
+					{
+						Name: "host-etcselinux-volume",
+						VolumeSource: v1.VolumeSource{
+							HostPath: &v1.HostPathVolumeSource{
+								Path: "/etc/selinux",
+								Type: &hostPathDirectory,
+							},
+						},
+					},
+					{
+						Name: "host-varlibselinux-volume",
+						VolumeSource: v1.VolumeSource{
+							HostPath: &v1.HostPathVolumeSource{
+								Path: "/var/lib/selinux",
+								Type: &hostPathDirectory,
+							},
+						},
+					},
 				},
 				Tolerations: []v1.Toleration{
 					{
diff --git a/internal/pkg/controllers/spod/configmap_controller.go b/internal/pkg/controllers/spod/configmap_controller.go
index 04fee4938..ecbdbd8a5 100644
--- a/internal/pkg/controllers/spod/configmap_controller.go
+++ b/internal/pkg/controllers/spod/configmap_controller.go
@@ -19,6 +19,7 @@ package spod
 import (
 	"context"
 	"fmt"
+	"strconv"
 
 	"github.com/crossplane/crossplane-runtime/pkg/event"
 	"github.com/go-logr/logr"
@@ -96,10 +97,26 @@ func (r *ReconcileSPOd) handleCreate(ctx context.Context, cfg *corev1.ConfigMap)
 func (r *ReconcileSPOd) getConfiguredSPOd(cfg *corev1.ConfigMap) *appsv1.DaemonSet {
 	newSPOd := r.baseSPOd.DeepCopy()
 
-	imagePullPolicyStr, found := cfg.Data["SPOdImagePullPolicy"]
+	newSPOd.Spec.Template.Spec.Containers = []corev1.Container{r.baseSPOd.Spec.Template.Spec.Containers[0]}
+
+	enableSelinux, err := strconv.ParseBool(cfg.Data[config.SPOcEnableSelinux])
+	if err == nil && enableSelinux {
+		newSPOd.Spec.Template.Spec.Containers = append(
+			newSPOd.Spec.Template.Spec.Containers,
+			r.baseSPOd.Spec.Template.Spec.Containers[1])
+
+		newSPOd.Spec.Template.Spec.Containers[0].Args = append(
+			newSPOd.Spec.Template.Spec.Containers[0].Args,
+			"--with-selinux=true")
+	}
+
+	imagePullPolicyStr, found := cfg.Data[config.SPOdImagePullPolicy]
 	if found {
 		pullPolicy := corev1.PullPolicy(imagePullPolicyStr)
-		newSPOd.Spec.Template.Spec.Containers[0].ImagePullPolicy = pullPolicy
+		for i := range newSPOd.Spec.Template.Spec.Containers {
+			newSPOd.Spec.Template.Spec.Containers[i].ImagePullPolicy = pullPolicy
+		}
 	}
+
 	return newSPOd
 }
diff --git a/internal/pkg/controllers/spod/setup.go b/internal/pkg/controllers/spod/setup.go
index 2d83bf53d..73f164352 100644
--- a/internal/pkg/controllers/spod/setup.go
+++ b/internal/pkg/controllers/spod/setup.go
@@ -39,11 +39,12 @@ const cmIsSPOdConfig = "security-profiles-operator/config"
 type DaemonTunables struct {
 	DaemonImage         string
 	NonRootEnablerImage string
+	SelinuxdImage       string
 	WatchNamespace      string
 }
 
 // Setup adds a controller that reconciles the SPOd DaemonSet.
-func Setup(ctx context.Context, mgr ctrl.Manager, dt DaemonTunables, l logr.Logger) error {
+func Setup(ctx context.Context, mgr ctrl.Manager, dt *DaemonTunables, l logr.Logger) error {
 	return ctrl.NewControllerManagedBy(mgr).
 		Named("spod-config").
 		For(&corev1.ConfigMap{}).
@@ -58,20 +59,25 @@ func Setup(ctx context.Context, mgr ctrl.Manager, dt DaemonTunables, l logr.Logg
 		})
 }
 
-func getEffectiveSPOd(dt DaemonTunables) *appsv1.DaemonSet {
+func getEffectiveSPOd(dt *DaemonTunables) *appsv1.DaemonSet {
 	refSPOd := bindata.Manifest.DeepCopy()
-	cnt := &refSPOd.Spec.Template.Spec.Containers[0]
-	cnt.Image = dt.DaemonImage
 
+	daemon := &refSPOd.Spec.Template.Spec.Containers[0]
+	daemon.Image = dt.DaemonImage
 	if dt.WatchNamespace != "" {
-		cnt.Env = append(cnt.Env, corev1.EnvVar{
+		daemon.Env = append(daemon.Env, corev1.EnvVar{
 			Name:  config.RestrictNamespaceEnvKey,
 			Value: dt.WatchNamespace,
 		})
 	}
 
+	selinuxd := &refSPOd.Spec.Template.Spec.Containers[1]
+	selinuxd.Image = dt.SelinuxdImage
+
 	initcnt := &refSPOd.Spec.Template.Spec.InitContainers[0]
 	initcnt.Image = dt.NonRootEnablerImage
+	sepolImage := &refSPOd.Spec.Template.Spec.InitContainers[1]
+	sepolImage.Image = dt.SelinuxdImage // selinuxd ships the policies as well
 	return refSPOd
 }
 


Test patch:
diff --git a/internal/pkg/controllers/spod/setup_test.go b/internal/pkg/controllers/spod/setup_test.go
index a926f7874..0cf82140f 100644
--- a/internal/pkg/controllers/spod/setup_test.go
+++ b/internal/pkg/controllers/spod/setup_test.go
@@ -34,13 +34,13 @@ func Test_getEffectiveSPOd(t *testing.T) {
 	}{
 		{
 			"Should correctly set the image",
-			DaemonTunables{"foo:bar", "bar:baz", ""},
+			DaemonTunables{"foo:bar", "bar:baz", "brot:wurst", ""},
 			false,
 			false,
 		},
 		{
 			"Should correctly set the namespace",
-			DaemonTunables{"foo:bar", "bar:baz", "my-ns"},
+			DaemonTunables{"foo:bar", "bar:baz", "brot:wurst", "my-ns"},
 			true,
 			false,
 		},
@@ -49,8 +49,9 @@ func Test_getEffectiveSPOd(t *testing.T) {
 		tt := tt
 		t.Run(tt.name, func(t *testing.T) {
 			t.Parallel()
-			got := getEffectiveSPOd(tt.dt)
+			got := getEffectiveSPOd(&tt.dt)
 			require.Equal(t, tt.dt.DaemonImage, got.Spec.Template.Spec.Containers[0].Image)
+			require.Equal(t, tt.dt.SelinuxdImage, got.Spec.Template.Spec.Containers[1].Image)
 			require.Equal(t, tt.dt.NonRootEnablerImage, got.Spec.Template.Spec.InitContainers[0].Image)
 			var found bool
 			for _, env := range got.Spec.Template.Spec.Containers[0].Env {
diff --git a/test/e2e_test.go b/test/e2e_test.go
index b9f6f4fb7..aed8518aa 100644
--- a/test/e2e_test.go
+++ b/test/e2e_test.go
@@ -38,7 +38,7 @@ const (
 	// NOTE(jaosorior): We should be able to decrease this once we
 	// migrate to a single daemonset-based implementation for the
 	// SELinux pieces.
-	defaultSelinuxOpTimeout = "180s"
+	defaultSelinuxOpTimeout = "360s"
 	defaultWaitTime         = 5 * time.Second
 )
 
@@ -158,6 +158,13 @@ func (e *e2e) deployOperator(manifest, profiles string) {
 		"pod", "-l", "app.kubernetes.io/instance=cert-manager",
 	)
 
+	if e.platformSupportsSelinux() {
+		e.run(
+			"sed", "-i", "s/EnableSelinux: \"false\"/EnableSelinux: \"true\"/",
+			manifest,
+		)
+	}
+
 	// Deploy the operator
 	e.logf("Deploying operator")
 	e.kubectl("create", "-f", manifest)
@@ -240,3 +247,12 @@ func (e *e2e) getSELinuxPolicyUsage(policy string) string {
 	// the name of the policy in the node
 	return e.kubectl("get", "selinuxpolicy", "-n", ns, policy, "-o", "jsonpath={.status.usage}")
 }
+
+func (e *e2e) sliceContainsString(slice []string, s string) bool {
+	for _, item := range slice {
+		if item == s {
+			return true
+		}
+	}
+	return false
+}
diff --git a/test/suite_test.go b/test/suite_test.go
index 831610fea..fef24f97a 100644
--- a/test/suite_test.go
+++ b/test/suite_test.go
@@ -22,6 +22,7 @@ import (
 	"os/exec"
 	"path/filepath"
 	"runtime"
+	"strconv"
 	"strings"
 	"testing"
 	"time"
@@ -41,8 +42,9 @@ const (
 )
 
 var (
-	clusterType      = os.Getenv("E2E_CLUSTER_TYPE")
-	containerRuntime = os.Getenv("CONTAINER_RUNTIME")
+	clusterType        = os.Getenv("E2E_CLUSTER_TYPE")
+	envSkipBuildImages = os.Getenv("E2E_SKIP_BUILD_IMAGES")
+	containerRuntime   = os.Getenv("CONTAINER_RUNTIME")
 )
 
 type e2e struct {
@@ -62,6 +64,7 @@ type kinde2e struct {
 
 type openShifte2e struct {
 	e2e
+	skipBuildImages bool
 }
 
 func TestSuite(t *testing.T) {
@@ -79,6 +82,11 @@ func TestSuite(t *testing.T) {
 			"", "",
 		})
 	case strings.EqualFold(clusterType, "openshift"):
+		skipBuildImages, err := strconv.ParseBool(envSkipBuildImages)
+		if err != nil {
+			skipBuildImages = false
+		}
+
 		suite.Run(t, &openShifte2e{
 			e2e{
 				logger: klogr.New(),
@@ -86,6 +94,7 @@ func TestSuite(t *testing.T) {
 				// image registry and not on the nodes.
 				pullPolicy: "Always",
 			},
+			skipBuildImages,
 		})
 	default:
 		t.Fatalf("Unknown cluster type.")
@@ -149,10 +158,16 @@ func (e *kinde2e) SetupTest() {
 	// Build and load the test image
 	e.logf("Building operator container image")
 	e.run("make", "image", "IMAGE="+e.testImage)
-	e.logf("Loading container image into nodes")
+	e.logf("Loading container images into nodes")
 	e.run(
 		e.kindPath, "load", "docker-image", "--name="+e.clusterName, e.testImage,
 	)
+	e.run(
+		"docker", "pull", "quay.io/jaosorior/selinuxd",
+	)
+	e.run(
+		e.kindPath, "load", "docker-image", "--name="+e.clusterName, "quay.io/jaosorior/selinuxd",
+	)
 }
 
 // TearDownTest stops the kind cluster.
@@ -199,8 +214,10 @@ func (e *openShifte2e) SetupSuite() {
 	testImageRef := config.OperatorName + ":latest"
 
 	// Build and load the test image
-	e.logf("Building operator container image")
-	e.run("make", "image", "IMAGE="+testImageRef)
+	if !e.skipBuildImages {
+		e.logf("Building operator container image")
+		e.run("make", "image", "IMAGE="+testImageRef)
+	}
 	e.logf("Loading container image into nodes")
 
 	// Get credentials
@@ -298,10 +315,14 @@ func (e *e2e) logf(format string, a ...interface{}) {
 	e.logger.Info(fmt.Sprintf(format, a...))
 }
 
-func (e *e2e) selinuxtOnlyTestCase() {
+func (e *e2e) platformSupportsSelinux() bool {
 	// TODO(jaosorior): Come up with better way to assert if a cluster
 	// supports SELinux or not.
-	if !strings.EqualFold(clusterType, "openshift") {
+	return strings.EqualFold(clusterType, "openshift")
+}
+
+func (e *e2e) selinuxtOnlyTestCase() {
+	if !e.platformSupportsSelinux() {
 		e.T().Skip("Skipping SELinux-related test from non-OpenShift cluster")
 	}
 }
diff --git a/test/tc_selinux_base_usage_test.go b/test/tc_selinux_base_usage_test.go
index 9fcc29c6d..57172e5db 100644
--- a/test/tc_selinux_base_usage_test.go
+++ b/test/tc_selinux_base_usage_test.go
@@ -19,11 +19,15 @@ package e2e_test
 import (
 	"fmt"
 	"strings"
+	"time"
 )
 
 func (e *e2e) testCaseSelinuxBaseUsage(nodes []string) {
 	e.selinuxtOnlyTestCase()
 
+	const maxNodeIterations = 3
+	const sleepBetweenIterations = 5 * time.Second
+
 	// nolint:lll
 	const podWithPolicyFmt = `
 apiVersion: v1
@@ -76,17 +80,27 @@ spec:
 	rawPolicyName := e.getSELinuxPolicyName("errorlogger")
 
 	e.logf("assert policy is installed")
-	for _, node := range nodes {
-		var found bool
-		policiesRaw := e.execNode(node, "semodule", "-l")
-		for _, policy := range strings.Split(policiesRaw, "\n") {
-			if policy == rawPolicyName {
-				found = true
+
+	for i := 0; i < maxNodeIterations; i++ {
+		var missingPolName string
+
+		for _, node := range nodes {
+			policiesRaw := e.execNode(node, "semodule", "-l")
+			if !e.sliceContainsString(strings.Split(policiesRaw, "\n"), rawPolicyName) {
+				missingPolName = node
 				break
 			}
 		}
-		e.Truef(found, "The SelinuxPolicy errorlogger wasn't found in the %s node with the name %s",
-			node, rawPolicyName)
+
+		if missingPolName != "" {
+			if i == maxNodeIterations-1 {
+				e.Failf("The SelinuxPolicy errorlogger wasn't found in the %s node with the name %s",
+					missingPolName, rawPolicyName)
+			} else {
+				e.logf("the policy was stil present, trying again")
+				time.Sleep(sleepBetweenIterations)
+			}
+		}
 	}
 
 	e.logf("creating workload")
@@ -112,15 +126,24 @@ spec:
 	e.kubectl("delete", "selinuxpolicy", "errorlogger")
 
 	e.logf("assert policy was removed")
-	for _, node := range nodes {
-		var found bool
-		policiesRaw := e.execNode(node, "semodule", "-l")
-		for _, policy := range strings.Split(policiesRaw, "\n") {
-			if policy == rawPolicyName {
-				found = true
+	for i := 0; i < maxNodeIterations; i++ {
+		var nodeHasPolName string
+
+		for _, node := range nodes {
+			policiesRaw := e.execNode(node, "semodule", "-l")
+			if e.sliceContainsString(strings.Split(policiesRaw, "\n"), rawPolicyName) {
+				nodeHasPolName = node
 				break
 			}
 		}
-		e.Falsef(found, "The SelinuxPolicy errorlogger should have been removed from %s node", node)
+
+		if nodeHasPolName != "" {
+			if i == maxNodeIterations-1 {
+				e.Failf("The SelinuxPolicy errorlogger should have been removed from %s node", nodeHasPolName)
+			} else {
+				e.logf("the policy was stil present, trying again")
+				time.Sleep(sleepBetweenIterations)
+			}
+		}
 	}
 }