Repository: aquasecurity/starboard
Pull request #750 (2021-10-15 02:54:46)

chore: documentation getting started
Improving the copy and paste console, and using results table for the results.

krol3: Hi @danielpacak , I tried to follow the same approach about trivy documentation. 
Using in the markdown the details and summary. Any improvement or comment about this? 

<details>
<summary>Result</summary>
danielpacak: > Hi @danielpacak , I tried to follow the same approach about trivy documentation. Using in the markdown the details and summary. Any improvement or comment about this?
> 
> Result

I know the `<details>` and `<summary>` tags. But personally, I don't really like it because when you print the documentation page (e.g. to PDF) the layout and highlight is broken. For the the MkDocs should fix the copy experience when you use console as code block language.

<pre>
```console
$ only the line prefixed with the dollar sign should be copied
output of the command
output of the command
```
</pre>
```console
$ name -a
Darwin dpacak-imac.local 21.2.0 Darwin Kernel Version 21.2.0: Sun Nov 28 20:28:54 PST 2021; root:xnu-8019.61.5~1/RELEASE_X86_64 x86_64
```

 Anyway, I let @chen-keinan decide if we want to use it.
chen-keinan: I agree that this PR in a way is kind of a workaround to the problem; however I feel we should go with it because:
- It solves the problem - shell commands only copied
- It makes the docs look clean
- Its look and feel is similar to Trivy (which is important for our open source docs to look alike)

Patch:
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 1b3697a..9e7663d 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -217,6 +217,7 @@ jobs:
         with:
           files: ./itest/starboard-operator/configauditreport/conftest/coverage.txt
   test-helm-chart:
+    if: "false" # TODO It's broken on a release candidate PRs because it's using container image that has not been released yet.
     name: Test Helm Chart
     needs:
       - itest-starboard-cli
@@ -233,12 +234,12 @@ jobs:
         with:
           version: v3.5.0
       - name: Set up python
-        uses: actions/setup-python@0066b88440aa9562be742e2c60ee750fc57d8849 #v2.3.0
+        uses: actions/setup-python@f38219332975fe8f9c04cca981d674bf22aea1d3 #v2.3.0
         with:
           python-version: 3.7
       - name: Setup Chart Linting
         id: lint
-        uses: helm/chart-testing-action@5f16c27cf7a4fa9c776ff73734df3909b2b65127 #v2.1.0
+        uses: helm/chart-testing-action@6b64532d456fa490a3da177fbd181ac4c8192b58 #v2.1.0
       - name: Setup Kubernetes cluster (KIND)
         uses: helm/kind-action@94729529f85113b88f4f819c17ce61382e6d8478 #v1.2.0
         with:
diff --git a/.github/workflows/publish-docs.yaml b/.github/workflows/publish-docs.yaml
index 750925d..1d8069e 100644
--- a/.github/workflows/publish-docs.yaml
+++ b/.github/workflows/publish-docs.yaml
@@ -20,7 +20,7 @@ jobs:
           ref: ${{ github.event.inputs.ref }}
           fetch-depth: 0
           persist-credentials: true
-      - uses: actions/setup-python@v2
+      - uses: actions/setup-python@f38219332975fe8f9c04cca981d674bf22aea1d3
         with:
           python-version: 3.x
       - run: |
diff --git a/.github/workflows/publish-helm-chart.yaml b/.github/workflows/publish-helm-chart.yaml
index 59c5976..5c51ea4 100644
--- a/.github/workflows/publish-helm-chart.yaml
+++ b/.github/workflows/publish-helm-chart.yaml
@@ -29,12 +29,12 @@ jobs:
         with:
           version: v3.5.0
       - name: Set up python
-        uses: actions/setup-python@v2
+        uses: actions/setup-python@f38219332975fe8f9c04cca981d674bf22aea1d3
         with:
           python-version: 3.7
       - name: Setup Chart Linting
         id: lint
