Repository: kubernetes-sigs/security-profiles-operator
Pull request #207 (2021-01-18 13:23:05)

Update kind node image to v1.20.0

#### What type of PR is this?

/kind cleanup


#### What this PR does / why we need it:
This will bump the minor Kubernetes version for the e2e test suite.

#### 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 #

or

None
-->
None
#### Special notes for your reviewer:
None
#### 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
None
```


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/207#" title="Author self-approved">saschagrunert</a>*

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

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

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

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

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

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

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

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

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

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

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
k8s-ci-robot: @saschagrunert: The following test **failed**, say `/retest` to rerun all failed tests:

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-security-profiles-operator-test-e2e | 1728357f4c5e504f41ab22ed96373abdab9bfa5d | [link](https://prow.k8s.io/view/gs/kubernetes-jenkins/pr-logs/pull/kubernetes-sigs_security-profiles-operator/207/pull-security-profiles-operator-test-e2e/1351162658652426240) | `/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=207). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Asaschagrunert). 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 -->
saschagrunert: Strange, locally it works but in the CI it seems to become not ready… :thinking: 

Patch:
diff --git a/.gitignore b/.gitignore
index 897bb1b07..6a06c1a94 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 *.orig
 build
+.idea
diff --git a/OWNERS b/OWNERS
index 75c799295..a246eeca7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,3 +6,4 @@ approvers:
   - saschagrunert
 reviewers:
   - cmurphy
