Repository: kubernetes-sigs/security-profiles-operator
Pull request #1053 (2022-07-27 06:56:09)

feat: provide an option to deploy statically all webhook resources
<!--  Thanks for sending a pull request!  Here are some tips for you:

- If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
- Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issuepr-kind-label
- If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
- If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

#### What type of PR is this?

<!--
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->

/kind feature 

#### What this PR does / why we need it:

It provides an option to deploy statically all webhook resources. It this mode the operator will not manage any webhook related resources but it will expect that all are already in place at deployment time. This allowed to reduce some cluster-wide permissions on RBAC role. 

This PR also slight refactored the e2e tests to allow the configuration of operator manifest.  This was required in order to be able to configured the static webhook manifest instead of standard operator. 
#### Which issue(s) this PR fixes:

<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.

Fixes #1014 

or

None
-->

#### Does this PR have test?

Yes, but the e2e tests are not yet enabled in the CI. 

<!--
If tests aren't applicable just write N/A.
-->

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?

<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->

```release-note
Add an option to deploy statically all webhook resources in order to improve the operator security.
```


k8s-ci-robot: @ccojocar: 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 @ccojocar. 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/1053#" title="Author self-approved">ccojocar</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign jhrozek for approval by writing `/assign @jhrozek` in a comment. For more information see:[The Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

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/main/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":["jhrozek"]} -->
codecov-commenter: # [Codecov](https://codecov.io/gh/kubernetes-sigs/security-profiles-operator/pull/1053?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#1053](https://codecov.io/gh/kubernetes-sigs/security-profiles-operator/pull/1053?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (63d0f2e) into [main](https://codecov.io/gh/kubernetes-sigs/security-profiles-operator/commit/69aa038dc2007fefab0ea8edcb410893ac15a0ea?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (69aa038) will **decrease** coverage by `0.11%`.
> The diff coverage is `3.84%`.

```diff
@@            Coverage Diff             @@
##             main    #1053      +/-   ##
==========================================
- Coverage   50.09%   49.97%   -0.12%     
==========================================
  Files          42       42              
  Lines        4779     4792      +13     
==========================================
+ Hits         2394     2395       +1     
- Misses       2299     2311      +12     
  Partials       86       86              
```

JAORMX: /ok-to-test

k8s-ci-robot: @ccojocar: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-verify | 63d0f2e814118d4f63079b484d6d59c7d7b1719a | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-verify/1552187320050913280) | true | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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: @ccojocar: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-verify | 8dc250b351b935e0f8ce47bcfa33a1fcea09dc1b | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-verify/1552194067192877056) | true | `/test pull-security-profiles-operator-verify`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=security-profiles-operator&pr=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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: @ccojocar: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-verify | 8dc250b351b935e0f8ce47bcfa33a1fcea09dc1b | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-verify/1552194067192877056) | true | `/test pull-security-profiles-operator-verify`
pull-security-profiles-operator-test-e2e | 8dc250b351b935e0f8ce47bcfa33a1fcea09dc1b | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-test-e2e/1552194067310317568) | true | `/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=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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 -->
ccojocar: /test all
saschagrunert: @ccojocar please rebase to get the latest CI changes in :)
k8s-ci-robot: @ccojocar: 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>
ccojocar: @saschagrunert @janetkuo @JAORMX All tests passed. Any chance you can review this pull request? Thanks 
k8s-ci-robot: @ccojocar: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 12ec8bfe03df2f307ed19ab0ef19cc3377a6c2e9 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-test-e2e/1552632859871678464) | true | `/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=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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 -->
ccojocar: /test all
ccojocar: /test all
k8s-ci-robot: @ccojocar: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 17c87b195711cf8d3df2867740699d0a520c6838 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-test-e2e/1552639601674293248) | true | `/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=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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: @ccojocar: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 17c87b195711cf8d3df2867740699d0a520c6838 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-test-e2e/1552647947164848128) | true | `/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=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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 -->
janetkuo: I'm not familiar with this project so you probably want to find someone else to review it. 
ccojocar: @janetkuo sorry for the noise. I picked up your handler by mistake. 
k8s-ci-robot: @ccojocar: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-test-e2e | f775326091bd7f3942c5bf1de0dd9673fef852c6 | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-test-e2e/1552918795897540608) | true | `/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=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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 -->
ccojocar: /test all
k8s-ci-robot: @ccojocar: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-security-profiles-operator-test-e2e | bfdea51a70c8f0408f48c5eb41598df6eaf2b82e | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/1053/pull-security-profiles-operator-test-e2e/1552932419517026304) | true | `/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=1053). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Accojocar). 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 -->
ccojocar: /test all
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/1053#" title="Author self-approved">ccojocar</a>*, *<a href="https://github.com/kubernetes-sigs/security-profiles-operator/pull/1053#pullrequestreview-1055390158" 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/main/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: Well done! 

Patch:
diff --git a/Makefile b/Makefile
index e934cd103..dba48c12a 100644
--- a/Makefile
+++ b/Makefile
@@ -161,6 +161,7 @@ deployments: $(BUILD_DIR)/kustomize manifests generate ## Generate the deploymen
 	$(BUILD_DIR)/kustomize build --reorder=none deploy/overlays/openshift-dev -o deploy/openshift-dev.yaml
 	$(BUILD_DIR)/kustomize build --reorder=none deploy/overlays/helm -o deploy/helm/templates/static-resources.yaml
 	$(BUILD_DIR)/kustomize build --reorder=none deploy/base-crds -o deploy/helm/crds/crds.yaml
+	$(BUILD_DIR)/kustomize build --reorder=legacy deploy/overlays/webhook -o deploy/webhook-operator.yaml
 
 .PHONY: image
 image: ## Build the container image
diff --git a/api/spod/v1alpha1/spod_types.go b/api/spod/v1alpha1/spod_types.go
index 55809027a..4927c4bb0 100644
--- a/api/spod/v1alpha1/spod_types.go
+++ b/api/spod/v1alpha1/spod_types.go
@@ -84,6 +84,12 @@ type SPODSpec struct {
 	// to retrieve the container ID for a process ID. This can be helpful for
 	// nested environments, for example when using "kind".
 	HostProcVolumePath string `json:"hostProcVolumePath,omitempty"`
+	// StaticWebhookConfig indicates whether the webhook configuration and its
+	// related resources are statically deployed. In this case, the operator will
+	// not create or update the webhook configuration and its related resources.
+	// +optional
+	StaticWebhookConfig bool `json:"staticWebhookConfig"`
+
 	// WebhookOpts set custom namespace selectors and failure mode for
 	// SPO's webhooks
 	// +optional
diff --git a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml
index 9b01b6c8d..f88aaba01 100644
--- a/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml
+++ b/bundle/manifests/security-profiles-operator.clusterserviceversion.yaml
@@ -388,8 +388,6 @@ spec:
           strategy: {}
           template:
             metadata:
-              annotations:
-                seccomp.security.alpha.kubernetes.io/pod: runtime/default
               labels:
                 app: security-profiles-operator
                 name: security-profiles-operator
@@ -418,6 +416,9 @@ spec:
                 securityContext:
                   allowPrivilegeEscalation: false
                   readOnlyRootFilesystem: true
+              securityContext:
+                seccompProfile:
+                  type: RuntimeDefault
               serviceAccountName: security-profiles-operator
               tolerations:
               - effect: NoSchedule
diff --git a/bundle/manifests/security-profiles-operator.x-k8s.io_securityprofilesoperatordaemons.yaml b/bundle/manifests/security-profiles-operator.x-k8s.io_securityprofilesoperatordaemons.yaml
index 958a13b4e..ab2f6b39f 100644
--- a/bundle/manifests/security-profiles-operator.x-k8s.io_securityprofilesoperatordaemons.yaml
+++ b/bundle/manifests/security-profiles-operator.x-k8s.io_securityprofilesoperatordaemons.yaml
@@ -108,6 +108,12 @@ spec:
                 description: If specified, the SELinux type tag applied to the security
                   context of SPOD.
                 type: string
+              staticWebhookConfig:
+                description: StaticWebhookConfig indicates whether the webhook configuration
+                  and its related resources are statically deployed. In this case,
+                  the operator will not create or update the webhook configuration
+                  and its related resources.
+                type: boolean
               tolerations:
                 description: If specified, the SPOD's tolerations.
                 items:
diff --git a/cmd/security-profiles-operator/main.go b/cmd/security-profiles-operator/main.go
index ae07e101f..38d29b68b 100644
--- a/cmd/security-profiles-operator/main.go
+++ b/cmd/security-profiles-operator/main.go
@@ -67,6 +67,7 @@ const (
 	selinuxFlag        string = "with-selinux"
 	apparmorFlag       string = "with-apparmor"
 	labelDenialsFlag   string = "label-denials"
+	webhookFlag        string = "webhook"
 	defaultWebhookPort int    = 9443
 )
 
@@ -121,6 +122,14 @@ func main() {
 			Action: func(ctx *cli.Context) error {
 				return runManager(ctx, info)
 			},
+			Flags: []cli.Flag{
+				&cli.BoolFlag{
+					Name:    webhookFlag,
+					Aliases: []string{"w"},
+					Value:   true,
+					Usage:   "the webhook k8s resources are managed by the operator(default true)",
+				},
+			},
 		},
 		&cli.Command{
 			Before:  initialize,
@@ -158,6 +167,12 @@ func main() {
 					Value:   defaultWebhookPort,
 					Usage:   "the port on which to expose the webhook service (default 9443)",
 				},
+				&cli.BoolFlag{
+					Name:    "static",
+					Aliases: []string{"s"},
+					Value:   false,
+					Usage:   "the webhook k8s resources are statically managed (default false)",
+				},
 			},
 		},
 		&cli.Command{
@@ -270,6 +285,10 @@ func printInfo(component string, info *version.Info) {
 	)
 }
 