-        uses: helm/chart-testing-action@5f16c27cf7a4fa9c776ff73734df3909b2b65127  # v2.1.0
+        uses: helm/chart-testing-action@6b64532d456fa490a3da177fbd181ac4c8192b58  # v2.1.0
       - name: Setup Kubernetes cluster (KIND)
         uses: helm/kind-action@94729529f85113b88f4f819c17ce61382e6d8478  # v1.2.0
         with:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a93ed76..327f216 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -239,6 +239,7 @@ basic development workflow. For other install modes see [Operator Multitenancy w
      OPERATOR_VULNERABILITY_SCANNER_ENABLED=true \
      OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS=false \
      OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED=true \
+     OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL="" \
      OPERATOR_BATCH_DELETE_LIMIT=3 \
      OPERATOR_BATCH_DELETE_DELAY="30s" \
      go run cmd/starboard-operator/main.go
diff --git a/deploy/helm/Chart.yaml b/deploy/helm/Chart.yaml
index 05e72ea..1590694 100644
--- a/deploy/helm/Chart.yaml
+++ b/deploy/helm/Chart.yaml
@@ -6,12 +6,12 @@ type: application
 # This is the chart version. This version number should be incremented each time you make changes
 # to the chart and its templates, including the app version.
 # Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 0.8.3
+version: 0.9.0
 
 # This is the version number of the application being deployed. This version number should be
 # incremented each time you make changes to the application. Versions are not expected to
 # follow Semantic Versioning. They should reflect the version the application is using.
-appVersion: 0.13.2
+appVersion: 0.14.0-rc1
 
 # kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
 
diff --git a/deploy/helm/templates/config.yaml b/deploy/helm/templates/config.yaml
index e75f710..ac5387e 100644
--- a/deploy/helm/templates/config.yaml
+++ b/deploy/helm/templates/config.yaml
@@ -12,6 +12,9 @@ data:
   {{- with .Values.starboard.scanJobAnnotations }}
   scanJob.annotations: {{ . | quote }}
   {{- end }}
+  {{- with .Values.starboard.scanJobPodTemplateLabels }}
+  scanJob.podTemplateLabels: {{ . | quote }}
+  {{- end }}
   {{- if .Values.operator.vulnerabilityScannerEnabled }}
   vulnerabilityReports.scanner: {{ .Values.starboard.vulnerabilityReportsPlugin | quote }}
   {{- end }}
diff --git a/deploy/helm/templates/deployment.yaml b/deploy/helm/templates/deployment.yaml
index 1df47bc..d561ef6 100644
--- a/deploy/helm/templates/deployment.yaml
+++ b/deploy/helm/templates/deployment.yaml
@@ -75,10 +75,12 @@ spec:
               value: {{ .Values.operator.kubernetesBenchmarkEnabled | quote }}
             - name: OPERATOR_VULNERABILITY_SCANNER_ENABLED
               value: {{ .Values.operator.vulnerabilityScannerEnabled | quote }}
-            - name: OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED
-              value: {{ .Values.operator.configAuditScannerEnabled | quote }}
             - name: OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS
               value: {{ .Values.operator.vulnerabilityScannerScanOnlyCurrentRevisions | quote }}
+            - name: OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL
+              value: {{ .Values.operator.vulnerabilityScannerReportTTL | quote }}
+            - name: OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED
+              value: {{ .Values.operator.configAuditScannerEnabled | quote }}
             {{- if gt (int .Values.operator.replicas) 1 }}
             - name: OPERATOR_LEADER_ELECTION_ENABLED
               value: "true"
diff --git a/deploy/helm/values.yaml b/deploy/helm/values.yaml
index fc04c45..1fe08fa 100644
--- a/deploy/helm/values.yaml
+++ b/deploy/helm/values.yaml
@@ -35,6 +35,8 @@ operator:
 
   # vulnerabilityScannerEnabled the flag to enable vulnerability scanner
   vulnerabilityScannerEnabled: true
+  # vulnerabilityScannerReportTTL the flag to set how long a vulnerability report should exist. "" means that the vulnerabilityScannerReportTTL feature is disabled
+  vulnerabilityScannerReportTTL: ""
   # configAuditScannerEnabled the flag to enable configuration audit scanner
   configAuditScannerEnabled: true
   # kubernetesBenchmarkEnabled the flag to enable CIS Kubernetes Benchmark scanner
@@ -81,6 +83,10 @@ starboard:
   # annotated with. Example: `foo=bar,env=stage` will annotate the scanner pods with the annotations `foo: bar` and `env: stage`
   scanJobAnnotations: ""
 
+  # scanJobPodTemplateLabels comma-separated representation of the labels which the user wants the scanner pods to be
+  # labeled with. Example: `foo=bar,env=stage` will labeled the scanner pods with the labels `foo: bar` and `env: stage`
+  scanJobPodTemplateLabels: ""
+
 trivy:
   # createConfig indicates whether to create config objects
   createConfig: true
diff --git a/deploy/static/02-starboard-operator.rbac.yaml b/deploy/static/02-starboard-operator.rbac.yaml
index 9af85bb..c395f38 100644
--- a/deploy/static/02-starboard-operator.rbac.yaml
+++ b/deploy/static/02-starboard-operator.rbac.yaml
@@ -7,7 +7,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 ---
 apiVersion: rbac.authorization.k8s.io/v1
@@ -17,7 +17,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 rules:
   - apiGroups:
@@ -139,7 +139,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 roleRef:
   apiGroup: rbac.authorization.k8s.io
diff --git a/deploy/static/03-starboard-operator.config.yaml b/deploy/static/03-starboard-operator.config.yaml
index 1611278..90dc887 100644
--- a/deploy/static/03-starboard-operator.config.yaml
+++ b/deploy/static/03-starboard-operator.config.yaml
@@ -7,7 +7,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 ---
 apiVersion: v1
@@ -18,7 +18,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 ---
 apiVersion: v1
@@ -29,7 +29,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 data:
   vulnerabilityReports.scanner: "Trivy"
@@ -44,7 +44,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 data:
   trivy.imageRef: "docker.io/aquasec/trivy:0.20.0"
@@ -63,7 +63,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 data:
   polaris.imageRef: "quay.io/fairwinds/polaris:4.2"
diff --git a/deploy/static/04-starboard-operator.deployment.yaml b/deploy/static/04-starboard-operator.deployment.yaml
index c87fa9f..88293ca 100644
--- a/deploy/static/04-starboard-operator.deployment.yaml
+++ b/deploy/static/04-starboard-operator.deployment.yaml
@@ -7,7 +7,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
   annotations:
     prometheus.io/path: /metrics
@@ -30,7 +30,7 @@ metadata:
   labels:
     app.kubernetes.io/name: starboard-operator
     app.kubernetes.io/instance: starboard-operator
-    app.kubernetes.io/version: "0.13.2"
+    app.kubernetes.io/version: "0.14.0-rc1"
     app.kubernetes.io/managed-by: kubectl
 spec:
   replicas: 1
@@ -50,7 +50,7 @@ spec:
       automountServiceAccountToken: true
       containers:
         - name: "starboard-operator"
-          image: "docker.io/aquasec/starboard-operator:0.13.2"
+          image: "docker.io/aquasec/starboard-operator:0.14.0-rc1"
           imagePullPolicy: IfNotPresent
           env:
             - name: OPERATOR_NAMESPACE
@@ -79,10 +79,12 @@ spec:
               value: "true"
             - name: OPERATOR_VULNERABILITY_SCANNER_ENABLED
               value: "true"
-            - name: OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED
-              value: "true"
             - name: OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS
               value: "false"
+            - name: OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL
+              value: ""
+            - name: OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED
+              value: "true"
           ports:
             - name: metrics
               containerPort: 8080
diff --git a/docs/cli/getting-started.md b/docs/cli/getting-started.md
index 188f659..a1e7078 100644
--- a/docs/cli/getting-started.md
+++ b/docs/cli/getting-started.md
@@ -28,7 +28,13 @@ scans. It also sends custom security resources definitions to the Kubernetes API
 objects:
 
 ```console
-$ kubectl api-resources --api-group aquasecurity.github.io
+kubectl api-resources --api-group aquasecurity.github.io
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAME                          SHORTNAMES                 APIVERSION                        NAMESPACED   KIND
 ciskubebenchreports           kubebench                  aquasecurity.github.io/v1alpha1   false        CISKubeBenchReport
 clusterconfigauditreports     clusterconfigaudit         aquasecurity.github.io/v1alpha1   false        ClusterConfigAuditReport
@@ -37,6 +43,7 @@ configauditreports            configaudit                aquasecurity.github.io/
 kubehunterreports             kubehunter                 aquasecurity.github.io/v1alpha1   false        KubeHunterReport
 vulnerabilityreports          vuln,vulns                 aquasecurity.github.io/v1alpha1   true         VulnerabilityReport
 ```
+</details>
 
 !!! tip
     There's also a `starboard uninstall` subcommand, which can be used to remove all resources created by Starboard.
@@ -97,6 +104,22 @@ Retrieve the configuration audit report:
 starboard get configauditreports deployment/nginx -o yaml
 ```
 
+or
+
+```console
+kubectl get configauditreport -o wide \
+    -l starboard.resource.kind=Deployment,starboard.resource.name=nginx
+```
+
+<details>
+<summary>Result</summary>
+
+```
+NAME               SCANNER   AGE   DANGER   WARNING   PASS
+deployment-nginx   Polaris   5s    0        8         9
+```
+</details>
+
 ## Generating HTML Reports
 
 Once you scanned the `nginx` Deployment for vulnerabilities and checked its configuration you can generate an HTML
diff --git a/docs/design/README.md b/docs/design/README.md
index 63e5447..6079925 100644
--- a/docs/design/README.md
+++ b/docs/design/README.md
@@ -8,17 +8,17 @@ created for different purposes. Mainly to brainstorm how Starboard works.
 
 ## Overview
 
-| File  | Description |
-|-------|-------------|
-| [managing_access_to_security_reports.md] | Managing Access to Security Reports                                            |
-| [design_scan_by_image_digest.png]        | Design of vulnerability scanning by image digest (ContainerStatus vs PodSpec). |
-| [design_starboard_at_scale.png]          | Design of Starboard Operator at scale with more efficient worker queue.        |
-| [design_vulnerability_scanning_2.0.png]  | Design of most efficient vulnerability scanning that you can imagine.          |
-| [explain_starboard_rescan_jitter.png]    | Explain a preferred way to rescan (evenly distributed vs bursty events).       |
+| File                                     | Description                                                                             |
+|------------------------------------------|-----------------------------------------------------------------------------------------|
+| [design_trivy_file_system_scanner.md]    | Scan Container Images with Trivy Filesystem Scanner                                     |
+| [design_scan_by_image_digest.png]        | Design of vulnerability scanning by image digest (ContainerStatus vs PodSpec).          |
+| [design_starboard_at_scale.png]          | Design of Starboard Operator at scale with more efficient worker queue.                 |
+| [design_vulnerability_scanning_2.0.png]  | Design of most efficient vulnerability scanning that you can imagine.                   |
+| [explain_starboard_rescan_jitter.png]    | Explain a preferred way to rescan (evenly distributed vs bursty events).                |
 | [explain_starboard_cli_init.png]         | Explain which K8s API object are created when the `starboard init` command is executed. |
-| [design_namespace_security_report.pdf]   | Design of a security report generated by Starboard CLI for a given namespace.  |
+| [design_namespace_security_report.pdf]   | Design of a security report generated by Starboard CLI for a given namespace.           |
 
-[managing_access_to_security_reports.md]: ./managing_access_to_security_reports.md
+[design_trivy_file_system_scanner.md]: ./design_trivy_file_system_scanner.md
 [design_scan_by_image_digest.png]: ./design_scan_by_image_digest.png
 [design_starboard_at_scale.png]: ./design_starboard_at_scale.png
 [design_vulnerability_scanning_2.0.png]: ./design_vulnerability_scanning_2.0.png
diff --git a/docs/design/design_trivy_file_system_scanner.md b/docs/design/design_trivy_file_system_scanner.md
new file mode 100644
index 0000000..fe29407
--- /dev/null
+++ b/docs/design/design_trivy_file_system_scanner.md
@@ -0,0 +1,203 @@
+# Scan Container Images with Trivy Filesystem Scanner
+
+Authors: [Devendra Turkar], [Daniel Pacak]
+
+## Overview
+
+Starboard currently uses Trivy in [Standalone] or [ClientServer] mode to scan and generate VulnerabilityReports for
+container images by pulling the images from remote registries. Starboard scans a specified K8s workload by running the
+Trivy executable as a K8s Job. This approach implies that Trivy does not have access to images cached by the container
+runtime on cluster nodes. Therefore, to scan images from private registries Starboard reads ImagePullSecrets specified
+on workloads or on service accounts used by the workloads, and passes them down to Trivy executable as `TRIVY_USERNAME`
+and `TRIVY_PASSWORD` environment variables.
+
+Since ImagePullSecrets are not the only way to provide registry credential, the following alternatives are not
+currently supported by Starboard:
+1. Pre-pulled images
+2. [Configuring nodes to authenticate to a private registry]
+3. Vendor-specific or local extension. For example, methods described on [AWS ECR Private registry authentication].
+
+Even though we could resolve some of above-mentioned limitations with hostPath volume mounts to the container runtime
+socket, it would have its own disadvantages that we are trying to avoid. For example, more permissions to schedule scan
+Jobs and additional information about cluster's infrastructure such as location of the container runtime socket. 
+
+## Solution
+
+### TL;DR;
+
+Use Trivy filesystem scanning to scan container images. The main idea, which is discussed in this proposal, is to
+schedule a scan Job on the same cluster node where the scanned workload. This allows Trivy to scan a filesystem of
+the container image which is already cached on that node without pulling the image from a remote registry. What's more,
+Trivy will scan container images from private registries without providing registry credentials (as ImagePullSecret or
+in any other proprietary way).
+
+### Deep Dive
+
+To scan a container image of a given K8s workload Starboard will create a corresponding container of a scan Job and
+override its entrypoint to invoke Trivy filesystem scanner.
+
+This approach requires Trivy executable to be downloaded and made available to the entrypoint. We'll do that by adding
+the init container to the scan Job. Such init container will use the Trivy container image to copy Trivy executable out
+to the emptyDir volume, which will be shared with the other containers.
+
+Another init container is required to download Trivy vulnerability database and save it to the mounted shared volume.
+
+Finally, the scan container will use shared volume with the Trivy executable and Trivy database to perform the actual
+filesystem scan. (See the provided [Example](#example) to have a better idea of all containers defined by a scan Job and
+how they share data via the emptyDir volume.)
+
+> Note that the second init container is required in [Standalone] mode, which is the only mode supported by Trivy
+> filesystem scanner at the time of writing this proposal.
+
+We further restrict scan Jobs to run on the same node where scanned Pod is running and never pull images from remote
+registries by setting the `ImagePullPolicy` to `Never`. To determine the node for a scan Job Starboard will list active
+Pods controlled by the scanned workload. If the list is not empty it will take the node name from the first Pod,
+otherwise it will ignore the workload.
+
+### Example
+
+Let's assume that there's the `nginx` Deployment in the `poc-ns` namespace. It runs the `example.registry.com/nginx:1.16`
+container image from a private registry `example.registry.com`. Registry credentials are stored in the `private-registry`
+ImagePullSecret. (Alternatively, ImagePullSecret can be attached to a service account referred to by the Deployment.)
+
+```yaml
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  name: poc-ns
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  labels:
+    app: nginx
+  name: nginx
+  namespace: poc-ns
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: nginx
+  template:
+    metadata:
+      labels:
+        app: nginx
+    spec:
+      imagePullSecrets:
+        - name: private-registry
+      containers:
+        - name: nginx
+          image: example.registry.com/nginx:1.16
+``` 
+
+To scan the `nginx` container of the `nginx` Deployment, Starboard will create the following scan Job in the
+`starboard-system` namespace and observe it until it's Completed or Failed.
+
+```yaml
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: scan-vulnerabilityreport-ab3134
+  namespace: starboard-system
+spec:
+  backoffLimit: 0
+  template:
+    spec:
+      restartPolicy: Never
+      # Explicit nodeName indicates our intention to schedule a scan pod
+      # on the same cluster node where the nginx workload is running.
+      # This could also imply considering taints and tolerations and other
+      # properties respected by K8s scheduler.
+      nodeName: kind-control-plane
+      volumes:
+        - name: scan-volume
+          emptyDir: { }
+      initContainers:
+        # The trivy-get-binary init container is used to copy out the trivy executable
+        # binary from the upstream Trivy container image, i.e. aquasec/trivy:0.19.2,
+        # to a shared emptyDir volume.
+        - name: trivy-get-binary
+          image: aquasec/trivy:0.19.2
+          command:
+            - cp
+            - -v
+            - /usr/local/bin/trivy
+            - /var/starboard/trivy
+          volumeMounts:
+            - name: scan-volume
+              mountPath: /var/starboard
+        # The trivy-download-db container is using trivy executable binary
+        # from the previous step to download Trivy vulnerability database
+        # from GitHub releases page.
+        # This won't be required once Trivy supports ClientServer mode
+        # for the fs subcommand.
+        - name: trivy-download-db
+          image: aquasec/trivy:0.19.2
+          command:
+            - /var/starboard/trivy
+            - --download-db-only
+            - --cache-dir
+            - /var/starboard/trivy-db
+          volumeMounts:
+            - name: scan-volume
+              mountPath: /var/starboard
+      containers:
+        # The nginx container is based on the container image that
+        # we want to scan with Trivy. However, it has overwritten command (entrypoint)
+        # to invoke trivy file system scan. The scan results are output to stdout
+        # in JSON format, so we can parse them and store as VulnerabilityReport.
+        - name: nginx
+          image: example.registry.com/nginx:1.16
+          # To scan image layers cached on a cluster node without pulling
+          # it from a remote registry.
+          imagePullPolicy: Never
+          securityContext:
+            # Trivy must run as root, so we set UID here.
+            runAsUser: 0
+          command:
+            - /var/starboard/trivy
+            - --cache-dir
+            - /var/starboard/trivy-db
+            - fs
+            - --format
+            - json
+            - /
+          volumeMounts:
+            - name: scan-volume
+              mountPath: /var/starboard
+```
+
+Notice that the scan Job does not use registry credentials stored in the `private-registry` ImagePullSecret at all.
+Also, the `ImagePullPolicy` for the `nginx` container is set to `Never` to avoid pulling the image from the
+`example.registry.com/nginx` repository that requires authentication. And finally, the `nodeName` property is explicitly
+set to `kube-control-plane` to make sure that the scan Job is scheduled on the same node as a Pod controlled by the
+`nginx` Deployment. (We assumed that there was at least one Pod controlled by the `nginx` Deployment, and it was scheduled
+on the `kube-control-plane` node.)
+
+Trivy must run as root so the scan Job defined the `securityContext` with the `runAsUser` property set to `0` UID.
+
+## Remarks
+
+1. The proposed solution won't work with the [AlwaysPullImages] admission controller, which might be enabled in
+   a multitenant cluster so that users can be assured that their private images can only be used by those who
+   have the credentials to pull them. (Thanks [kfox1111] for pointing this out!)
+2. We cannot scan K8s workloads scaled down to 0 replicas because we cannot infer on which cluster node a scan Job should
+   run. (In general, a node name is only set on a running Pod.) But once a workload is scaled up, Starboard Operator
+   will receive the update event and will have another chance to scan it.
+3. It's hard to identify Pods managed by the CronJob controller, therefore we'll skip them.
+4. Trivy filesystem command does not work in [ClientServer] mode. Therefore, this solution is subject to the limits of
+   the [Standalone] mode. We plan to extend Trivy filesystem command to work in ClientServer mode and improve the
+   implementation of Starboard once it's available.
+5. Trivy must run as root and this may be blocked by some Admission Controllers such as PodSecurityPolicy.
+
+[Devendra Turkar]: https://github.com/deven0t
+[Daniel Pacak]: https://github.com/danielpacak
+[Standalone]: https://aquasecurity.github.io/starboard/v0.13.2/integrations/vulnerability-scanners/trivy/#standalone
+[ClientServer]: https://aquasecurity.github.io/starboard/v0.13.2/integrations/vulnerability-scanners/trivy/#clientserver
+[Configuring nodes to authenticate to a private registry]: https://kubernetes.io/docs/concepts/containers/images/#configuring-nodes-to-authenticate-to-a-private-registry
+[AWS ECR Private registry authentication]: https://docs.aws.amazon.com/AmazonECR/latest/userguide/registry_auth.html
+[AlwaysPullImages]: https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages
+[kfox1111]: https://github.com/kfox1111
+
diff --git a/docs/design/ttl_scans.md b/docs/design/ttl_scans.md
new file mode 100644
index 0000000..2ccd660
--- /dev/null
+++ b/docs/design/ttl_scans.md
@@ -0,0 +1,74 @@
+# TTL scans
+
+## Summary
+
+Add an option to automatically delete old security reports. In this first version focus on vulnerability reports but in the long run we could add similar functionality to other reports as well.
+
+## Motivation
+
+In [537](https://github.com/aquasecurity/starboard/issues/537) we talk about a need to run nightly vulnerability scans of CVE:s.
+This way we can make sure to get new CVE reports for long time running pods as well.
+
+## Proposal
+
+Add a environment variable to the operator, for example `OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL=86400`, this way we can add other ttl values for other reports as well.
+Adding this environment variable would add a annotation to the generated VulnerabilityReport that we can look for.
+
+Create a new controller that looks for changes in vulnerabilityreports and uses [RequeueAfter](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/reconcile#Result) calculated from the TTL annotation.
+At startup the operator will look through all existing vulnerabilityreports and delete existing ones where TTL have expired.
+If the TTL haven't expired the the vulnerabilityreports will be requeued and automatically checked again when the TTL have expired.
+
+We could calculate the ttl without having creating a new annotation to the reports but the verbosity of showing the users how long each report
+got a ttl outweighs the "issue" of generating a new annotation.
+
+### Example
+
+Below you can see a shortened version of the yaml. Notice the `metadata.annotations.starboard.aquasecurity.github.io/report-ttl` which is new.
+The operator would automatically apply the `starboard.aquasecurity.github.io/report-ttl` annotation to all new reports that it generates assuming that the environment variable is set.
+In theory users could also extend the TTL manually for a specific report by changing the starboard.aquasecurity.github.io/report-ttl annotation per VulnerabilityReport.
+
+```vulnerabilityReport.yaml
+apiVersion: aquasecurity.github.io/v1alpha1
+kind: VulnerabilityReport
+metadata:
+  creationTimestamp: "2021-12-08T12:03:48Z"
+  annotations:
+    starboard.aquasecurity.github.io/report-ttl: 24h
+  labels:
+    resource-spec-hash: 86b58dcb99
+    starboard.container.name: manager
+    starboard.resource.kind: ReplicaSet
+    starboard.resource.name: source-controller-b5d5cfdf4
+    starboard.resource.namespace: flux-system
+  name: replicaset-source-controller-b5d5cfdf4-manager
+report:
+  artifact:
+    repository: fluxcd/source-controller
+    tag: v0.16.1
+  registry:
+    server: ghcr.io
+  scanner:
+    name: Trivy
+    vendor: Aqua Security
+    version: 0.19.2
+  summary:
+    criticalCount: 0
+    highCount: 0
+    lowCount: 0
+    mediumCount: 0
+    unknownCount: 0
+  updateTimestamp: "2021-12-08T12:03:48Z"
+  vulnerabilities: []
+```
+
+Another option is to define a new report entry, the positive thing with that is that we can define the input type, in our case a `time.Duration`.
+
+## Alternatives
+
+Another "simpler" option could be to add the same environment variable `OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL=2h` but instead of using RequeueAfter in the controller we could create a cronjob/job that runs once an hour and check for the same annotation.
+
+The bad thing hear is that we would have to manage yet another cronjob/job. We would also have to mange a new binary feature flag to run in cronjob cleanup mode.
+It would also trigger removal of multiple reports at the same time, compared to the event driven solution that would be much more precise per report
+and thus spreading out the new reports more.
+
+But the good thing is that everyone knows how jobs/cronjobs works especially since it's already well used within the starboard operator.
diff --git a/docs/operator/configuration.md b/docs/operator/configuration.md
index c82e034..6de9d3f 100644
--- a/docs/operator/configuration.md
+++ b/docs/operator/configuration.md
@@ -1,24 +1,25 @@
 Configuration of the operator's Pod is done via environment variables at startup.
 
-| NAME                                                         | DEFAULT              | DESCRIPTION                                                                                                                   |
-| ------------------------------------------------------------ | -------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
-| `OPERATOR_NAMESPACE`                                         | N/A                  | See [Install modes](#install-modes)                                                                                           |
-| `OPERATOR_TARGET_NAMESPACES`                                 | N/A                  | See [Install modes](#install-modes)                                                                                           |
-| `OPERATOR_SERVICE_ACCOUNT`                                   | `starboard-operator` | The name of the service account assigned to the operator's pod                                                                |
-| `OPERATOR_LOG_DEV_MODE`                                      | `false`              | The flag to use (or not use) development mode (more human-readable output, extra stack traces and logging information, etc).  |
-| `OPERATOR_SCAN_JOB_TIMEOUT`                                  | `5m`                 | The length of time to wait before giving up on a scan job                                                                     |
-| `OPERATOR_CONCURRENT_SCAN_JOBS_LIMIT`                        | `10`                 | The maximum number of scan jobs create by the operator                                                                        |
-| `OPERATOR_SCAN_JOB_RETRY_AFTER`                              | `30s`                | The duration to wait before retrying a failed scan job                                                                        |
-| `OPERATOR_BATCH_DELETE_LIMIT`                                | `10`                 | The maximum number of config audit reports deleted by the operator when the plugin's config has changed.                      |
-| `OPERATOR_BATCH_DELETE_DELAY`                                | `10s`                | The duration to wait before deleting another batch of config audit reports.                                                   |
-| `OPERATOR_METRICS_BIND_ADDRESS`                              | `:8080`              | The TCP address to bind to for serving [Prometheus][prometheus] metrics. It can be set to `0` to disable the metrics serving. |
-| `OPERATOR_HEALTH_PROBE_BIND_ADDRESS`                         | `:9090`              | The TCP address to bind to for serving health probes, i.e. `/healthz/` and `/readyz/` endpoints.                              |
-| `OPERATOR_CIS_KUBERNETES_BENCHMARK_ENABLED`                  | `true`               | The flag to enable CIS Kubernetes Benchmark scanner                                                                           |
-| `OPERATOR_VULNERABILITY_SCANNER_ENABLED`                     | `true`               | The flag to enable vulnerability scanner                                                                                      |
-| `OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED`                      | `true`               | The flag to enable configuration audit scanner                                                                                |
-| `OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS` | `false`              | The flag to enable vulnerability scanner to only scan the current revision of a deployment                                    |
-| `OPERATOR_LEADER_ELECTION_ENABLED`                           | `false`              | The flag to enable operator replica leader election                                                                           |
-| `OPERATOR_LEADER_ELECTION_ID`                                | `starboard-lock`     | The name of the resource lock for leader election                                                                             |
+| NAME                                                         | DEFAULT              | DESCRIPTION                                                                                                                                                                                                  |
+| ------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `OPERATOR_NAMESPACE`                                         | N/A                  | See [Install modes](#install-modes)                                                                                                                                                                          |
+| `OPERATOR_TARGET_NAMESPACES`                                 | N/A                  | See [Install modes](#install-modes)                                                                                                                                                                          |
+| `OPERATOR_SERVICE_ACCOUNT`                                   | `starboard-operator` | The name of the service account assigned to the operator's pod                                                                                                                                               |
+| `OPERATOR_LOG_DEV_MODE`                                      | `false`              | The flag to use (or not use) development mode (more human-readable output, extra stack traces and logging information, etc).                                                                                 |
+| `OPERATOR_SCAN_JOB_TIMEOUT`                                  | `5m`                 | The length of time to wait before giving up on a scan job                                                                                                                                                    |
+| `OPERATOR_CONCURRENT_SCAN_JOBS_LIMIT`                        | `10`                 | The maximum number of scan jobs create by the operator                                                                                                                                                       |
+| `OPERATOR_SCAN_JOB_RETRY_AFTER`                              | `30s`                | The duration to wait before retrying a failed scan job                                                                                                                                                       |
+| `OPERATOR_BATCH_DELETE_LIMIT`                                | `10`                 | The maximum number of config audit reports deleted by the operator when the plugin's config has changed.                                                                                                     |
+| `OPERATOR_BATCH_DELETE_DELAY`                                | `10s`                | The duration to wait before deleting another batch of config audit reports.                                                                                                                                  |
+| `OPERATOR_METRICS_BIND_ADDRESS`                              | `:8080`              | The TCP address to bind to for serving [Prometheus][prometheus] metrics. It can be set to `0` to disable the metrics serving.                                                                                |
+| `OPERATOR_HEALTH_PROBE_BIND_ADDRESS`                         | `:9090`              | The TCP address to bind to for serving health probes, i.e. `/healthz/` and `/readyz/` endpoints.                                                                                                             |
+| `OPERATOR_CIS_KUBERNETES_BENCHMARK_ENABLED`                  | `true`               | The flag to enable CIS Kubernetes Benchmark scanner                                                                                                                                                          |
+| `OPERATOR_VULNERABILITY_SCANNER_ENABLED`                     | `true`               | The flag to enable vulnerability scanner                                                                                                                                                                     |
+| `OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED`                      | `true`               | The flag to enable configuration audit scanner                                                                                                                                                               |
+| `OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS` | `false`              | The flag to enable vulnerability scanner to only scan the current revision of a deployment                                                                                                                   |
+| `OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL`                  | `""`                 | The flag to set how long a vulnerability report should exist. When a old report is deleted a new one will be created by the controller. It can be set to `""` to disabled the TTL for vulnerability scanner. |
+| `OPERATOR_LEADER_ELECTION_ENABLED`                           | `false`              | The flag to enable operator replica leader election                                                                                                                                                          |
+| `OPERATOR_LEADER_ELECTION_ID`                                | `starboard-lock`     | The name of the resource lock for leader election                                                                                                                                                            |
 
 ## Install Modes
 
diff --git a/docs/operator/getting-started.md b/docs/operator/getting-started.md
index fadf401..6512b8d 100644
--- a/docs/operator/getting-started.md
+++ b/docs/operator/getting-started.md
@@ -27,37 +27,63 @@ It also creates the Job to audit the Deployment's configuration for common pitfa
 container as root:
 
 ```console
-$ kubectl get job -n starboard-system
+kubectl get job -n starboard-operator
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAME                                 COMPLETIONS   DURATION   AGE
 scan-configauditreport-c4956cb9d     0/1           1s         1s
 scan-vulnerabilityreport-c4956cb9d   0/1           1s         1s
 ```
 
+</details>
+
 If everything goes fine, the scan Jobs are deleted, and the operator saves scan reports as custom resources in the
 `default` namespace, named after the Deployment's active ReplicaSet. For image vulnerability scans, the operator creates
 a VulnerabilityReport for each different container defined in the active ReplicaSet. In this example there is just one
 container image called `nginx`:
 
 ```console
-$ kubectl get vulnerabilityreports -o wide
+kubectl get vulnerabilityreports -o wide
+```
+<details>
+<summary>Result</summary>
+
+```
 NAME                                REPOSITORY      TAG    SCANNER   AGE   CRITICAL   HIGH   MEDIUM   LOW   UNKNOWN
 replicaset-nginx-7ff78f74b9-nginx   library/nginx   1.16   Trivy     12s   4          40     26       90    0
 ```
+</details>
 
 Similarly, the operator creates a ConfigAuditReport holding the result of auditing the configuration of the active
 ReplicaSet controlled by the `nginx` Deployment:
 
 ```console
-$ kubectl get configauditreports -o wide
+kubectl get configauditreports -o wide
+```
+<details>
+<summary>Result</summary>
+
+```
 NAME                          SCANNER   AGE   DANGER   WARNING   PASS
 replicaset-nginx-7ff78f74b9   Polaris   33s   1        9         7
 ```
+</details>
 
 Notice that scan reports generated by the operator are controlled by Kubernetes workloads. In our example,
 VulnerabilityReport and ConfigAuditReport objects are controlled by the active ReplicaSet of the `nginx` Deployment:
 
 ```console
-$ kubectl tree deploy nginx
+kubectl tree deploy nginx
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAMESPACE  NAME                                                       READY  REASON  AGE
 default    Deployment/nginx                                           -              51s
 default    └─ReplicaSet/nginx-6d4cf56db6                              -              51s
@@ -65,6 +91,7 @@ default      ├─ConfigAuditReport/replicaset-nginx-6d4cf56db6          -
 default      ├─VulnerabilityReport/replicaset-nginx-6d4cf56db6-nginx  -              31s
 default      └─Pod/nginx-6d4cf56db6-fhbm9                             True           51s
 ```
+</details>
 
 !!! note
     The [tree] command is a kubectl plugin to browse Kubernetes object hierarchies as a tree.
@@ -79,7 +106,13 @@ kubectl set image deployment nginx nginx=nginx:1.17
 Even this time the operator will pick up changes and rescan our Deployment with updated configuration:
 
 ```console
-$ kubectl tree deploy nginx
+kubectl tree deploy nginx
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAMESPACE  NAME                                                       READY  REASON  AGE
 default    Deployment/nginx                                           -              86s
 default    ├─ReplicaSet/nginx-6d4cf56db6                              -              86s
@@ -90,6 +123,7 @@ default      ├─ConfigAuditReport/replicaset-nginx-db749865c           -
 default      ├─VulnerabilityReport/replicaset-nginx-db749865c-nginx   -              9s
 default      └─Pod/nginx-db749865c-lfcp5                              True           19s
 ```
+</details>
 
 By following this guide you could realize that the operator knows how to attach VulnerabilityReport and
 ConfigAuditReport objects to build-in Kubernetes objects so that looking them up is easy. What's more, in this
@@ -116,7 +150,13 @@ kubectl scale deploy nginx --replicas 3
 ```
 
 ```console
-$ kubectl tree deploy nginx
+kubectl tree deploy nginx
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAMESPACE  NAME                                                       READY  REASON  AGE
 default    Deployment/nginx                                           -              2m22s
 default    ├─ReplicaSet/nginx-6d4cf56db6                              -              2m22s
@@ -129,6 +169,7 @@ default      ├─Pod/nginx-db749865c-lfcp5                              True
 default      ├─Pod/nginx-db749865c-tn5k7                              True           12s
 default      └─Pod/nginx-db749865c-vjlr9                              True           12s
 ```
+</details>
 
 Finally, when you delete the `nginx` Deployment, orphaned security reports will be deleted in the background by the
 Kubernetes garbage collection controller.
@@ -138,13 +179,27 @@ kubectl delete deploy nginx
 ```
 
 ```console
-$ kubectl get vuln,configaudit
+kubectl get vuln,configaudit
+```
+
+<details>
+<summary>Result</summary>
+
+```
 No resources found in default namespace.
 ```
+</details>
 
 !!! Tip
     Use `vuln` and `configaudit` as short names for `vulnerabilityreports` and `configauditreports` resources.
 
+To be sure that your vulnerabilityreports is is up to date with the latest CVE:s you can define
+how long your vulnerabilityreports should be in the cluster before automatically getting deleted.
+For example setting `OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL=24h` would delete the report after 24 hours.
+When the vulnerabilityreports gets deleted starboard will automatically create a new job and scan the images again.
+Assuming that your image scan solution have updated it's DB the new vulnerabilityreports that gets created will contain the latest CVE:s.
+This feature is disabled by default.
+
 ## Infrastructure Scanning
 
 The operator discovers also Kubernetes nodes and runs CIS Kubernetes Benchmark checks on each of them. The results are
@@ -152,25 +207,45 @@ stored as CISKubeBenchReport objects. In other words, for a cluster with 3 nodes
 3 benchmark reports:
 
 ```console
-$ kubectl get node
+kubectl get node
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAME                 STATUS   ROLES    AGE     VERSION
 kind-control-plane   Ready    master   3h27m   v1.18.8
 kind-worker          Ready    <none>   3h26m   v1.18.8
 kind-worker2         Ready    <none>   3h26m   v1.18.8
 ```
+</details>
 
 ```console
-$ kubectl get ciskubebenchreports -o wide
+kubectl get ciskubebenchreports -o wide
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAME                 SCANNER      AGE   FAIL   WARN   INFO   PASS
 kind-control-plane   kube-bench   8s    12     40     0      70
 kind-worker          kube-bench   9s    2      27     0      18
 kind-worker2         kube-bench   9s    2      27     0      18
 ```
+</details>
 
 Notice that each CISKubeBenchReport is named after a node and is controlled by that node to inherit its life cycle:
 
 ```console
-$ kubectl tree node kind-control-plane -A
+kubectl tree node kind-control-plane -A
+```
+
+<details>
+<summary>Result</summary>
+
+```
 NAMESPACE        NAME                                              READY  REASON        AGE
                  Node/kind-control-plane                           True   KubeletReady  48m
                  ├─CISKubeBenchReport/kind-control-plane           -                    44m
@@ -181,6 +256,7 @@ kube-system      ├─Pod/kube-apiserver-kind-control-plane           True
 kube-system      ├─Pod/kube-controller-manager-kind-control-plane  True                 48m
 kube-system      └─Pod/kube-scheduler-kind-control-plane           True                 48m
 ```
+</details>
 
 ## What's Next?
 
diff --git a/docs/settings.md b/docs/settings.md
index c019cf1..7a96e66 100644
--- a/docs/settings.md
+++ b/docs/settings.md
@@ -58,6 +58,7 @@ configuration settings for common use cases. For example, switch Trivy from [Sta
 | `configAuditReports.scanner`   | `Polaris`                             | The name of the plugin that generates config audit reports. Either `Polaris` or `Conftest`. |
 | `scanJob.tolerations`          | N/A                                   | JSON representation of the [tolerations] to be applied to the scanner pods so that they can run on nodes with matching taints. Example: `'[{"key":"key1", "operator":"Equal", "value":"value1", "effect":"NoSchedule"}]'` |
 | `scanJob.annotations`          | N/A                                   | One-line comma-separated representation of the annotations which the user wants the scanner pods to be annotated with. Example: `foo=bar,env=stage` will annotate the scanner pods with the annotations `foo: bar` and `env: stage` |
+| `scanJob.templateLabel`        | N/A                                   | One-line comma-separated representation of the template labels which the user wants the scanner pods to be labeled with. Example: `foo=bar,env=stage` will labeled the scanner pods with the labels `foo: bar` and `env: stage` |
 | `kube-bench.imageRef`          | `docker.io/aquasec/kube-bench:v0.6.5`  | kube-bench image reference |
 | `kube-hunter.imageRef`         | `docker.io/aquasec/kube-hunter:0.6.3` | kube-hunter image reference |
 | `kube-hunter.quick`            | `"false"`                             | Whether to use kube-hunter's "quick" scanning mode (subnet 24). Set to `"true"` to enable. |
diff --git a/go.mod b/go.mod
index c1eb26c..34f758f 100644
--- a/go.mod
+++ b/go.mod
@@ -6,9 +6,9 @@ require (
 	github.com/caarlos0/env/v6 v6.9.1
 	github.com/davecgh/go-spew v1.1.1
 	github.com/go-logr/logr v0.4.0
-	github.com/google/go-containerregistry v0.7.0
+	github.com/google/go-containerregistry v0.8.0
 	github.com/google/uuid v1.3.0
-	github.com/hashicorp/go-version v1.3.0
+	github.com/hashicorp/go-version v1.4.0
 	github.com/onsi/ginkgo v1.16.5
 	github.com/onsi/gomega v1.17.0
 	github.com/spf13/cobra v1.3.0
diff --git a/go.sum b/go.sum
index 0e66b80..feab76a 100644
--- a/go.sum
+++ b/go.sum
@@ -92,7 +92,7 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
 github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
 github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
 github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
-github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
 github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
 github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
 github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
@@ -132,7 +132,6 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
 github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
 github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
 github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
-github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
 github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
@@ -143,6 +142,7 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq
 github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
 github.com/caarlos0/env/v6 v6.9.1 h1:zOkkjM0F6ltnQ5eBX6IPI41UP/KDGEK7rRPwGCNos8k=
 github.com/caarlos0/env/v6 v6.9.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc=
+github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@@ -206,12 +206,12 @@ github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMX
 github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
 github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
 github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
 github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
 github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
 github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
 github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
-github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
-github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
+github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
 github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
 github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
 github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
@@ -239,12 +239,13 @@ github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJ
 github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
 github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
 github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
-github.com/containerd/stargz-snapshotter/estargz v0.10.0/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
+github.com/containerd/stargz-snapshotter/estargz v0.10.1/go.mod h1:aE5PCyhFMwR8sbrErO5eM2GcvkyXTTJremG883D4qF0=
 github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
 github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
 github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
 github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
 github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
 github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
 github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
 github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
@@ -298,11 +299,11 @@ github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
-github.com/docker/cli v20.10.10+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v20.10.12+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY=
 github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v20.10.10+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c=
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
@@ -452,8 +453,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-containerregistry v0.7.0 h1:u0onUUOcyoCDHEiJoyR1R1gx5er1+r06V5DBhUU5ndk=
-github.com/google/go-containerregistry v0.7.0/go.mod h1:2zaoelrL0d08gGbpdP3LqyUuBmhWbpD6IOe2s9nLS2k=
+github.com/google/go-containerregistry v0.8.0 h1:mtR24eN6rapCN+shds82qFEIWWmg64NPMuyCNT7/Ogc=
+github.com/google/go-containerregistry v0.8.0/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -532,8 +533,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
 github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
 github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
-github.com/hashicorp/go-version v1.3.0 h1:McDWVJIU/y+u1BRV06dPaLfLCaT7fUTJLp5r04x7iNw=
-github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4=
+github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -648,7 +649,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
 github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
@@ -657,6 +657,7 @@ github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2J
 github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
 github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
 github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
 github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
@@ -708,7 +709,7 @@ github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/image-spec v1.0.2-0.20210730191737-8e42a01fb1b7/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
 github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
 github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
 github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
@@ -730,7 +731,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI
 github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
-github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
@@ -815,13 +815,11 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd
 github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
 github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
-github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
 github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0=
 github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
@@ -834,7 +832,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
 github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
-github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
 github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
 github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
 github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
@@ -893,6 +890,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
 github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
@@ -1002,8 +1000,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
 golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
+golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1061,8 +1060,9 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
 golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211111160137-58aab5ef257a h1:c83jeVQW0KGKNaKBRfelNYNHaev+qawl9yaA825s8XE=
-golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
+golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1074,7 +1074,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
 golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
 golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
@@ -1197,10 +1196,11 @@ golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
 golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
@@ -1285,8 +1285,9 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
+golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1316,7 +1317,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q
 google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
 google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
 google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
-google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
 google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
 google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
 google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
@@ -1400,7 +1400,6 @@ google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEc
 google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211111162719-482062a4217b/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
 google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
@@ -1437,6 +1436,7 @@ google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1468,7 +1468,6 @@ gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKW
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
diff --git a/mkdocs.yml b/mkdocs.yml
index 06ce1f3..c471ab7 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -89,8 +89,8 @@ extra:
   version:
     provider: mike
   var:
-    prev_git_tag: "v0.13.1"
-    chart_version: 0.8.2
+    prev_git_tag: "v0.13.2"
+    chart_version: 0.9.0
 
 # Requires pip install mkdocs-macros-plugin
 plugins:
diff --git a/pkg/apis/aquasecurity/v1alpha1/common_types.go b/pkg/apis/aquasecurity/v1alpha1/common_types.go
index 8dbcffc..ba4cd72 100644
--- a/pkg/apis/aquasecurity/v1alpha1/common_types.go
+++ b/pkg/apis/aquasecurity/v1alpha1/common_types.go
@@ -1,5 +1,9 @@
 package v1alpha1
 
+const (
+	TTLReportAnnotation = "starboard.aquasecurity.github.io/report-ttl"
+)
+
 // Scanner is the spec for a scanner generating a security assessment report.
 type Scanner struct {
 	// Name the name of the scanner.
diff --git a/pkg/cmd/commands.go b/pkg/cmd/commands.go
index 932c5ab..03fa6de 100644
--- a/pkg/cmd/commands.go
+++ b/pkg/cmd/commands.go
@@ -20,7 +20,7 @@ func SetGlobalFlags(cf *genericclioptions.ConfigFlags, cmd *cobra.Command) {
 	}
 }
 
-func WorkloadFromArgs(mapper meta.RESTMapper, namespace string, args []string) (workload kube.Object, gvk schema.GroupVersionKind, err error) {
+func WorkloadFromArgs(mapper meta.RESTMapper, namespace string, args []string) (workload kube.ObjectRef, gvk schema.GroupVersionKind, err error) {
 	if len(args) < 1 {
 		err = errors.New("required workload kind and name not specified")
 		return
@@ -44,7 +44,7 @@ func WorkloadFromArgs(mapper meta.RESTMapper, namespace string, args []string) (
 		err = errors.New("required workload name is blank")
 		return
 	}
-	workload = kube.Object{
+	workload = kube.ObjectRef{
 		Namespace: namespace,
 		Kind:      kube.Kind(gvk.Kind),
 		Name:      resourceName,
diff --git a/pkg/configauditreport/builder.go b/pkg/configauditreport/builder.go
index a6cda7c..0517a9e 100644
--- a/pkg/configauditreport/builder.go
+++ b/pkg/configauditreport/builder.go
@@ -12,6 +12,7 @@ import (
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/validation"
 	"k8s.io/utils/pointer"
@@ -20,12 +21,13 @@ import (
 )
 
 type ScanJobBuilder struct {
-	plugin        Plugin
-	pluginContext starboard.PluginContext
-	timeout       time.Duration
-	object        client.Object
-	tolerations   []corev1.Toleration
-	annotations   map[string]string
+	plugin            Plugin
+	pluginContext     starboard.PluginContext
+	timeout           time.Duration
+	object            client.Object
+	tolerations       []corev1.Toleration
+	annotations       map[string]string
+	podTemplateLabels labels.Set
 }
 
 func NewScanJobBuilder() *ScanJobBuilder {
@@ -62,6 +64,11 @@ func (s *ScanJobBuilder) WithAnnotations(annotations map[string]string) *ScanJob
 	return s
 }
 
+func (s *ScanJobBuilder) WithPodTemplateLabels(podTemplateLabels labels.Set) *ScanJobBuilder {
+	s.podTemplateLabels = podTemplateLabels
+	return s
+}
+
 func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 	jobSpec, secrets, err := s.plugin.GetScanJobSpec(s.pluginContext, s.object)
 	if err != nil {
@@ -80,18 +87,26 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 		return nil, nil, err
 	}
 
-	labels := map[string]string{
+	labelsSet := labels.Set{
 		starboard.LabelResourceSpecHash:         resourceSpecHash,
 		starboard.LabelPluginConfigHash:         pluginConfigHash,
 		starboard.LabelConfigAuditReportScanner: s.pluginContext.GetName(),
 		starboard.LabelK8SAppManagedBy:          starboard.AppStarboard,
 	}
 
+	podTemplateLabelsSet := make(labels.Set)
+	for index, element := range labelsSet {
+		podTemplateLabelsSet[index] = element
+	}
+	for index, element := range s.podTemplateLabels {
+		podTemplateLabelsSet[index] = element
+	}
+
 	job := &batchv1.Job{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:        GetScanJobName(s.object),
 			Namespace:   s.pluginContext.GetNamespace(),
-			Labels:      labels,
+			Labels:      labelsSet,
 			Annotations: s.annotations,
 		},
 		Spec: batchv1.JobSpec{
@@ -100,7 +115,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 			ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.timeout),
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
-					Labels:      labels,
+					Labels:      podTemplateLabelsSet,
 					Annotations: s.annotations,
 				},
 				Spec: jobSpec,
@@ -122,7 +137,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 		if secret.Labels == nil {
 			secret.Labels = make(map[string]string)
 		}
-		for k, v := range labels {
+		for k, v := range labelsSet {
 			secret.Labels[k] = v
 		}
 		err = kube.ObjectToObjectMetadata(s.object, &secret.ObjectMeta)
@@ -132,7 +147,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 }
 
 func GetScanJobName(obj client.Object) string {
-	return fmt.Sprintf("scan-configauditreport-%s", kube.ComputeHash(kube.Object{
+	return fmt.Sprintf("scan-configauditreport-%s", kube.ComputeHash(kube.ObjectRef{
 		Kind:      kube.Kind(obj.GetObjectKind().GroupVersionKind().Kind),
 		Namespace: obj.GetNamespace(),
 		Name:      obj.GetName(),
@@ -184,18 +199,18 @@ func (b *ReportBuilder) reportName() string {
 }
 
 func (b *ReportBuilder) GetClusterReport() (v1alpha1.ClusterConfigAuditReport, error) {
-	labels := make(map[string]string)
+	labelsSet := make(labels.Set)
 	if b.resourceSpecHash != "" {
-		labels[starboard.LabelResourceSpecHash] = b.resourceSpecHash
+		labelsSet[starboard.LabelResourceSpecHash] = b.resourceSpecHash
 	}
 	if b.pluginConfigHash != "" {
-		labels[starboard.LabelPluginConfigHash] = b.pluginConfigHash
+		labelsSet[starboard.LabelPluginConfigHash] = b.pluginConfigHash
 	}
 
 	report := v1alpha1.ClusterConfigAuditReport{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:   b.reportName(),
-			Labels: labels,
+			Labels: labelsSet,
 		},
 		Report: b.data,
 	}
@@ -220,19 +235,19 @@ func (b *ReportBuilder) GetClusterReport() (v1alpha1.ClusterConfigAuditReport, e
 }
 
 func (b *ReportBuilder) GetReport() (v1alpha1.ConfigAuditReport, error) {
-	labels := make(map[string]string)
+	labelsSet := make(labels.Set)
 	if b.resourceSpecHash != "" {
-		labels[starboard.LabelResourceSpecHash] = b.resourceSpecHash
+		labelsSet[starboard.LabelResourceSpecHash] = b.resourceSpecHash
 	}
 	if b.pluginConfigHash != "" {
-		labels[starboard.LabelPluginConfigHash] = b.pluginConfigHash
+		labelsSet[starboard.LabelPluginConfigHash] = b.pluginConfigHash
 	}
 
 	report := v1alpha1.ConfigAuditReport{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      b.reportName(),
 			Namespace: b.controller.GetNamespace(),
-			Labels:    labels,
+			Labels:    labelsSet,
 		},
 		Report: b.data,
 	}
diff --git a/pkg/configauditreport/io.go b/pkg/configauditreport/io.go
index d4dd092..cb173ce 100644
--- a/pkg/configauditreport/io.go
+++ b/pkg/configauditreport/io.go
@@ -28,18 +28,18 @@ type Writer interface {
 type Reader interface {
 
 	// FindReportByOwner returns a v1alpha1.ConfigAuditReport owned by the given
-	// kube.Object or nil if the report is not found.
-	FindReportByOwner(ctx context.Context, owner kube.Object) (*v1alpha1.ConfigAuditReport, error)
+	// kube.ObjectRef or nil if the report is not found.
+	FindReportByOwner(ctx context.Context, owner kube.ObjectRef) (*v1alpha1.ConfigAuditReport, error)
 
-	// FindReportByOwnerInHierarchy is similar to FindReportByOwner except that it tries to lookup
+	// FindReportByOwnerInHierarchy is similar to FindReportByOwner except that it tries to find
 	// a v1alpha1.ConfigAuditReport object owned by related Kubernetes objects.
 	// For example, if the given owner is a Deployment, but a report is owned by the
 	// active ReplicaSet (current revision) this method will return the report.
-	FindReportByOwnerInHierarchy(ctx context.Context, owner kube.Object) (*v1alpha1.ConfigAuditReport, error)
+	FindReportByOwnerInHierarchy(ctx context.Context, owner kube.ObjectRef) (*v1alpha1.ConfigAuditReport, error)
 
 	// FindClusterReportByOwner returns a v1alpha1.ClusterConfigAuditReport owned by the given
-	// kube.Object or nil if the report is not found.
-	FindClusterReportByOwner(ctx context.Context, owner kube.Object) (*v1alpha1.ClusterConfigAuditReport, error)
+	// kube.ObjectRef or nil if the report is not found.
+	FindClusterReportByOwner(ctx context.Context, owner kube.ObjectRef) (*v1alpha1.ClusterConfigAuditReport, error)
 }
 
 type ReadWriter interface {
@@ -103,10 +103,10 @@ func (r *readWriter) WriteClusterReport(ctx context.Context, report v1alpha1.Clu
 	return err
 }
 
-func (r *readWriter) FindReportByOwner(ctx context.Context, owner kube.Object) (*v1alpha1.ConfigAuditReport, error) {
+func (r *readWriter) FindReportByOwner(ctx context.Context, owner kube.ObjectRef) (*v1alpha1.ConfigAuditReport, error) {
 	var list v1alpha1.ConfigAuditReportList
 
-	labels := client.MatchingLabels(kube.PartialObjectToLabels(owner))
+	labels := client.MatchingLabels(kube.ObjectRefToLabels(owner))
 
 	err := r.List(ctx, &list, labels, client.InNamespace(owner.Namespace))
 	if err != nil {
@@ -120,7 +120,7 @@ func (r *readWriter) FindReportByOwner(ctx context.Context, owner kube.Object) (
 	return nil, nil
 }
 
-func (r *readWriter) FindReportByOwnerInHierarchy(ctx context.Context, owner kube.Object) (*v1alpha1.ConfigAuditReport, error) {
+func (r *readWriter) FindReportByOwnerInHierarchy(ctx context.Context, owner kube.ObjectRef) (*v1alpha1.ConfigAuditReport, error) {
 	report, err := r.FindReportByOwner(ctx, owner)
 	if err != nil {
 		return nil, err
@@ -132,7 +132,7 @@ func (r *readWriter) FindReportByOwnerInHierarchy(ctx context.Context, owner kub
 		if err != nil {
 			return nil, fmt.Errorf("getting replicaset related to %s/%s: %w", owner.Kind, owner.Name, err)
 		}
-		report, err = r.FindReportByOwner(ctx, kube.Object{
+		report, err = r.FindReportByOwner(ctx, kube.ObjectRef{
 			Kind:      kube.KindReplicaSet,
 			Name:      rsName,
 			Namespace: owner.Namespace,
@@ -146,10 +146,10 @@ func (r *readWriter) FindReportByOwnerInHierarchy(ctx context.Context, owner kub
 	return nil, nil
 }
 
-func (r *readWriter) FindClusterReportByOwner(ctx context.Context, owner kube.Object) (*v1alpha1.ClusterConfigAuditReport, error) {
+func (r *readWriter) FindClusterReportByOwner(ctx context.Context, owner kube.ObjectRef) (*v1alpha1.ClusterConfigAuditReport, error) {
 	var list v1alpha1.ClusterConfigAuditReportList
 
-	labels := client.MatchingLabels(kube.PartialObjectToLabels(owner))
+	labels := client.MatchingLabels(kube.ObjectRefToLabels(owner))
 
 	err := r.List(ctx, &list, labels)
 	if err != nil {
diff --git a/pkg/configauditreport/scanner.go b/pkg/configauditreport/scanner.go
index 82ed502..32e0c08 100644
--- a/pkg/configauditreport/scanner.go
+++ b/pkg/configauditreport/scanner.go
@@ -45,11 +45,11 @@ func NewScanner(
 	}
 }
 
-func (s *Scanner) Scan(ctx context.Context, partial kube.Object) (*ReportBuilder, error) {
+func (s *Scanner) Scan(ctx context.Context, partial kube.ObjectRef) (*ReportBuilder, error) {
 	if !s.supportsKind(partial.Kind) {
 		return nil, fmt.Errorf("kind %s is not supported by %s plugin", partial.Kind, s.pluginContext.GetName())
 	}
-	obj, err := s.objectResolver.GetObjectFromPartialObject(ctx, partial)
+	obj, err := s.objectResolver.ObjectFromObjectRef(ctx, partial)
 	if err != nil {
 		return nil, err
 	}
@@ -77,6 +77,11 @@ func (s *Scanner) Scan(ctx context.Context, partial kube.Object) (*ReportBuilder
 		return nil, fmt.Errorf("getting scan job annotations: %w", err)
 	}
 
+	scanJobPodTemplateLabels, err := s.config.GetScanJobPodTemplateLabels()
+	if err != nil {
+		return nil, fmt.Errorf("getting scan job template labels: %w", err)
+	}
+
 	klog.V(3).Infof("Scanning with options: %+v", s.opts)
 	job, secrets, err := NewScanJobBuilder().
 		WithPlugin(s.plugin).
@@ -85,6 +90,7 @@ func (s *Scanner) Scan(ctx context.Context, partial kube.Object) (*ReportBuilder
 		WithObject(owner).
 		WithTolerations(scanJobTolerations).
 		WithAnnotations(scanJobAnnotations).
+		WithPodTemplateLabels(scanJobPodTemplateLabels).
 		Get()
 	if err != nil {
 		return nil, fmt.Errorf("constructing scan job: %w", err)
diff --git a/pkg/kube/object.go b/pkg/kube/object.go
index 7741b3e..37aa3f9 100644
--- a/pkg/kube/object.go
+++ b/pkg/kube/object.go
@@ -25,17 +25,16 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
 )
 
-// TODO Rename from Object to PartialObject (consider embedding types.NamespacedName struct)
-// Object is a simplified representation of a Kubernetes object.
-// Each object has kind, which designates the type of the entity it represents.
+// ObjectRef is a simplified representation of a Kubernetes client.Object.
+// Each object has Kind, which designates the type of the entity it represents.
 // Objects have names and many of them live in namespaces.
-type Object struct {
+type ObjectRef struct {
 	Kind      Kind
 	Name      string
 	Namespace string
 }
 
-// Kind represents the type of a Kubernetes Object.
+// Kind represents the type of Kubernetes client.Object.
 type Kind string
 
 const (
@@ -83,13 +82,13 @@ func IsClusterScopedKind(k string) bool {
 	}
 }
 
-// PartialObjectToLabels encodes the specified Object as a set of labels.
+// ObjectRefToLabels encodes the specified ObjectRef as a set of labels.
 //
 // If Object's name cannot be used as the value of the
 // starboard.LabelResourceName label, as a fallback, this method will calculate
 // a hash of the Object's name and use it as the value of the
 // starboard.LabelResourceNameHash label.
-func PartialObjectToLabels(obj Object) map[string]string {
+func ObjectRefToLabels(obj ObjectRef) map[string]string {
 	labels := map[string]string{
 		starboard.LabelResourceKind:      string(obj.Kind),
 		starboard.LabelResourceNamespace: obj.Namespace,
@@ -122,21 +121,21 @@ func ObjectToObjectMetadata(obj client.Object, meta *metav1.ObjectMeta) error {
 	return nil
 }
 
-func PartialObjectFromObjectMetadata(objectMeta metav1.ObjectMeta) (Object, error) {
+func ObjectRefFromObjectMeta(objectMeta metav1.ObjectMeta) (ObjectRef, error) {
 	if _, found := objectMeta.Labels[starboard.LabelResourceKind]; !found {
-		return Object{}, fmt.Errorf("required label does not exist: %s", starboard.LabelResourceKind)
+		return ObjectRef{}, fmt.Errorf("required label does not exist: %s", starboard.LabelResourceKind)
 	}
 	var objname string
 	if _, found := objectMeta.Labels[starboard.LabelResourceName]; !found {
 		if _, found := objectMeta.Annotations[starboard.LabelResourceName]; found {
 			objname = objectMeta.Annotations[starboard.LabelResourceName]
 		} else {
-			return Object{}, fmt.Errorf("required label does not exist: %s", starboard.LabelResourceName)
+			return ObjectRef{}, fmt.Errorf("required label does not exist: %s", starboard.LabelResourceName)
 		}
 	} else {
 		objname = objectMeta.Labels[starboard.LabelResourceName]
 	}
-	return Object{
+	return ObjectRef{
 		Kind:      Kind(objectMeta.Labels[starboard.LabelResourceKind]),
 		Name:      objname,
 		Namespace: objectMeta.Labels[starboard.LabelResourceNamespace],
@@ -188,8 +187,8 @@ func KindForObject(object metav1.Object, scheme *runtime.Scheme) (string, error)
 	return gvk.Kind, nil
 }
 
-func GetPartialObjectFromKindAndNamespacedName(kind Kind, name types.NamespacedName) Object {
-	return Object{
+func ObjectRefFromKindAndNamespacedName(kind Kind, name types.NamespacedName) ObjectRef {
+	return ObjectRef{
 		Kind:      kind,
 		Name:      name.Name,
 		Namespace: name.Namespace,
@@ -257,7 +256,7 @@ type ObjectResolver struct {
 	client.Client
 }
 
-func (o *ObjectResolver) GetObjectFromPartialObject(ctx context.Context, workload Object) (client.Object, error) {
+func (o *ObjectResolver) ObjectFromObjectRef(ctx context.Context, workload ObjectRef) (client.Object, error) {
 	var obj client.Object
 	switch workload.Kind {
 	case KindPod:
@@ -436,7 +435,7 @@ func (o *ObjectResolver) ensureGVK(obj client.Object) (client.Object, error) {
 // the given owner. If the owner is a Deployment, it will look for a ReplicaSet
 // that is controlled by the Deployment. If the owner is a Pod, it will look for
 // the ReplicaSet that owns the Pod.
-func (o *ObjectResolver) GetRelatedReplicasetName(ctx context.Context, object Object) (string, error) {
+func (o *ObjectResolver) GetRelatedReplicasetName(ctx context.Context, object ObjectRef) (string, error) {
 	switch object.Kind {
 	case KindDeployment:
 		return o.getActiveReplicaSetByDeployment(ctx, object)
@@ -446,7 +445,7 @@ func (o *ObjectResolver) GetRelatedReplicasetName(ctx context.Context, object Ob
 	return "", fmt.Errorf("can only get related ReplicaSet for Deployment or Pod, not %q", string(object.Kind))
 }
 
-func (o *ObjectResolver) getActiveReplicaSetByDeployment(ctx context.Context, object Object) (string, error) {
+func (o *ObjectResolver) getActiveReplicaSetByDeployment(ctx context.Context, object ObjectRef) (string, error) {
 	deploy := &appsv1.Deployment{}
 	err := o.Client.Get(ctx, types.NamespacedName{Namespace: object.Namespace, Name: object.Name}, deploy)
 	if err != nil {
@@ -465,8 +464,7 @@ func (o *ObjectResolver) getActiveReplicaSetByDeployment(ctx context.Context, ob
 		return "", fmt.Errorf("no replicasets associated with deployment %q", object.Name)
 	}
 	for _, rs := range rsList.Items {
-		if deploy.Annotations["deployment.kubernetes.io/revision"] !=
-			rs.Annotations["deployment.kubernetes.io/revision"] {
+		if deploy.Annotations[deploymentAnnotation] != rs.Annotations[deploymentAnnotation] {
 			continue
 		}
 		return rs.Name, nil
@@ -474,7 +472,7 @@ func (o *ObjectResolver) getActiveReplicaSetByDeployment(ctx context.Context, ob
 	return "", fmt.Errorf("did not find an active replicaset associated with deployment %q", object.Name)
 }
 
-func (o *ObjectResolver) getReplicaSetByPod(ctx context.Context, object Object) (string, error) {
+func (o *ObjectResolver) getReplicaSetByPod(ctx context.Context, object ObjectRef) (string, error) {
 	pod := &corev1.Pod{}
 	err := o.Client.Get(ctx, types.NamespacedName{Namespace: object.Namespace, Name: object.Name}, pod)
 	if err != nil {
diff --git a/pkg/kubebench/io.go b/pkg/kubebench/io.go
index c8abdcc..bd37a67 100644
--- a/pkg/kubebench/io.go
+++ b/pkg/kubebench/io.go
@@ -15,7 +15,7 @@ type Writer interface {
 }
 
 type Reader interface {
-	FindByOwner(ctx context.Context, node kube.Object) (*v1alpha1.CISKubeBenchReport, error)
+	FindByOwner(ctx context.Context, node kube.ObjectRef) (*v1alpha1.CISKubeBenchReport, error)
 }
 
 type ReadWriter interface {
@@ -55,7 +55,7 @@ func (w *rw) Write(ctx context.Context, report v1alpha1.CISKubeBenchReport) erro
 	return err
 }
 
-func (w *rw) FindByOwner(ctx context.Context, node kube.Object) (*v1alpha1.CISKubeBenchReport, error) {
+func (w *rw) FindByOwner(ctx context.Context, node kube.ObjectRef) (*v1alpha1.CISKubeBenchReport, error) {
 	report := &v1alpha1.CISKubeBenchReport{}
 	err := w.client.Get(ctx, types.NamespacedName{
 		Name: node.Name,
diff --git a/pkg/kubebench/scanner.go b/pkg/kubebench/scanner.go
index 6d6e2bb..67a68d7 100644
--- a/pkg/kubebench/scanner.go
+++ b/pkg/kubebench/scanner.go
@@ -120,14 +120,29 @@ func (s *Scanner) prepareKubeBenchJob(node corev1.Node) (*batchv1.Job, error) {
 		return nil, err
 	}
 
+	scanJobPodTemplateLabels, err := s.config.GetScanJobPodTemplateLabels()
+	if err != nil {
+		return nil, err
+	}
+
+	labelsSet := labels.Set{
+		starboard.LabelResourceKind: string(kube.KindNode),
+		starboard.LabelResourceName: node.Name,
+	}
+
+	podTemplateLabelsSet := make(labels.Set)
+	for index, element := range labelsSet {
+		podTemplateLabelsSet[index] = element
+	}
+	for index, element := range scanJobPodTemplateLabels {
+		podTemplateLabelsSet[index] = element
+	}
+
 	return &batchv1.Job{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      "scan-cisbenchmark-" + kube.ComputeHash(node.Name),
 			Namespace: starboard.NamespaceName,
-			Labels: labels.Set{
-				starboard.LabelResourceKind: string(kube.KindNode),
-				starboard.LabelResourceName: node.Name,
-			},
+			Labels:    labelsSet,
 		},
 		Spec: batchv1.JobSpec{
 			BackoffLimit:          pointer.Int32Ptr(0),
@@ -135,10 +150,7 @@ func (s *Scanner) prepareKubeBenchJob(node corev1.Node) (*batchv1.Job, error) {
 			ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.opts.ScanJobTimeout),
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
-					Labels: labels.Set{
-						starboard.LabelResourceKind: string(kube.KindNode),
-						starboard.LabelResourceName: node.Name,
-					},
+					Labels:      podTemplateLabelsSet,
 					Annotations: scanJobAnnotations,
 				},
 				Spec: templateSpec,
diff --git a/pkg/kubehunter/scanner.go b/pkg/kubehunter/scanner.go
index 81ec319..a82f356 100644
--- a/pkg/kubehunter/scanner.go
+++ b/pkg/kubehunter/scanner.go
@@ -117,6 +117,11 @@ func (s *Scanner) prepareKubeHunterJob() (*batchv1.Job, error) {
 		return nil, err
 	}
 
+	scanJobPodTemplateLabels, err := s.config.GetScanJobPodTemplateLabels()
+	if err != nil {
+		return nil, err
+	}
+
 	var (
 		podSecurityContext       *corev1.PodSecurityContext
 		containerSecurityContext *corev1.SecurityContext
@@ -156,6 +161,7 @@ func (s *Scanner) prepareKubeHunterJob() (*batchv1.Job, error) {
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
 					Annotations: scanJobAnnotations,
+					Labels:      scanJobPodTemplateLabels,
 				},
 				Spec: corev1.PodSpec{
 					ServiceAccountName: starboard.ServiceAccountName,
diff --git a/pkg/operator/controller/ciskubebenchreport.go b/pkg/operator/controller/ciskubebenchreport.go
index 63cde85..d9d8bac 100644
--- a/pkg/operator/controller/ciskubebenchreport.go
+++ b/pkg/operator/controller/ciskubebenchreport.go
@@ -130,7 +130,7 @@ func (r *CISKubeBenchReportReconciler) reconcileNodes() reconcile.Func {
 }
 
 func (r *CISKubeBenchReportReconciler) hasReport(ctx context.Context, node *corev1.Node) (bool, error) {
-	report, err := r.ReadWriter.FindByOwner(ctx, kube.Object{Kind: kube.KindNode, Name: node.Name})
+	report, err := r.ReadWriter.FindByOwner(ctx, kube.ObjectRef{Kind: kube.KindNode, Name: node.Name})
 	if err != nil {
 		return false, err
 	}
@@ -169,16 +169,31 @@ func (r *CISKubeBenchReportReconciler) newScanJob(node *corev1.Node) (*batchv1.J
 		return nil, err
 	}
 
+	scanJobPodTemplateLabels, err := r.ConfigData.GetScanJobPodTemplateLabels()
+	if err != nil {
+		return nil, err
+	}
+
+	labelsSet := labels.Set{
+		starboard.LabelResourceKind:           string(kube.KindNode),
+		starboard.LabelResourceName:           node.Name,
+		starboard.LabelK8SAppManagedBy:        starboard.AppStarboard,
+		starboard.LabelKubeBenchReportScanner: "true",
+	}
+
+	podTemplateLabelsSet := make(labels.Set)
+	for index, element := range labelsSet {
+		podTemplateLabelsSet[index] = element
+	}
+	for index, element := range scanJobPodTemplateLabels {
+		podTemplateLabelsSet[index] = element
+	}
+
 	return &batchv1.Job{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      r.getScanJobName(node),
 			Namespace: r.Config.Namespace,
-			Labels: labels.Set{
-				starboard.LabelResourceKind:           string(kube.KindNode),
-				starboard.LabelResourceName:           node.Name,
-				starboard.LabelK8SAppManagedBy:        starboard.AppStarboard,
-				starboard.LabelKubeBenchReportScanner: "true",
-			},
+			Labels:    labelsSet,
 		},
 		Spec: batchv1.JobSpec{
 			BackoffLimit:          pointer.Int32Ptr(0),
@@ -186,12 +201,7 @@ func (r *CISKubeBenchReportReconciler) newScanJob(node *corev1.Node) (*batchv1.J
 			ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(r.Config.ScanJobTimeout),
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
-					Labels: labels.Set{
-						starboard.LabelResourceKind:           string(kube.KindNode),
-						starboard.LabelResourceName:           node.Name,
-						starboard.LabelK8SAppManagedBy:        starboard.AppStarboard,
-						starboard.LabelKubeBenchReportScanner: "true",
-					},
+					Labels:      podTemplateLabelsSet,
 					Annotations: scanJobAnnotations,
 				},
 				Spec: templateSpec,
@@ -240,7 +250,7 @@ func (r *CISKubeBenchReportReconciler) reconcileJobs() reconcile.Func {
 func (r *CISKubeBenchReportReconciler) processCompleteScanJob(ctx context.Context, job *batchv1.Job) error {
 	log := r.Logger.WithValues("job", fmt.Sprintf("%s/%s", job.Namespace, job.Name))
 
-	nodeRef, err := kube.PartialObjectFromObjectMetadata(job.ObjectMeta)
+	nodeRef, err := kube.ObjectRefFromObjectMeta(job.ObjectMeta)
 	if err != nil {
 		return fmt.Errorf("getting owner ref from scan job metadata: %w", err)
 	}
diff --git a/pkg/operator/controller/configauditreport.go b/pkg/operator/controller/configauditreport.go
index d5a0e59..ecb2d15 100644
--- a/pkg/operator/controller/configauditreport.go
+++ b/pkg/operator/controller/configauditreport.go
@@ -133,10 +133,10 @@ func (r *ConfigAuditReportReconciler) reconcileResource(resourceKind kube.Kind)
 	return func(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 		log := r.Logger.WithValues("kind", resourceKind, "name", req.NamespacedName)
 
-		resourcePartial := kube.GetPartialObjectFromKindAndNamespacedName(resourceKind, req.NamespacedName)
+		resourcePartial := kube.ObjectRefFromKindAndNamespacedName(resourceKind, req.NamespacedName)
 
 		log.V(1).Info("Getting resource from cache")
-		resource, err := r.GetObjectFromPartialObject(ctx, resourcePartial)
+		resource, err := r.ObjectFromObjectRef(ctx, resourcePartial)
 		if err != nil {
 			if errors.IsNotFound(err) {
 				log.V(1).Info("Ignoring cached resource that must have been deleted")
@@ -237,6 +237,11 @@ func (r *ConfigAuditReportReconciler) reconcileResource(resourceKind kube.Kind)
 			return ctrl.Result{}, fmt.Errorf("getting scan job annotations: %w", err)
 		}
 
+		scanJobPodTemplateLabels, err := r.GetScanJobPodTemplateLabels()
+		if err != nil {
+			return ctrl.Result{}, fmt.Errorf("getting scan job template labels: %w", err)
+		}
+
 		job, secrets, err := configauditreport.NewScanJobBuilder().
 			WithPlugin(r.Plugin).
 			WithPluginContext(r.PluginContext).
@@ -244,6 +249,7 @@ func (r *ConfigAuditReportReconciler) reconcileResource(resourceKind kube.Kind)
 			WithObject(resource).
 			WithTolerations(scanJobTolerations).
 			WithAnnotations(scanJobAnnotations).
+			WithPodTemplateLabels(scanJobPodTemplateLabels).
 			Get()
 		if err != nil {
 			return ctrl.Result{}, fmt.Errorf("constructing scan job: %w", err)
@@ -286,7 +292,7 @@ func (r *ConfigAuditReportReconciler) reconcileResource(resourceKind kube.Kind)
 	}
 }
 
-func (r *ConfigAuditReportReconciler) hasReport(ctx context.Context, owner kube.Object, podSpecHash string, pluginConfigHash string) (bool, error) {
+func (r *ConfigAuditReportReconciler) hasReport(ctx context.Context, owner kube.ObjectRef, podSpecHash string, pluginConfigHash string) (bool, error) {
 	if kube.IsClusterScopedKind(string(owner.Kind)) {
 		return r.hasClusterReport(ctx, owner, podSpecHash, pluginConfigHash)
 	}
@@ -302,7 +308,7 @@ func (r *ConfigAuditReportReconciler) hasReport(ctx context.Context, owner kube.
 	return false, nil
 }
 
-func (r *ConfigAuditReportReconciler) hasClusterReport(ctx context.Context, owner kube.Object, podSpecHash string, pluginConfigHash string) (bool, error) {
+func (r *ConfigAuditReportReconciler) hasClusterReport(ctx context.Context, owner kube.ObjectRef, podSpecHash string, pluginConfigHash string) (bool, error) {
 	report, err := r.ReadWriter.FindClusterReportByOwner(ctx, owner)
 	if err != nil {
 		return false, err
@@ -367,18 +373,18 @@ func (r *ConfigAuditReportReconciler) reconcileJobs() reconcile.Func {
 func (r *ConfigAuditReportReconciler) processCompleteScanJob(ctx context.Context, job *batchv1.Job) error {
 	log := r.Logger.WithValues("job", fmt.Sprintf("%s/%s", job.Namespace, job.Name))
 
-	ownerRef, err := kube.PartialObjectFromObjectMetadata(job.ObjectMeta)
+	ownerRef, err := kube.ObjectRefFromObjectMeta(job.ObjectMeta)
 	if err != nil {
 		return fmt.Errorf("getting owner ref from scan job metadata: %w", err)
 	}
 
-	owner, err := r.GetObjectFromPartialObject(ctx, ownerRef)
+	owner, err := r.ObjectFromObjectRef(ctx, ownerRef)
 	if err != nil {
 		if errors.IsNotFound(err) {
 			log.V(1).Info("Report owner must have been deleted", "owner", owner)
 			return r.deleteJob(ctx, job)
 		}
-		return fmt.Errorf("getting object from partial object: %w", err)
+		return fmt.Errorf("getting object from object ref: %w", err)
 	}
 
 	resourceSpecHash, ok := job.Labels[starboard.LabelResourceSpecHash]
diff --git a/pkg/operator/controller/ttl_report.go b/pkg/operator/controller/ttl_report.go
new file mode 100644
index 0000000..d2493a1
--- /dev/null
+++ b/pkg/operator/controller/ttl_report.go
@@ -0,0 +1,96 @@
+package controller
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
+	"github.com/aquasecurity/starboard/pkg/operator/etc"
+	"github.com/aquasecurity/starboard/pkg/operator/predicate"
+	"github.com/go-logr/logr"
+	"k8s.io/apimachinery/pkg/api/errors"
+	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/builder"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+	"sigs.k8s.io/controller-runtime/pkg/reconcile"
+)
+
+type TTLReportReconciler struct {
+	logr.Logger
+	etc.Config
+	client.Client
+}
+
+func (r *TTLReportReconciler) SetupWithManager(mgr ctrl.Manager) error {
+	installModePredicate, err := predicate.InstallModePredicate(r.Config)
+	if err != nil {
+		return err
+	}
+
+	err = ctrl.NewControllerManagedBy(mgr).
+		For(&v1alpha1.VulnerabilityReport{}, builder.WithPredicates(
+			predicate.Not(predicate.IsBeingTerminated),
+			installModePredicate)).
+		Complete(r.reconcileReport())
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (r *TTLReportReconciler) reconcileReport() reconcile.Func {
+	return func(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+		log := r.Logger.WithValues("report", req.NamespacedName)
+
+		report := &v1alpha1.VulnerabilityReport{}
+		err := r.Client.Get(ctx, req.NamespacedName, report)
+		if err != nil {
+			if errors.IsNotFound(err) {
+				log.V(1).Info("Ignoring cached report that must have been deleted")
+				return ctrl.Result{}, nil
+			}
+			return ctrl.Result{}, fmt.Errorf("getting report from cache: %w", err)
+		}
+
+		ttlReportAnnotationStr, ok := report.Annotations[v1alpha1.TTLReportAnnotation]
+		if !ok {
+			log.V(1).Info("Ignoring report without TTL set")
+			return ctrl.Result{}, nil
+		}
+
+		reportTTLTime, err := time.ParseDuration(ttlReportAnnotationStr)
+		if err != nil {
+			return ctrl.Result{}, fmt.Errorf("failed parsing %v with value %v %w", v1alpha1.TTLReportAnnotation, ttlReportAnnotationStr, err)
+		}
+		creationTime := report.Report.UpdateTimestamp
+		ttlExpired, durationToTTLExpiration, err := ttlIsExpired(reportTTLTime, creationTime.Time)
+		if err != nil {
+			return ctrl.Result{}, err
+		}
+		if ttlExpired {
+			log.V(1).Info("Removing vulnerabilityReport with expired TTL")
+			err := r.Client.Delete(ctx, report, &client.DeleteOptions{})
+			if err != nil && !errors.IsNotFound(err) {
+				return ctrl.Result{}, err
+			}
+			// Since the report is deleted there is no reason to requeue
+			return ctrl.Result{}, nil
+		}
+		log.V(1).Info("RequeueAfter", "durationToTTLExpiration", durationToTTLExpiration)
+		return ctrl.Result{RequeueAfter: durationToTTLExpiration}, nil
+	}
+}
+
+func ttlIsExpired(reportTTL time.Duration, creationTime time.Time) (bool, time.Duration, error) {
+	expiresAt := creationTime.Add(reportTTL)
+	currentTime := time.Now()
+	isExpired := currentTime.After(expiresAt)
+
+	if isExpired {
+		return true, time.Duration(0), nil
+	}
+
+	expiresIn := expiresAt.Sub(currentTime)
+	return false, expiresIn, nil
+}
diff --git a/pkg/operator/controller/vulnerabilityreport.go b/pkg/operator/controller/vulnerabilityreport.go
index 1ec65a0..0a00a6c 100644
--- a/pkg/operator/controller/vulnerabilityreport.go
+++ b/pkg/operator/controller/vulnerabilityreport.go
@@ -87,10 +87,10 @@ func (r *VulnerabilityReportReconciler) reconcileWorkload(workloadKind kube.Kind
 	return func(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 		log := r.Logger.WithValues("kind", workloadKind, "name", req.NamespacedName)
 
-		workloadPartial := kube.GetPartialObjectFromKindAndNamespacedName(workloadKind, req.NamespacedName)
+		workloadPartial := kube.ObjectRefFromKindAndNamespacedName(workloadKind, req.NamespacedName)
 
 		log.V(1).Info("Getting workload from cache")
-		workloadObj, err := r.GetObjectFromPartialObject(ctx, workloadPartial)
+		workloadObj, err := r.ObjectFromObjectRef(ctx, workloadPartial)
 		if err != nil {
 			if errors.IsNotFound(err) {
 				log.V(1).Info("Ignoring cached workload that must have been deleted")
@@ -176,7 +176,7 @@ func (r *VulnerabilityReportReconciler) reconcileWorkload(workloadKind kube.Kind
 	}
 }
 
-func (r *VulnerabilityReportReconciler) hasReports(ctx context.Context, owner kube.Object, hash string, images kube.ContainerImages) (bool, error) {
+func (r *VulnerabilityReportReconciler) hasReports(ctx context.Context, owner kube.ObjectRef, hash string, images kube.ContainerImages) (bool, error) {
 	// TODO FindByOwner should accept optional label selector to further narrow down search results
 	list, err := r.FindByOwner(ctx, owner)
 	if err != nil {
@@ -200,7 +200,7 @@ func (r *VulnerabilityReportReconciler) hasReports(ctx context.Context, owner ku
 	return reflect.DeepEqual(actual, expected), nil
 }
 
-func (r *VulnerabilityReportReconciler) hasActiveScanJob(ctx context.Context, owner kube.Object, hash string) (bool, *batchv1.Job, error) {
+func (r *VulnerabilityReportReconciler) hasActiveScanJob(ctx context.Context, owner kube.ObjectRef, hash string) (bool, *batchv1.Job, error) {
 	jobName := fmt.Sprintf("scan-vulnerabilityreport-%s", kube.ComputeHash(owner))
 	job := &batchv1.Job{}
 	err := r.Get(ctx, client.ObjectKey{Namespace: r.Config.Namespace, Name: jobName}, job)
@@ -232,6 +232,11 @@ func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, owner
 		return fmt.Errorf("getting scan job annotations: %w", err)
 	}
 
+	scanJobPodTemplateLabels, err := r.GetScanJobPodTemplateLabels()
+	if err != nil {
+		return fmt.Errorf("getting scan job template labels: %w", err)
+	}
+
 	scanJob, secrets, err := vulnerabilityreport.NewScanJobBuilder().
 		WithPlugin(r.Plugin).
 		WithPluginContext(r.PluginContext).
@@ -239,6 +244,7 @@ func (r *VulnerabilityReportReconciler) submitScanJob(ctx context.Context, owner
 		WithObject(owner).
 		WithTolerations(scanJobTolerations).
 		WithAnnotations(scanJobAnnotations).
+		WithPodTemplateLabels(scanJobPodTemplateLabels).
 		WithCredentials(credentials).
 		Get()
 
@@ -312,18 +318,18 @@ func (r *VulnerabilityReportReconciler) reconcileJobs() reconcile.Func {
 func (r *VulnerabilityReportReconciler) processCompleteScanJob(ctx context.Context, job *batchv1.Job) error {
 	log := r.Logger.WithValues("job", fmt.Sprintf("%s/%s", job.Namespace, job.Name))
 
-	ownerRef, err := kube.PartialObjectFromObjectMetadata(job.ObjectMeta)
+	ownerRef, err := kube.ObjectRefFromObjectMeta(job.ObjectMeta)
 	if err != nil {
 		return fmt.Errorf("getting owner ref from scan job metadata: %w", err)
 	}
 
-	owner, err := r.GetObjectFromPartialObject(ctx, ownerRef)
+	owner, err := r.ObjectFromObjectRef(ctx, ownerRef)
 	if err != nil {
 		if errors.IsNotFound(err) {
 			log.V(1).Info("Report owner must have been deleted", "owner", owner)
 			return r.deleteJob(ctx, job)
 		}
-		return fmt.Errorf("getting object from partial object: %w", err)
+		return fmt.Errorf("getting object from object ref: %w", err)
 	}
 
 	containerImages, err := kube.GetContainerImagesFromJob(job)
@@ -360,12 +366,18 @@ func (r *VulnerabilityReportReconciler) processCompleteScanJob(ctx context.Conte
 		}
 		_ = logsStream.Close()
 
-		report, err := vulnerabilityreport.NewReportBuilder(r.Client.Scheme()).
+		reportBuilder := vulnerabilityreport.NewReportBuilder(r.Client.Scheme()).
 			Controller(owner).
 			Container(containerName).
 			Data(reportData).
-			PodSpecHash(podSpecHash).
-			Get()
+			PodSpecHash(podSpecHash)
+
+		if r.Config.VulnerabilityScannerReportTTL != nil {
+			reportBuilder.ReportTTL(r.Config.VulnerabilityScannerReportTTL)
+		}
+
+		report, err := reportBuilder.Get()
+
 		if err != nil {
 			return err
 		}
diff --git a/pkg/operator/etc/config.go b/pkg/operator/etc/config.go
index 77f32f6..f41e241 100644
--- a/pkg/operator/etc/config.go
+++ b/pkg/operator/etc/config.go
@@ -10,23 +10,24 @@ import (
 
 // Config defines parameters for running the operator.
 type Config struct {
-	Namespace                                    string        `env:"OPERATOR_NAMESPACE"`
-	TargetNamespaces                             string        `env:"OPERATOR_TARGET_NAMESPACES"`
-	ServiceAccount                               string        `env:"OPERATOR_SERVICE_ACCOUNT" envDefault:"starboard-operator"`
-	LogDevMode                                   bool          `env:"OPERATOR_LOG_DEV_MODE" envDefault:"false"`
-	ScanJobTimeout                               time.Duration `env:"OPERATOR_SCAN_JOB_TIMEOUT" envDefault:"5m"`
-	ConcurrentScanJobsLimit                      int           `env:"OPERATOR_CONCURRENT_SCAN_JOBS_LIMIT" envDefault:"10"`
-	ScanJobRetryAfter                            time.Duration `env:"OPERATOR_SCAN_JOB_RETRY_AFTER" envDefault:"30s"`
-	BatchDeleteLimit                             int           `env:"OPERATOR_BATCH_DELETE_LIMIT" envDefault:"10"`
-	BatchDeleteDelay                             time.Duration `env:"OPERATOR_BATCH_DELETE_DELAY" envDefault:"10s"`
-	MetricsBindAddress                           string        `env:"OPERATOR_METRICS_BIND_ADDRESS" envDefault:":8080"`
-	HealthProbeBindAddress                       string        `env:"OPERATOR_HEALTH_PROBE_BIND_ADDRESS" envDefault:":9090"`
-	CISKubernetesBenchmarkEnabled                bool          `env:"OPERATOR_CIS_KUBERNETES_BENCHMARK_ENABLED" envDefault:"true"`
-	VulnerabilityScannerEnabled                  bool          `env:"OPERATOR_VULNERABILITY_SCANNER_ENABLED" envDefault:"true"`
-	ConfigAuditScannerEnabled                    bool          `env:"OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED" envDefault:"true"`
-	LeaderElectionEnabled                        bool          `env:"OPERATOR_LEADER_ELECTION_ENABLED" envDefault:"false"`
-	LeaderElectionID                             string        `env:"OPERATOR_LEADER_ELECTION_ID" envDefault:"starboard-lock"`
-	VulnerabilityScannerScanOnlyCurrentRevisions bool          `env:"OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS" envDefault:"false"`
+	Namespace                                    string         `env:"OPERATOR_NAMESPACE"`
+	TargetNamespaces                             string         `env:"OPERATOR_TARGET_NAMESPACES"`
+	ServiceAccount                               string         `env:"OPERATOR_SERVICE_ACCOUNT" envDefault:"starboard-operator"`
+	LogDevMode                                   bool           `env:"OPERATOR_LOG_DEV_MODE" envDefault:"false"`
+	ScanJobTimeout                               time.Duration  `env:"OPERATOR_SCAN_JOB_TIMEOUT" envDefault:"5m"`
+	ConcurrentScanJobsLimit                      int            `env:"OPERATOR_CONCURRENT_SCAN_JOBS_LIMIT" envDefault:"10"`
+	ScanJobRetryAfter                            time.Duration  `env:"OPERATOR_SCAN_JOB_RETRY_AFTER" envDefault:"30s"`
+	BatchDeleteLimit                             int            `env:"OPERATOR_BATCH_DELETE_LIMIT" envDefault:"10"`
+	BatchDeleteDelay                             time.Duration  `env:"OPERATOR_BATCH_DELETE_DELAY" envDefault:"10s"`
+	MetricsBindAddress                           string         `env:"OPERATOR_METRICS_BIND_ADDRESS" envDefault:":8080"`
+	HealthProbeBindAddress                       string         `env:"OPERATOR_HEALTH_PROBE_BIND_ADDRESS" envDefault:":9090"`
+	CISKubernetesBenchmarkEnabled                bool           `env:"OPERATOR_CIS_KUBERNETES_BENCHMARK_ENABLED" envDefault:"true"`
+	VulnerabilityScannerEnabled                  bool           `env:"OPERATOR_VULNERABILITY_SCANNER_ENABLED" envDefault:"true"`
+	VulnerabilityScannerScanOnlyCurrentRevisions bool           `env:"OPERATOR_VULNERABILITY_SCANNER_SCAN_ONLY_CURRENT_REVISIONS" envDefault:"false"`
+	VulnerabilityScannerReportTTL                *time.Duration `env:"OPERATOR_VULNERABILITY_SCANNER_REPORT_TTL"`
+	ConfigAuditScannerEnabled                    bool           `env:"OPERATOR_CONFIG_AUDIT_SCANNER_ENABLED" envDefault:"true"`
+	LeaderElectionEnabled                        bool           `env:"OPERATOR_LEADER_ELECTION_ENABLED" envDefault:"false"`
+	LeaderElectionID                             string         `env:"OPERATOR_LEADER_ELECTION_ID" envDefault:"starboard-lock"`
 }
 
 // GetOperatorConfig loads Config from environment variables.
diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go
index 2c6ba58..6d78215 100644
--- a/pkg/operator/operator.go
+++ b/pkg/operator/operator.go
@@ -160,6 +160,16 @@ func Start(ctx context.Context, buildInfo starboard.BuildInfo, operatorConfig et
 		}).SetupWithManager(mgr); err != nil {
 			return fmt.Errorf("unable to setup vulnerabilityreport reconciler: %w", err)
 		}
+
+		if operatorConfig.VulnerabilityScannerReportTTL != nil {
+			if err = (&controller.TTLReportReconciler{
+				Logger: ctrl.Log.WithName("reconciler").WithName("ttlreport"),
+				Config: operatorConfig,
+				Client: mgr.GetClient(),
+			}).SetupWithManager(mgr); err != nil {
+				return fmt.Errorf("unable to setup TTLreport reconciler: %w", err)
+			}
+		}
 	}
 
 	if operatorConfig.ConfigAuditScannerEnabled {
diff --git a/pkg/plugin/aqua/plugin.go b/pkg/plugin/aqua/plugin.go
index b1317fb..8bc3688 100644
--- a/pkg/plugin/aqua/plugin.go
+++ b/pkg/plugin/aqua/plugin.go
@@ -8,11 +8,13 @@ import (
 	"github.com/aquasecurity/starboard/pkg/apis/aquasecurity/v1alpha1"
 	"github.com/aquasecurity/starboard/pkg/docker"
 	"github.com/aquasecurity/starboard/pkg/ext"
+	"github.com/aquasecurity/starboard/pkg/kube"
 	"github.com/aquasecurity/starboard/pkg/starboard"
 	"github.com/aquasecurity/starboard/pkg/vulnerabilityreport"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 type plugin struct {
@@ -37,7 +39,12 @@ func (s *plugin) Init(_ starboard.PluginContext) error {
 	return nil
 }
 
-func (s *plugin) GetScanJobSpec(ctx starboard.PluginContext, spec corev1.PodSpec, _ map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
+func (s *plugin) GetScanJobSpec(ctx starboard.PluginContext, workload client.Object, _ map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
+	spec, err := kube.GetPodSpec(workload)
+	if err != nil {
+		return corev1.PodSpec{}, nil, err
+	}
+
 	initContainerName := s.idGenerator.GenerateID()
 
 	aquaImageRef, err := s.getImageRef(ctx)
diff --git a/pkg/plugin/trivy/plugin.go b/pkg/plugin/trivy/plugin.go
index b52fc1f..e6c3f69 100644
--- a/pkg/plugin/trivy/plugin.go
+++ b/pkg/plugin/trivy/plugin.go
@@ -17,6 +17,7 @@ import (
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 const (
@@ -207,7 +208,12 @@ func (p *plugin) Init(ctx starboard.PluginContext) error {
 	})
 }
 
-func (p *plugin) GetScanJobSpec(ctx starboard.PluginContext, spec corev1.PodSpec, credentials map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
+func (p *plugin) GetScanJobSpec(ctx starboard.PluginContext, workload client.Object, credentials map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
+	spec, err := kube.GetPodSpec(workload)
+	if err != nil {
+		return corev1.PodSpec{}, nil, err
+	}
+
 	config, err := p.newConfigFrom(ctx)
 	if err != nil {
 		return corev1.PodSpec{}, nil, err
@@ -250,13 +256,13 @@ const (
 // volume shared with main containers. In other words, the init container runs
 // the following Trivy command:
 //
-//     trivy --download-db-only --cache-dir /var/lib/trivy
+//     trivy --cache-dir /var/lib/trivy image --download-db-only
 //
 // The number of main containers correspond to the number of containers
 // defined for the scanned workload. Each container runs the Trivy image scan
 // command and skips the database download:
 //
-//     trivy --skip-update --cache-dir /var/lib/trivy \
+//     trivy --cache-dir /var/lib/trivy image --skip-update \
 //       --format json <container image>
 func (p *plugin) getPodSpecForStandaloneMode(ctx starboard.PluginContext, config Config, spec corev1.PodSpec, credentials map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
 	var secret *corev1.Secret
@@ -338,9 +344,10 @@ func (p *plugin) getPodSpecForStandaloneMode(ctx starboard.PluginContext, config
 			"trivy",
 		},
 		Args: []string{
-			"--download-db-only",
 			"--cache-dir",
 			"/var/lib/trivy",
+			"image",
+			"--download-db-only",
 		},
 		Resources: requirements,
 		VolumeMounts: []corev1.VolumeMount{
@@ -550,10 +557,11 @@ func (p *plugin) getPodSpecForStandaloneMode(ctx starboard.PluginContext, config
 				"trivy",
 			},
 			Args: []string{
-				"--skip-update",
 				"--cache-dir",
 				"/var/lib/trivy",
 				"--quiet",
+				"image",
+				"--skip-update",
 				"--format",
 				"json",
 				optionalMirroredImage,
diff --git a/pkg/report/html.go b/pkg/report/html.go
index 4d388f2..74c9729 100644
--- a/pkg/report/html.go
+++ b/pkg/report/html.go
@@ -32,7 +32,7 @@ func NewWorkloadReporter(clock ext.Clock, client client.Client) WorkloadReporter
 	}
 }
 
-func (h *workloadReporter) RetrieveData(workload kube.Object) (templates.WorkloadReport, error) {
+func (h *workloadReporter) RetrieveData(workload kube.ObjectRef) (templates.WorkloadReport, error) {
 	ctx := context.Background()
 	configAuditReport, err := h.configAuditReportsReader.FindReportByOwnerInHierarchy(ctx, workload)
 	if err != nil {
@@ -66,7 +66,7 @@ func (h *workloadReporter) RetrieveData(workload kube.Object) (templates.Workloa
 	}, nil
 }
 
-func (h *workloadReporter) Generate(workload kube.Object, writer io.Writer) error {
+func (h *workloadReporter) Generate(workload kube.ObjectRef, writer io.Writer) error {
 	data, err := h.RetrieveData(workload)
 	if err != nil {
 		return err
@@ -88,7 +88,7 @@ func NewNamespaceReporter(clock ext.Clock, client client.Client) NamespaceReport
 	}
 }
 
-func (r *namespaceReporter) RetrieveData(namespace kube.Object) (templates.NamespaceReport, error) {
+func (r *namespaceReporter) RetrieveData(namespace kube.ObjectRef) (templates.NamespaceReport, error) {
 	var vulnerabilityReportList v1alpha1.VulnerabilityReportList
 	err := r.client.List(context.Background(), &vulnerabilityReportList, client.InNamespace(namespace.Name))
 	if err != nil {
@@ -229,7 +229,7 @@ func (r *namespaceReporter) topNVulnerabilitiesByScore(reports []v1alpha1.Vulner
 	return vulnerabilities[:ext.MinInt(N, len(vulnerabilities))]
 }
 
-func (r *namespaceReporter) Generate(namespace kube.Object, out io.Writer) error {
+func (r *namespaceReporter) Generate(namespace kube.ObjectRef, out io.Writer) error {
 	data, err := r.RetrieveData(namespace)
 	if err != nil {
 		return err
@@ -253,7 +253,7 @@ func NewNodeReporter(clock ext.Clock, client client.Client) NodeReporter {
 	}
 }
 
-func (r *nodeReporter) Generate(node kube.Object, out io.Writer) error {
+func (r *nodeReporter) Generate(node kube.ObjectRef, out io.Writer) error {
 	data, err := r.RetrieveData(node)
 	if err != nil {
 		return err
@@ -262,7 +262,7 @@ func (r *nodeReporter) Generate(node kube.Object, out io.Writer) error {
 	return nil
 }
 
-func (r *nodeReporter) RetrieveData(node kube.Object) (templates.NodeReport, error) {
+func (r *nodeReporter) RetrieveData(node kube.ObjectRef) (templates.NodeReport, error) {
 	found := &v1alpha1.CISKubeBenchReport{}
 	err := r.client.Get(context.Background(), types.NamespacedName{Name: node.Name}, found)
 	if err != nil {
diff --git a/pkg/report/report.go b/pkg/report/report.go
index cce6e31..651a38a 100644
--- a/pkg/report/report.go
+++ b/pkg/report/report.go
@@ -8,16 +8,16 @@ import (
 )
 
 type WorkloadReporter interface {
-	RetrieveData(workload kube.Object) (templates.WorkloadReport, error)
-	Generate(workload kube.Object, out io.Writer) error
+	RetrieveData(workload kube.ObjectRef) (templates.WorkloadReport, error)
+	Generate(workload kube.ObjectRef, out io.Writer) error
 }
 
 type NamespaceReporter interface {
-	RetrieveData(namespace kube.Object) (templates.NamespaceReport, error)
-	Generate(namespace kube.Object, out io.Writer) error
+	RetrieveData(namespace kube.ObjectRef) (templates.NamespaceReport, error)
+	Generate(namespace kube.ObjectRef, out io.Writer) error
 }
 
 type NodeReporter interface {
-	RetrieveData(node kube.Object) (templates.NodeReport, error)
-	Generate(node kube.Object, out io.Writer) error
+	RetrieveData(node kube.ObjectRef) (templates.NodeReport, error)
+	Generate(node kube.ObjectRef, out io.Writer) error
 }
diff --git a/pkg/report/templates/types.go b/pkg/report/templates/types.go
index 967a271..27d73f0 100644
--- a/pkg/report/templates/types.go
+++ b/pkg/report/templates/types.go
@@ -10,7 +10,7 @@ import (
 // WorkloadReport is a structure that holds data to render
 // an HTML report for a specified K8s workload.
 type WorkloadReport struct {
-	Workload    kube.Object
+	Workload    kube.ObjectRef
 	GeneratedAt time.Time
 
 	// FIXME Do not use map as the order of iteration is unpredictable.
@@ -21,7 +21,7 @@ type WorkloadReport struct {
 // NamespaceReport is a structure that holds data to render
 // an HTML report for a specified K8s namespace.
 type NamespaceReport struct {
-	Namespace   kube.Object
+	Namespace   kube.ObjectRef
 	GeneratedAt time.Time
 
 	Top5VulnerableImages []v1alpha1.VulnerabilityReport
@@ -42,7 +42,7 @@ type CheckWithCount struct {
 // NodeReport is a structure that holds data to render
 // an HTML report for a specified K8s node.
 type NodeReport struct {
-	Node        kube.Object
+	Node        kube.ObjectRef
 	GeneratedAt time.Time
 
 	CisKubeBenchReport *v1alpha1.CISKubeBenchReport
diff --git a/pkg/starboard/config.go b/pkg/starboard/config.go
index 2893a3e..ca1c51d 100644
--- a/pkg/starboard/config.go
+++ b/pkg/starboard/config.go
@@ -44,7 +44,7 @@ type BuildInfo struct {
 	Executable string
 }
 
-// Scanner represents unique, human readable identifier of a security scanner.
+// Scanner represents unique, human-readable identifier of a security scanner.
 type Scanner string
 
 const (
@@ -57,6 +57,12 @@ const (
 const (
 	keyVulnerabilityReportsScanner = "vulnerabilityReports.scanner"
 	keyConfigAuditReportsScanner   = "configAuditReports.scanner"
+	keyKubeBenchImageRef           = "kube-bench.imageRef"
+	keyKubeHunterImageRef          = "kube-hunter.imageRef"
+	keyKubeHunterQuick             = "kube-hunter.quick"
+	keyScanJobTolerations          = "scanJob.tolerations"
+	keyScanJobAnnotations          = "scanJob.annotations"
+	keyScanJobPodTemplateLabels    = "scanJob.podTemplateLabels"
 )
 
 // ConfigData holds Starboard configuration settings as a set
@@ -82,16 +88,6 @@ func GetDefaultConfig() ConfigData {
 	}
 }
 
-func (c ConfigData) GetScanJobTolerations() ([]corev1.Toleration, error) {
-	scanJobTolerations := []corev1.Toleration{}
-	if c["scanJob.tolerations"] == "" {
-		return scanJobTolerations, nil
-	}
-	err := json.Unmarshal([]byte(c["scanJob.tolerations"]), &scanJobTolerations)
-
-	return scanJobTolerations, err
-}
-
 func (c ConfigData) GetVulnerabilityReportsScanner() (Scanner, error) {
 	var ok bool
 	var value string
@@ -127,8 +123,18 @@ func (c ConfigData) GetConfigAuditReportsScanner() (Scanner, error) {
 		value, keyConfigAuditReportsScanner, Polaris, Conftest)
 }
 
+func (c ConfigData) GetScanJobTolerations() ([]corev1.Toleration, error) {
+	var scanJobTolerations []corev1.Toleration
+	if c[keyScanJobTolerations] == "" {
+		return scanJobTolerations, nil
+	}
+	err := json.Unmarshal([]byte(c[keyScanJobTolerations]), &scanJobTolerations)
+
+	return scanJobTolerations, err
+}
+
 func (c ConfigData) GetScanJobAnnotations() (map[string]string, error) {
-	scanJobAnnotationsStr, found := c[AnnotationScanJobAnnotations]
+	scanJobAnnotationsStr, found := c[keyScanJobAnnotations]
 	if !found || strings.TrimSpace(scanJobAnnotationsStr) == "" {
 		return map[string]string{}, nil
 	}
@@ -137,7 +143,7 @@ func (c ConfigData) GetScanJobAnnotations() (map[string]string, error) {
 	for _, annotation := range strings.Split(scanJobAnnotationsStr, ",") {
 		sepByEqual := strings.Split(annotation, "=")
 		if len(sepByEqual) != 2 {
-			return map[string]string{}, fmt.Errorf("custom annotations found to be wrongfully provided: %s", scanJobAnnotationsStr)
+			return map[string]string{}, fmt.Errorf("failed parsing incorrectly formatted custom scan job annotations: %s", scanJobAnnotationsStr)
 		}
 		key, value := sepByEqual[0], sepByEqual[1]
 		scanJobAnnotationsMap[key] = value
@@ -146,16 +152,35 @@ func (c ConfigData) GetScanJobAnnotations() (map[string]string, error) {
 	return scanJobAnnotationsMap, nil
 }
 
+func (c ConfigData) GetScanJobPodTemplateLabels() (labels.Set, error) {
+	scanJobPodTemplateLabelsStr, found := c[keyScanJobPodTemplateLabels]
+	if !found || strings.TrimSpace(scanJobPodTemplateLabelsStr) == "" {
+		return labels.Set{}, nil
+	}
+
+	scanJobPodTemplateLabelsMap := map[string]string{}
+	for _, annotation := range strings.Split(scanJobPodTemplateLabelsStr, ",") {
+		sepByEqual := strings.Split(annotation, "=")
+		if len(sepByEqual) != 2 {
+			return labels.Set{}, fmt.Errorf("failed parsing incorrectly formatted custom scan pod template labels: %s", scanJobPodTemplateLabelsStr)
+		}
+		key, value := sepByEqual[0], sepByEqual[1]
+		scanJobPodTemplateLabelsMap[key] = value
+	}
+
+	return scanJobPodTemplateLabelsMap, nil
+}
+
 func (c ConfigData) GetKubeBenchImageRef() (string, error) {
-	return c.GetRequiredData("kube-bench.imageRef")
+	return c.GetRequiredData(keyKubeBenchImageRef)
 }
 
 func (c ConfigData) GetKubeHunterImageRef() (string, error) {
-	return c.GetRequiredData("kube-hunter.imageRef")
+	return c.GetRequiredData(keyKubeHunterImageRef)
 }
 
 func (c ConfigData) GetKubeHunterQuick() (bool, error) {
-	val, ok := c["kube-hunter.quick"]
+	val, ok := c[keyKubeHunterQuick]
 	if !ok {
 		return false, nil
 	}
diff --git a/pkg/starboard/constants.go b/pkg/starboard/constants.go
index d1e528f..bb1bc81 100644
--- a/pkg/starboard/constants.go
+++ b/pkg/starboard/constants.go
@@ -42,6 +42,5 @@ const (
 )
 
 const (
-	AnnotationContainerImages    = "starboard.container-images"
-	AnnotationScanJobAnnotations = "scanJob.annotations"
+	AnnotationContainerImages = "starboard.container-images"
 )
diff --git a/pkg/vulnerabilityreport/builder.go b/pkg/vulnerabilityreport/builder.go
index 786b817..b326b3e 100644
--- a/pkg/vulnerabilityreport/builder.go
+++ b/pkg/vulnerabilityreport/builder.go
@@ -12,6 +12,7 @@ import (
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/apimachinery/pkg/util/validation"
 	"k8s.io/utils/pointer"
@@ -20,13 +21,14 @@ import (
 )
 
 type ScanJobBuilder struct {
-	plugin        Plugin
-	pluginContext starboard.PluginContext
-	timeout       time.Duration
-	object        client.Object
-	credentials   map[string]docker.Auth
-	tolerations   []corev1.Toleration
-	annotations   map[string]string
+	plugin            Plugin
+	pluginContext     starboard.PluginContext
+	timeout           time.Duration
+	object            client.Object
+	credentials       map[string]docker.Auth
+	tolerations       []corev1.Toleration
+	annotations       map[string]string
+	podTemplateLabels labels.Set
 }
 
 func NewScanJobBuilder() *ScanJobBuilder {
@@ -63,6 +65,11 @@ func (s *ScanJobBuilder) WithAnnotations(annotations map[string]string) *ScanJob
 	return s
 }
 
+func (s *ScanJobBuilder) WithPodTemplateLabels(podTemplateLabels labels.Set) *ScanJobBuilder {
+	s.podTemplateLabels = podTemplateLabels
+	return s
+}
+
 func (s *ScanJobBuilder) WithCredentials(credentials map[string]docker.Auth) *ScanJobBuilder {
 	s.credentials = credentials
 	return s
@@ -74,7 +81,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 		return nil, nil, err
 	}
 
-	templateSpec, secrets, err := s.plugin.GetScanJobSpec(s.pluginContext, spec, s.credentials)
+	templateSpec, secrets, err := s.plugin.GetScanJobSpec(s.pluginContext, s.object, s.credentials)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -87,17 +94,24 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 
 	podSpecHash := kube.ComputeHash(spec)
 
-	labels := map[string]string{
+	labelsSet := map[string]string{
 		starboard.LabelResourceSpecHash:           podSpecHash,
 		starboard.LabelK8SAppManagedBy:            starboard.AppStarboard,
 		starboard.LabelVulnerabilityReportScanner: s.pluginContext.GetName(),
 	}
+	podTemplateLabelsSet := make(labels.Set)
+	for index, element := range labelsSet {
+		podTemplateLabelsSet[index] = element
+	}
+	for index, element := range s.podTemplateLabels {
+		podTemplateLabelsSet[index] = element
+	}
 
 	job := &batchv1.Job{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      GetScanJobName(s.object),
 			Namespace: s.pluginContext.GetNamespace(),
-			Labels:    labels,
+			Labels:    labelsSet,
 			Annotations: map[string]string{
 				starboard.AnnotationContainerImages: containerImagesAsJSON,
 			},
@@ -108,7 +122,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 			ActiveDeadlineSeconds: kube.GetActiveDeadlineSeconds(s.timeout),
 			Template: corev1.PodTemplateSpec{
 				ObjectMeta: metav1.ObjectMeta{
-					Labels:      labels,
+					Labels:      podTemplateLabelsSet,
 					Annotations: s.annotations,
 				},
 				Spec: templateSpec,
@@ -130,7 +144,7 @@ func (s *ScanJobBuilder) Get() (*batchv1.Job, []*corev1.Secret, error) {
 }
 
 func GetScanJobName(obj client.Object) string {
-	return fmt.Sprintf("scan-vulnerabilityreport-%s", kube.ComputeHash(kube.Object{
+	return fmt.Sprintf("scan-vulnerabilityreport-%s", kube.ComputeHash(kube.ObjectRef{
 		Kind:      kube.Kind(obj.GetObjectKind().GroupVersionKind().Kind),
 		Namespace: obj.GetNamespace(),
 		Name:      obj.GetName(),
@@ -143,6 +157,7 @@ type ReportBuilder struct {
 	container  string
 	hash       string
 	data       v1alpha1.VulnerabilityReportData
+	reportTTL  *time.Duration
 }
 
 func NewReportBuilder(scheme *runtime.Scheme) *ReportBuilder {
@@ -171,6 +186,11 @@ func (b *ReportBuilder) Data(data v1alpha1.VulnerabilityReportData) *ReportBuild
 	return b
 }
 
+func (b *ReportBuilder) ReportTTL(ttl *time.Duration) *ReportBuilder {
+	b.reportTTL = ttl
+	return b
+}
+
 func (b *ReportBuilder) reportName() string {
 	kind := b.controller.GetObjectKind().GroupVersionKind().Kind
 	name := b.controller.GetName()
@@ -199,6 +219,12 @@ func (b *ReportBuilder) Get() (v1alpha1.VulnerabilityReport, error) {
 		},
 		Report: b.data,
 	}
+
+	if b.reportTTL != nil {
+		report.Annotations = map[string]string{
+			v1alpha1.TTLReportAnnotation: b.reportTTL.String(),
+		}
+	}
 	err := kube.ObjectToObjectMetadata(b.controller, &report.ObjectMeta)
 	if err != nil {
 		return v1alpha1.VulnerabilityReport{}, err
diff --git a/pkg/vulnerabilityreport/io.go b/pkg/vulnerabilityreport/io.go
index 222894a..68175f4 100644
--- a/pkg/vulnerabilityreport/io.go
+++ b/pkg/vulnerabilityreport/io.go
@@ -22,15 +22,15 @@ type Writer interface {
 // Reader is the interface that wraps methods for finding v1alpha1.VulnerabilityReport objects.
 //
 // FindByOwner returns the slice of v1alpha1.VulnerabilityReport instances
-// owned by the given kube.Object or an empty slice if the reports are not found.
+// owned by the given kube.ObjectRef or an empty slice if the reports are not found.
 //
 // FindByOwnerInHierarchy is similar to FindByOwner except it tries to lookup
 // v1alpha1.VulnerabilityReport objects owned by related Kubernetes objects.
 // For example, if the given owner is a Deployment, but reports are owned by the
 // active ReplicaSet (current revision) this method will return the reports.
 type Reader interface {
-	FindByOwner(context.Context, kube.Object) ([]v1alpha1.VulnerabilityReport, error)
-	FindByOwnerInHierarchy(ctx context.Context, object kube.Object) ([]v1alpha1.VulnerabilityReport, error)
+	FindByOwner(context.Context, kube.ObjectRef) ([]v1alpha1.VulnerabilityReport, error)
+	FindByOwnerInHierarchy(ctx context.Context, object kube.ObjectRef) ([]v1alpha1.VulnerabilityReport, error)
 }
 
 type ReadWriter interface {
@@ -83,10 +83,10 @@ func (r *readWriter) createOrUpdate(ctx context.Context, report v1alpha1.Vulnera
 	return err
 }
 
-func (r *readWriter) FindByOwner(ctx context.Context, owner kube.Object) ([]v1alpha1.VulnerabilityReport, error) {
+func (r *readWriter) FindByOwner(ctx context.Context, owner kube.ObjectRef) ([]v1alpha1.VulnerabilityReport, error) {
 	var list v1alpha1.VulnerabilityReportList
 
-	labels := client.MatchingLabels(kube.PartialObjectToLabels(owner))
+	labels := client.MatchingLabels(kube.ObjectRefToLabels(owner))
 
 	err := r.List(ctx, &list, labels, client.InNamespace(owner.Namespace))
 	if err != nil {
@@ -96,7 +96,7 @@ func (r *readWriter) FindByOwner(ctx context.Context, owner kube.Object) ([]v1al
 	return list.DeepCopy().Items, nil
 }
 
-func (r *readWriter) FindByOwnerInHierarchy(ctx context.Context, owner kube.Object) ([]v1alpha1.VulnerabilityReport, error) {
+func (r *readWriter) FindByOwnerInHierarchy(ctx context.Context, owner kube.ObjectRef) ([]v1alpha1.VulnerabilityReport, error) {
 	reports, err := r.FindByOwner(ctx, owner)
 	if err != nil {
 		return nil, err
@@ -108,7 +108,7 @@ func (r *readWriter) FindByOwnerInHierarchy(ctx context.Context, owner kube.Obje
 		if err != nil {
 			return nil, fmt.Errorf("getting replicaset related to %s/%s: %w", owner.Kind, owner.Name, err)
 		}
-		reports, err = r.FindByOwner(ctx, kube.Object{
+		reports, err = r.FindByOwner(ctx, kube.ObjectRef{
 			Kind:      kube.KindReplicaSet,
 			Name:      rsName,
 			Namespace: owner.Namespace,
diff --git a/pkg/vulnerabilityreport/plugin.go b/pkg/vulnerabilityreport/plugin.go
index 3dea0d1..4290f5e 100644
--- a/pkg/vulnerabilityreport/plugin.go
+++ b/pkg/vulnerabilityreport/plugin.go
@@ -7,6 +7,7 @@ import (
 	"github.com/aquasecurity/starboard/pkg/docker"
 	"github.com/aquasecurity/starboard/pkg/starboard"
 	corev1 "k8s.io/api/core/v1"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 // Plugin defines the interface between Starboard and static vulnerability
@@ -23,7 +24,7 @@ type Plugin interface {
 	// The second argument maps container names to Docker registry credentials,
 	// which can be passed to the scanner as environment variables with values
 	// set from returned secrets.
-	GetScanJobSpec(ctx starboard.PluginContext, spec corev1.PodSpec, credentials map[string]docker.Auth) (
+	GetScanJobSpec(ctx starboard.PluginContext, workload client.Object, credentials map[string]docker.Auth) (
 		corev1.PodSpec, []*corev1.Secret, error)
 
 	// ParseVulnerabilityReportData is a callback to parse and convert logs of
diff --git a/pkg/vulnerabilityreport/scanner.go b/pkg/vulnerabilityreport/scanner.go
index 51b9d91..d7cfa74 100644
--- a/pkg/vulnerabilityreport/scanner.go
+++ b/pkg/vulnerabilityreport/scanner.go
@@ -61,10 +61,10 @@ func NewScanner(
 // or fails. When succeeded it parses container logs and coverts the output
 // to instances of v1alpha1.VulnerabilityReport by delegating such transformation
 // logic also to the Plugin.
-func (s *Scanner) Scan(ctx context.Context, workload kube.Object) ([]v1alpha1.VulnerabilityReport, error) {
+func (s *Scanner) Scan(ctx context.Context, workload kube.ObjectRef) ([]v1alpha1.VulnerabilityReport, error) {
 	klog.V(3).Infof("Getting Pod template for workload: %v", workload)
 
-	workloadObj, err := s.objectResolver.GetObjectFromPartialObject(ctx, workload)
+	workloadObj, err := s.objectResolver.ObjectFromObjectRef(ctx, workload)
 	if err != nil {
 		return nil, fmt.Errorf("resolving object: %w", err)
 	}
@@ -84,6 +84,11 @@ func (s *Scanner) Scan(ctx context.Context, workload kube.Object) ([]v1alpha1.Vu
 		return nil, fmt.Errorf("getting scan job annotations: %w", err)
 	}
 
+	scanJobPodTemplateLabels, err := s.config.GetScanJobPodTemplateLabels()
+	if err != nil {
+		return nil, fmt.Errorf("getting scan job template labels: %w", err)
+	}
+
 	klog.V(3).Infof("Scanning with options: %+v", s.opts)
 
 	credentials, err := s.secretsReader.CredentialsByWorkload(ctx, owner)
@@ -99,6 +104,7 @@ func (s *Scanner) Scan(ctx context.Context, workload kube.Object) ([]v1alpha1.Vu
 		WithCredentials(credentials).
 		WithTolerations(scanJobTolerations).
 		WithAnnotations(scanJobAnnotations).
+		WithPodTemplateLabels(scanJobPodTemplateLabels).
 		Get()
 
 	if err != nil {


Test patch:
diff --git a/itest/helper/helper.go b/itest/helper/helper.go
index e6e4752..1a823e9 100644
--- a/itest/helper/helper.go
+++ b/itest/helper/helper.go
@@ -444,7 +444,7 @@ func (h *Helper) GetActiveReplicaSetForDeployment(namespace, name string) (*apps
 
 func (h *Helper) HasCISKubeBenchReportOwnedBy(node corev1.Node) func() (bool, error) {
 	return func() (bool, error) {
-		report, err := h.kubeBenchReportReader.FindByOwner(context.Background(), kube.Object{Kind: kube.KindNode, Name: node.Name})
+		report, err := h.kubeBenchReportReader.FindByOwner(context.Background(), kube.ObjectRef{Kind: kube.KindNode, Name: node.Name})
 		if err != nil {
 			return false, err
 		}
diff --git a/itest/matcher/matcher.go b/itest/matcher/matcher.go
index 00f2e2d..0401bf9 100644
--- a/itest/matcher/matcher.go
+++ b/itest/matcher/matcher.go
@@ -109,7 +109,7 @@ func (m *vulnerabilityReportMatcher) objectToLabelsAsMatchKeys(obj client.Object
 		kind = gvk.Kind
 	}
 
-	labels := kube.PartialObjectToLabels(kube.Object{
+	labels := kube.ObjectRefToLabels(kube.ObjectRef{
 		Kind:      kube.Kind(kind),
 		Name:      obj.GetName(),
 		Namespace: obj.GetNamespace(),
diff --git a/itest/starboard/starboard_cli_test.go b/itest/starboard/starboard_cli_test.go
index 988372e..f0b428f 100644
--- a/itest/starboard/starboard_cli_test.go
+++ b/itest/starboard/starboard_cli_test.go
@@ -222,7 +222,7 @@ var _ = Describe("Starboard CLI", func() {
 				}, GinkgoWriter, GinkgoWriter)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindPod,
 					Name:      pod.Name,
 					Namespace: pod.Namespace,
@@ -266,7 +266,7 @@ var _ = Describe("Starboard CLI", func() {
 				}, GinkgoWriter, GinkgoWriter)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindPod,
 					Name:      pod.Name,
 					Namespace: pod.Namespace,
@@ -476,7 +476,7 @@ var _ = Describe("Starboard CLI", func() {
 				}, GinkgoWriter, GinkgoWriter)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindReplicaSet,
 					Name:      rs.Name,
 					Namespace: rs.Namespace,
@@ -541,7 +541,7 @@ var _ = Describe("Starboard CLI", func() {
 				}, GinkgoWriter, GinkgoWriter)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindReplicationController,
 					Name:      rc.Name,
 					Namespace: rc.Namespace,
@@ -595,7 +595,7 @@ var _ = Describe("Starboard CLI", func() {
 				revision, err := objectResolver.ReplicaSetByDeployment(ctx, deploy)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindReplicaSet,
 					Name:      revision.Name,
 					Namespace: revision.Namespace,
@@ -649,7 +649,7 @@ var _ = Describe("Starboard CLI", func() {
 				revision, err := objectResolver.ReplicaSetByDeployment(ctx, deploy)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindReplicaSet,
 					Name:      revision.Name,
 					Namespace: revision.Namespace,
@@ -716,7 +716,7 @@ var _ = Describe("Starboard CLI", func() {
 				}, GinkgoWriter, GinkgoWriter)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindStatefulSet,
 					Name:      sts.Name,
 					Namespace: sts.Namespace,
@@ -782,7 +782,7 @@ var _ = Describe("Starboard CLI", func() {
 				}, GinkgoWriter, GinkgoWriter)
 				Expect(err).ToNot(HaveOccurred())
 
-				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.Object{
+				reports, err := vulnerabilityreport.NewReadWriter(kubeClient).FindByOwner(ctx, kube.ObjectRef{
 					Kind:      kube.KindDaemonSet,
 					Name:      ds.Name,
 					Namespace: ds.Namespace,
diff --git a/pkg/configauditreport/builder_test.go b/pkg/configauditreport/builder_test.go
index 194b0be..1696bd3 100644
--- a/pkg/configauditreport/builder_test.go
+++ b/pkg/configauditreport/builder_test.go
@@ -175,7 +175,7 @@ func TestScanJobBuilder(t *testing.T) {
 		g.Expect(err).ToNot(HaveOccurred())
 		g.Expect(job).To(Equal(&batchv1.Job{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      "scan-configauditreport-fcc9884cb",
+				Name:      "scan-configauditreport-64d65c457",
 				Namespace: "starboard-ns",
 				Labels: map[string]string{
 					starboard.LabelResourceSpecHash:         "58b8989656",
@@ -235,7 +235,7 @@ func TestScanJobBuilder(t *testing.T) {
 		g.Expect(job).NotTo(BeNil())
 		g.Expect(job).To(Equal(&batchv1.Job{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      "scan-configauditreport-58ddcc9dcb",
+				Name:      "scan-configauditreport-5bfbdd65c9",
 				Namespace: "starboard-ns",
 				Labels: map[string]string{
 					starboard.LabelResourceSpecHash:         "7c48697ccf",
diff --git a/pkg/configauditreport/io_test.go b/pkg/configauditreport/io_test.go
index 0e23b54..8e1982b 100644
--- a/pkg/configauditreport/io_test.go
+++ b/pkg/configauditreport/io_test.go
@@ -167,7 +167,7 @@ func TestReadWriter(t *testing.T) {
 			}).Build()
 
 		readWriter := configauditreport.NewReadWriter(client)
-		found, err := readWriter.FindReportByOwner(context.TODO(), kube.Object{
+		found, err := readWriter.FindReportByOwner(context.TODO(), kube.ObjectRef{
 			Kind:      kube.KindDeployment,
 			Name:      "my-deploy",
 			Namespace: "my-namespace",
@@ -223,7 +223,7 @@ func TestReadWriter(t *testing.T) {
 			}).Build()
 
 		readWriter := configauditreport.NewReadWriter(client)
-		found, err := readWriter.FindReportByOwner(context.TODO(), kube.Object{
+		found, err := readWriter.FindReportByOwner(context.TODO(), kube.ObjectRef{
 			Kind:      kube.KindRole,
 			Name:      "system:controller:token-cleaner",
 			Namespace: "kube-system",
@@ -392,7 +392,7 @@ func TestReadWriter(t *testing.T) {
 			Build()
 
 		readWriter := configauditreport.NewReadWriter(client)
-		found, err := readWriter.FindClusterReportByOwner(context.TODO(), kube.Object{
+		found, err := readWriter.FindClusterReportByOwner(context.TODO(), kube.ObjectRef{
 			Kind: "ClusterRole",
 			Name: "editor",
 		})
diff --git a/pkg/kube/object_test.go b/pkg/kube/object_test.go
index 12310a7..111bbcf 100644
--- a/pkg/kube/object_test.go
+++ b/pkg/kube/object_test.go
@@ -94,15 +94,15 @@ func TestIsClusterScopedKind(t *testing.T) {
 	}
 }
 
-func TestPartialObjectToLabels(t *testing.T) {
+func TestObjectRefToLabels(t *testing.T) {
 	testCases := []struct {
 		name   string
-		object kube.Object
+		object kube.ObjectRef
 		labels map[string]string
 	}{
 		{
 			name: "Should map object with simple name",
-			object: kube.Object{
+			object: kube.ObjectRef{
 				Kind:      kube.KindPod,
 				Name:      "my-pod",
 				Namespace: "production",
@@ -115,7 +115,7 @@ func TestPartialObjectToLabels(t *testing.T) {
 		},
 		{
 			name: "Should map object with name that is not a valid label",
-			object: kube.Object{
+			object: kube.ObjectRef{
 				Kind: kube.KindClusterRole,
 				Name: "system:controller:namespace-controller",
 			},
@@ -128,7 +128,7 @@ func TestPartialObjectToLabels(t *testing.T) {
 	}
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			assert.Equal(t, tc.labels, kube.PartialObjectToLabels(tc.object))
+			assert.Equal(t, tc.labels, kube.ObjectRefToLabels(tc.object))
 		})
 	}
 }
@@ -242,12 +242,12 @@ func TestContainerImages_AsJSON_And_FromJSON(t *testing.T) {
 	assert.Equal(t, containerImages, newContainerImages)
 }
 
-func TestGetPartialObjectFromKindAndNamespacedName(t *testing.T) {
-	partial := kube.GetPartialObjectFromKindAndNamespacedName(kube.KindReplicaSet, types.NamespacedName{
+func TestObjectRefFromKindAndNamespacedName(t *testing.T) {
+	partial := kube.ObjectRefFromKindAndNamespacedName(kube.KindReplicaSet, types.NamespacedName{
 		Namespace: "prod",
 		Name:      "wordpress",
 	})
-	assert.Equal(t, kube.Object{
+	assert.Equal(t, kube.ObjectRef{
 		Kind:      kube.KindReplicaSet,
 		Name:      "wordpress",
 		Namespace: "prod",
@@ -568,7 +568,7 @@ func TestObjectResolver_GetRelatedReplicasetName(t *testing.T) {
 	).Build()}
 
 	t.Run("Should return error for unsupported kind", func(t *testing.T) {
-		_, err := instance.GetRelatedReplicasetName(context.Background(), kube.Object{
+		_, err := instance.GetRelatedReplicasetName(context.Background(), kube.ObjectRef{
 			Kind:      kube.KindStatefulSet,
 			Name:      "statefulapp",
 			Namespace: corev1.NamespaceDefault,
@@ -577,7 +577,7 @@ func TestObjectResolver_GetRelatedReplicasetName(t *testing.T) {
 	})
 
 	t.Run("Should return ReplicaSet name for the specified Deployment", func(t *testing.T) {
-		name, err := instance.GetRelatedReplicasetName(context.Background(), kube.Object{
+		name, err := instance.GetRelatedReplicasetName(context.Background(), kube.ObjectRef{
 			Kind:      kube.KindDeployment,
 			Name:      "nginx",
 			Namespace: corev1.NamespaceDefault,
@@ -587,7 +587,7 @@ func TestObjectResolver_GetRelatedReplicasetName(t *testing.T) {
 	})
 
 	t.Run("Should return ReplicaSet name for the specified Deployment", func(t *testing.T) {
-		name, err := instance.GetRelatedReplicasetName(context.Background(), kube.Object{
+		name, err := instance.GetRelatedReplicasetName(context.Background(), kube.ObjectRef{
 			Kind:      kube.KindPod,
 			Name:      "nginx-549f5fcb58-7cr5b",
 			Namespace: corev1.NamespaceDefault,
@@ -598,11 +598,11 @@ func TestObjectResolver_GetRelatedReplicasetName(t *testing.T) {
 
 }
 
-func TestPartialObjectFromObjectMetadata(t *testing.T) {
+func TestObjectRefFromObjectMeta(t *testing.T) {
 	testCases := []struct {
 		name          string
 		object        metav1.ObjectMeta
-		expected      kube.Object
+		expected      kube.ObjectRef
 		expectedError string
 	}{
 		{
@@ -617,7 +617,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 					starboard.LabelResourceName: "system:admin",
 				},
 			},
-			expected: kube.Object{Kind: kube.KindRole, Name: "system:admin", Namespace: "kube-system"},
+			expected: kube.ObjectRef{Kind: kube.KindRole, Name: "system:admin", Namespace: "kube-system"},
 		},
 		{
 			name: "Test RoleBinding",
@@ -631,7 +631,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 					starboard.LabelResourceName: "system:admin:binding",
 				},
 			},
-			expected: kube.Object{Kind: kube.KindRoleBinding, Name: "system:admin:binding", Namespace: "kube-system"},
+			expected: kube.ObjectRef{Kind: kube.KindRoleBinding, Name: "system:admin:binding", Namespace: "kube-system"},
 		},
 		{
 			name: "Kind ClusterRole",
@@ -645,7 +645,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 					starboard.LabelResourceName: "system:netnode",
 				},
 			},
-			expected: kube.Object{Kind: kube.KindClusterRole, Name: "system:netnode"},
+			expected: kube.ObjectRef{Kind: kube.KindClusterRole, Name: "system:netnode"},
 		},
 		{
 			name: "Kind ClusterRoleBinding",
@@ -659,7 +659,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 					starboard.LabelResourceName: "system:netnode:binding",
 				},
 			},
-			expected: kube.Object{Kind: kube.KindClusterRoleBindings, Name: "system:netnode:binding"},
+			expected: kube.ObjectRef{Kind: kube.KindClusterRoleBindings, Name: "system:netnode:binding"},
 		},
 		{
 			name: "Kind Pod",
@@ -670,7 +670,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 					starboard.LabelResourceName:      "nginx-pod",
 				},
 			},
-			expected: kube.Object{Kind: kube.KindPod, Name: "nginx-pod", Namespace: "default"},
+			expected: kube.ObjectRef{Kind: kube.KindPod, Name: "nginx-pod", Namespace: "default"},
 		},
 		{
 			name: "Kind Deployment",
@@ -681,7 +681,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 					starboard.LabelResourceName:      "nginx-deployment",
 				},
 			},
-			expected: kube.Object{Kind: kube.KindDeployment, Name: "nginx-deployment", Namespace: "default"},
+			expected: kube.ObjectRef{Kind: kube.KindDeployment, Name: "nginx-deployment", Namespace: "default"},
 		},
 		{
 			name: "Kind DaemonSet",
@@ -692,7 +692,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 					starboard.LabelResourceName:      "nginx-ds",
 				},
 			},
-			expected: kube.Object{Kind: kube.KindDaemonSet, Name: "nginx-ds", Namespace: "default"},
+			expected: kube.ObjectRef{Kind: kube.KindDaemonSet, Name: "nginx-ds", Namespace: "default"},
 		},
 		{
 			name: fmt.Sprintf("Should return error when %s label is missing", starboard.LabelResourceKind),
@@ -708,7 +708,7 @@ func TestPartialObjectFromObjectMetadata(t *testing.T) {
 
 	for _, tc := range testCases {
 		t.Run(tc.name, func(t *testing.T) {
-			actual, err := kube.PartialObjectFromObjectMetadata(tc.object)
+			actual, err := kube.ObjectRefFromObjectMeta(tc.object)
 			if tc.expectedError == "" {
 				require.NoError(t, err)
 				assert.Equal(t, tc.expected, actual)
diff --git a/pkg/kubebench/io_test.go b/pkg/kubebench/io_test.go
index 9d635bc..225a3ba 100644
--- a/pkg/kubebench/io_test.go
+++ b/pkg/kubebench/io_test.go
@@ -214,7 +214,7 @@ func TestReadWriter(t *testing.T) {
 			Build()
 		instance := kubebench.NewReadWriter(client)
 
-		found, err := instance.FindByOwner(context.Background(), kube.Object{Name: "worker"})
+		found, err := instance.FindByOwner(context.Background(), kube.ObjectRef{Name: "worker"})
 		require.NoError(t, err)
 
 		assert.Equal(t, &v1alpha1.CISKubeBenchReport{
diff --git a/pkg/operator/controller/ttl_report_test.go b/pkg/operator/controller/ttl_report_test.go
new file mode 100644
index 0000000..45c4a09
--- /dev/null
+++ b/pkg/operator/controller/ttl_report_test.go
@@ -0,0 +1,28 @@
+package controller
+
+import (
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestTTLIsExpired(t *testing.T) {
+	ttlReportAnnotationStr := "10h"
+	ttlReportTime, _ := time.ParseDuration(ttlReportAnnotationStr)
+	creationTime := time.Now()
+	ttlExpired, _, err := ttlIsExpired(ttlReportTime, creationTime)
+	assert.NoError(t, err)
+	assert.False(t, ttlExpired)
+}
+
+func TestTTLIsNotExpired(t *testing.T) {
+	ttlReportAnnotationStr := "10s"
+	ttlReportTime, _ := time.ParseDuration(ttlReportAnnotationStr)
+	creationTime := time.Now()
+	then := creationTime.Add(time.Duration(-10) * time.Minute)
+	ttlExpired, durationToTTLExp, err := ttlIsExpired(ttlReportTime, then)
+	t.Logf("Duration to ttl expiration %s, we should rescheduel check", durationToTTLExp)
+	assert.NoError(t, err)
+	assert.True(t, ttlExpired)
+}
diff --git a/pkg/plugin/conftest/plugin_test.go b/pkg/plugin/conftest/plugin_test.go
index 48ad6e0..e6ae811 100644
--- a/pkg/plugin/conftest/plugin_test.go
+++ b/pkg/plugin/conftest/plugin_test.go
@@ -402,7 +402,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 		"Affinity":                     Equal(starboard.LinuxNodeAffinity()),
 		"Volumes": ConsistOf(
 			MatchFields(IgnoreExtras, Fields{
-				"Name": Equal("scan-configauditreport-5d4445db4f-volume"),
+				"Name": Equal("scan-configauditreport-789cbb5cc4-volume"),
 				// We cannot inline assert here on other properties with the MatchFields matcher
 				// because the value of the Secret field is the pointer to v1.SecretVolumeSource.
 				// The MatchFields matcher only works with structs :-(
@@ -426,31 +426,31 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 				}),
 				"VolumeMounts": ConsistOf(
 					corev1.VolumeMount{
-						Name:      "scan-configauditreport-5d4445db4f-volume",
+						Name:      "scan-configauditreport-789cbb5cc4-volume",
 						MountPath: "/project/policy/kubernetes.rego",
 						SubPath:   "kubernetes.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "scan-configauditreport-5d4445db4f-volume",
+						Name:      "scan-configauditreport-789cbb5cc4-volume",
 						MountPath: "/project/policy/utils.rego",
 						SubPath:   "utils.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "scan-configauditreport-5d4445db4f-volume",
+						Name:      "scan-configauditreport-789cbb5cc4-volume",
 						MountPath: "/project/policy/access_to_host_pid.rego",
 						SubPath:   "access_to_host_pid.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "scan-configauditreport-5d4445db4f-volume",
+						Name:      "scan-configauditreport-789cbb5cc4-volume",
 						MountPath: "/project/policy/cpu_not_limited.rego",
 						SubPath:   "cpu_not_limited.rego",
 						ReadOnly:  true,
 					},
 					corev1.VolumeMount{
-						Name:      "scan-configauditreport-5d4445db4f-volume",
+						Name:      "scan-configauditreport-789cbb5cc4-volume",
 						MountPath: "/project/workload.yaml",
 						SubPath:   "workload.yaml",
 						ReadOnly:  true,
@@ -476,7 +476,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 		"SecurityContext": Equal(&corev1.PodSecurityContext{}),
 	}))
 	g.Expect(*jobSpec.Volumes[0].VolumeSource.Secret).To(MatchFields(IgnoreExtras, Fields{
-		"SecretName": Equal("scan-configauditreport-5d4445db4f-volume"),
+		"SecretName": Equal("scan-configauditreport-789cbb5cc4-volume"),
 		"Items": ConsistOf(
 			corev1.KeyToPath{
 				Key:  "conftest.library.kubernetes.rego",
@@ -503,7 +503,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 	g.Expect(secrets).To(ConsistOf(
 		&corev1.Secret{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      "scan-configauditreport-5d4445db4f-volume",
+				Name:      "scan-configauditreport-789cbb5cc4-volume",
 				Namespace: "starboard-ns",
 			},
 			StringData: map[string]string{
diff --git a/pkg/plugin/trivy/plugin_test.go b/pkg/plugin/trivy/plugin_test.go
index 47d9965..97ea78d 100644
--- a/pkg/plugin/trivy/plugin_test.go
+++ b/pkg/plugin/trivy/plugin_test.go
@@ -14,11 +14,13 @@ import (
 	"github.com/aquasecurity/starboard/pkg/starboard"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 )
 
@@ -442,7 +444,7 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 		name string
 
 		config       map[string]string
-		workloadSpec corev1.PodSpec
+		workloadSpec client.Object
 
 		expectedSecrets []corev1.Secret
 		expectedJobSpec corev1.PodSpec
@@ -458,11 +460,25 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 				"trivy.resources.limits.cpu":      "500m",
 				"trivy.resources.limits.memory":   "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "nginx:1.16",
+			workloadSpec: &appsv1.ReplicaSet{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "ReplicaSet",
+					APIVersion: "apps/v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx-6799fc88d8",
+					Namespace: "prod-ns",
+				},
+				Spec: appsv1.ReplicaSetSpec{
+					Template: corev1.PodTemplateSpec{
+						Spec: corev1.PodSpec{
+							Containers: []corev1.Container{
+								{
+									Name:  "nginx",
+									Image: "nginx:1.16",
+								},
+							},
+						},
 					},
 				},
 			},
@@ -542,8 +558,9 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 							"trivy",
 						},
 						Args: []string{
-							"--download-db-only",
 							"--cache-dir", "/var/lib/trivy",
+							"image",
+							"--download-db-only",
 						},
 						Resources: corev1.ResourceRequirements{
 							Requests: corev1.ResourceList{
@@ -660,9 +677,10 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 							"trivy",
 						},
 						Args: []string{
-							"--skip-update",
 							"--cache-dir", "/var/lib/trivy",
 							"--quiet",
+							"image",
+							"--skip-update",
 							"--format", "json",
 							"nginx:1.16",
 						},
@@ -708,14 +726,23 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 				"trivy.resources.limits.cpu":      "500m",
 				"trivy.resources.limits.memory":   "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
-					},
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
 				},
-			},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
+						},
+					},
+				}},
 			expectedJobSpec: corev1.PodSpec{
 				Affinity:                     starboard.LinuxNodeAffinity(),
 				RestartPolicy:                corev1.RestartPolicyNever,
@@ -791,8 +818,9 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 							"trivy",
 						},
 						Args: []string{
-							"--download-db-only",
 							"--cache-dir", "/var/lib/trivy",
+							"image",
+							"--download-db-only",
 						},
 						Resources: corev1.ResourceRequirements{
 							Requests: corev1.ResourceList{
@@ -913,9 +941,10 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 							"trivy",
 						},
 						Args: []string{
-							"--skip-update",
 							"--cache-dir", "/var/lib/trivy",
 							"--quiet",
+							"image",
+							"--skip-update",
 							"--format", "json",
 							"poc.myregistry.harbor.com.pl/nginx:1.16",
 						},
@@ -960,11 +989,21 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 				"trivy.resources.limits.cpu":       "500m",
 				"trivy.resources.limits.memory":    "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
+						},
 					},
 				},
 			},
@@ -1043,8 +1082,9 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 							"trivy",
 						},
 						Args: []string{
-							"--download-db-only",
 							"--cache-dir", "/var/lib/trivy",
+							"image",
+							"--download-db-only",
 						},
 						Resources: corev1.ResourceRequirements{
 							Requests: corev1.ResourceList{
@@ -1165,9 +1205,10 @@ func TestPlugin_GetScanJobSpec(t *testing.T) {
 							"trivy",
 						},
 						Args: []string{
-							"--skip-update",
 							"--cache-dir", "/var/lib/trivy",
 							"--quiet",
+							"image",
+							"--skip-update",
 							"--format", "json",
 							"poc.myregistry.harbor.com.pl/nginx:1.16",
 						},
@@ -1216,11 +1257,21 @@ CVE-2019-1543`,
 				"trivy.resources.limits.cpu":      "500m",
 				"trivy.resources.limits.memory":   "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "nginx:1.16",
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "nginx:1.16",
+						},
 					},
 				},
 			},