+  - JAORMX
diff --git a/api/seccompprofile/v1alpha1/seccompprofile_types.go b/api/seccompprofile/v1alpha1/seccompprofile_types.go
index e6f4d54b0..89285090a 100644
--- a/api/seccompprofile/v1alpha1/seccompprofile_types.go
+++ b/api/seccompprofile/v1alpha1/seccompprofile_types.go
@@ -28,7 +28,6 @@ type SeccompProfileSpec struct {
 	TargetWorkload string `json:"targetWorkload"`
 
 	// name of base profile (in the same namespace) what will be unioned into this profile
-	//nolint:lll
 	BaseProfileName string `json:"baseProfileName,omitempty"`
 
 	// Properties from containers/common/pkg/seccomp.Seccomp type
diff --git a/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go b/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go
index bcf65b3cd..6f1e34541 100644
--- a/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go
+++ b/api/seccompprofile/v1alpha1/zz_generated.deepcopy.go
@@ -1,7 +1,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2020 The Kubernetes Authors.
+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.
diff --git a/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go b/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go
index 3255eda16..af4287ced 100644
--- a/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go
+++ b/api/selinuxpolicy/v1alpha1/zz_generated.deepcopy.go
@@ -1,7 +1,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2020 The Kubernetes Authors.
+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.
diff --git a/cmd/security-profiles-operator/main.go b/cmd/security-profiles-operator/main.go
index dadbb9b42..6524e846d 100644
--- a/cmd/security-profiles-operator/main.go
+++ b/cmd/security-profiles-operator/main.go
@@ -38,7 +38,6 @@ import (
 
 const (
 	jsonFlag               string = "json"
-	restrictNSKey          string = "RESTRICT_TO_NAMESPACE"
 	operatorImageKey       string = "RELATED_IMAGE_OPERATOR"
 	nonRootEnablerImageKey string = "RELATED_IMAGE_NON_ROOT_ENABLER"
 )
@@ -168,21 +167,21 @@ func runManager(ctx *cli.Context) error {
 	return nil
 }
 
-func getTunables() (spod.DaemonTunables, error) {
-	var dt spod.DaemonTunables
-	restrictNS := os.Getenv(restrictNSKey)
+func getTunables() (dt spod.DaemonTunables, err error) {
+	dt.WatchNamespace = os.Getenv(config.RestrictNamespaceEnvKey)
+
 	operatorImage := os.Getenv(operatorImageKey)
 	if operatorImage == "" {
 		return dt, errors.New("invalid operator image")
 	}
+	dt.DaemonImage = operatorImage
+
 	nonRootEnableImage := os.Getenv(nonRootEnablerImageKey)
-	if operatorImage == "" {
-		return dt, errors.New("invalid operator image")
+	if nonRootEnableImage == "" {
+		return dt, errors.New("invalid non-root enabler image")
 	}
-
-	dt.DaemonImage = operatorImage
 	dt.NonRootEnablerImage = nonRootEnableImage
-	dt.WatchNamespace = restrictNS
+
 	return dt, nil
 }
 
@@ -200,8 +199,8 @@ func runDaemon(ctx *cli.Context) error {
 		SyncPeriod: &sync,
 	}
 
-	if os.Getenv(restrictNSKey) != "" {
-		ctrlOpts.Namespace = os.Getenv(restrictNSKey)
+	if os.Getenv(config.RestrictNamespaceEnvKey) != "" {
+		ctrlOpts.Namespace = os.Getenv(config.RestrictNamespaceEnvKey)
 	}
 
 	mgr, err := ctrl.NewManager(cfg, ctrlOpts)
diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go
index 0c6cbe2ce..b8601b912 100644
--- a/internal/pkg/config/config.go
+++ b/internal/pkg/config/config.go
@@ -31,6 +31,10 @@ const (
 	// NodeNameEnvKey is the default environment variable key for retrieving
 	// the name of the current node.
 	NodeNameEnvKey = "NODE_NAME"
+
+	// RestrictNamespaceEnvKey is the environment variable key for restricting
+	// the operator to work on only a single Kubernetes namespace.
+	RestrictNamespaceEnvKey = "RESTRICT_TO_NAMESPACE"
 )
 
 // GetOperatorNamespace gets the namespace that the operator is currently running on.
diff --git a/internal/pkg/controllers/spod/bindata/bindata.go b/internal/pkg/controllers/spod/bindata/bindata.go
deleted file mode 100644
index ec293cc69..000000000
--- a/internal/pkg/controllers/spod/bindata/bindata.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package bindata
-
-import (
-	"fmt"
-	"strings"
-
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	k8syaml "k8s.io/apimachinery/pkg/util/yaml"
-)
-
-func rawObjectToUnstructured(in string) (*unstructured.Unstructured, error) {
-	obj := &unstructured.Unstructured{}
-	dec := k8syaml.NewYAMLToJSONDecoder(strings.NewReader(in))
-	if err := dec.Decode(obj); err != nil {
-		return nil, fmt.Errorf("couldn't decode YAML: %w", err)
-	}
-	return obj, nil
-}
diff --git a/internal/pkg/controllers/spod/bindata/spod.go b/internal/pkg/controllers/spod/bindata/spod.go
index 8dd24cfa7..976dc786a 100644
--- a/internal/pkg/controllers/spod/bindata/spod.go
+++ b/internal/pkg/controllers/spod/bindata/spod.go
@@ -17,157 +17,205 @@ limitations under the License.
 package bindata
 
 import (
-	"fmt"
-
 	appsv1 "k8s.io/api/apps/v1"
-	"k8s.io/apimachinery/pkg/runtime"
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/resource"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
+)
+
+var (
+	falsely                         = false
+	truly                           = true
+	userRoot                  int64 = 0
+	userRootless              int64 = 2000
+	hostPathDirectory               = v1.HostPathDirectory
+	hostPathDirectoryOrCreate       = v1.HostPathDirectoryOrCreate
 )
 
-// NOTE(jaosorior): We should switch this for a proper bindata solution.
-// nolint: lll
-const spodManifest = `---
-apiVersion: apps/v1
-kind: DaemonSet
-metadata:
-  name: security-profiles-operator
-  namespace: security-profiles-operator
-spec:
-  selector:
-    matchLabels:
-      app: spod
-  template:
-    metadata:
-      annotations:
-        openshift.io/scc: privileged
-        seccomp.security.alpha.kubernetes.io/pod: runtime/default
-        container.seccomp.security.alpha.kubernetes.io/security-profiles-operator: localhost/security-profiles-operator.json
-      labels:
-        app: spod
-    spec:
-      serviceAccountName: security-profiles-operator
-      initContainers:
-        - name: non-root-enabler
-          image: bash
-          # Creates folder /var/lib/security-profiles-operator, sets 2000:2000 as its
-          # owner and symlink it to /var/lib/kubelet/seccomp/operator. This is
-          # required to allow the main container to run as non-root.
-          command: [bash, -c]
-          args:
-            - |+
-              set -euo pipefail
+const operatorRoot = "/var/lib/security-profiles-operator"
 
-              if [ ! -d $KUBELET_SECCOMP_ROOT ]; then
-                /bin/mkdir -m 0744 -p $KUBELET_SECCOMP_ROOT
-              fi
+var Manifest = &appsv1.DaemonSet{
+	ObjectMeta: metav1.ObjectMeta{
+		Name:      config.OperatorName,
+		Namespace: config.OperatorName,
+	},
+	Spec: appsv1.DaemonSetSpec{
+		Selector: &metav1.LabelSelector{
+			MatchLabels: map[string]string{"app": "spod"},
+		},
+		Template: v1.PodTemplateSpec{
+			ObjectMeta: metav1.ObjectMeta{
+				Annotations: map[string]string{
+					"openshift.io/scc":         "privileged",
+					v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
+					v1.SeccompContainerAnnotationKeyPrefix + config.OperatorName: "localhost/security-profiles-operator.json",
+				},
+				Labels: map[string]string{
+					"app": "spod",
+				},
+			},
+			Spec: v1.PodSpec{
+				ServiceAccountName: config.OperatorName,
+				InitContainers: []v1.Container{{
+					Name: "non-root-enabler",
+					// Creates directory /var/lib/security-profiles-operator,
+					// sets 2000:2000 as its owner and symlink it to
+					// /var/lib/kubelet/seccomp/operator. This is required
+					// to allow the main container to run as non-root.
+					Command: []string{"bash", "-c"},
+					Args: []string{`
+						set -euo pipefail
 
-              /bin/mkdir -p $OPERATOR_ROOT
-              /bin/chmod 0744 $OPERATOR_ROOT
+						if [ ! -d ` + config.KubeletSeccompRootPath + ` ]; then
+							/bin/mkdir -m 0744 -p ` + config.KubeletSeccompRootPath + `
+						fi
 
-              if [ ! -L $OPERATOR_SYMLINK ]; then
-                /bin/ln -s $OPERATOR_ROOT $OPERATOR_SYMLINK
-              fi
+						/bin/mkdir -p ` + operatorRoot + `
+						/bin/chmod 0744 ` + operatorRoot + `
 
-              /bin/chown -R 2000:2000 $OPERATOR_ROOT
-              cp -f -v /opt/seccomp-profiles/* $KUBELET_SECCOMP_ROOT
-          env:
-            - name: KUBELET_SECCOMP_ROOT
-              value: /var/lib/kubelet/seccomp
-            - name: OPERATOR_SYMLINK
-              value: $(KUBELET_SECCOMP_ROOT)/operator
-            - name: OPERATOR_ROOT
-              value: /var/lib/security-profiles-operator
-          volumeMounts:
-            - name: host-varlib-volume
-              mountPath: /var/lib
-            - name: profile-configmap-volume
-              mountPath: /opt/seccomp-profiles
-              readOnly: true
-          securityContext:
-            allowPrivilegeEscalation: false
-            readOnlyRootFilesystem: true
-            capabilities:
-              drop: ["ALL"]
-              add: ["CHOWN", "FOWNER", "FSETID", "DAC_OVERRIDE"]
-            runAsUser: 0
-            seLinuxOptions:
-              # FIXME(jaosorior): Use a more restricted selinux type
-              type: spc_t
-          resources:
-            requests:
-              memory: "32Mi"
-              cpu: "100m"
-              ephemeral-storage: "10Mi"
-            limits:
-              memory: "64Mi"
-              cpu: "250m"
-              ephemeral-storage: "50Mi"
-      containers:
-        - name: security-profiles-operator
-          image: security-profiles-operator
-          args:
-          - daemon
-          imagePullPolicy: Always
-          volumeMounts:
-          - name: host-operator-volume
-            mountPath: /var/lib/kubelet/seccomp/operator
-          securityContext:
-            allowPrivilegeEscalation: false
-            readOnlyRootFilesystem: true
-            runAsUser: 2000
-            runAsGroup: 2000
-            capabilities:
-              drop: ["ALL"]
-            seLinuxOptions:
-              # FIXME(jaosorior): Use a more restricted selinux type
-              type: spc_t
-          resources:
-            requests:
-              memory: "64Mi"
-              cpu: "100m"
-              ephemeral-storage: "50Mi"
-            limits:
-              memory: "128Mi"
-              cpu: "300m"
-              ephemeral-storage: "200Mi"
-          env:
-            - name: NODE_NAME
-              valueFrom:
-                fieldRef:
-                  fieldPath: spec.nodeName
-      volumes:
-      # /var/lib is used as symlinks cannot be created across different volumes
-      - name: host-varlib-volume
-        hostPath:
-          path: /var/lib
-          type: Directory
-      - name: host-operator-volume
-        hostPath:
-          path: /var/lib/security-profiles-operator
-          type: DirectoryOrCreate
-      - name: profile-configmap-volume
-        configMap:
-          name: security-profiles-operator-profile
-      tolerations:
-        - effect: NoSchedule
-          key: node-role.kubernetes.io/master
-        - effect: NoSchedule
-          key: node-role.kubernetes.io/control-plane
-        - effect: NoExecute
-          key: node.kubernetes.io/not-ready
-          operator: Exists
-      nodeSelector:
-        kubernetes.io/os: linux
-`
+						if [ ! -L ` + config.ProfilesRootPath + ` ]; then
+							/bin/ln -s ` + operatorRoot + ` ` + config.ProfilesRootPath + `
+						fi
 
-func GetReferenceSPOd() (*appsv1.DaemonSet, error) {
-	rawDS, err := rawObjectToUnstructured(spodManifest)
-	if err != nil {
-		return nil, fmt.Errorf("error parsing DS manifest: %w", err)
-	}
-	spod := &appsv1.DaemonSet{}
-	err = runtime.DefaultUnstructuredConverter.FromUnstructured(rawDS.Object, spod)
-	if err != nil {
-		return nil, fmt.Errorf("error converting unstructured DS to implementation object: %w", err)
-	}
-	return spod, nil
+						/bin/chown -R 2000:2000 ` + operatorRoot + `
+						cp -f -v /opt/seccomp-profiles/* ` + config.KubeletSeccompRootPath + `
+					`},
+					VolumeMounts: []v1.VolumeMount{
+						{
+							Name:      "host-varlib-volume",
+							MountPath: "/var/lib",
+						},
+						{
+							Name:      "profile-configmap-volume",
+							MountPath: "/opt/seccomp-profiles",
+							ReadOnly:  true,
+						},
+					},
+					SecurityContext: &v1.SecurityContext{
+						AllowPrivilegeEscalation: &falsely,
+						ReadOnlyRootFilesystem:   &truly,
+						Capabilities: &v1.Capabilities{
+							Drop: []v1.Capability{"ALL"},
+							Add:  []v1.Capability{"CHOWN", "FOWNER", "FSETID", "DAC_OVERRIDE"},
+						},
+						RunAsUser: &userRoot,
+						SELinuxOptions: &v1.SELinuxOptions{
+							// TODO(jaosorior): Use a more restricted selinux type
+							Type: "spc_t",
+						},
+					},
+					Resources: v1.ResourceRequirements{
+						Requests: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("32Mi"),
+							v1.ResourceCPU:              resource.MustParse("100m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("10Mi"),
+						},
+						Limits: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("64Mi"),
+							v1.ResourceCPU:              resource.MustParse("250m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+						},
+					},
+				}},
+				Containers: []v1.Container{{
+					Name:            config.OperatorName,
+					Args:            []string{"daemon"},
+					ImagePullPolicy: v1.PullAlways,
+					VolumeMounts: []v1.VolumeMount{
+						{
+							Name:      "host-operator-volume",
+							MountPath: config.ProfilesRootPath,
+						},
+					},
+					SecurityContext: &v1.SecurityContext{
+						AllowPrivilegeEscalation: &falsely,
+						ReadOnlyRootFilesystem:   &truly,
+						Capabilities: &v1.Capabilities{
+							Drop: []v1.Capability{"ALL"},
+						},
+						RunAsUser:  &userRootless,
+						RunAsGroup: &userRootless,
+						SELinuxOptions: &v1.SELinuxOptions{
+							// TODO(jaosorior): Use a more restricted selinux type
+							Type: "spc_t",
+						},
+					},
+					Resources: v1.ResourceRequirements{
+						Requests: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("64Mi"),
+							v1.ResourceCPU:              resource.MustParse("100m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("50Mi"),
+						},
+						Limits: v1.ResourceList{
+							v1.ResourceMemory:           resource.MustParse("128Mi"),
+							v1.ResourceCPU:              resource.MustParse("300m"),
+							v1.ResourceEphemeralStorage: resource.MustParse("200Mi"),
+						},
+					},
+					Env: []v1.EnvVar{
+						{
+							Name: config.NodeNameEnvKey,
+							ValueFrom: &v1.EnvVarSource{
+								FieldRef: &v1.ObjectFieldSelector{
+									FieldPath: "spec.nodeName",
+								},
+							},
+						},
+					},
+				}},
+				Volumes: []v1.Volume{
+					// /var/lib is used as symlinks cannot be created across
+					// different volumes
+					{
+						Name: "host-varlib-volume",
+						VolumeSource: v1.VolumeSource{
+							HostPath: &v1.HostPathVolumeSource{
+								Path: "/var/lib",
+								Type: &hostPathDirectory,
+							},
+						},
+					},
+					{
+						Name: "host-operator-volume",
+						VolumeSource: v1.VolumeSource{
+							HostPath: &v1.HostPathVolumeSource{
+								Path: "/var/lib/security-profiles-operator",
+								Type: &hostPathDirectoryOrCreate,
+							},
+						},
+					},
+					{
+						Name: "profile-configmap-volume",
+						VolumeSource: v1.VolumeSource{
+							ConfigMap: &v1.ConfigMapVolumeSource{
+								LocalObjectReference: v1.LocalObjectReference{
+									Name: "security-profiles-operator-profile",
+								},
+							},
+						},
+					},
+				},
+				Tolerations: []v1.Toleration{
+					{
+						Effect: v1.TaintEffectNoSchedule,
+						Key:    "node-role.kubernetes.io/master",
+					},
+					{
+						Effect: v1.TaintEffectNoSchedule,
+						Key:    "node-role.kubernetes.io/control-plane",
+					},
+					{
+						Effect:   v1.TaintEffectNoExecute,
+						Key:      "node.kubernetes.io/not-ready",
+						Operator: v1.TolerationOpExists,
+					},
+				},
+				NodeSelector: map[string]string{
+					"kubernetes.io/os": "linux",
+				},
+			},
+		},
+	},
 }
diff --git a/internal/pkg/controllers/spod/setup.go b/internal/pkg/controllers/spod/setup.go
index 70582840b..2d83bf53d 100644
--- a/internal/pkg/controllers/spod/setup.go
+++ b/internal/pkg/controllers/spod/setup.go
@@ -18,7 +18,6 @@ package spod
 
 import (
 	"context"
-	"fmt"
 
 	"github.com/crossplane/crossplane-runtime/pkg/event"
 	"github.com/crossplane/crossplane-runtime/pkg/resource"
@@ -45,17 +44,13 @@ type DaemonTunables struct {
 
 // Setup adds a controller that reconciles the SPOd DaemonSet.
 func Setup(ctx context.Context, mgr ctrl.Manager, dt DaemonTunables, l logr.Logger) error {
-	refSPOd, err := getEffectiveSPOd(dt)
-	if err != nil {
-		return err
-	}
 	return ctrl.NewControllerManagedBy(mgr).
 		Named("spod-config").
 		For(&corev1.ConfigMap{}).
 		WithEventFilter(resource.NewPredicates(isSPOdConfig)).
 		Owns(&appsv1.DaemonSet{}).
 		Complete(&ReconcileSPOd{
-			baseSPOd: refSPOd,
+			baseSPOd: getEffectiveSPOd(dt),
 			client:   mgr.GetClient(),
 			log:      l,
 			record:   event.NewAPIRecorder(mgr.GetEventRecorderFor("spod-config")),
@@ -63,23 +58,21 @@ func Setup(ctx context.Context, mgr ctrl.Manager, dt DaemonTunables, l logr.Logg
 		})
 }
 
-func getEffectiveSPOd(dt DaemonTunables) (*appsv1.DaemonSet, error) {
-	refSPOd, err := bindata.GetReferenceSPOd()
-	if err != nil {
-		return nil, fmt.Errorf("couldn't get reference SPO DaemonSet: %w", err)
-	}
+func getEffectiveSPOd(dt DaemonTunables) *appsv1.DaemonSet {
+	refSPOd := bindata.Manifest.DeepCopy()
 	cnt := &refSPOd.Spec.Template.Spec.Containers[0]
 	cnt.Image = dt.DaemonImage
+
 	if dt.WatchNamespace != "" {
 		cnt.Env = append(cnt.Env, corev1.EnvVar{
-			Name:  "RESTRICT_TO_NAMESPACE",
+			Name:  config.RestrictNamespaceEnvKey,
 			Value: dt.WatchNamespace,
 		})
 	}
 
 	initcnt := &refSPOd.Spec.Template.Spec.InitContainers[0]
 	initcnt.Image = dt.NonRootEnablerImage
-	return refSPOd, nil
+	return refSPOd
 }
 
 func isSPOdConfig(obj runtime.Object) bool {


Test patch:
diff --git a/internal/pkg/controllers/spod/setup_test.go b/internal/pkg/controllers/spod/setup_test.go
index 1cc74ff0e..572ae2f77 100644
--- a/internal/pkg/controllers/spod/setup_test.go
+++ b/internal/pkg/controllers/spod/setup_test.go
@@ -20,6 +20,8 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/require"
+
+	"sigs.k8s.io/security-profiles-operator/internal/pkg/config"
 )
 
 func Test_getEffectiveSPOd(t *testing.T) {
@@ -44,23 +46,19 @@ func Test_getEffectiveSPOd(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			got, err := getEffectiveSPOd(tt.dt)
-			if (err != nil) != tt.wantErr {
-				t.Errorf("getEffectiveSPOd() error = %v, wantErr %v", err, tt.wantErr)
-				return
-			}
+			got := getEffectiveSPOd(tt.dt)
 			require.Equal(t, tt.dt.DaemonImage, got.Spec.Template.Spec.Containers[0].Image)
 			require.Equal(t, tt.dt.NonRootEnablerImage, got.Spec.Template.Spec.InitContainers[0].Image)
 			var found bool
 			for _, env := range got.Spec.Template.Spec.Containers[0].Env {
-				if env.Name == "RESTRICT_TO_NAMESPACE" {
+				if env.Name == config.RestrictNamespaceEnvKey {
 					require.Equal(t, tt.dt.WatchNamespace, env.Value)
 					found = true
 					break
 				}
 			}
 			if tt.nsIsSet && !found {
-				t.Errorf("RESTRICT_TO_NAMESPACE env variable wasn't set")
+				t.Errorf("%s env variable wasn't set", config.RestrictNamespaceEnvKey)
 			}
 		})
 	}
diff --git a/test/suite_test.go b/test/suite_test.go
index 663d39da1..7d97c0b7c 100644
--- a/test/suite_test.go
+++ b/test/suite_test.go
@@ -37,7 +37,7 @@ import (
 const (
 	kindVersion = "v0.9.0"
 	kindSHA512  = "e7152acf5fd7a4a56af825bda64b1b8343a1f91588f9b3ddd5420ae5c5a95577d87431f2e417a7e03dd23914e1da9bed855ec19d0c4602729b311baccb30bd7f" // nolint: lll
-	kindImage   = "kindest/node:v1.19.1"
+	kindImage   = "kindest/node:v1.20.0"
 )
 
 var (