+func manageWebhook(ctx *cli.Context) bool {
+	return ctx.Bool(webhookFlag)
+}
+
 func runManager(ctx *cli.Context, info *version.Info) error {
 	printInfo("security-profiles-operator", info)
 	cfg, err := ctrl.GetConfig()
@@ -311,11 +330,13 @@ func runManager(ctx *cli.Context, info *version.Info) error {
 		return fmt.Errorf("add ServiceMonitor API to scheme: %w", err)
 	}
 
-	if err := setupEnabledControllers(ctx.Context, []controller.Controller{
-		nodestatus.NewController(),
-		spod.NewController(),
-		workloadannotator.NewController(),
-	}, mgr, nil); err != nil {
+	if err := setupEnabledControllers(
+		context.WithValue(ctx.Context, spod.ManageWebhookKey, manageWebhook(ctx)),
+		[]controller.Controller{
+			nodestatus.NewController(),
+			spod.NewController(),
+			workloadannotator.NewController(),
+		}, mgr, nil); err != nil {
 		return fmt.Errorf("enable controllers: %w", err)
 	}
 
diff --git a/deploy/base-crds/crds/securityprofilesoperatordaemon.yaml b/deploy/base-crds/crds/securityprofilesoperatordaemon.yaml
index f3b4f266a..b23458ea0 100644
--- a/deploy/base-crds/crds/securityprofilesoperatordaemon.yaml
+++ b/deploy/base-crds/crds/securityprofilesoperatordaemon.yaml
@@ -106,6 +106,12 @@ spec:
                 description: If specified, the SELinux type tag applied to the security
                   context of SPOD.
                 type: string
+              staticWebhookConfig:
+                description: StaticWebhookConfig indicates whether the webhook configuration
+                  and its related resources are statically deployed. In this case,
+                  the operator will not create or update the webhook configuration
+                  and its related resources.
+                type: boolean
               tolerations:
                 description: If specified, the SPOD's tolerations.
                 items:
diff --git a/deploy/helm/crds/crds.yaml b/deploy/helm/crds/crds.yaml
index 99cb0015d..32f8ff847 100644
--- a/deploy/helm/crds/crds.yaml
+++ b/deploy/helm/crds/crds.yaml
@@ -625,6 +625,12 @@ spec:
                 description: If specified, the SELinux type tag applied to the security
                   context of SPOD.
                 type: string
+              staticWebhookConfig:
+                description: StaticWebhookConfig indicates whether the webhook configuration
+                  and its related resources are statically deployed. In this case,
+                  the operator will not create or update the webhook configuration
+                  and its related resources.
+                type: boolean
               tolerations:
                 description: If specified, the SPOD's tolerations.
                 items:
diff --git a/deploy/kustomize-deployment/manager_deployment.yaml b/deploy/kustomize-deployment/manager_deployment.yaml
index 69587c34b..b573d596b 100644
--- a/deploy/kustomize-deployment/manager_deployment.yaml
+++ b/deploy/kustomize-deployment/manager_deployment.yaml
@@ -11,11 +11,12 @@ spec:
       name: security-profiles-operator
   template:
     metadata:
-      annotations:
-        seccomp.security.alpha.kubernetes.io/pod: runtime/default
       labels:
         name: security-profiles-operator
     spec:
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       serviceAccountName: security-profiles-operator
       containers:
         - name: security-profiles-operator
diff --git a/deploy/namespace-operator.yaml b/deploy/namespace-operator.yaml
index eb2649c42..fc5ab306b 100644
--- a/deploy/namespace-operator.yaml
+++ b/deploy/namespace-operator.yaml
@@ -625,6 +625,12 @@ spec:
                 description: If specified, the SELinux type tag applied to the security
                   context of SPOD.
                 type: string
+              staticWebhookConfig:
+                description: StaticWebhookConfig indicates whether the webhook configuration
+                  and its related resources are statically deployed. In this case,
+                  the operator will not create or update the webhook configuration
+                  and its related resources.
+                type: boolean
               tolerations:
                 description: If specified, the SPOD's tolerations.
                 items:
@@ -1969,8 +1975,6 @@ spec:
       name: security-profiles-operator
   template:
     metadata:
-      annotations:
-        seccomp.security.alpha.kubernetes.io/pod: runtime/default
       labels:
         app: security-profiles-operator
         name: security-profiles-operator
@@ -2001,6 +2005,9 @@ spec:
         securityContext:
           allowPrivilegeEscalation: false
           readOnlyRootFilesystem: true
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       serviceAccountName: security-profiles-operator
       tolerations:
       - effect: NoSchedule
diff --git a/deploy/openshift-dev.yaml b/deploy/openshift-dev.yaml
index ab0f600a3..5cfda0edd 100644
--- a/deploy/openshift-dev.yaml
+++ b/deploy/openshift-dev.yaml
@@ -625,6 +625,12 @@ spec:
                 description: If specified, the SELinux type tag applied to the security
                   context of SPOD.
                 type: string
+              staticWebhookConfig:
+                description: StaticWebhookConfig indicates whether the webhook configuration
+                  and its related resources are statically deployed. In this case,
+                  the operator will not create or update the webhook configuration
+                  and its related resources.
+                type: boolean
               tolerations:
                 description: If specified, the SPOD's tolerations.
                 items:
@@ -1969,8 +1975,6 @@ spec:
       name: security-profiles-operator
   template:
     metadata:
-      annotations:
-        seccomp.security.alpha.kubernetes.io/pod: runtime/default
       labels:
         app: security-profiles-operator
         name: security-profiles-operator
@@ -1999,6 +2003,9 @@ spec:
         securityContext:
           allowPrivilegeEscalation: false
           readOnlyRootFilesystem: true
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       serviceAccountName: security-profiles-operator
       tolerations:
       - effect: NoSchedule
diff --git a/deploy/operator.yaml b/deploy/operator.yaml
index 0252bb213..ae81234c0 100644
--- a/deploy/operator.yaml
+++ b/deploy/operator.yaml
@@ -625,6 +625,12 @@ spec:
                 description: If specified, the SELinux type tag applied to the security
                   context of SPOD.
                 type: string
+              staticWebhookConfig:
+                description: StaticWebhookConfig indicates whether the webhook configuration
+                  and its related resources are statically deployed. In this case,
+                  the operator will not create or update the webhook configuration
+                  and its related resources.
+                type: boolean
               tolerations:
                 description: If specified, the SPOD's tolerations.
                 items:
@@ -1969,8 +1975,6 @@ spec:
       name: security-profiles-operator
   template:
     metadata:
-      annotations:
-        seccomp.security.alpha.kubernetes.io/pod: runtime/default
       labels:
         app: security-profiles-operator
         name: security-profiles-operator
@@ -1999,6 +2003,9 @@ spec:
         securityContext:
           allowPrivilegeEscalation: false
           readOnlyRootFilesystem: true
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       serviceAccountName: security-profiles-operator
       tolerations:
       - effect: NoSchedule
diff --git a/deploy/overlays/webhook/deployment.yaml b/deploy/overlays/webhook/deployment.yaml
new file mode 100644
index 000000000..ec5451e14
--- /dev/null
+++ b/deploy/overlays/webhook/deployment.yaml
@@ -0,0 +1,13 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: security-profiles-operator
+  namespace: security-profiles-operator
+spec:
+  template:
+    spec:
+      containers:
+        - name: security-profiles-operator
+          args:
+          - manager
+          - "--webhook=false"
diff --git a/deploy/overlays/webhook/kustomization.yaml b/deploy/overlays/webhook/kustomization.yaml
new file mode 100644
index 000000000..7a67f79e3
--- /dev/null
+++ b/deploy/overlays/webhook/kustomization.yaml
@@ -0,0 +1,28 @@
+# This is the namespaced deployment, which only watches configMaps for one
+# namespace.
+---
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+bases:
+  - ../cluster
+
+patchesStrategicMerge:
+  - webhook_config.yaml
+  - deployment.yaml
+
+patches:
+  - target:
+      kind: ClusterRole
+      name: security-profiles-operator
+    path: role.yaml
+
+resources:
+  - webhook_cert.yaml
+  - webhook_deployment.yaml
+  - webhook_service.yaml
+
+images:
+  - name: security-profiles-operator
+    newName: gcr.io/k8s-staging-sp-operator/security-profiles-operator
+    newTag: latest
+
diff --git a/deploy/overlays/webhook/role.yaml b/deploy/overlays/webhook/role.yaml
new file mode 100644
index 000000000..97221506b
--- /dev/null
+++ b/deploy/overlays/webhook/role.yaml
@@ -0,0 +1,3 @@
+---
+- path: /rules/1
+  op: remove
diff --git a/deploy/overlays/webhook/spod-config.yaml b/deploy/overlays/webhook/spod-config.yaml
new file mode 100644
index 000000000..2278698a0
--- /dev/null
+++ b/deploy/overlays/webhook/spod-config.yaml
@@ -0,0 +1,19 @@
+apiVersion: security-profiles-operator.x-k8s.io/v1alpha1
+kind: SecurityProfilesOperatorDaemon
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spod
+  namespace: security-profiles-operator
+spec:
+  staticWebhookConfig: true
+  tolerations:
+  - effect: NoSchedule
+    key: node-role.kubernetes.io/master
+    operator: Exists
+  - effect: NoSchedule
+    key: node-role.kubernetes.io/control-plane
+    operator: Exists
+  - effect: NoExecute
+    key: node.kubernetes.io/not-ready
+    operator: Exists
diff --git a/deploy/overlays/webhook/webhook_cert.yaml b/deploy/overlays/webhook/webhook_cert.yaml
new file mode 100644
index 000000000..5b397b553
--- /dev/null
+++ b/deploy/overlays/webhook/webhook_cert.yaml
@@ -0,0 +1,16 @@
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  name: webhook-cert
+  namespace: security-profiles-operator
+  labels:
+    app: security-profiles-operator
+spec:
+  secretName: webhook-server-cert
+  issuerRef:
+    name: selfsigned-issuer
+    kind: Issuer
+  dnsNames:
+    - webhook-service.security-profiles-operator.svc
+    - webhook-service.security-profiles-operator.svc.cluster.local
diff --git a/deploy/overlays/webhook/webhook_config.yaml b/deploy/overlays/webhook/webhook_config.yaml
new file mode 100644
index 000000000..efddb3b71
--- /dev/null
+++ b/deploy/overlays/webhook/webhook_config.yaml
@@ -0,0 +1,51 @@
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  name: spo-mutating-webhook-configuration
+  namespace: security-profiles-operator
+  annotations:
+    cert-manager.io/inject-ca-from: "security-profiles-operator/webhook-cert"
+webhooks:
+  - name: binding.spo.io
+    failurePolicy: Fail
+    sideEffects: None
+    rules:
+      - operations: ["CREATE", "UPDATE", "DELETE"]
+        apiGroups: ["*"]
+        apiVersions: ["v1"]
+        resources: ["pods"]
+    objectSelector:
+      matchExpressions: 
+        - key: name
+          operator: NotIn
+          values: ["security-profiles-operator", "security-profiles-operator-webhook"]
+    namespaceSelector: {}
+    clientConfig:
+      service:
+        namespace: "security-profiles-operator"
+        name: "webhook-service"
+        path: "/mutate-v1-pod-binding"
+      caBundle: "Cg=="
+    admissionReviewVersions: ["v1beta1"]
+  - name: recording.spo.io
+    failurePolicy: Fail
+    sideEffects: None
+    rules:
+      - operations: ["CREATE", "UPDATE", "DELETE"]
+        apiGroups: ["*"]
+        apiVersions: ["v1"]
+        resources: ["pods"]
+    objectSelector:
+      matchExpressions: 
+        - key: name
+          operator: NotIn
+          values: ["security-profiles-operator", "security-profiles-operator-webhook"]
+    namespaceSelector: {}
+    clientConfig:
+      service:
+        namespace: "security-profiles-operator"
+        name: "webhook-service"
+        path: "/mutate-v1-pod-recording"
+      caBundle: "Cg=="
+    admissionReviewVersions: ["v1beta1"]
diff --git a/deploy/overlays/webhook/webhook_deployment.yaml b/deploy/overlays/webhook/webhook_deployment.yaml
new file mode 100644
index 000000000..1df5cbc15
--- /dev/null
+++ b/deploy/overlays/webhook/webhook_deployment.yaml
@@ -0,0 +1,67 @@
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: security-profiles-operator-webhook
+  namespace: security-profiles-operator
+spec:
+  replicas: 3
+  selector:
+    matchLabels:
+      name: security-profiles-operator-webhook
+      app: security-profiles-operator
+  template:
+    metadata:
+      annotations:
+        openshift.io/scc: privileged
+      labels:
+        name: security-profiles-operator-webhook
+        app: security-profiles-operator
+    spec:
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
+      serviceAccountName: spo-webhook
+      containers:
+        - name: security-profiles-operator
+          image: security-profiles-operator
+          args:
+          - webhook
+          imagePullPolicy: Always
+          securityContext:
+            readOnlyRootFilesystem: true
+            allowPrivilegeEscalation: false
+          ports:
+            - name: webhook
+              containerPort: 9443 
+              protocol: TCP
+          resources:
+            requests:
+              memory: 32Mi
+              cpu: 250m
+            limits:
+              memory: 64Mi
+          env:
+            - name: OPERATOR_NAMESPACE
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.namespace
+          volumeMounts:
+            - name: cert
+              mountPath: /tmp/k8s-webhook-server/serving-certs
+              readOnly: true
+      volumes:
+        - name: cert
+          secret:
+            secretName: webhook-server-cert
+            defaultMode: 420
+      tolerations:
+        - key: "node-role.kubernetes.io/master"
+          operator: "Exists"
+          effect: "NoSchedule"
+        - key: "node-role.kubernetes.io/control-plane"
+          operator: "Exists"
+          effect: "NoSchedule"
+        - key: "node.kubernetes.io/not-ready"
+          operator: "Exists"
+          effect: "NoExecute"
diff --git a/deploy/overlays/webhook/webhook_service.yaml b/deploy/overlays/webhook/webhook_service.yaml
new file mode 100644
index 000000000..c9798d0b7
--- /dev/null
+++ b/deploy/overlays/webhook/webhook_service.yaml
@@ -0,0 +1,18 @@
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: webhook-service
+  namespace: security-profiles-operator
+  labels:
+    name: security-profiles-operator
+spec:
+  selector:
+    app: security-profiles-operator
+    name: security-profiles-operator-webhook
+  ports:
+  - name: webhook
+    protocol: TCP
+    port: 443 
+    targetPort: 9443
+
diff --git a/deploy/webhook-operator.yaml b/deploy/webhook-operator.yaml
new file mode 100644
index 000000000..0545771bc
--- /dev/null
+++ b/deploy/webhook-operator.yaml
@@ -0,0 +1,2172 @@
+apiVersion: v1
+kind: Namespace
+metadata:
+  labels:
+    app: security-profiles-operator
+    pod-security.kubernetes.io/audit: privileged
+    pod-security.kubernetes.io/enforce: privileged
+    pod-security.kubernetes.io/warn: privileged
+  name: security-profiles-operator
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.8.0
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: apparmorprofiles.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: AppArmorProfile
+    listKind: AppArmorProfileList
+    plural: apparmorprofiles
+    shortNames:
+    - aa
+    singular: apparmorprofile
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: AppArmorProfile is the Schema for the apparmorprofiles API
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: AppArmorProfileSpec defines the desired state of AppArmorProfile
+            properties:
+              policy:
+                type: string
+            required:
+            - policy
+            type: object
+          status:
+            description: AppArmorProfileStatus defines the observed state of AppArmorProfile
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+status:
+  acceptedNames:
+    kind: ""
+    plural: ""
+  conditions: []
+  storedVersions: []
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: profilebindings.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: ProfileBinding
+    listKind: ProfileBindingList
+    plural: profilebindings
+    singular: profilebinding
+  scope: Namespaced
+  versions:
+  - name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: ProfileBinding is the Schema for the profilebindings API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: ProfileBindingSpec defines the desired state of ProfileBinding.
+            properties:
+              image:
+                description: Image name within pod containers to match to the profile.
+                type: string
+              profileRef:
+                description: ProfileRef references a SeccompProfile or other profile
+                  type in the current namespace.
+                properties:
+                  kind:
+                    description: Kind of object to be bound.
+                    enum:
+                    - SeccompProfile
+                    - SelinuxProfile
+                    type: string
+                  name:
+                    description: Name of the profile within the current namespace
+                      to which to bind the selected pods.
+                    type: string
+                required:
+                - kind
+                - name
+                type: object
+            required:
+            - image
+            - profileRef
+            type: object
+          status:
+            description: ProfileBindingStatus contains status of the Profilebinding.
+            properties:
+              activeWorkloads:
+                items:
+                  type: string
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: profilerecordings.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: ProfileRecording
+    listKind: ProfileRecordingList
+    plural: profilerecordings
+    singular: profilerecording
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .spec.podSelector
+      name: PodSelector
+      priority: 10
+      type: string
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: ProfileRecording is the Schema for the profilerecordings API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: ProfileRecordingSpec defines the desired state of ProfileRecording.
+            properties:
+              containers:
+                description: Containers is a set of containers to record. This allows
+                  to select only specific containers to record instead of all containers
+                  present in the pod.
+                items:
+                  type: string
+                type: array
+              kind:
+                description: Kind of object to be recorded.
+                enum:
+                - SeccompProfile
+                - SelinuxProfile
+                type: string
+              podSelector:
+                description: PodSelector selects the pods to record. This field follows
+                  standard label selector semantics. An empty podSelector matches
+                  all pods in this namespace.
+                properties:
+                  matchExpressions:
+                    description: matchExpressions is a list of label selector requirements.
+                      The requirements are ANDed.
+                    items:
+                      description: A label selector requirement is a selector that
+                        contains values, a key, and an operator that relates the key
+                        and values.
+                      properties:
+                        key:
+                          description: key is the label key that the selector applies
+                            to.
+                          type: string
+                        operator:
+                          description: operator represents a key's relationship to
+                            a set of values. Valid operators are In, NotIn, Exists
+                            and DoesNotExist.
+                          type: string
+                        values:
+                          description: values is an array of string values. If the
+                            operator is In or NotIn, the values array must be non-empty.
+                            If the operator is Exists or DoesNotExist, the values
+                            array must be empty. This array is replaced during a strategic
+                            merge patch.
+                          items:
+                            type: string
+                          type: array
+                      required:
+                      - key
+                      - operator
+                      type: object
+                    type: array
+                  matchLabels:
+                    additionalProperties:
+                      type: string
+                    description: matchLabels is a map of {key,value} pairs. A single
+                      {key,value} in the matchLabels map is equivalent to an element
+                      of matchExpressions, whose key field is "key", the operator
+                      is "In", and the values array contains only "value". The requirements
+                      are ANDed.
+                    type: object
+                type: object
+                x-kubernetes-map-type: atomic
+              recorder:
+                description: Recorder to be used.
+                enum:
+                - bpf
+                - hook
+                - logs
+                type: string
+            required:
+            - kind
+            - podSelector
+            - recorder
+            type: object
+          status:
+            description: ProfileRecordingStatus contains status of the ProfileRecording.
+            properties:
+              activeWorkloads:
+                items:
+                  type: string
+                type: array
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: rawselinuxprofiles.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: RawSelinuxProfile
+    listKind: RawSelinuxProfileList
+    plural: rawselinuxprofiles
+    singular: rawselinuxprofile
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status.usage
+      name: Usage
+      type: string
+    - jsonPath: .status.status
+      name: State
+      type: string
+    name: v1alpha2
+    schema:
+      openAPIV3Schema:
+        description: RawSelinuxProfile is the Schema for the rawselinuxprofiles API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: RawSelinuxProfileSpec defines the desired state of RawSelinuxProfile.
+            properties:
+              policy:
+                type: string
+            type: object
+          status:
+            description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
+            properties:
+              activeWorkloads:
+                items:
+                  type: string
+                type: array
+              conditions:
+                description: Conditions of the resource.
+                items:
+                  description: A Condition that may apply to a resource.
+                  properties:
+                    lastTransitionTime:
+                      description: LastTransitionTime is the last time this condition
+                        transitioned from one status to another.
+                      format: date-time
+                      type: string
+                    message:
+                      description: A Message containing details about this condition's
+                        last transition from one status to another, if any.
+                      type: string
+                    reason:
+                      description: A Reason for this condition's last transition from
+                        one status to another.
+                      type: string
+                    status:
+                      description: Status of this condition; is it currently True,
+                        False, or Unknown?
+                      type: string
+                    type:
+                      description: Type of this condition. At most one of each condition
+                        type may apply to a resource at any point in time.
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              status:
+                description: ProfileState defines the state that the profile is in.
+                  A profile in this context refers to a SeccompProfile or a SELinux
+                  profile, the states are shared between them as well as the management
+                  API.
+                type: string
+              usage:
+                description: Represents the string that the SelinuxProfile object
+                  can be referenced as in a pod seLinuxOptions section.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: seccompprofiles.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: SeccompProfile
+    listKind: SeccompProfileList
+    plural: seccompprofiles
+    shortNames:
+    - sp
+    singular: seccompprofile
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status.status
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .status.localhostProfile
+      name: LocalhostProfile
+      priority: 10
+      type: string
+    name: v1beta1
+    schema:
+      openAPIV3Schema:
+        description: SeccompProfile is a cluster level specification for a seccomp
+          profile. See https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#seccomp
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: SeccompProfileSpec defines the desired state of SeccompProfile.
+            properties:
+              architectures:
+                description: the architecture used for system calls
+                items:
+                  enum:
+                  - SCMP_ARCH_NATIVE
+                  - SCMP_ARCH_X86
+                  - SCMP_ARCH_X86_64
+                  - SCMP_ARCH_X32
+                  - SCMP_ARCH_ARM
+                  - SCMP_ARCH_AARCH64
+                  - SCMP_ARCH_MIPS
+                  - SCMP_ARCH_MIPS64
+                  - SCMP_ARCH_MIPS64N32
+                  - SCMP_ARCH_MIPSEL
+                  - SCMP_ARCH_MIPSEL64
+                  - SCMP_ARCH_MIPSEL64N32
+                  - SCMP_ARCH_PPC
+                  - SCMP_ARCH_PPC64
+                  - SCMP_ARCH_PPC64LE
+                  - SCMP_ARCH_S390
+                  - SCMP_ARCH_S390X
+                  - SCMP_ARCH_PARISC
+                  - SCMP_ARCH_PARISC64
+                  - SCMP_ARCH_RISCV64
+                  type: string
+                type: array
+              baseProfileName:
+                description: name of base profile (in the same namespace) what will
+                  be unioned into this profile
+                type: string
+              defaultAction:
+                description: the default action for seccomp
+                enum:
+                - SCMP_ACT_KILL
+                - SCMP_ACT_KILL_PROCESS
+                - SCMP_ACT_KILL_THREAD
+                - SCMP_ACT_TRAP
+                - SCMP_ACT_ERRNO
+                - SCMP_ACT_TRACE
+                - SCMP_ACT_ALLOW
+                - SCMP_ACT_LOG
+                - SCMP_ACT_NOTIFY
+                type: string
+              flags:
+                description: list of flags to use with seccomp(2)
+                items:
+                  enum:
+                  - SECCOMP_FILTER_FLAG_TSYNC
+                  - SECCOMP_FILTER_FLAG_LOG
+                  - SECCOMP_FILTER_FLAG_SPEC_ALLOW
+                  type: string
+                type: array
+              listenerMetadata:
+                description: opaque data to pass to the seccomp agent
+                type: string
+              listenerPath:
+                description: path of UNIX domain socket to contact a seccomp agent
+                  for SCMP_ACT_NOTIFY
+                type: string
+              syscalls:
+                description: match a syscall in seccomp. While this property is OPTIONAL,
+                  some values of defaultAction are not useful without syscalls entries.
+                  For example, if defaultAction is SCMP_ACT_KILL and syscalls is empty
+                  or unset, the kernel will kill the container process on its first
+                  syscall
+                items:
+                  description: Syscall defines a syscall in seccomp.
+                  properties:
+                    action:
+                      description: the action for seccomp rules
+                      enum:
+                      - SCMP_ACT_KILL
+                      - SCMP_ACT_KILL_PROCESS
+                      - SCMP_ACT_KILL_THREAD
+                      - SCMP_ACT_TRAP
+                      - SCMP_ACT_ERRNO
+                      - SCMP_ACT_TRACE
+                      - SCMP_ACT_ALLOW
+                      - SCMP_ACT_LOG
+                      - SCMP_ACT_NOTIFY
+                      type: string
+                    args:
+                      description: the specific syscall in seccomp
+                      items:
+                        description: Arg defines the specific syscall in seccomp.
+                        properties:
+                          index:
+                            description: the index for syscall arguments in seccomp
+                            minimum: 0
+                            type: integer
+                          op:
+                            description: the operator for syscall arguments in seccomp
+                            enum:
+                            - SCMP_CMP_NE
+                            - SCMP_CMP_LT
+                            - SCMP_CMP_LE
+                            - SCMP_CMP_EQ
+                            - SCMP_CMP_GE
+                            - SCMP_CMP_GT
+                            - SCMP_CMP_MASKED_EQ
+                            type: string
+                          value:
+                            description: the value for syscall arguments in seccomp
+                            format: int64
+                            minimum: 0
+                            type: integer
+                          valueTwo:
+                            description: the value for syscall arguments in seccomp
+                            format: int64
+                            minimum: 0
+                            type: integer
+                        required:
+                        - index
+                        - op
+                        type: object
+                      maxItems: 6
+                      type: array
+                    errnoRet:
+                      description: the errno return code to use. Some actions like
+                        SCMP_ACT_ERRNO and SCMP_ACT_TRACE allow to specify the errno
+                        code to return
+                      type: string
+                    names:
+                      description: the names of the syscalls
+                      items:
+                        type: string
+                      type: array
+                  required:
+                  - action
+                  - names
+                  type: object
+                type: array
+            required:
+            - defaultAction
+            type: object
+          status:
+            description: SeccompProfileStatus contains status of the deployed SeccompProfile.
+            properties:
+              activeWorkloads:
+                items:
+                  type: string
+                type: array
+              conditions:
+                description: Conditions of the resource.
+                items:
+                  description: A Condition that may apply to a resource.
+                  properties:
+                    lastTransitionTime:
+                      description: LastTransitionTime is the last time this condition
+                        transitioned from one status to another.
+                      format: date-time
+                      type: string
+                    message:
+                      description: A Message containing details about this condition's
+                        last transition from one status to another, if any.
+                      type: string
+                    reason:
+                      description: A Reason for this condition's last transition from
+                        one status to another.
+                      type: string
+                    status:
+                      description: Status of this condition; is it currently True,
+                        False, or Unknown?
+                      type: string
+                    type:
+                      description: Type of this condition. At most one of each condition
+                        type may apply to a resource at any point in time.
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              localhostProfile:
+                description: The path that should be provided to the `securityContext.seccompProfile.localhostProfile`
+                  field of a Pod or container spec
+                type: string
+              path:
+                type: string
+              status:
+                description: ProfileState defines the state that the profile is in.
+                  A profile in this context refers to a SeccompProfile or a SELinux
+                  profile, the states are shared between them as well as the management
+                  API.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: securityprofilenodestatuses.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: SecurityProfileNodeStatus
+    listKind: SecurityProfileNodeStatusList
+    plural: securityprofilenodestatuses
+    shortNames:
+    - spns
+    singular: securityprofilenodestatus
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status
+      name: Status
+      type: string
+    - jsonPath: .metadata.creationTimestamp
+      name: Age
+      type: date
+    - jsonPath: .nodeName
+      name: Node
+      priority: 10
+      type: string
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: SecurityProfileNodeStatus is a per-node status of a security
+          profile
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          nodeName:
+            type: string
+          spec:
+            type: object
+          status:
+            description: ProfileState defines the state that the profile is in. A
+              profile in this context refers to a SeccompProfile or a SELinux profile,
+              the states are shared between them as well as the management API.
+            type: string
+        required:
+        - nodeName
+        type: object
+    served: true
+    storage: true
+    subresources: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: securityprofilesoperatordaemons.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: SecurityProfilesOperatorDaemon
+    listKind: SecurityProfilesOperatorDaemonList
+    plural: securityprofilesoperatordaemons
+    shortNames:
+    - spod
+    singular: securityprofilesoperatordaemon
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status.state
+      name: State
+      type: string
+    name: v1alpha1
+    schema:
+      openAPIV3Schema:
+        description: SecurityProfilesOperatorDaemon is the Schema to configure the
+          spod deployment.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: SPODStatus defines the desired state of SPOD.
+            properties:
+              allowedSeccompActions:
+                description: AllowedSeccompActions if specified, a list of allowed
+                  seccomp actions.
+                items:
+                  description: Action taken upon Seccomp rule match
+                  type: string
+                type: array
+              allowedSyscalls:
+                description: AllowedSyscalls if specified, a list of system calls
+                  which are allowed in seccomp profiles.
+                items:
+                  type: string
+                type: array
+              enableAppArmor:
+                description: tells the operator whether or not to enable AppArmor
+                  support for this SPOD instance.
+                type: boolean
+              enableBpfRecorder:
+                description: tells the operator whether or not to enable bpf recorder
+                  support for this SPOD instance.
+                type: boolean
+              enableLogEnricher:
+                description: tells the operator whether or not to enable log enrichment
+                  support for this SPOD instance.
+                type: boolean
+              enableProfiling:
+                description: EnableProfiling tells the operator whether or not to
+                  enable profiling support for this SPOD instance.
+                type: boolean
+              enableSelinux:
+                description: tells the operator whether or not to enable SELinux support
+                  for this SPOD instance.
+                type: boolean
+              hostProcVolumePath:
+                description: HostProcVolumePath is the path for specifying a custom
+                  host /proc volume, which is required for the log-enricher as well
+                  as bpf-recorder to retrieve the container ID for a process ID. This
+                  can be helpful for nested environments, for example when using "kind".
+                type: string
+              labelPodDenials:
+                description: tells the operator whether or not to apply labels to
+                  pods that present security policy-related denials. Note that this
+                  will be done cluster-wide. Note that this currently requires the
+                  log enricher to be enabled.
+                type: boolean
+              selinuxOptions:
+                description: Defines options specific to the SELinux functionality
+                  of the SecurityProfilesOperator
+                properties:
+                  allowedSystemProfiles:
+                    default:
+                    - container
+                    description: Lists the profiles coming from the system itself
+                      that are allowed to be inherited by workloads. Use this with
+                      care, as this might provide a lot of permissions depending on
+                      the policy.
+                    items:
+                      type: string
+                    type: array
+                type: object
+              selinuxTypeTag:
+                default: spc_t
+                description: If specified, the SELinux type tag applied to the security
+                  context of SPOD.
+                type: string
+              staticWebhookConfig:
+                description: StaticWebhookConfig indicates whether the webhook configuration
+                  and its related resources are statically deployed. In this case,
+                  the operator will not create or update the webhook configuration
+                  and its related resources.
+                type: boolean
+              tolerations:
+                description: If specified, the SPOD's tolerations.
+                items:
+                  description: The pod this Toleration is attached to tolerates any
+                    taint that matches the triple <key,value,effect> using the matching
+                    operator <operator>.
+                  properties:
+                    effect:
+                      description: Effect indicates the taint effect to match. Empty
+                        means match all taint effects. When specified, allowed values
+                        are NoSchedule, PreferNoSchedule and NoExecute.
+                      type: string
+                    key:
+                      description: Key is the taint key that the toleration applies
+                        to. Empty means match all taint keys. If the key is empty,
+                        operator must be Exists; this combination means to match all
+                        values and all keys.
+                      type: string
+                    operator:
+                      description: Operator represents a key's relationship to the
+                        value. Valid operators are Exists and Equal. Defaults to Equal.
+                        Exists is equivalent to wildcard for value, so that a pod
+                        can tolerate all taints of a particular category.
+                      type: string
+                    tolerationSeconds:
+                      description: TolerationSeconds represents the period of time
+                        the toleration (which must be of effect NoExecute, otherwise
+                        this field is ignored) tolerates the taint. By default, it
+                        is not set, which means tolerate the taint forever (do not
+                        evict). Zero and negative values will be treated as 0 (evict
+                        immediately) by the system.
+                      format: int64
+                      type: integer
+                    value:
+                      description: Value is the taint value the toleration matches
+                        to. If the operator is Exists, the value should be empty,
+                        otherwise just a regular string.
+                      type: string
+                  type: object
+                type: array
+              verbosity:
+                description: Verbosity specifies the logging verbosity of the daemon.
+                type: integer
+              webhookOptions:
+                description: WebhookOpts set custom namespace selectors and failure
+                  mode for SPO's webhooks
+                items:
+                  properties:
+                    failurePolicy:
+                      description: FailurePolicy sets the webhook failure policy
+                      type: string
+                    name:
+                      description: Name specifies which webhook do we configure
+                      type: string
+                    namespaceSelector:
+                      description: NamespaceSelector sets webhook's namespace selector
+                      properties:
+                        matchExpressions:
+                          description: matchExpressions is a list of label selector
+                            requirements. The requirements are ANDed.
+                          items:
+                            description: A label selector requirement is a selector
+                              that contains values, a key, and an operator that relates
+                              the key and values.
+                            properties:
+                              key:
+                                description: key is the label key that the selector
+                                  applies to.
+                                type: string
+                              operator:
+                                description: operator represents a key's relationship
+                                  to a set of values. Valid operators are In, NotIn,
+                                  Exists and DoesNotExist.
+                                type: string
+                              values:
+                                description: values is an array of string values.
+                                  If the operator is In or NotIn, the values array
+                                  must be non-empty. If the operator is Exists or
+                                  DoesNotExist, the values array must be empty. This
+                                  array is replaced during a strategic merge patch.
+                                items:
+                                  type: string
+                                type: array
+                            required:
+                            - key
+                            - operator
+                            type: object
+                          type: array
+                        matchLabels:
+                          additionalProperties:
+                            type: string
+                          description: matchLabels is a map of {key,value} pairs.
+                            A single {key,value} in the matchLabels map is equivalent
+                            to an element of matchExpressions, whose key field is
+                            "key", the operator is "In", and the values array contains
+                            only "value". The requirements are ANDed.
+                          type: object
+                      type: object
+                      x-kubernetes-map-type: atomic
+                  type: object
+                type: array
+            type: object
+          status:
+            description: SPODStatus defines the observed state of SPOD.
+            properties:
+              conditions:
+                description: Conditions of the resource.
+                items:
+                  description: A Condition that may apply to a resource.
+                  properties:
+                    lastTransitionTime:
+                      description: LastTransitionTime is the last time this condition
+                        transitioned from one status to another.
+                      format: date-time
+                      type: string
+                    message:
+                      description: A Message containing details about this condition's
+                        last transition from one status to another, if any.
+                      type: string
+                    reason:
+                      description: A Reason for this condition's last transition from
+                        one status to another.
+                      type: string
+                    status:
+                      description: Status of this condition; is it currently True,
+                        False, or Unknown?
+                      type: string
+                    type:
+                      description: Type of this condition. At most one of each condition
+                        type may apply to a resource at any point in time.
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              state:
+                description: 'Represents the state that the policy is in. Can be:
+                  PENDING, IN-PROGRESS, RUNNING or ERROR'
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.9.2
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: selinuxprofiles.security-profiles-operator.x-k8s.io
+spec:
+  group: security-profiles-operator.x-k8s.io
+  names:
+    kind: SelinuxProfile
+    listKind: SelinuxProfileList
+    plural: selinuxprofiles
+    singular: selinuxprofile
+  scope: Namespaced
+  versions:
+  - additionalPrinterColumns:
+    - jsonPath: .status.usage
+      name: Usage
+      type: string
+    - jsonPath: .status.status
+      name: State
+      type: string
+    name: v1alpha2
+    schema:
+      openAPIV3Schema:
+        description: SelinuxProfile is the Schema for the selinuxprofiles API.
+        properties:
+          apiVersion:
+            description: 'APIVersion defines the versioned schema of this representation
+              of an object. Servers should convert recognized schemas to the latest
+              internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+            type: string
+          kind:
+            description: 'Kind is a string value representing the REST resource this
+              object represents. Servers may infer this from the endpoint the client
+              submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+            type: string
+          metadata:
+            type: object
+          spec:
+            description: SelinuxProfileSpec defines the desired state of SelinuxProfile.
+            properties:
+              allow:
+                additionalProperties:
+                  additionalProperties:
+                    items:
+                      type: string
+                    type: array
+                  type: object
+                description: Defines the allow policy for the profile
+                type: object
+              inherit:
+                default:
+                - kind: System
+                  name: container
+                description: A SELinuxProfile or set of profiles that this inherits
+                  from. Note that they need to be in the same namespace.
+                items:
+                  properties:
+                    kind:
+                      default: System
+                      description: The Kind of the policy that this inherits from.
+                        Can be a SelinuxProfile object Or "System" if an already installed
+                        policy will be used. The allowed "System" policies are available
+                        in the SecurityProfilesOpertorDaemon instance.
+                      enum:
+                      - System
+                      - SelinuxProfile
+                      type: string
+                    name:
+                      description: The name of the policy that this inherits from.
+                      type: string
+                  required:
+                  - name
+                  type: object
+                type: array
+            type: object
+          status:
+            description: SelinuxProfileStatus defines the observed state of SelinuxProfile.
+            properties:
+              activeWorkloads:
+                items:
+                  type: string
+                type: array
+              conditions:
+                description: Conditions of the resource.
+                items:
+                  description: A Condition that may apply to a resource.
+                  properties:
+                    lastTransitionTime:
+                      description: LastTransitionTime is the last time this condition
+                        transitioned from one status to another.
+                      format: date-time
+                      type: string
+                    message:
+                      description: A Message containing details about this condition's
+                        last transition from one status to another, if any.
+                      type: string
+                    reason:
+                      description: A Reason for this condition's last transition from
+                        one status to another.
+                      type: string
+                    status:
+                      description: Status of this condition; is it currently True,
+                        False, or Unknown?
+                      type: string
+                    type:
+                      description: Type of this condition. At most one of each condition
+                        type may apply to a resource at any point in time.
+                      type: string
+                  required:
+                  - lastTransitionTime
+                  - reason
+                  - status
+                  - type
+                  type: object
+                type: array
+              status:
+                description: ProfileState defines the state that the profile is in.
+                  A profile in this context refers to a SeccompProfile or a SELinux
+                  profile, the states are shared between them as well as the management
+                  API.
+                type: string
+              usage:
+                description: Represents the string that the SelinuxProfile object
+                  can be referenced as in a pod seLinuxOptions section.
+                type: string
+            type: object
+        type: object
+    served: true
+    storage: true
+    subresources:
+      status: {}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: security-profiles-operator
+  namespace: security-profiles-operator
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spo-webhook
+  namespace: security-profiles-operator
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spod
+  namespace: security-profiles-operator
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: security-profiles-operator
+  namespace: security-profiles-operator
+rules:
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - create
+  - get
+  - update
+- apiGroups:
+  - security.openshift.io
+  resources:
+  - securitycontextconstraints
+  verbs:
+  - use
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: spo-webhook
+  namespace: security-profiles-operator
+rules:
+- apiGroups:
+  - coordination.k8s.io
+  resources:
+  - leases
+  verbs:
+  - create
+- apiGroups:
+  - coordination.k8s.io
+  resourceNames:
+  - security-profiles-operator-webhook-lock
+  resources:
+  - leases
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security.openshift.io
+  resources:
+  - securitycontextconstraints
+  verbs:
+  - use
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: spod
+  namespace: security-profiles-operator
+rules:
+- apiGroups:
+  - security.openshift.io
+  resources:
+  - securitycontextconstraints
+  verbs:
+  - use
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: security-profiles-operator
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - services
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - daemonsets
+  - deployments
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - apps
+  resources:
+  - daemonsets/finalizers
+  - deployments
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - cert-manager.io
+  resources:
+  - certificates
+  - issuers
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - config.openshift.io
+  resources:
+  - clusteroperators
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - monitoring.coreos.com
+  resources:
+  - servicemonitors
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - rawselinuxprofiles
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - rawselinuxprofiles/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - rawselinuxprofiles/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - seccompprofiles
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - seccompprofiles/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - seccompprofiles/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - securityprofilenodestatuses
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - securityprofilesoperatordaemons
+  verbs:
+  - create
+  - get
+  - list
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - securityprofilesoperatordaemons/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - securityprofilesoperatordaemons/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - selinuxprofiles
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - selinuxprofiles/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - selinuxprofiles/status
+  verbs:
+  - get
+  - patch
+  - update
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spo-metrics-client
+rules:
+- nonResourceURLs:
+  - /metrics
+  - /metrics-spod
+  verbs:
+  - get
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: spo-webhook
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - profilebindings
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - profilebindings/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - profilebindings/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - profilerecordings
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - profilerecordings/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - profilerecordings/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - seccompprofiles
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - selinuxprofiles
+  verbs:
+  - get
+  - list
+  - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  labels:
+    app: security-profiles-operator
+  name: spod
+rules:
+- apiGroups:
+  - authentication.k8s.io
+  resources:
+  - subjectaccessreviews
+  - tokenreviews
+  verbs:
+  - create
+- apiGroups:
+  - authorization.k8s.io
+  resources:
+  - subjectaccessreviews
+  verbs:
+  - create
+- apiGroups:
+  - ""
+  resources:
+  - events
+  verbs:
+  - create
+  - get
+  - patch
+  - update
+- apiGroups:
+  - ""
+  resources:
+  - nodes
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  verbs:
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - apparmorprofiles
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - apparmorprofiles/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - apparmorprofiles/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - rawselinuxprofiles
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - rawselinuxprofiles/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - rawselinuxprofiles/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - seccompprofiles
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - seccompprofiles/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - seccompprofiles/status
+  verbs:
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - securityprofilenodestatuses
+  verbs:
+  - create
+  - delete
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - securityprofilesoperatordaemons
+  verbs:
+  - get
+  - list
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - selinuxprofiles
+  verbs:
+  - create
+  - get
+  - list
+  - patch
+  - update
+  - watch
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - selinuxprofiles/finalizers
+  verbs:
+  - delete
+  - get
+  - patch
+  - update
+- apiGroups:
+  - security-profiles-operator.x-k8s.io
+  resources:
+  - selinuxprofiles/status
+  verbs:
+  - get
+  - patch
+  - update
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: security-profiles-operator
+  namespace: security-profiles-operator
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: security-profiles-operator
+subjects:
+- kind: ServiceAccount
+  name: security-profiles-operator
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spo-webhook
+  namespace: security-profiles-operator
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: spo-webhook
+subjects:
+- kind: ServiceAccount
+  name: spo-webhook
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spod
+  namespace: security-profiles-operator
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: spod
+subjects:
+- kind: ServiceAccount
+  name: spod
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: security-profiles-operator
+  namespace: security-profiles-operator
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: security-profiles-operator
+subjects:
+- kind: ServiceAccount
+  name: security-profiles-operator
+  namespace: security-profiles-operator
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spo-webhook
+  namespace: security-profiles-operator
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: spo-webhook
+subjects:
+- kind: ServiceAccount
+  name: spo-webhook
+  namespace: security-profiles-operator
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spod
+  namespace: security-profiles-operator
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: spod
+subjects:
+- kind: ServiceAccount
+  name: spod
+  namespace: security-profiles-operator
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: spo-metrics-client
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: spo-metrics-client
+subjects:
+- kind: ServiceAccount
+  name: default
+  namespace: security-profiles-operator
+---
+apiVersion: v1
+data:
+  security-profiles-operator.json: |
+    {
+      "defaultAction": "SCMP_ACT_ERRNO",
+      "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_X86", "SCMP_ARCH_X32"],
+      "syscalls": [
+        {
+          "names": [
+            "accept4",
+            "arch_prctl",
+            "bind",
+            "brk",
+            "capget",
+            "capset",
+            "clone",
+            "clone3",
+            "close",
+            "connect",
+            "chdir",
+            "epoll_create1",
+            "epoll_ctl",
+            "epoll_pwait",
+            "epoll_wait",
+            "execve",
+            "exit",
+            "exit_group",
+            "fcntl",
+            "fchown",
+            "fstat",
+            "fstatfs",
+            "futex",
+            "getcwd",
+            "getdents64",
+            "getgid",
+            "getpeername",
+            "getpgrp",
+            "getpid",
+            "getppid",
+            "getrandom",
+            "getsockname",
+            "getsockopt",
+            "gettid",
+            "getuid",
+            "inotify_add_watch",
+            "inotify_init1",
+            "listen",
+            "madvise",
+            "membarrier",
+            "mkdirat",
+            "mlock",
+            "mmap",
+            "mprotect",
+            "nanosleep",
+            "newfstatat",
+            "open",
+            "openat",
+            "pipe2",
+            "pread64",
+            "prctl",
+            "read",
+            "readlinkat",
+            "rt_sigaction",
+            "rt_sigprocmask",
+            "rt_sigreturn",
+            "sched_getaffinity",
+            "sched_yield",
+            "setgid",
+            "setgroups",
+            "setsockopt",
+            "set_tid_address",
+            "setuid",
+            "sigaltstack",
+            "socket",
+            "tgkill",
+            "uname",
+            "unlinkat",
+            "write"
+          ],
+          "action": "SCMP_ACT_ALLOW"
+        }
+      ]
+    }
+  selinuxd.cil: |
+    (block selinuxd
+        (blockinherit container)
+        (allow process process ( capability ( dac_override dac_read_search lease audit_write audit_control )))
+
+        (allow process default_context_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write )))
+        (allow process default_context_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process default_context_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process default_context_t ( sock_file ( append getattr open read write )))
+        (allow process etc_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write watch )))
+        (allow process etc_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process etc_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process etc_t ( sock_file ( append getattr open read write )))
+        (allow process file_context_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write )))
+        (allow process file_context_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process file_context_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process file_context_t ( sock_file ( append getattr open read write )))
+        (allow process security_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process security_t ( security ( load_policy )))
+        (allow process selinux_config_t ( dir ( add_name create getattr ioctl lock open read remove_name rename rmdir search setattr write )))
+        (allow process selinux_config_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process selinux_config_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process selinux_config_t ( sock_file ( append getattr open read write )))
+        (allow process selinux_login_config_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write )))
+        (allow process selinux_login_config_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process selinux_login_config_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process selinux_login_config_t ( sock_file ( append getattr open read write )))
+        (allow process semanage_read_lock_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write )))
+        (allow process semanage_read_lock_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process semanage_read_lock_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process semanage_read_lock_t ( sock_file ( append getattr open read write )))
+        (allow process semanage_store_t ( dir ( add_name create getattr ioctl lock open read rename remove_name rmdir search setattr write )))
+        (allow process semanage_store_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process semanage_store_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process semanage_store_t ( sock_file ( append getattr open read write )))
+        (allow process semanage_trans_lock_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write )))
+        (allow process semanage_trans_lock_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process semanage_trans_lock_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process semanage_trans_lock_t ( sock_file ( append getattr open read write )))
+        (allow process sysfs_t ( dir ( add_name create getattr ioctl lock open read remove_name rmdir search setattr write )))
+        (allow process sysfs_t ( fifo_file ( getattr read write append ioctl lock open )))
+        (allow process sysfs_t ( file ( append create getattr ioctl lock map open read rename setattr unlink write )))
+        (allow process sysfs_t ( sock_file ( append getattr open read write )))
+    )
+  selinuxrecording.cil: |
+    (block selinuxrecording
+      (blockinherit container)
+      (typepermissive process)
+    )
+kind: ConfigMap
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: security-profiles-operator-profile
+  namespace: security-profiles-operator
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  annotations:
+    kubernetes.io/service-account.name: default
+  labels:
+    app: security-profiles-operator
+  name: metrics-token
+  namespace: security-profiles-operator
+type: kubernetes.io/service-account-token
+---
+apiVersion: v1
+kind: Service
+metadata:
+  labels:
+    name: security-profiles-operator
+  name: webhook-service
+  namespace: security-profiles-operator
+spec:
+  ports:
+  - name: webhook
+    port: 443
+    protocol: TCP
+    targetPort: 9443
+  selector:
+    app: security-profiles-operator
+    name: security-profiles-operator-webhook
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: security-profiles-operator
+  namespace: security-profiles-operator
+spec:
+  replicas: 3
+  selector:
+    matchLabels:
+      app: security-profiles-operator
+      name: security-profiles-operator
+  template:
+    metadata:
+      labels:
+        app: security-profiles-operator
+        name: security-profiles-operator
+    spec:
+      containers:
+      - args:
+        - manager
+        - --webhook=false
+        env:
+        - name: RELATED_IMAGE_RBAC_PROXY
+          value: quay.io/brancz/kube-rbac-proxy:v0.11.0
+        - name: RELATED_IMAGE_SELINUXD
+          value: quay.io/security-profiles-operator/selinuxd
+        - name: OPERATOR_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+        imagePullPolicy: Always
+        name: security-profiles-operator
+        resources:
+          limits:
+            memory: 128Mi
+          requests:
+            cpu: 250m
+            memory: 50Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
+      serviceAccountName: security-profiles-operator
+      tolerations:
+      - effect: NoSchedule
+        key: node-role.kubernetes.io/master
+        operator: Exists
+      - effect: NoSchedule
+        key: node-role.kubernetes.io/control-plane
+        operator: Exists
+      - effect: NoExecute
+        key: node.kubernetes.io/not-ready
+        operator: Exists
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: security-profiles-operator-webhook
+  namespace: security-profiles-operator
+spec:
+  replicas: 3
+  selector:
+    matchLabels:
+      app: security-profiles-operator
+      name: security-profiles-operator-webhook
+  template:
+    metadata:
+      annotations:
+        openshift.io/scc: privileged
+      labels:
+        app: security-profiles-operator
+        name: security-profiles-operator-webhook
+    spec:
+      containers:
+      - args:
+        - webhook
+        env:
+        - name: OPERATOR_NAMESPACE
+          valueFrom:
+            fieldRef:
+              fieldPath: metadata.namespace
+        image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+        imagePullPolicy: Always
+        name: security-profiles-operator
+        ports:
+        - containerPort: 9443
+          name: webhook
+          protocol: TCP
+        resources:
+          limits:
+            memory: 64Mi
+          requests:
+            cpu: 250m
+            memory: 32Mi
+        securityContext:
+          allowPrivilegeEscalation: false
+          readOnlyRootFilesystem: true
+        volumeMounts:
+        - mountPath: /tmp/k8s-webhook-server/serving-certs
+          name: cert
+          readOnly: true
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
+      serviceAccountName: spo-webhook
+      tolerations:
+      - effect: NoSchedule
+        key: node-role.kubernetes.io/master
+        operator: Exists
+      - effect: NoSchedule
+        key: node-role.kubernetes.io/control-plane
+        operator: Exists
+      - effect: NoExecute
+        key: node.kubernetes.io/not-ready
+        operator: Exists
+      volumes:
+      - name: cert
+        secret:
+          defaultMode: 420
+          secretName: webhook-server-cert
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  labels:
+    app: security-profiles-operator
+  name: webhook-cert
+  namespace: security-profiles-operator
+spec:
+  dnsNames:
+  - webhook-service.security-profiles-operator.svc
+  - webhook-service.security-profiles-operator.svc.cluster.local
+  issuerRef:
+    kind: Issuer
+    name: selfsigned-issuer
+  secretName: webhook-server-cert
+---
+apiVersion: admissionregistration.k8s.io/v1
+kind: MutatingWebhookConfiguration
+metadata:
+  annotations:
+    cert-manager.io/inject-ca-from: security-profiles-operator/webhook-cert
+  labels:
+    app: security-profiles-operator
+  name: spo-mutating-webhook-configuration
+webhooks:
+- admissionReviewVersions:
+  - v1beta1
+  clientConfig:
+    caBundle: Cg==
+    service:
+      name: webhook-service
+      namespace: security-profiles-operator
+      path: /mutate-v1-pod-binding
+  failurePolicy: Fail
+  name: binding.spo.io
+  namespaceSelector: {}
+  objectSelector:
+    matchExpressions:
+    - key: name
+      operator: NotIn
+      values:
+      - security-profiles-operator
+      - security-profiles-operator-webhook
+  rules:
+  - apiGroups:
+    - '*'
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    - DELETE
+    resources:
+    - pods
+  sideEffects: None
+- admissionReviewVersions:
+  - v1beta1
+  clientConfig:
+    caBundle: Cg==
+    service:
+      name: webhook-service
+      namespace: security-profiles-operator
+      path: /mutate-v1-pod-recording
+  failurePolicy: Fail
+  name: recording.spo.io
+  namespaceSelector: {}
+  objectSelector:
+    matchExpressions:
+    - key: name
+      operator: NotIn
+      values:
+      - security-profiles-operator
+      - security-profiles-operator-webhook
+  rules:
+  - apiGroups:
+    - '*'
+    apiVersions:
+    - v1
+    operations:
+    - CREATE
+    - UPDATE
+    - DELETE
+    resources:
+    - pods
+  sideEffects: None
diff --git a/hack/deploy-webhook-localhost.patch b/hack/deploy-webhook-localhost.patch
new file mode 100644
index 000000000..db01e7071
--- /dev/null
+++ b/hack/deploy-webhook-localhost.patch
@@ -0,0 +1,44 @@
+diff --git a/deploy/webhook-operator.yaml b/deploy/webhook-operator.yaml
+index 2de0b5bb..b29950ed 100644
+--- a/deploy/webhook-operator.yaml
++++ b/deploy/webhook-operator.yaml
+@@ -1967,7 +1967,7 @@ metadata:
+   name: security-profiles-operator
+   namespace: security-profiles-operator
+ spec:
+-  replicas: 3
++  replicas: 1
+   selector:
+     matchLabels:
+       app: security-profiles-operator
+@@ -1990,8 +1990,8 @@ spec:
+           valueFrom:
+             fieldRef:
+               fieldPath: metadata.namespace
+-        image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+-        imagePullPolicy: Always
++        image: localhost/security-profiles-operator:latest
++        imagePullPolicy: IfNotPresent
+         name: security-profiles-operator
+         resources:
+           limits:
+@@ -2023,7 +2023,7 @@ metadata:
+   name: security-profiles-operator-webhook
+   namespace: security-profiles-operator
+ spec:
+-  replicas: 3
++  replicas: 1
+   selector:
+     matchLabels:
+       app: security-profiles-operator
+@@ -2044,8 +2044,8 @@ spec:
+           valueFrom:
+             fieldRef:
+               fieldPath: metadata.namespace
+-        image: gcr.io/k8s-staging-sp-operator/security-profiles-operator:latest
+-        imagePullPolicy: Always
++        image: localhost/security-profiles-operator:latest
++        imagePullPolicy: IfNotPresent
+         name: security-profiles-operator
+         ports:
+         - containerPort: 9443
diff --git a/internal/pkg/manager/spod/bindata/spod.go b/internal/pkg/manager/spod/bindata/spod.go
index 0de055808..614894197 100644
--- a/internal/pkg/manager/spod/bindata/spod.go
+++ b/internal/pkg/manager/spod/bindata/spod.go
@@ -71,12 +71,13 @@ var DefaultSPOD = &spodv1alpha1.SecurityProfilesOperatorDaemon{
 		Labels: map[string]string{"app": config.OperatorName},
 	},
 	Spec: spodv1alpha1.SPODSpec{
-		Verbosity:          0,
-		EnableProfiling:    false,
-		EnableSelinux:      nil,
-		EnableLogEnricher:  false,
-		EnableBpfRecorder:  false,
-		HostProcVolumePath: DefaultHostProcPath,
+		Verbosity:           0,
+		EnableProfiling:     false,
+		EnableSelinux:       nil,
+		EnableLogEnricher:   false,
+		EnableBpfRecorder:   false,
+		StaticWebhookConfig: false,
+		HostProcVolumePath:  DefaultHostProcPath,
 		SelinuxOpts: spodv1alpha1.SelinuxOptions{
 			AllowedSystemProfiles: []string{
 				"container",
diff --git a/internal/pkg/manager/spod/setup.go b/internal/pkg/manager/spod/setup.go
index 547f94316..a63718265 100644
--- a/internal/pkg/manager/spod/setup.go
+++ b/internal/pkg/manager/spod/setup.go
@@ -36,7 +36,12 @@ import (
 	"sigs.k8s.io/security-profiles-operator/internal/pkg/manager/spod/bindata"
 )
 
+// CtxKey type for spod context keys.
+type CtxKey string
+
 const (
+	// ManageWebhookKey value key used in the Setup.Context for ManageWebhook value.
+	ManageWebhookKey  CtxKey = "ManageWebhook"
 	selinuxdImageKey  string = "RELATED_IMAGE_SELINUXD"
 	rbacProxyImageKey string = "RELATED_IMAGE_RBAC_PROXY"
 )
@@ -86,6 +91,7 @@ func (r *ReconcileSPOd) Setup(
 func (r *ReconcileSPOd) createConfigIfNotExist(ctx context.Context) error {
 	obj := bindata.DefaultSPOD.DeepCopy()
 	obj.Namespace = config.GetOperatorNamespace()
+	obj.Spec.StaticWebhookConfig = isStaticWebhook(ctx)
 
 	if err := r.client.Create(ctx, obj); err != nil && !k8serrors.IsAlreadyExists(err) {
 		return fmt.Errorf("create SecurityProfilesOperatorDaemon object: %w", err)
@@ -94,6 +100,15 @@ func (r *ReconcileSPOd) createConfigIfNotExist(ctx context.Context) error {
 	return nil
 }
 
+func isStaticWebhook(ctx context.Context) bool {
+	v, ok := ctx.Value(ManageWebhookKey).(bool)
+	if ok {
+		return !v
+	}
+	// the webhook is by default managed by the operator
+	return false
+}
+
 func getTunables() (*daemonTunables, error) {
 	dt := &daemonTunables{}
 	dt.watchNamespace = os.Getenv(config.RestrictNamespaceEnvKey)
@@ -135,6 +150,7 @@ func getEffectiveSPOd(dt *daemonTunables) *appsv1.DaemonSet {
 
 	sepolImage := &refSPOd.Spec.Template.Spec.InitContainers[1]
 	sepolImage.Image = dt.selinuxdImage // selinuxd ships the policies as well
+
 	return refSPOd
 }
 
diff --git a/internal/pkg/manager/spod/spod_controller.go b/internal/pkg/manager/spod/spod_controller.go
index f41309ffe..8de94d66b 100644
--- a/internal/pkg/manager/spod/spod_controller.go
+++ b/internal/pkg/manager/spod/spod_controller.go
@@ -182,16 +182,20 @@ func (r *ReconcileSPOd) Reconcile(_ context.Context, req reconcile.Request) (rec
 	}
 
 	spodUpdate := spodNeedsUpdate(configuredSPOd, foundSPOd)
-	hookUpdate, err := webhook.NeedsUpdate(ctx, r.client)
-	if err != nil {
-		return reconcile.Result{}, fmt.Errorf("determining if webhook needs update: %w", err)
+
+	var hookUpdate bool
+	if !spod.Spec.StaticWebhookConfig {
+		hookUpdate, err = webhook.NeedsUpdate(ctx, r.client)
+		if err != nil {
+			return reconcile.Result{}, fmt.Errorf("determining if webhook needs update: %w", err)
+		}
 	}
 
 	if spodUpdate || hookUpdate {
 		updatedSPod := foundSPOd.DeepCopy()
 		updatedSPod.Spec.Template = configuredSPOd.Spec.Template
 		updateErr := r.handleUpdate(
-			ctx, updatedSPod, webhook, metricsService, certManagerResources,
+			ctx, spod, updatedSPod, webhook, metricsService, certManagerResources,
 		)
 		if updateErr != nil {
 			r.record.Event(spod, event.Warning(reasonCannotUpdateSPOD, updateErr))
@@ -285,9 +289,11 @@ func (r *ReconcileSPOd) handleCreate(
 		}
 	}
 
-	r.log.Info("Deploying operator webhook")
-	if err := webhook.Create(ctx, r.client); err != nil {
-		return fmt.Errorf("creating webhook: %w", err)
+	if !cfg.Spec.StaticWebhookConfig {
+		r.log.Info("Deploying operator webhook")
+		if err := webhook.Create(ctx, r.client); err != nil {
+			return fmt.Errorf("creating webhook: %w", err)
+		}
 	}
 
 	r.log.Info("Creating operator resources")
@@ -345,6 +351,7 @@ func (r *ReconcileSPOd) handleCreate(
 
 func (r *ReconcileSPOd) handleUpdate(
 	ctx context.Context,
+	cfg *spodv1alpha1.SecurityProfilesOperatorDaemon,
 	spodInstance *appsv1.DaemonSet,
 	webhook *bindata.Webhook,
 	metricsService *corev1.Service,
@@ -357,9 +364,11 @@ func (r *ReconcileSPOd) handleUpdate(
 		}
 	}
 
-	r.log.Info("Updating operator webhook")
-	if err := webhook.Update(ctx, r.client); err != nil {
-		return fmt.Errorf("updating webhook: %w", err)
+	if !cfg.Spec.StaticWebhookConfig {
+		r.log.Info("Updating operator webhook")
+		if err := webhook.Update(ctx, r.client); err != nil {
+			return fmt.Errorf("updating webhook: %w", err)
+		}
 	}
 
 	r.log.Info("Updating operator daemonset")


Test patch:
diff --git a/hack/ci/e2e-static-webhook.sh b/hack/ci/e2e-static-webhook.sh
new file mode 100755
index 000000000..ae8b646fa
--- /dev/null
+++ b/hack/ci/e2e-static-webhook.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+# Copyright 2021 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.
+
+set -euo pipefail
+
+export E2E_CLUSTER_TYPE=vanilla
+export OPERATOR_MANIFEST="deploy/webhook-operator.yaml" 
+export E2E_TEST_SELINUX=true
+export E2E_TEST_LOG_ENRICHER=true
+export E2E_TEST_LABEL_POD_DENIALS=true
+export E2E_TEST_BPF_RECORDER=true
+export E2E_TEST_PROFILE_RECORDING=true
+export E2E_SKIP_NAMESPACED_TESTS=true
+export E2E_TEST_SECCOMP=true
+export E2E_TEST_WEBHOOK_CONFIG=false
+
+make test-e2e
diff --git a/test/e2e_test.go b/test/e2e_test.go
index 397036af1..31a89977f 100644
--- a/test/e2e_test.go
+++ b/test/e2e_test.go
@@ -33,7 +33,6 @@ import (
 
 const (
 	certmanager       = "https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml"
-	manifest          = "deploy/operator.yaml"
 	namespaceManifest = "deploy/namespace-operator.yaml"
 	testNamespace     = "test-ns"
 	defaultNamespace  = "default"
@@ -48,6 +47,12 @@ const (
 	defaultWaitTime               = 15 * time.Second
 )
 
+// testCase define a type for a e2e test case.
+type testCase struct {
+	description string
+	fn          func(nodes []string)
+}
+
 func (e *e2e) TestSecurityProfilesOperator() {
 	e.waitForReadyPods()
 
@@ -55,7 +60,7 @@ func (e *e2e) TestSecurityProfilesOperator() {
 	e.deployCertManager()
 
 	// Deploy the operator
-	e.deployOperator(manifest)
+	e.deployOperator(e.operatorManifest)
 
 	// On some distros (OCP), the SA needs to give additional
 	// roles to the workload, like the ability to use custom
@@ -69,10 +74,7 @@ func (e *e2e) TestSecurityProfilesOperator() {
 	// Execute the test cases. Each test case should cleanup on its own and
 	// leave a working operator behind.
 	e.logf("testing cluster-wide operator")
-	testCases := []struct {
-		description string
-		fn          func(nodes []string)
-	}{
+	testCases := []testCase{
 		{
 			"Seccomp: Verify default and example profiles",
 			e.testCaseDefaultAndExampleProfiles,
@@ -185,8 +187,16 @@ func (e *e2e) TestSecurityProfilesOperator() {
 	})
 
 	// Clean up cluster-wide deployment to prepare for namespace deployment
-	e.cleanupOperator(manifest)
-	e.run("git", "checkout", manifest)
+	e.cleanupOperator(e.operatorManifest)
+	e.run("git", "checkout", e.operatorManifest)
+
+	e.testNamespacedOperator(namespaceManifest, testNamespace, testCases, nodes)
+}
+
+func (e *e2e) testNamespacedOperator(manifest, namespace string, testCases []testCase, nodes []string) {
+	if e.skipNamespacedTests {
+		return
+	}
 
 	e.logf("testing namespace operator")
 
@@ -194,11 +204,11 @@ func (e *e2e) TestSecurityProfilesOperator() {
 	testCases[5].fn = e.testCaseReDeployNamespaceOperator
 
 	// Deploy the namespace operator
-	e.kubectl("create", "namespace", testNamespace)
-	e.updateManifest(namespaceManifest, "NS_REPLACE", testNamespace)
+	e.kubectl("create", "namespace", namespace)
+	e.updateManifest(manifest, "NS_REPLACE", namespace)
 	// All following operations such as create pod will be in the test namespace
-	e.kubectl("config", "set-context", "--current", "--namespace", testNamespace)
-	e.deployOperator(namespaceManifest)
+	e.kubectl("config", "set-context", "--current", "--namespace", namespace)
+	e.deployOperator(manifest)
 
 	for _, testCase := range testCases {
 		tc := testCase
@@ -206,7 +216,7 @@ func (e *e2e) TestSecurityProfilesOperator() {
 			tc.fn(nodes)
 		})
 	}
-	e.run("git", "checkout", namespaceManifest)
+	e.run("git", "checkout", manifest)
 }
 
 func doDeployCertManager(e *e2e) {
diff --git a/test/suite_test.go b/test/suite_test.go
index 76ecee8ab..7db0aa411 100644
--- a/test/suite_test.go
+++ b/test/suite_test.go
@@ -50,14 +50,17 @@ var (
 	envSkipBuildImages              = os.Getenv("E2E_SKIP_BUILD_IMAGES")
 	envTestImage                    = os.Getenv("E2E_SPO_IMAGE")
 	spodConfig                      = os.Getenv("E2E_SPOD_CONFIG")
+	envSkipNamespacedTests          = os.Getenv("E2E_SKIP_NAMESPACED_TESTS")
 	envSelinuxTestsEnabled          = os.Getenv("E2E_TEST_SELINUX")
 	envLogEnricherTestsEnabled      = os.Getenv("E2E_TEST_LOG_ENRICHER")
 	envSeccompTestsEnabled          = os.Getenv("E2E_TEST_SECCOMP")
 	envProfileRecordingTestsEnabled = os.Getenv("E2E_TEST_PROFILE_RECORDING")
 	envBpfRecorderTestsEnabled      = os.Getenv("E2E_TEST_BPF_RECORDER")
 	envLabelPodDenialsEnabled       = os.Getenv("E2E_TEST_LABEL_POD_DENIALS")
+	envWebhookConfigTestsEnabled    = os.Getenv("E2E_TEST_WEBHOOK_CONFIG")
 	containerRuntime                = os.Getenv("CONTAINER_RUNTIME")
 	nodeRootfsPrefix                = os.Getenv("NODE_ROOTFS_PREFIX")
+	operatorManifest                = os.Getenv("OPERATOR_MANIFEST")
 )
 
 const (
@@ -70,6 +73,10 @@ const (
 	containerRuntimeDocker = "docker"
 )
 
+const (
+	defaultManifest = "deploy/operator.yaml"
+)
+
 type e2e struct {
 	suite.Suite
 	containerRuntime       string
@@ -79,12 +86,15 @@ type e2e struct {
 	pullPolicy             string
 	spodConfig             string
 	nodeRootfsPrefix       string
+	operatorManifest       string
 	selinuxEnabled         bool
 	logEnricherEnabled     bool
 	testSeccomp            bool
 	testProfileRecording   bool
 	labelPodDenialsEnabled bool
 	bpfRecorderEnabled     bool
+	skipNamespacedTests    bool
+	testWebhookConfig      bool
 	logger                 logr.Logger
 	execNode               func(node string, args ...string) string
 	waitForReadyPods       func()
@@ -147,6 +157,20 @@ func TestSuite(t *testing.T) {
 		labelPodDenialsEnabled = false
 	}
 
+	skipNamespacedTests, err := strconv.ParseBool(envSkipNamespacedTests)
+	if err != nil {
+		skipNamespacedTests = false
+	}
+
+	testWebhookConfig, err := strconv.ParseBool(envWebhookConfigTestsEnabled)
+	if err != nil {
+		testWebhookConfig = true
+	}
+
+	if operatorManifest == "" {
+		operatorManifest = defaultManifest
+	}
+
 	selinuxdImage := "quay.io/security-profiles-operator/selinuxd"
 	switch {
 	case clusterType == "" || strings.EqualFold(clusterType, clusterTypeKind):
@@ -168,6 +192,9 @@ func TestSuite(t *testing.T) {
 				selinuxdImage:          selinuxdImage,
 				bpfRecorderEnabled:     bpfRecorderEnabled,
 				labelPodDenialsEnabled: labelPodDenialsEnabled,
+				skipNamespacedTests:    skipNamespacedTests,
+				operatorManifest:       operatorManifest,
+				testWebhookConfig:      testWebhookConfig,
 			},
 			"", "",
 		})
@@ -197,6 +224,9 @@ func TestSuite(t *testing.T) {
 				selinuxdImage:          selinuxdImage,
 				bpfRecorderEnabled:     bpfRecorderEnabled,
 				labelPodDenialsEnabled: labelPodDenialsEnabled,
+				skipNamespacedTests:    skipNamespacedTests,
+				operatorManifest:       operatorManifest,
+				testWebhookConfig:      testWebhookConfig,
 			},
 			skipBuildImages,
 			skipPushImages,
@@ -221,6 +251,9 @@ func TestSuite(t *testing.T) {
 				selinuxdImage:          selinuxdImage,
 				bpfRecorderEnabled:     bpfRecorderEnabled,
 				labelPodDenialsEnabled: labelPodDenialsEnabled,
+				skipNamespacedTests:    skipNamespacedTests,
+				operatorManifest:       operatorManifest,
+				testWebhookConfig:      testWebhookConfig,
 			},
 		})
 	default:
diff --git a/test/tc_redeploy_operator_test.go b/test/tc_redeploy_operator_test.go
index b19b408d9..e668a9052 100644
--- a/test/tc_redeploy_operator_test.go
+++ b/test/tc_redeploy_operator_test.go
@@ -20,10 +20,10 @@ func (e *e2e) testCaseReDeployOperator([]string) {
 	e.seccompOnlyTestCase()
 
 	// Clean up the operator
-	e.cleanupOperator(manifest)
+	e.cleanupOperator(e.operatorManifest)
 
 	// Deploy the operator again
-	e.deployOperator(manifest)
+	e.deployOperator(e.operatorManifest)
 }
 
 func (e *e2e) testCaseReDeployNamespaceOperator([]string) {
diff --git a/test/tc_webhook_config_test.go b/test/tc_webhook_config_test.go
index 539def744..35a34770b 100644
--- a/test/tc_webhook_config_test.go
+++ b/test/tc_webhook_config_test.go
@@ -24,6 +24,9 @@ import (
 const whNamespaceSelector = `{"matchExpressions":[{"key":"prod","operator":"In","values":["true"]}]}`
 
 func (e *e2e) testCaseWebhookOptionsChange([]string) {
+	if !e.testWebhookConfig {
+		e.T().Skip("Skipping webhook config related tests")
+	}
 	e.logf("Change webhook options")
 	origOutput0 := e.kubectlOperatorNS("get", "MutatingWebhookConfiguration",
 		"spo-mutating-webhook-configuration",