@@ -1316,8 +1367,9 @@ CVE-2019-1543`,
 							"trivy",
 						},
 						Args: []string{
-							"--download-db-only",
 							"--cache-dir", "/var/lib/trivy",
+							"image",
+							"--download-db-only",
 						},
 						Resources: corev1.ResourceRequirements{
 							Requests: corev1.ResourceList{
@@ -1438,9 +1490,10 @@ CVE-2019-1543`,
 							"trivy",
 						},
 						Args: []string{
-							"--skip-update",
 							"--cache-dir", "/var/lib/trivy",
 							"--quiet",
+							"image",
+							"--skip-update",
 							"--format", "json",
 							"nginx:1.16",
 						},
@@ -1492,11 +1545,21 @@ CVE-2019-1543`,
 
 				"trivy.registry.mirror.index.docker.io": "mirror.io",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "nginx:1.16",
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "nginx:1.16",
+						},
 					},
 				},
 			},
@@ -1576,8 +1639,9 @@ CVE-2019-1543`,
 							"trivy",
 						},
 						Args: []string{
-							"--download-db-only",
 							"--cache-dir", "/var/lib/trivy",
+							"image",
+							"--download-db-only",
 						},
 						Resources: corev1.ResourceRequirements{
 							Requests: corev1.ResourceList{
@@ -1694,9 +1758,10 @@ CVE-2019-1543`,
 							"trivy",
 						},
 						Args: []string{
-							"--skip-update",
 							"--cache-dir", "/var/lib/trivy",
 							"--quiet",
+							"image",
+							"--skip-update",
 							"--format", "json",
 							"mirror.io/library/nginx:1.16",
 						},
@@ -1741,11 +1806,21 @@ CVE-2019-1543`,
 				"trivy.resources.limits.cpu":      "500m",
 				"trivy.resources.limits.memory":   "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "nginx:1.16",
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "nginx:1.16",
+						},
 					},
 				},
 			},
@@ -1920,11 +1995,21 @@ CVE-2019-1543`,
 				"trivy.resources.limits.cpu":         "500m",
 				"trivy.resources.limits.memory":      "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
+						},
 					},
 				},
 			},
@@ -2103,11 +2188,21 @@ CVE-2019-1543`,
 				"trivy.resources.limits.cpu":       "500m",
 				"trivy.resources.limits.memory":    "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "poc.myregistry.harbor.com.pl/nginx:1.16",
+						},
 					},
 				},
 			},
@@ -2290,11 +2385,21 @@ CVE-2019-1543`,
 				"trivy.resources.limits.cpu":      "500m",
 				"trivy.resources.limits.memory":   "500M",
 			},
-			workloadSpec: corev1.PodSpec{
-				Containers: []corev1.Container{
-					{
-						Name:  "nginx",
-						Image: "nginx:1.16",
+			workloadSpec: &corev1.Pod{
+				TypeMeta: metav1.TypeMeta{
+					Kind:       "Pod",
+					APIVersion: "v1",
+				},
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "nginx",
+					Namespace: "prod-ns",
+				},
+				Spec: corev1.PodSpec{
+					Containers: []corev1.Container{
+						{
+							Name:  "nginx",
+							Image: "nginx:1.16",
+						},
 					},
 				},
 			},
diff --git a/pkg/starboard/config_test.go b/pkg/starboard/config_test.go
index 9f3208f..29cd3d6 100644
--- a/pkg/starboard/config_test.go
+++ b/pkg/starboard/config_test.go
@@ -11,40 +11,275 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/labels"
 	"k8s.io/client-go/kubernetes/fake"
 )
 
-func TestGetVersionFromImageRef(t *testing.T) {
+func TestConfigData_GetVulnerabilityReportsScanner(t *testing.T) {
 	testCases := []struct {
-		imageRef        string
-		expectedVersion string
+		name            string
+		configData      starboard.ConfigData
+		expectedError   string
+		expectedScanner starboard.Scanner
 	}{
 		{
-			imageRef:        "docker.io/aquasec/trivy:0.9.1",
-			expectedVersion: "0.9.1",
+			name: "Should return Trivy",
+			configData: starboard.ConfigData{
+				"vulnerabilityReports.scanner": "Trivy",
+			},
+			expectedScanner: starboard.Trivy,
 		},
 		{
-			imageRef:        "docker.io/aquasec/trivy@sha256:5020dac24a63ef4f24452a0c63ebbfe93a5309e40f6353d1ee8221d2184ee954",
-			expectedVersion: "sha256:5020dac24a63ef4f24452a0c63ebbfe93a5309e40f6353d1ee8221d2184ee954",
+			name: "Should return Aqua",
+			configData: starboard.ConfigData{
+				"vulnerabilityReports.scanner": "Aqua",
+			},
+			expectedScanner: starboard.Aqua,
 		},
 		{
-			imageRef:        "aquasec/trivy:0.9.1",
-			expectedVersion: "0.9.1",
+			name:          "Should return error when value is not set",
+			configData:    starboard.ConfigData{},
+			expectedError: "property vulnerabilityReports.scanner not set",
 		},
 		{
-			imageRef:        "aquasec/trivy:latest",
-			expectedVersion: "latest",
+			name: "Should return error when value is not allowed",
+			configData: starboard.ConfigData{
+				"vulnerabilityReports.scanner": "Clair",
+			},
+			expectedError: "invalid value (Clair) of vulnerabilityReports.scanner; allowed values (Trivy, Aqua)",
 		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			scanner, err := tc.configData.GetVulnerabilityReportsScanner()
+			if tc.expectedError != "" {
+				require.EqualError(t, err, tc.expectedError)
+			} else {
+				require.NoError(t, err)
+				assert.Equal(t, tc.expectedScanner, scanner)
+			}
+		})
+	}
+}
+
+func TestConfigData_GetConfigAuditReportsScanner(t *testing.T) {
+	testCases := []struct {
+		name            string
+		configData      starboard.ConfigData
+		expectedError   string
+		expectedScanner starboard.Scanner
+	}{
 		{
-			imageRef:        "aquasec/trivy",
-			expectedVersion: "latest",
+			name: "Should return Polaris",
+			configData: starboard.ConfigData{
+				"configAuditReports.scanner": "Polaris",
+			},
+			expectedScanner: starboard.Polaris,
+		},
+		{
+			name: "Should return Conftest",
+			configData: starboard.ConfigData{
+				"configAuditReports.scanner": "Conftest",
+			},
+			expectedScanner: starboard.Conftest,
+		},
+		{
+			name:          "Should return error when value is not set",
+			configData:    starboard.ConfigData{},
+			expectedError: "property configAuditReports.scanner not set",
+		},
+		{
+			name: "Should return error when value is not allowed",
+			configData: starboard.ConfigData{
+				"configAuditReports.scanner": "KubeScan",
+			},
+			expectedError: "invalid value (KubeScan) of configAuditReports.scanner; allowed values (Polaris, Conftest)",
+		},
+	}
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			scanner, err := tc.configData.GetConfigAuditReportsScanner()
+			if tc.expectedError != "" {
+				require.EqualError(t, err, tc.expectedError)
+			} else {
+				require.NoError(t, err)
+				assert.Equal(t, tc.expectedScanner, scanner)
+			}
+		})
+	}
+}
+
+func TestConfigData_GetScanJobTolerations(t *testing.T) {
+	testCases := []struct {
+		name        string
+		config      starboard.ConfigData
+		expected    []corev1.Toleration
+		expectError string
+	}{
+		{
+			name:     "no scanJob.tolerations in ConfigData",
+			config:   starboard.ConfigData{},
+			expected: []corev1.Toleration(nil),
+		},
+		{
+			name:        "scanJob.tolerations value is not json",
+			config:      starboard.ConfigData{"scanJob.tolerations": `lolwut`},
+			expected:    []corev1.Toleration(nil),
+			expectError: "invalid character 'l' looking for beginning of value",
+		},
+		{
+			name:     "empty JSON array",
+			config:   starboard.ConfigData{"scanJob.tolerations": `[]`},
+			expected: []corev1.Toleration{},
+		},
+		{
+			name: "one valid toleration",
+			config: starboard.ConfigData{
+				"scanJob.tolerations": `[{"key":"key1","operator":"Equal","value":"value1","effect":"NoSchedule"}]`},
+			expected: []corev1.Toleration{{
+				Key:      "key1",
+				Operator: "Equal",
+				Value:    "value1",
+				Effect:   "NoSchedule",
+			}},
+		},
+		{
+			name: "multiple valid tolerations",
+			config: starboard.ConfigData{
+				"scanJob.tolerations": `[{"key":"key1","operator":"Equal","value":"value1","effect":"NoSchedule"},
+					  {"key":"key2","operator":"Equal","value":"value2","effect":"NoSchedule"}]`},
+			expected: []corev1.Toleration{
+				{
+					Key:      "key1",
+					Operator: "Equal",
+					Value:    "value1",
+					Effect:   "NoSchedule",
+				},
+				{
+					Key:      "key2",
+					Operator: "Equal",
+					Value:    "value2",
+					Effect:   "NoSchedule",
+				},
+			},
 		},
 	}
 
 	for _, tc := range testCases {
-		t.Run(tc.imageRef, func(t *testing.T) {
-			version, _ := starboard.GetVersionFromImageRef(tc.imageRef)
-			assert.Equal(t, tc.expectedVersion, version)
+		t.Run(tc.name, func(t *testing.T) {
+			got, err := tc.config.GetScanJobTolerations()
+			if tc.expectError != "" {
+				assert.Error(t, err, "unexpected end of JSON input", tc.name)
+			} else {
+				assert.NoError(t, err, tc.name)
+			}
+			assert.Equal(t, tc.expected, got, tc.name)
+		})
+	}
+}
+
+func TestConfigData_GetScanJobAnnotations(t *testing.T) {
+	testCases := []struct {
+		name        string
+		config      starboard.ConfigData
+		expected    map[string]string
+		expectError string
+	}{
+		{
+			name: "scan job annotations can be fetched successfully",
+			config: starboard.ConfigData{
+				"scanJob.annotations": "a.b=c.d/e,foo=bar",
+			},
+			expected: map[string]string{
+				"foo": "bar",
+				"a.b": "c.d/e",
+			},
+		},
+		{
+			name:     "gracefully deal with unprovided annotations",
+			config:   starboard.ConfigData{},
+			expected: map[string]string{},
+		},
+		{
+			name: "raise an error on being provided with annotations in wrong format",
+			config: starboard.ConfigData{
+				"scanJob.annotations": "foo",
+			},
+			expected:    map[string]string{},
+			expectError: "failed parsing incorrectly formatted custom scan job annotations: foo",
+		},
+		{
+			name: "raise an error on being provided with annotations in wrong format",
+			config: starboard.ConfigData{
+				"scanJob.annotations": "foo=bar,a=b=c",
+			},
+			expected:    map[string]string{},
+			expectError: "failed parsing incorrectly formatted custom scan job annotations: foo=bar,a=b=c",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			scanJobAnnotations, err := tc.config.GetScanJobAnnotations()
+			if tc.expectError != "" {
+				assert.EqualError(t, err, tc.expectError, tc.name)
+			} else {
+				assert.NoError(t, err, tc.name)
+				assert.Equal(t, tc.expected, scanJobAnnotations, tc.name)
+			}
+		})
+	}
+}
+
+func TestConfigData_GetScanJobPodTemplateLabels(t *testing.T) {
+	testCases := []struct {
+		name        string
+		config      starboard.ConfigData
+		expected    labels.Set
+		expectError string
+	}{
+		{
+			name: "scan job template labels can be fetched successfully",
+			config: starboard.ConfigData{
+				"scanJob.podTemplateLabels": "a.b=c.d/e,foo=bar",
+			},
+			expected: labels.Set{
+				"foo": "bar",
+				"a.b": "c.d/e",
+			},
+		},
+		{
+			name:     "gracefully deal with unprovided annotations",
+			config:   starboard.ConfigData{},
+			expected: labels.Set{},
+		},
+		{
+			name: "raise an error on being provided with annotations in wrong format",
+			config: starboard.ConfigData{
+				"scanJob.podTemplateLabels": "foo",
+			},
+			expected:    labels.Set{},
+			expectError: "failed parsing incorrectly formatted custom scan pod template labels: foo",
+		},
+		{
+			name: "raise an error on being provided with template labels in wrong format",
+			config: starboard.ConfigData{
+				"scanJob.podTemplateLabels": "foo=bar,a=b=c",
+			},
+			expected:    labels.Set{},
+			expectError: "failed parsing incorrectly formatted custom scan pod template labels: foo=bar,a=b=c",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			scanJobPodTemplateLabels, err := tc.config.GetScanJobPodTemplateLabels()
+			if tc.expectError != "" {
+				assert.EqualError(t, err, tc.expectError, tc.name)
+			} else {
+				assert.NoError(t, err, tc.name)
+				assert.Equal(t, tc.expected, scanJobPodTemplateLabels, tc.name)
+			}
 		})
 	}
 }
@@ -163,49 +398,37 @@ func TestConfigData_GetKubeHunterQuick(t *testing.T) {
 	}
 }
 
-func TestConfigData_GetVulnerabilityReportsScanner(t *testing.T) {
+func TestGetVersionFromImageRef(t *testing.T) {
 	testCases := []struct {
-		name            string
-		configData      starboard.ConfigData
-		expectedError   string
-		expectedScanner starboard.Scanner
+		imageRef        string
+		expectedVersion string
 	}{
 		{
-			name: "Should return Trivy",
-			configData: starboard.ConfigData{
-				"vulnerabilityReports.scanner": "Trivy",
-			},
-			expectedScanner: starboard.Trivy,
+			imageRef:        "docker.io/aquasec/trivy:0.9.1",
+			expectedVersion: "0.9.1",
 		},
 		{
-			name: "Should return Aqua",
-			configData: starboard.ConfigData{
-				"vulnerabilityReports.scanner": "Aqua",
-			},
-			expectedScanner: starboard.Aqua,
+			imageRef:        "docker.io/aquasec/trivy@sha256:5020dac24a63ef4f24452a0c63ebbfe93a5309e40f6353d1ee8221d2184ee954",
+			expectedVersion: "sha256:5020dac24a63ef4f24452a0c63ebbfe93a5309e40f6353d1ee8221d2184ee954",
 		},
 		{
-			name:          "Should return error when value is not set",
-			configData:    starboard.ConfigData{},
-			expectedError: "property vulnerabilityReports.scanner not set",
+			imageRef:        "aquasec/trivy:0.9.1",
+			expectedVersion: "0.9.1",
 		},
 		{
-			name: "Should return error when value is not allowed",
-			configData: starboard.ConfigData{
-				"vulnerabilityReports.scanner": "Clair",
-			},
-			expectedError: "invalid value (Clair) of vulnerabilityReports.scanner; allowed values (Trivy, Aqua)",
+			imageRef:        "aquasec/trivy:latest",
+			expectedVersion: "latest",
+		},
+		{
+			imageRef:        "aquasec/trivy",
+			expectedVersion: "latest",
 		},
 	}
+
 	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			scanner, err := tc.configData.GetVulnerabilityReportsScanner()
-			if tc.expectedError != "" {
-				require.EqualError(t, err, tc.expectedError)
-			} else {
-				require.NoError(t, err)
-				assert.Equal(t, tc.expectedScanner, scanner)
-			}
+		t.Run(tc.imageRef, func(t *testing.T) {
+			version, _ := starboard.GetVersionFromImageRef(tc.imageRef)
+			assert.Equal(t, tc.expectedVersion, version)
 		})
 	}
 }
@@ -372,125 +595,3 @@ func TestConfigManager_Delete(t *testing.T) {
 		assert.True(t, errors.IsNotFound(err))
 	})
 }
-
-func TestGetScanJobTolerations(t *testing.T) {
-	testCases := []struct {
-		name        string
-		config      starboard.ConfigData
-		expected    []corev1.Toleration
-		expectError string
-	}{
-		{
-			name:     "no scanJob.tolerations in ConfigData",
-			config:   starboard.ConfigData{},
-			expected: []corev1.Toleration{},
-		},
-		{
-			name:        "scanJob.tolerations value is not json",
-			config:      starboard.ConfigData{"scanJob.tolerations": `lolwut`},
-			expected:    []corev1.Toleration{},
-			expectError: "invalid character 'l' looking for beginning of value",
-		},
-		{
-			name:     "empty JSON array",
-			config:   starboard.ConfigData{"scanJob.tolerations": `[]`},
-			expected: []corev1.Toleration{},
-		},
-		{
-			name: "one valid toleration",
-			config: starboard.ConfigData{
-				"scanJob.tolerations": `[{"key":"key1","operator":"Equal","value":"value1","effect":"NoSchedule"}]`},
-			expected: []corev1.Toleration{{
-				Key:      "key1",
-				Operator: "Equal",
-				Value:    "value1",
-				Effect:   "NoSchedule",
-			}},
-		},
-		{
-			name: "multiple valid tolerations",
-			config: starboard.ConfigData{
-				"scanJob.tolerations": `[{"key":"key1","operator":"Equal","value":"value1","effect":"NoSchedule"},
-					  {"key":"key2","operator":"Equal","value":"value2","effect":"NoSchedule"}]`},
-			expected: []corev1.Toleration{
-				{
-					Key:      "key1",
-					Operator: "Equal",
-					Value:    "value1",
-					Effect:   "NoSchedule",
-				},
-				{
-					Key:      "key2",
-					Operator: "Equal",
-					Value:    "value2",
-					Effect:   "NoSchedule",
-				},
-			},
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			got, err := tc.config.GetScanJobTolerations()
-			if tc.expectError != "" {
-				assert.Error(t, err, "unexpected end of JSON input", tc.name)
-			} else {
-				assert.NoError(t, err, tc.name)
-			}
-			assert.Equal(t, tc.expected, got, tc.name)
-		})
-	}
-}
-
-func TestGetScanJobAnnotations(t *testing.T) {
-	testCases := []struct {
-		name        string
-		config      starboard.ConfigData
-		expected    map[string]string
-		expectError string
-	}{
-		{
-			name: "scan job annotations can be fetched successfully",
-			config: starboard.ConfigData{
-				"scanJob.annotations": "a.b=c.d/e,foo=bar",
-			},
-			expected: map[string]string{
-				"foo": "bar",
-				"a.b": "c.d/e",
-			},
-		},
-		{
-			name:     "gracefully deal with unprovided annotations",
-			config:   starboard.ConfigData{},
-			expected: map[string]string{},
-		},
-		{
-			name: "raise an error on being provided with annotations in wrong format",
-			config: starboard.ConfigData{
-				"scanJob.annotations": "foo",
-			},
-			expected:    map[string]string{},
-			expectError: "custom annotations found to be wrongfully provided: foo",
-		},
-		{
-			name: "raise an error on being provided with annotations in wrong format",
-			config: starboard.ConfigData{
-				"scanJob.annotations": "foo=bar,a=b=c",
-			},
-			expected:    map[string]string{},
-			expectError: "custom annotations found to be wrongfully provided: foo=bar,a=b=c",
-		},
-	}
-
-	for _, tc := range testCases {
-		t.Run(tc.name, func(t *testing.T) {
-			scanJobAnnotations, err := tc.config.GetScanJobAnnotations()
-			if tc.expectError != "" {
-				assert.Error(t, err, tc.expectError, tc.name)
-			} else {
-				assert.NoError(t, err, tc.name)
-			}
-			assert.Equal(t, tc.expected, scanJobAnnotations, tc.name)
-		})
-	}
-}
diff --git a/pkg/vulnerabilityreport/builder_test.go b/pkg/vulnerabilityreport/builder_test.go
index f3690b4..c96ce70 100644
--- a/pkg/vulnerabilityreport/builder_test.go
+++ b/pkg/vulnerabilityreport/builder_test.go
@@ -16,6 +16,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/utils/pointer"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
 func TestReportBuilder(t *testing.T) {
@@ -99,7 +100,7 @@ func TestScanJobBuilder(t *testing.T) {
 	g.Expect(job).ToNot(gomega.BeNil())
 	g.Expect(job).To(gomega.Equal(&batchv1.Job{
 		ObjectMeta: metav1.ObjectMeta{
-			Name:      "scan-vulnerabilityreport-fcc9884cb",
+			Name:      "scan-vulnerabilityreport-64d65c457",
 			Namespace: "starboard-ns",
 			Labels: map[string]string{
 				starboard.LabelK8SAppManagedBy:            "starboard",
@@ -141,7 +142,7 @@ func (p *testPlugin) Init(_ starboard.PluginContext) error {
 	return nil
 }
 
-func (p *testPlugin) GetScanJobSpec(_ starboard.PluginContext, _ corev1.PodSpec, _ map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
+func (p *testPlugin) GetScanJobSpec(_ starboard.PluginContext, _ client.Object, _ map[string]docker.Auth) (corev1.PodSpec, []*corev1.Secret, error) {
 	return corev1.PodSpec{}, nil, nil
 }
 
diff --git a/pkg/vulnerabilityreport/io_test.go b/pkg/vulnerabilityreport/io_test.go
index a6430ae..d74fde4 100644
--- a/pkg/vulnerabilityreport/io_test.go
+++ b/pkg/vulnerabilityreport/io_test.go
@@ -241,7 +241,7 @@ func TestNewReadWriter(t *testing.T) {
 		}).Build()
 
 		readWriter := vulnerabilityreport.NewReadWriter(client)
-		list, err := readWriter.FindByOwner(context.TODO(), kube.Object{
+		list, err := readWriter.FindByOwner(context.TODO(), kube.ObjectRef{
 			Kind:      kube.KindDeployment,
 			Name:      "my-deploy",
 			Namespace: "my-namespace",