Repository: FairwindsOps/polaris
Pull request #277 (2020-04-27 11:42:43)

Bump github.com/sirupsen/logrus from 1.4.2 to 1.5.0
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.4.2 to 1.5.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/sirupsen/logrus/releases">github.com/sirupsen/logrus's releases</a>.</em></p>
<blockquote>
<h2>v1.5.0</h2>
<p>This new release introduces:</p>
<ul>
<li>Ability to DisableHTMLEscape when using the JSON formatter: <a href="https://github-redirect.dependabot.com/sirupsen/logrus/pull/524">sirupsen/logrus#524</a></li>
<li>Support/fixes for go 1.14</li>
<li>Many many bugfixes</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/sirupsen/logrus/commit/d417be0fe654de640a82370515129985b407c7e3"><code>d417be0</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/sirupsen/logrus/issues/1108">#1108</a> from cirelli94/fix-wrong-caller</li>
<li><a href="https://github.com/sirupsen/logrus/commit/32fd1078164014048662f58c9a2ab4a45c185381"><code>32fd107</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/sirupsen/logrus/issues/1103">#1103</a> from sirupsen/fix-go114</li>
<li><a href="https://github.com/sirupsen/logrus/commit/ddb57a2a54811e7f39c5d947d69c88a4623f797b"><code>ddb57a2</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/sirupsen/logrus/issues/1110">#1110</a> from Dattax/patch-1</li>
<li><a href="https://github.com/sirupsen/logrus/commit/a635f0489d2a980cbb55728885bcdddf99bd4667"><code>a635f04</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/sirupsen/logrus/issues/1113">#1113</a> from davidraleigh/html-escape</li>
<li><a href="https://github.com/sirupsen/logrus/commit/4ddc9cf62ed5abfc09e0f8ab08002a1238d6cf1f"><code>4ddc9cf</code></a> Merge pull request <a href="https://github-redirect.dependabot.com/sirupsen/logrus/issues/1116">#1116</a> from admacleod/master</li>
<li><a href="https://github.com/sirupsen/logrus/commit/e3e40605a2a706827801190746fd3ae99f6f4872"><code>e3e4060</code></a> remove errant whitespace</li>
<li><a href="https://github.com/sirupsen/logrus/commit/ba670baee189f68debc2d23e69b848d46436916a"><code>ba670ba</code></a> fix deadlock in previous entry race condition fix</li>
<li><a href="https://github.com/sirupsen/logrus/commit/b28acda22db49a5e5ff39f3c23968b02a3585dda"><code>b28acda</code></a> fix race condition in entry</li>
<li><a href="https://github.com/sirupsen/logrus/commit/e76a5c4450e47f607abd9161feb7700ec944a750"><code>e76a5c4</code></a> create test to prove issue <a href="https://github-redirect.dependabot.com/sirupsen/logrus/issues/954">sirupsen/logrus#954</a></li>
<li><a href="https://github.com/sirupsen/logrus/commit/0fb945b034620199c178b1b7067672a9f8f69c3a"><code>0fb945b</code></a> resolved conflicts</li>
<li>Additional commits viewable in <a href="https://github.com/sirupsen/logrus/compare/v1.4.2...v1.5.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://api.dependabot.com/badges/compatibility_score?dependency-name=github.com/sirupsen/logrus&package-manager=go_modules&previous-version=1.4.2&new-version=1.5.0)](https://dependabot.com/compatibility-score/?dependency-name=github.com/sirupsen/logrus&package-manager=go_modules&previous-version=1.4.2&new-version=1.5.0)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

**Note:** This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit.

You can always request more updates by clicking `Bump now` in your [Dependabot dashboard](https://app.dependabot.com).

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language
- `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme

Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com):
- Update frequency (including time of day and day of week)
- Pull request limits (per update run and/or open at any time)
- Automerge options (never/patch/minor, and dev/runtime dependencies)
- Out-of-range updates (receive only lockfile updates, if desired)
- Security updates (receive only security updates, if desired)



</details>

codecov[bot]: # [Codecov](https://codecov.io/gh/FairwindsOps/polaris/pull/277?src=pr&el=h1) Report
> Merging [#277](https://codecov.io/gh/FairwindsOps/polaris/pull/277?src=pr&el=desc) into [master](https://codecov.io/gh/FairwindsOps/polaris/commit/cfc0d213cd603793d8e36eecfb0def1579a34997&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/FairwindsOps/polaris/pull/277/graphs/tree.svg?width=650&height=150&src=pr&token=RR1ySHa61e)](https://codecov.io/gh/FairwindsOps/polaris/pull/277?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master     #277   +/-   ##
=======================================
  Coverage   55.64%   55.64%           
=======================================
  Files          12       12           
  Lines         629      629           
=======================================
  Hits          350      350           
  Misses        247      247           
  Partials       32       32           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/FairwindsOps/polaris/pull/277?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/FairwindsOps/polaris/pull/277?src=pr&el=footer). Last update [cfc0d21...a3fbef4](https://codecov.io/gh/FairwindsOps/polaris/pull/277?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/Dockerfile b/Dockerfile
index 3be51aab..5f573a4c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,13 +3,16 @@ WORKDIR /go/src/github.com/fairwindsops/polaris/
 
 ENV GO111MODULE=on
 ENV GOPROXY=https://proxy.golang.org
-
-COPY . .
-RUN go get -u github.com/gobuffalo/packr/v2/packr2
-
 ENV CGO_ENABLED=0
 ENV GOOS=linux
 ENV GOARCH=amd64
+
+COPY go.mod .
+COPY go.sum .
+RUN go mod download
+RUN go get -u github.com/gobuffalo/packr/v2/packr2
+
+COPY . .
 RUN packr2 build -a -o polaris *.go
 
 FROM alpine:3.10
diff --git a/checks/notReadOnlyRootFileSystem.yaml b/checks/notReadOnlyRootFilesystem.yaml
similarity index 100%
rename from checks/notReadOnlyRootFileSystem.yaml
rename to checks/notReadOnlyRootFilesystem.yaml
diff --git a/cmd/polaris/webhook.go b/cmd/polaris/webhook.go
index be9fa5ea..443947d8 100644
--- a/cmd/polaris/webhook.go
+++ b/cmd/polaris/webhook.go
@@ -15,7 +15,6 @@
 package cmd
 
 import (
-	"fmt"
 	"io/ioutil"
 	"os"
 	"strings"
@@ -23,6 +22,14 @@ import (
 	fwebhook "github.com/fairwindsops/polaris/pkg/webhook"
 	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
+	appsv1 "k8s.io/api/apps/v1"
+	appsv1beta1 "k8s.io/api/apps/v1beta1"
+	appsv1beta2 "k8s.io/api/apps/v1beta2"
+	batchv1 "k8s.io/api/batch/v1"
+	batchv1beta1 "k8s.io/api/batch/v1beta1"
+	batchv2alpha1 "k8s.io/api/batch/v2alpha1"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/runtime"
 	apitypes "k8s.io/apimachinery/pkg/types"
 	k8sConfig "sigs.k8s.io/controller-runtime/pkg/client/config"
 	"sigs.k8s.io/controller-runtime/pkg/manager"
@@ -30,6 +37,28 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/webhook"
 )
 
+var supportedVersions = map[string]runtime.Object{
+	"appsv1/Deployment":      &appsv1.Deployment{},
+	"appsv1beta1/Deployment": &appsv1beta1.Deployment{},
+	"appsv1beta2/Deployment": &appsv1beta2.Deployment{},
+
+	"appsv1/StatefulSet":      &appsv1.StatefulSet{},
+	"appsv1beta1/StatefulSet": &appsv1beta1.StatefulSet{},
+	"appsv1beta2/StatefulSet": &appsv1beta2.StatefulSet{},
+
+	"appsv1/DaemonSet":      &appsv1.DaemonSet{},
+	"appsv1beta2/DaemonSet": &appsv1beta2.DaemonSet{},
+
+	"batchv1/Job": &batchv1.Job{},
+
+	"batchv1beta1/CronJob":  &batchv1beta1.CronJob{},
+	"batchv2alpha1/CronJob": &batchv2alpha1.CronJob{},
+
+	"corev1/ReplicationController": &corev1.ReplicationController{},
+
+	"corev1/Pod": &corev1.Pod{},
+}
+
 var webhookPort int
 var disableWebhookConfigInstaller bool
 
@@ -102,14 +131,16 @@ var webhookCmd = &cobra.Command{
 		// Should only register controllers that are configured to be scanned
 		logrus.Debug("Registering webhooks to the webhook server")
 		var webhooks []webhook.Webhook
-		for index, controllerToScan := range config.ControllersToScan {
-			for innerIndex, supportedAPIType := range controllerToScan.ListSupportedAPIVersions() {
-				webhookName := strings.ToLower(fmt.Sprintf("%s-%d-%d", controllerToScan, index, innerIndex))
-				hook := fwebhook.NewWebhook(webhookName, mgr, fwebhook.Validator{Config: config}, supportedAPIType)
-				if hook != nil {
-					webhooks = append(webhooks, hook)
-				}
+		for name, supportedAPIType := range supportedVersions {
+			webhookName := strings.ToLower(name)
+			webhookName = strings.ReplaceAll(webhookName, "/", "-")
+			hook, err := fwebhook.NewWebhook(webhookName, mgr, fwebhook.Validator{Config: config}, supportedAPIType)
+			if err != nil {
+				logrus.Warningf("Couldn't build webhook %s: %v", webhookName, err)
+				continue
 			}
+			webhooks = append(webhooks, hook)
+			logrus.Infof("%s webhook started", webhookName)
 		}
 
 		if err = as.Register(webhooks...); err != nil {
diff --git a/deploy/dashboard.yaml b/deploy/dashboard.yaml
index ee514972..bc2cb776 100644
--- a/deploy/dashboard.yaml
+++ b/deploy/dashboard.yaml
@@ -33,7 +33,7 @@ data:
       # security
       hostIPCSet: error
       hostPIDSet: error
-      notReadOnlyRootFileSystem: warning
+      notReadOnlyRootFilesystem: warning
       privilegeEscalationAllowed: error
       runAsRootAllowed: warning
       runAsPrivileged: error
@@ -100,7 +100,7 @@ data:
           - tiller
           - kube2iam
         rules:
-          - notReadOnlyRootFileSystem
+          - notReadOnlyRootFilesystem
       - controllerNames:
           - cert-manager
           - dns-controller
@@ -128,7 +128,7 @@ data:
           - goldilocks
           - insights-agent-goldilocks-vpa-install
         rules:
-          - notReadOnlyRootFileSystem
+          - notReadOnlyRootFilesystem
       - controllerNames:
           - insights-agent-goldilocks-controller
         rules:
diff --git a/deploy/webhook.yaml b/deploy/webhook.yaml
index f288d958..55602485 100644
--- a/deploy/webhook.yaml
+++ b/deploy/webhook.yaml
@@ -46,7 +46,7 @@ data:
       # security
       hostIPCSet: error
       hostPIDSet: error
-      notReadOnlyRootFileSystem: warning
+      notReadOnlyRootFilesystem: warning
       privilegeEscalationAllowed: error
       runAsRootAllowed: warning
       runAsPrivileged: error
@@ -113,7 +113,7 @@ data:
           - tiller
           - kube2iam
         rules:
-          - notReadOnlyRootFileSystem
+          - notReadOnlyRootFilesystem
       - controllerNames:
           - cert-manager
           - dns-controller
@@ -141,7 +141,7 @@ data:
           - goldilocks
           - insights-agent-goldilocks-vpa-install
         rules:
-          - notReadOnlyRootFileSystem
+          - notReadOnlyRootFilesystem
       - controllerNames:
           - insights-agent-goldilocks-controller
         rules:
diff --git a/docs/check-documentation/security.md b/docs/check-documentation/security.md
index ba7b9a48..162d6f3c 100644
--- a/docs/check-documentation/security.md
+++ b/docs/check-documentation/security.md
@@ -6,7 +6,7 @@ key | default | description
 ----|---------|------------
 `security.hostIPCSet` | `error` | Fails when `hostIPC` attribute is configured.
 `security.hostPIDSet` | `error` | Fails when `hostPID` attribute is configured.
-`security.notReadOnlyRootFileSystem` | `warning` | Fails when `securityContext.readOnlyRootFilesystem` is not true.
+`security.notReadOnlyRootFilesystem` | `warning` | Fails when `securityContext.readOnlyRootFilesystem` is not true.
 `security.privilegeEscalationAllowed` | `error` | Fails when `securityContext.allowPrivilegeEscalation` is true.
 `security.runAsRootAllowed` | `error` | Fails when `securityContext.runAsNonRoot` is not true.
 `security.runAsPrivileged` | `error` | Fails when `securityContext.privileged` is true.
diff --git a/examples/config-full.yaml b/examples/config-full.yaml
index 8b2e916d..213dc389 100644
--- a/examples/config-full.yaml
+++ b/examples/config-full.yaml
@@ -17,7 +17,7 @@ checks:
   # security
   hostIPCSet: error
   hostPIDSet: error
-  notReadOnlyRootFileSystem: warning
+  notReadOnlyRootFilesystem: warning
   privilegeEscalationAllowed: error
   runAsRootAllowed: warning
   runAsPrivileged: error
@@ -72,13 +72,6 @@ customChecks:
           not:
             pattern: ^quay.io
 
-controllersToScan:
-  - Deployments
-  - StatefulSets
-  - DaemonSets
-  - CronJobs
-  - Jobs
-  - ReplicationControllers
 exemptions:
   - controllerNames:
     - dns-controller
@@ -133,7 +126,7 @@ exemptions:
     - tiller
     - kube2iam
     rules:
-    - notReadOnlyRootFileSystem
+    - notReadOnlyRootFilesystem
   - controllerNames:
     - cert-manager
     - dns-controller
diff --git a/examples/config.yaml b/examples/config.yaml
index e468175f..35095df2 100644
--- a/examples/config.yaml
+++ b/examples/config.yaml
@@ -16,19 +16,12 @@ checks:
   # security
   hostIPCSet: error
   hostPIDSet: error
-  notReadOnlyRootFileSystem: warning
+  notReadOnlyRootFilesystem: warning
   privilegeEscalationAllowed: error
   runAsRootAllowed: warning
   runAsPrivileged: error
   dangerousCapabilities: error
   insecureCapabilities: warning
-controllersToScan:
-  - Deployments
-  - StatefulSets
-  - DaemonSets
-  - CronJobs
-  - Jobs
-  - ReplicationControllers
 exemptions:
   - controllerNames:
       - dns-controller
@@ -83,7 +76,7 @@ exemptions:
       - tiller
       - kube2iam
     rules:
-      - notReadOnlyRootFileSystem
+      - notReadOnlyRootFilesystem
   - controllerNames:
       - cert-manager
       - dns-controller
@@ -111,7 +104,7 @@ exemptions:
       - goldilocks
       - insights-agent-goldilocks-vpa-install
     rules:
-      - notReadOnlyRootFileSystem
+      - notReadOnlyRootFilesystem
   - controllerNames:
       - insights-agent-goldilocks-controller
     rules:
diff --git a/go.mod b/go.mod
index b4a47654..aadd5aeb 100644
--- a/go.mod
+++ b/go.mod
@@ -47,19 +47,20 @@ require (
 	github.com/markbates/safe v1.0.1
 	github.com/matttproud/golang_protobuf_extensions v1.0.1
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
-	github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
+	github.com/modern-go/reflect2 v1.0.1
 	github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709
 	github.com/petar/GoLLRB v0.0.0-20190514000832-33fb24c13b99
 	github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
 	github.com/pkg/errors v0.9.1
 	github.com/pmezard/go-difflib v1.0.0
-	github.com/prometheus/client_golang v0.9.3
-	github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
+	github.com/prometheus/client_golang v1.0.0
+	github.com/prometheus/client_model v0.2.0
 	github.com/prometheus/common v0.9.1
 	github.com/prometheus/procfs v0.0.11
+	github.com/prometheus/tsdb v0.7.1 // indirect
 	github.com/qri-io/jsonschema v0.1.1
 	github.com/rogpeppe/go-internal v1.5.2
-	github.com/sirupsen/logrus v1.4.2
+	github.com/sirupsen/logrus v1.5.0
 	github.com/spf13/cobra v0.0.5
 	github.com/spf13/pflag v1.0.5
 	github.com/stretchr/testify v1.5.1
@@ -76,12 +77,12 @@ require (
 	golang.org/x/net v0.0.0-20190620200207-3b0461eec859
 	golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07
 	golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
-	golang.org/x/sys v0.0.0-20191218084908-4a24b4065292
+	golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e
 	golang.org/x/text v0.3.2
 	golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
 	golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40
 	google.golang.org/api v0.5.0
-	google.golang.org/appengine v1.6.0
+	google.golang.org/appengine v1.6.6
 	google.golang.org/genproto v0.0.0-20190516172635-bb713bdc0e52
 	google.golang.org/grpc v1.20.1
 	gopkg.in/inf.v0 v0.9.1
diff --git a/go.sum b/go.sum
index 4d4ac983..d56f563d 100644
--- a/go.sum
+++ b/go.sum
@@ -250,6 +250,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
 github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
 github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -284,11 +285,13 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
 github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@@ -330,6 +333,8 @@ github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/sirupsen/logrus v1.5.0 h1:1N5EYkVAPEywqZRJd7cwnRtCb6xJx7NH3T3WUTF980Q=
+github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo=
 github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
 github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -433,6 +438,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190514140710-3ec191127204 h1:4yG6GqBtw9C+UrLp6s2wtSniayy/Vd/3F7ffLE427XI=
 golang.org/x/net v0.0.0-20190514140710-3ec191127204/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -513,6 +519,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl
 google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
+google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 11671700..faa07005 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -30,7 +30,6 @@ import (
 type Configuration struct {
 	DisplayName        string                 `json:"displayName"`
 	Checks             map[string]Severity    `json:"checks"`
-	ControllersToScan  []SupportedController  `json:"controllersToScan"`
 	CustomChecks       map[string]SchemaCheck `json:"customChecks"`
 	Exemptions         []Exemption            `json:"exemptions"`
 	DisallowExemptions bool                   `json:"disallowExemptions"`
diff --git a/pkg/config/supportedcontrollers.go b/pkg/config/supportedcontrollers.go
deleted file mode 100644
index 2562859b..00000000
--- a/pkg/config/supportedcontrollers.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package config
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"strings"
-
-	appsv1 "k8s.io/api/apps/v1"
-	appsv1beta1 "k8s.io/api/apps/v1beta1"
-	appsv1beta2 "k8s.io/api/apps/v1beta2"
-	batchv1 "k8s.io/api/batch/v1"
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
-	batchv2alpha1 "k8s.io/api/batch/v2alpha1"
-	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-)
-
-const (
-	// Unsupported is the default enum for non-defined controller types
-	Unsupported SupportedController = iota
-	// Deployments are a supported controller for scanning pod specs
-	Deployments
-	// StatefulSets are a supported controller for scanning pod specs
-	StatefulSets
-	// DaemonSets are a supported controller for scanning pod specs
-	DaemonSets
-	// Jobs are a supported controller for scanning pod specs
-	Jobs
-	// CronJobs are a supported controller for scanning pod specs
-	CronJobs
-	// ReplicationControllers are supported controllers for scanning pod specs
-	ReplicationControllers
-	// NakedPods are a pseudo-controller for scanning pod specs
-	NakedPods
-)
-
-// ControllerStrings are strongly ordered to match the SupportedController enum
-var ControllerStrings = []string{
-	"Unsupported",
-	"Deployment",
-	"StatefulSet",
-	"DaemonSet",
-	"Job",
-	"CronJob",
-	"ReplicationController",
-	"NakedPod",
-}
-
-// stringLookupForSupportedControllers is the list of lowercase singular and plural strings for string to enum lookup
-var stringLookupForSupportedControllers = map[string]SupportedController{
-	"deployment":             Deployments,
-	"deployments":            Deployments,
-	"statefulset":            StatefulSets,
-	"statefulsets":           StatefulSets,
-	"daemonset":              DaemonSets,
-	"daemonsets":             DaemonSets,
-	"job":                    Jobs,
-	"jobs":                   Jobs,
-	"cronjob":                CronJobs,
-	"cronjobs":               CronJobs,
-	"replicationcontroller":  ReplicationControllers,
-	"replicationcontrollers": ReplicationControllers,
-	"nakedpod":               NakedPods,
-	"nakedpods":              NakedPods,
-}
-
-// SupportedController is a constant item of a controller that is supported for scanning pod specs
-type SupportedController int
-
-// String returns the string name for a given SupportedController enum
-func (s SupportedController) String() string {
-	return ControllerStrings[s]
-}
-
-// MarshalJSON manages writing the enum into json data or error on unsupported value
-func (s SupportedController) MarshalJSON() ([]byte, error) {
-	if s == Unsupported {
-		return []byte{}, fmt.Errorf("Unsupported is not a valid Supported Controller")
-	}
-	buffer := bytes.NewBufferString(`"`)
-	buffer.WriteString(s.String())
-	buffer.WriteString(`"`)
-	return buffer.Bytes(), nil
-}
-
-// UnmarshalJSON handles reading json data into enum
-func (s *SupportedController) UnmarshalJSON(b []byte) error {
-	var j string
-	err := json.Unmarshal(b, &j)
-	if err != nil {
-		return err
-	}
-
-	*s = GetSupportedControllerFromString(j)
-	if *s == Unsupported {
-		return fmt.Errorf("Unsupported controller kind: %s", j)
-	}
-	return nil
-}
-
-// ListSupportedAPIVersions for SupportedController returns all the apimachinery object type supported
-func (s SupportedController) ListSupportedAPIVersions() []runtime.Object {
-	var supportedVersions []runtime.Object
-	switch s {
-	case Deployments:
-		supportedVersions = []runtime.Object{
-			&appsv1.Deployment{},
-			&appsv1beta1.Deployment{},
-			&appsv1beta2.Deployment{},
-		}
-	case StatefulSets:
-		supportedVersions = []runtime.Object{
-			&appsv1.StatefulSet{},
-			&appsv1beta1.StatefulSet{},
-			&appsv1beta2.StatefulSet{},
-		}
-	case DaemonSets:
-		supportedVersions = []runtime.Object{
-			&appsv1.DaemonSet{},
-			&appsv1beta2.DaemonSet{},
-		}
-	case Jobs:
-		supportedVersions = []runtime.Object{
-			&batchv1.Job{},
-		}
-	case CronJobs:
-		supportedVersions = []runtime.Object{
-			&batchv1beta1.CronJob{},
-			&batchv2alpha1.CronJob{},
-		}
-	case ReplicationControllers:
-		supportedVersions = []runtime.Object{
-			&corev1.ReplicationController{},
-		}
-	case NakedPods:
-		supportedVersions = []runtime.Object{
-			&corev1.Pod{},
-		}
-	}
-	return supportedVersions
-}
-
-// GetSupportedControllerFromString fuzzy matches a string with a SupportedController Enum
-func GetSupportedControllerFromString(str string) SupportedController {
-	lowerStr := strings.ToLower(str)
-	controller, keyFound := stringLookupForSupportedControllers[lowerStr]
-	if !keyFound {
-		controller = Unsupported
-	}
-	return controller
-}
-
-// CheckIfKindIsConfiguredForValidation takes a kind (in string format) and checks if Polaris is configured to scan this type of controller
-func (c Configuration) CheckIfKindIsConfiguredForValidation(kind string) bool {
-	controller := GetSupportedControllerFromString(kind)
-	if controller != Unsupported {
-		for _, controllerToScan := range c.ControllersToScan {
-			if controller == controllerToScan {
-				return true
-			}
-		}
-	}
-	return false
-}
diff --git a/pkg/kube/resources.go b/pkg/kube/resources.go
index fc8d74f6..ebd2e03f 100644
--- a/pkg/kube/resources.go
+++ b/pkg/kube/resources.go
@@ -9,7 +9,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
 	"github.com/sirupsen/logrus"
 	"gopkg.in/yaml.v3"
 	corev1 "k8s.io/api/core/v1"
@@ -31,13 +30,15 @@ type ResourceProvider struct {
 	SourceType    string
 	Nodes         []corev1.Node
 	Namespaces    []corev1.Namespace
-	Controllers   []controllers.GenericController
+	Controllers   []GenericWorkload
 }
 
 type k8sResource struct {
 	Kind string `yaml:"kind"`
 }
 
+var podSpecFields = []string{"jobTemplate", "spec", "template"}
+
 // CreateResourceProvider returns a new ResourceProvider object to interact with k8s resources
 func CreateResourceProvider(directory string) (*ResourceProvider, error) {
 	if directory != "" {
@@ -54,7 +55,7 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
 		SourceName:    directory,
 		Nodes:         []corev1.Node{},
 		Namespaces:    []corev1.Namespace{},
-		Controllers:   []controllers.GenericController{},
+		Controllers:   []GenericWorkload{},
 	}
 
 	addYaml := func(contents string) error {
@@ -155,37 +156,46 @@ func CreateResourceProviderFromAPI(kube kubernetes.Interface, clusterName string
 }
 
 // LoadControllers loads a list of controllers from the kubeResources Pods
-func LoadControllers(pods []corev1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper) []controllers.GenericController {
-	interfaces := []controllers.GenericController{}
+func LoadControllers(pods []corev1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper) []GenericWorkload {
+	interfaces := []GenericWorkload{}
+	deduped := map[string]corev1.Pod{}
 	for _, pod := range pods {
-		interfaces = append(interfaces, controllers.NewGenericPodController(pod, dynamicClientPointer, restMapperPointer))
+		owners := pod.ObjectMeta.OwnerReferences
+		if len(owners) == 0 {
+			deduped[pod.ObjectMeta.Namespace+"/Pod/"+pod.ObjectMeta.Name] = pod
+			continue
+		}
+		deduped[pod.ObjectMeta.Namespace+"/"+owners[0].Kind+"/"+owners[0].Name] = pod
+	}
+	for _, pod := range deduped {
+		interfaces = append(interfaces, NewGenericWorkload(pod, dynamicClientPointer, restMapperPointer))
 	}
 	return deduplicateControllers(interfaces)
 }
 
 // Because the controllers with an Owner take on the name of the Owner, this eliminates any duplicates.
 // In cases like CronJobs older children can hang around, so this takes the most recent.
-func deduplicateControllers(inputControllers []controllers.GenericController) []controllers.GenericController {
-	controllerMap := make(map[string]controllers.GenericController)
+func deduplicateControllers(inputControllers []GenericWorkload) []GenericWorkload {
+	controllerMap := make(map[string]GenericWorkload)
 	for _, controller := range inputControllers {
-		key := controller.GetNamespace() + "/" + controller.GetKind() + "/" + controller.Name
+		key := controller.ObjectMeta.GetNamespace() + "/" + controller.Kind + "/" + controller.ObjectMeta.GetName()
 		oldController, ok := controllerMap[key]
-		if !ok || controller.CreatedTime.After(oldController.CreatedTime) {
+		if !ok || controller.ObjectMeta.GetCreationTimestamp().Time.After(oldController.ObjectMeta.GetCreationTimestamp().Time) {
 			controllerMap[key] = controller
 		}
 	}
-	results := make([]controllers.GenericController, 0)
+	results := make([]GenericWorkload, 0)
 	for _, controller := range controllerMap {
 		results = append(results, controller)
 	}
 	return results
 }
 
-func getPodSpec(yaml map[string]interface{}) interface{} {
-	allowedChildren := []string{"jobTemplate", "spec", "template"}
-	for _, child := range allowedChildren {
+// GetPodSpec looks inside arbitrary YAML for a PodSpec
+func GetPodSpec(yaml map[string]interface{}) interface{} {
+	for _, child := range podSpecFields {
 		if childYaml, ok := yaml[child]; ok {
-			return getPodSpec(childYaml.(map[string]interface{}))
+			return GetPodSpec(childYaml.(map[string]interface{}))
 		}
 	}
 	return yaml
@@ -209,7 +219,7 @@ func addResourceFromString(contents string, resources *ResourceProvider) error {
 	} else if resource.Kind == "Pod" {
 		pod := corev1.Pod{}
 		err = decoder.Decode(&pod)
-		resources.Controllers = append(resources.Controllers, controllers.NewGenericPodController(pod, nil, nil))
+		resources.Controllers = append(resources.Controllers, NewGenericWorkload(pod, nil, nil))
 	} else {
 		yamlNode := make(map[string]interface{})
 		err = yaml.Unmarshal(contentBytes, &yamlNode)
@@ -221,7 +231,7 @@ func addResourceFromString(contents string, resources *ResourceProvider) error {
 		finalDoc["metadata"] = yamlNode["metadata"]
 		finalDoc["apiVersion"] = "v1"
 		finalDoc["kind"] = "Pod"
-		finalDoc["spec"] = getPodSpec(yamlNode)
+		finalDoc["spec"] = GetPodSpec(yamlNode)
 		marshaledYaml, err := yaml.Marshal(finalDoc)
 		if err != nil {
 			logrus.Errorf("Could not marshal yaml: %v", err)
@@ -230,7 +240,7 @@ func addResourceFromString(contents string, resources *ResourceProvider) error {
 		decoder := k8sYaml.NewYAMLOrJSONDecoder(bytes.NewReader(marshaledYaml), 1000)
 		pod := corev1.Pod{}
 		err = decoder.Decode(&pod)
-		newController := controllers.NewGenericPodController(pod, nil, nil)
+		newController := NewGenericWorkload(pod, nil, nil)
 		newController.Kind = resource.Kind
 		resources.Controllers = append(resources.Controllers, newController)
 	}
diff --git a/pkg/kube/workload.go b/pkg/kube/workload.go
new file mode 100644
index 00000000..40fe5ba7
--- /dev/null
+++ b/pkg/kube/workload.go
@@ -0,0 +1,64 @@
+package kube
+
+import (
+	"fmt"
+
+	"github.com/sirupsen/logrus"
+	kubeAPICoreV1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/api/meta"
+	kubeAPIMetaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/client-go/dynamic"
+)
+
+// GenericWorkload is a base implementation with some free methods for inherited structs
+type GenericWorkload struct {
+	Kind       string
+	PodSpec    kubeAPICoreV1.PodSpec
+	ObjectMeta kubeAPIMetaV1.Object
+}
+
+// NewGenericWorkload builds a new workload for a given Pod
+func NewGenericWorkload(originalResource kubeAPICoreV1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper) GenericWorkload {
+	workload := GenericWorkload{}
+	workload.PodSpec = originalResource.Spec
+	workload.ObjectMeta = originalResource.ObjectMeta.GetObjectMeta()
+	workload.Kind = "Pod"
+	fmt.Println("get workload", workload.ObjectMeta.GetNamespace(), workload.ObjectMeta.GetName())
+
+	if dynamicClientPointer == nil || restMapperPointer == nil {
+		return workload
+	}
+	// If an owner exists then set the name to the workload.
+	// This allows us to handle CRDs creating Workloads or DeploymentConfigs in OpenShift.
+	owners := workload.ObjectMeta.GetOwnerReferences()
+	for len(owners) > 0 {
+		if len(owners) > 1 {
+			logrus.Warn("More than 1 owner found")
+		}
+		firstOwner := owners[0]
+		if firstOwner.Kind == "Node" {
+			break
+		}
+		workload.Kind = firstOwner.Kind
+
+		dynamicClient := *dynamicClientPointer
+		restMapper := *restMapperPointer
+		fqKind := schema.FromAPIVersionAndKind(firstOwner.APIVersion, firstOwner.Kind)
+		mapping, err := restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
+		if err != nil {
+			logrus.Warnf("Error retrieving mapping %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
+			return workload
+		}
+		parent, err := dynamicClient.Resource(mapping.Resource).Namespace(workload.ObjectMeta.GetNamespace()).Get(firstOwner.Name, kubeAPIMetaV1.GetOptions{})
+		if err != nil {
+			logrus.Warnf("Error retrieving parent object %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
+			return workload
+		}
+		objMeta, err := meta.Accessor(parent)
+		workload.ObjectMeta = objMeta
+		owners = parent.GetOwnerReferences()
+	}
+
+	return workload
+}
diff --git a/pkg/validator/container.go b/pkg/validator/container.go
index 91add9ad..25c59346 100644
--- a/pkg/validator/container.go
+++ b/pkg/validator/container.go
@@ -16,13 +16,13 @@ package validator
 
 import (
 	"github.com/fairwindsops/polaris/pkg/config"
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
+	"github.com/fairwindsops/polaris/pkg/kube"
 
 	corev1 "k8s.io/api/core/v1"
 )
 
 // ValidateContainer validates a single container from a given controller
-func ValidateContainer(conf *config.Configuration, controller controllers.GenericController, container *corev1.Container, isInit bool) (ContainerResult, error) {
+func ValidateContainer(conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ContainerResult, error) {
 	results, err := applyContainerSchemaChecks(conf, controller, container, isInit)
 	if err != nil {
 		return ContainerResult{}, err
@@ -37,9 +37,9 @@ func ValidateContainer(conf *config.Configuration, controller controllers.Generi
 }
 
 // ValidateAllContainers validates both init and regular containers
-func ValidateAllContainers(conf *config.Configuration, controller controllers.GenericController) ([]ContainerResult, error) {
+func ValidateAllContainers(conf *config.Configuration, controller kube.GenericWorkload) ([]ContainerResult, error) {
 	results := []ContainerResult{}
-	pod := controller.GetPodSpec()
+	pod := controller.PodSpec
 	for _, container := range pod.InitContainers {
 		result, err := ValidateContainer(conf, controller, &container, true)
 		if err != nil {
diff --git a/pkg/validator/controller.go b/pkg/validator/controller.go
index b3d5ee5c..72962fef 100644
--- a/pkg/validator/controller.go
+++ b/pkg/validator/controller.go
@@ -21,21 +21,20 @@ import (
 
 	conf "github.com/fairwindsops/polaris/pkg/config"
 	"github.com/fairwindsops/polaris/pkg/kube"
-	controller "github.com/fairwindsops/polaris/pkg/validator/controllers"
 )
 
 const exemptionAnnotationKey = "polaris.fairwinds.com/exempt"
 
 // ValidateController validates a single controller, returns a ControllerResult.
-func ValidateController(conf *conf.Configuration, controller controller.GenericController) (ControllerResult, error) {
+func ValidateController(conf *conf.Configuration, controller kube.GenericWorkload) (ControllerResult, error) {
 	podResult, err := ValidatePod(conf, controller)
 	if err != nil {
 		return ControllerResult{}, err
 	}
 	result := ControllerResult{
-		Kind:      controller.GetKind(),
-		Name:      controller.GetName(),
-		Namespace: controller.GetObjectMeta().Namespace,
+		Kind:      controller.Kind,
+		Name:      controller.ObjectMeta.GetName(),
+		Namespace: controller.ObjectMeta.GetNamespace(),
 		Results:   ResultSet{},
 		PodResult: podResult,
 	}
@@ -64,8 +63,8 @@ func ValidateControllers(config *conf.Configuration, kubeResources *kube.Resourc
 	return results, nil
 }
 
-func hasExemptionAnnotation(ctrl controller.GenericController) bool {
-	annot := ctrl.GetObjectMeta().Annotations
+func hasExemptionAnnotation(ctrl kube.GenericWorkload) bool {
+	annot := ctrl.ObjectMeta.GetAnnotations()
 	val := annot[exemptionAnnotationKey]
 	return strings.ToLower(val) == "true"
 }
diff --git a/pkg/validator/controllers/cronjob.go b/pkg/validator/controllers/cronjob.go
deleted file mode 100644
index 33a2c72e..00000000
--- a/pkg/validator/controllers/cronjob.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package controllers
-
-import (
-	"github.com/fairwindsops/polaris/pkg/config"
-	"github.com/sirupsen/logrus"
-	kubeAPIBatchV1beta1 "k8s.io/api/batch/v1beta1"
-)
-
-// NewCronJobController builds a new controller interface for Deployments
-func NewCronJobController(originalResource kubeAPIBatchV1beta1.CronJob) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec.JobTemplate.Spec.Template.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = config.CronJobs.String()
-	if controller.Name == "" {
-		logrus.Warn("Name is missing from controller", originalResource.Namespace)
-	}
-	return controller
-}
diff --git a/pkg/validator/controllers/daemonset.go b/pkg/validator/controllers/daemonset.go
deleted file mode 100644
index c8ce6d3e..00000000
--- a/pkg/validator/controllers/daemonset.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package controllers
-
-import (
-	"github.com/fairwindsops/polaris/pkg/config"
-	kubeAPIAppsV1 "k8s.io/api/apps/v1"
-)
-
-// NewDaemonSetController builds a new controller interface for Deployments
-func NewDaemonSetController(originalResource kubeAPIAppsV1.DaemonSet) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec.Template.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = config.DaemonSets.String()
-	return controller
-}
diff --git a/pkg/validator/controllers/deployment.go b/pkg/validator/controllers/deployment.go
deleted file mode 100644
index 2972d442..00000000
--- a/pkg/validator/controllers/deployment.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package controllers
-
-import (
-	"github.com/fairwindsops/polaris/pkg/config"
-	kubeAPIAppsV1 "k8s.io/api/apps/v1"
-)
-
-// NewDeploymentController builds a new controller interface for Deployments
-func NewDeploymentController(originalResource kubeAPIAppsV1.Deployment) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec.Template.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = config.Deployments.String()
-	return controller
-}
diff --git a/pkg/validator/controllers/generic.go b/pkg/validator/controllers/generic.go
deleted file mode 100644
index 3d78023c..00000000
--- a/pkg/validator/controllers/generic.go
+++ /dev/null
@@ -1,91 +0,0 @@
-package controllers
-
-import (
-	"time"
-
-	"github.com/sirupsen/logrus"
-	kubeAPICoreV1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/api/meta"
-	kubeAPIMetaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/apimachinery/pkg/runtime/schema"
-	"k8s.io/client-go/dynamic"
-)
-
-// GenericController is a base implementation with some free methods for inherited structs
-type GenericController struct {
-	Name        string
-	Namespace   string
-	PodSpec     kubeAPICoreV1.PodSpec
-	ObjectMeta  kubeAPIMetaV1.ObjectMeta
-	Kind        string
-	CreatedTime time.Time
-}
-
-// GetPodSpec returns the original kubernetes template pod spec
-func (g GenericController) GetPodSpec() *kubeAPICoreV1.PodSpec {
-	return &g.PodSpec
-}
-
-// GetObjectMeta returns the metadata
-func (g GenericController) GetObjectMeta() kubeAPIMetaV1.ObjectMeta {
-	return g.ObjectMeta
-}
-
-// GetKind returns the supportedcontroller enum type
-func (g GenericController) GetKind() string {
-	return g.Kind
-}
-
-// GetName is inherited by all controllers using generic controller to get the name of the controller
-func (g GenericController) GetName() string {
-	return g.Name
-}
-
-// GetNamespace is inherited by all controllers using generic controller to get the namespace of the controller
-func (g GenericController) GetNamespace() string {
-	return g.Namespace
-}
-
-// NewGenericPodController builds a new controller interface for anytype of Pod
-func NewGenericPodController(originalResource kubeAPICoreV1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = "Pod"
-	controller.CreatedTime = controller.GetObjectMeta().CreationTimestamp.Time
-
-	owners := controller.GetObjectMeta().OwnerReferences
-	if dynamicClientPointer == nil || restMapperPointer == nil {
-		return controller
-	}
-	// If an owner exists then set the name to the controller.
-	// This allows us to handle CRDs creating Controllers or DeploymentConfigs in OpenShift.
-	for len(owners) > 0 {
-		if len(owners) > 1 {
-			logrus.Warn("More than 1 owner found")
-		}
-		firstOwner := owners[0]
-		controller.Kind = firstOwner.Kind
-		controller.Name = firstOwner.Name
-
-		dynamicClient := *dynamicClientPointer
-		restMapper := *restMapperPointer
-		fqKind := schema.FromAPIVersionAndKind(firstOwner.APIVersion, firstOwner.Kind)
-		mapping, err := restMapper.RESTMapping(fqKind.GroupKind(), fqKind.Version)
-		if err != nil {
-			logrus.Warnf("Error retrieving mapping %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
-			return controller
-		}
-		getParents, err := dynamicClient.Resource(mapping.Resource).Namespace(controller.GetObjectMeta().Namespace).Get(firstOwner.Name, kubeAPIMetaV1.GetOptions{})
-		if err != nil {
-			logrus.Warnf("Error retrieving parent object %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
-			return controller
-		}
-		owners = getParents.GetOwnerReferences()
-
-	}
-
-	return controller
-}
diff --git a/pkg/validator/controllers/job.go b/pkg/validator/controllers/job.go
deleted file mode 100644
index 3377249f..00000000
--- a/pkg/validator/controllers/job.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package controllers
-
-import (
-	"github.com/fairwindsops/polaris/pkg/config"
-	kubeAPIBatchV1 "k8s.io/api/batch/v1"
-)
-
-// NewJobController builds a new controller interface for Deployments
-func NewJobController(originalResource kubeAPIBatchV1.Job) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec.Template.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = config.Jobs.String()
-	return controller
-}
diff --git a/pkg/validator/controllers/naked-pod.go b/pkg/validator/controllers/naked-pod.go
deleted file mode 100644
index b96a76ee..00000000
--- a/pkg/validator/controllers/naked-pod.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package controllers
-
-import (
-	"github.com/fairwindsops/polaris/pkg/config"
-	kubeAPICoreV1 "k8s.io/api/core/v1"
-)
-
-// NewNakedPodController builds a new controller interface for NakedPods
-func NewNakedPodController(originalResource kubeAPICoreV1.Pod) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = config.NakedPods.String()
-
-	return controller
-}
diff --git a/pkg/validator/controllers/replicationcontroller.go b/pkg/validator/controllers/replicationcontroller.go
deleted file mode 100644
index 1a9fa32f..00000000
--- a/pkg/validator/controllers/replicationcontroller.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package controllers
-
-import (
-	"github.com/fairwindsops/polaris/pkg/config"
-	kubeAPICoreV1 "k8s.io/api/core/v1"
-)
-
-// NewReplicationControllerController builds a new controller interface for Deployments
-func NewReplicationControllerController(originalResource kubeAPICoreV1.ReplicationController) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec.Template.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = config.ReplicationControllers.String()
-	return controller
-}
diff --git a/pkg/validator/controllers/statefulsets.go b/pkg/validator/controllers/statefulsets.go
deleted file mode 100644
index fab6b865..00000000
--- a/pkg/validator/controllers/statefulsets.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package controllers
-
-import (
-	"github.com/fairwindsops/polaris/pkg/config"
-	"github.com/sirupsen/logrus"
-	kubeAPIAppsV1 "k8s.io/api/apps/v1"
-)
-
-// NewStatefulSetController builds a statefulset controller
-func NewStatefulSetController(originalResource kubeAPIAppsV1.StatefulSet) GenericController {
-	controller := GenericController{}
-	controller.Name = originalResource.Name
-	controller.Namespace = originalResource.Namespace
-	controller.PodSpec = originalResource.Spec.Template.Spec
-	controller.ObjectMeta = originalResource.ObjectMeta
-	controller.Kind = config.StatefulSets.String()
-	if controller.Name == "" {
-		logrus.Warn("Name is missing from controller", originalResource.Namespace)
-	}
-	return controller
-}
diff --git a/pkg/validator/pod.go b/pkg/validator/pod.go
index f6678191..6bef7b91 100644
--- a/pkg/validator/pod.go
+++ b/pkg/validator/pod.go
@@ -16,11 +16,11 @@ package validator
 
 import (
 	"github.com/fairwindsops/polaris/pkg/config"
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
+	"github.com/fairwindsops/polaris/pkg/kube"
 )
 
 // ValidatePod validates that each pod conforms to the Polaris config, returns a ResourceResult.
-func ValidatePod(conf *config.Configuration, controller controllers.GenericController) (PodResult, error) {
+func ValidatePod(conf *config.Configuration, controller kube.GenericWorkload) (PodResult, error) {
 	podResults, err := applyPodSchemaChecks(conf, controller)
 	if err != nil {
 		return PodResult{}, err
diff --git a/pkg/validator/schema.go b/pkg/validator/schema.go
index 89f8c872..ec2ed81c 100644
--- a/pkg/validator/schema.go
+++ b/pkg/validator/schema.go
@@ -12,7 +12,7 @@ import (
 	"k8s.io/apimachinery/pkg/util/yaml"
 
 	"github.com/fairwindsops/polaris/pkg/config"
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
+	"github.com/fairwindsops/polaris/pkg/kube"
 )
 
 var (
@@ -37,7 +37,7 @@ var (
 		"hostPortSet",
 		"runAsRootAllowed",
 		"runAsPrivileged",
-		"notReadOnlyRootFileSystem",
+		"notReadOnlyRootFilesystem",
 		"privilegeEscalationAllowed",
 		"dangerousCapabilities",
 		"insecureCapabilities",
@@ -74,7 +74,7 @@ func parseCheck(rawBytes []byte) (config.SchemaCheck, error) {
 	}
 }
 
-func resolveCheck(conf *config.Configuration, checkID string, controller controllers.GenericController, target config.TargetKind, isInitContainer bool) (*config.SchemaCheck, error) {
+func resolveCheck(conf *config.Configuration, checkID string, controller kube.GenericWorkload, target config.TargetKind, isInitContainer bool) (*config.SchemaCheck, error) {
 	check, ok := conf.CustomChecks[checkID]
 	if !ok {
 		check, ok = builtInChecks[checkID]
@@ -82,10 +82,10 @@ func resolveCheck(conf *config.Configuration, checkID string, controller control
 	if !ok {
 		return nil, fmt.Errorf("Check %s not found", checkID)
 	}
-	if !conf.IsActionable(check.ID, controller.GetName()) {
+	if !conf.IsActionable(check.ID, controller.ObjectMeta.GetName()) {
 		return nil, nil
 	}
-	if !check.IsActionable(target, controller.GetKind(), isInitContainer) {
+	if !check.IsActionable(target, controller.Kind, isInitContainer) {
 		return nil, nil
 	}
 	return &check, nil
@@ -110,10 +110,10 @@ func getExemptKey(checkID string) string {
 	return fmt.Sprintf("polaris.fairwinds.com/%s-exempt", checkID)
 }
 
-func applyPodSchemaChecks(conf *config.Configuration, controller controllers.GenericController) (ResultSet, error) {
+func applyPodSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
 	results := ResultSet{}
 	checkIDs := getSortedKeys(conf.Checks)
-	objectAnnotations := controller.GetObjectMeta().Annotations
+	objectAnnotations := controller.ObjectMeta.GetAnnotations()
 	for _, checkID := range checkIDs {
 		exemptValue := objectAnnotations[getExemptKey(checkID)]
 		if strings.ToLower(exemptValue) == "true" {
@@ -126,7 +126,7 @@ func applyPodSchemaChecks(conf *config.Configuration, controller controllers.Gen
 		} else if check == nil {
 			continue
 		}
-		passes, err := check.CheckPod(controller.GetPodSpec())
+		passes, err := check.CheckPod(&controller.PodSpec)
 		if err != nil {
 			return nil, err
 		}
@@ -135,10 +135,10 @@ func applyPodSchemaChecks(conf *config.Configuration, controller controllers.Gen
 	return results, nil
 }
 
-func applyContainerSchemaChecks(conf *config.Configuration, controller controllers.GenericController, container *corev1.Container, isInit bool) (ResultSet, error) {
+func applyContainerSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ResultSet, error) {
 	results := ResultSet{}
 	checkIDs := getSortedKeys(conf.Checks)
-	objectAnnotations := controller.GetObjectMeta().Annotations
+	objectAnnotations := controller.ObjectMeta.GetAnnotations()
 	for _, checkID := range checkIDs {
 		exemptValue := objectAnnotations[getExemptKey(checkID)]
 		if strings.ToLower(exemptValue) == "true" {
@@ -152,7 +152,7 @@ func applyContainerSchemaChecks(conf *config.Configuration, controller controlle
 		}
 		var passes bool
 		if check.SchemaTarget == config.TargetPod {
-			podCopy := *controller.GetPodSpec()
+			podCopy := controller.PodSpec
 			podCopy.InitContainers = []corev1.Container{}
 			podCopy.Containers = []corev1.Container{*container}
 			passes, err = check.CheckPod(&podCopy)
diff --git a/pkg/webhook/validator.go b/pkg/webhook/webhook.go
similarity index 54%
rename from pkg/webhook/validator.go
rename to pkg/webhook/webhook.go
index b395ae56..0f7b63b1 100644
--- a/pkg/webhook/validator.go
+++ b/pkg/webhook/webhook.go
@@ -16,18 +16,16 @@ package webhook
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"net/http"
 
 	"github.com/fairwindsops/polaris/pkg/config"
+	"github.com/fairwindsops/polaris/pkg/kube"
 	validator "github.com/fairwindsops/polaris/pkg/validator"
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
 
 	"github.com/sirupsen/logrus"
 	admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
-	appsv1 "k8s.io/api/apps/v1"
-	batchv1 "k8s.io/api/batch/v1"
-	batchv1beta1 "k8s.io/api/batch/v1beta1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -64,7 +62,7 @@ func (v *Validator) InjectDecoder(d types.Decoder) error {
 var _ admission.Handler = &Validator{}
 
 // NewWebhook creates a validating admission webhook for the apiType.
-func NewWebhook(name string, mgr manager.Manager, validator Validator, apiType runtime.Object) *admission.Webhook {
+func NewWebhook(name string, mgr manager.Manager, validator Validator, apiType runtime.Object) (*admission.Webhook, error) {
 	name = fmt.Sprintf("%s.k8s.io", name)
 	path := fmt.Sprintf("/validating-%s", name)
 
@@ -78,86 +76,56 @@ func NewWebhook(name string, mgr manager.Manager, validator Validator, apiType r
 		Handlers(&validator).
 		Build()
 	if err != nil {
-		logrus.Errorf("Error building webhook: %v", err)
-		return nil
+		return nil, err
 	}
-	logrus.Info(name + " webhook started")
-	return webhook
+	return webhook, nil
 }
 
-// Handle for Validator to run validation checks.
-func (v *Validator) Handle(ctx context.Context, req types.Request) types.Response {
-	var err error
-	var podResult validator.PodResult
-
+func (v *Validator) handleInternal(ctx context.Context, req types.Request) (*validator.PodResult, error) {
+	pod := corev1.Pod{}
 	if req.AdmissionRequest.Kind.Kind == "Pod" {
-		pod := corev1.Pod{}
-		err = v.decoder.Decode(req, &pod) // err is handled below
-		nakedPod := controllers.NewNakedPodController(pod)
-		if err == nil {
-			podResult, err = validator.ValidatePod(&v.Config, nakedPod)
+		err := v.decoder.Decode(req, &pod)
+		if err != nil {
+			return nil, err
 		}
 	} else {
-		var controller controllers.GenericController
-		if yes := v.Config.CheckIfKindIsConfiguredForValidation(req.AdmissionRequest.Kind.Kind); !yes {
-			logrus.Warnf("Skipping, kind (%s) isn't something we are configured to scan", req.AdmissionRequest.Kind.Kind)
-			return admission.ValidationResponse(true, fmt.Sprintf("Skipping: (%s) isn't something we're configured to scan.", req.AdmissionRequest.Kind.Kind))
+		decoded := map[string]interface{}{}
+		err := json.Unmarshal(req.AdmissionRequest.Object.Raw, &decoded)
+		if err != nil {
+			return nil, err
 		}
-
-		// We should never hit this case unless something is misconfiured in CheckIfKindIsConfiguredForValidation
-		controllerType := config.GetSupportedControllerFromString(req.AdmissionRequest.Kind.Kind)
-		if controllerType == config.Unsupported {
-			msg := fmt.Errorf("Expected Kind (%s) to be a supported type", req.AdmissionRequest.Kind.Kind)
-			logrus.Error(msg)
-			return admission.ErrorResponse(http.StatusInternalServerError, msg)
-		}
-
-		// For each type, perform the scan
-		// TODO: This isn't really that elegant due to the decoder and NewXXXController setup :( could use love
-		switch controllerType {
-		case config.Deployments:
-			deploy := appsv1.Deployment{}
-			err = v.decoder.Decode(req, &deploy)
-			controller = controllers.NewDeploymentController(deploy)
-		case config.StatefulSets:
-			statefulSet := appsv1.StatefulSet{}
-			err = v.decoder.Decode(req, &statefulSet)
-			controller = controllers.NewStatefulSetController(statefulSet)
-		case config.DaemonSets:
-			daemonSet := appsv1.DaemonSet{}
-			err = v.decoder.Decode(req, &daemonSet)
-			controller = controllers.NewDaemonSetController(daemonSet)
-		case config.Jobs:
-			job := batchv1.Job{}
-			err = v.decoder.Decode(req, &job)
-			controller = controllers.NewJobController(job)
-		case config.CronJobs:
-			cronJob := batchv1beta1.CronJob{}
-			err = v.decoder.Decode(req, &cronJob)
-			controller = controllers.NewCronJobController(cronJob)
-		case config.ReplicationControllers:
-			replicationController := corev1.ReplicationController{}
-			err = v.decoder.Decode(req, &replicationController)
-			controller = controllers.NewReplicationControllerController(replicationController)
+		podMap := kube.GetPodSpec(decoded)
+		encoded, err := json.Marshal(podMap)
+		if err != nil {
+			return nil, err
 		}
-		if err == nil {
-			var controllerResult validator.ControllerResult
-			controllerResult, err = validator.ValidateController(&v.Config, controller)
-			podResult = controllerResult.PodResult
+		err = json.Unmarshal(encoded, &pod.Spec)
+		if err != nil {
+			return nil, err
 		}
 	}
+	controller := kube.NewGenericWorkload(pod, nil, nil)
+	controller.Kind = req.AdmissionRequest.Kind.Kind
+	controllerResult, err := validator.ValidateController(&v.Config, controller)
+	if err != nil {
+		return nil, err
+	}
+	return &controllerResult.PodResult, nil
+}
 
+// Handle for Validator to run validation checks.
+func (v *Validator) Handle(ctx context.Context, req types.Request) types.Response {
+	podResult, err := v.handleInternal(ctx, req)
 	if err != nil {
 		logrus.Errorf("Error validating request: %v", err)
 		return admission.ErrorResponse(http.StatusBadRequest, err)
 	}
-
 	allowed := true
 	reason := ""
 	numErrors := podResult.GetSummary().Errors
 	if numErrors > 0 {
 		allowed = false
-		reason = getFailureReason(podResult)
+		reason = getFailureReason(*podResult)
 	}
 	logrus.Infof("%d validation errors found when validating %s", numErrors, podResult.Name)
 	return admission.ValidationResponse(allowed, reason)


Test patch:
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index b13feb75..c8fe1704 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -31,16 +31,13 @@ var confInvalid = `test`
 var confValidYAML = `
 checks:
   cpuRequestsMissing: warning
-controllersToScan:
-  - Deployments
 `
 
 var confValidJSON = `
 {
   "checks": {
     "cpuRequestsMissing": "warning"
-  },
-  "controllersToScan": ["Deployments"]
+  }
 }
 `
 
@@ -160,5 +157,4 @@ func TestConfigWithCustomChecks(t *testing.T) {
 func testParsedConfig(t *testing.T, config *Configuration) {
 	assert.Equal(t, SeverityWarning, config.Checks["cpuRequestsMissing"])
 	assert.Equal(t, Severity(""), config.Checks["cpuLimitsMissing"])
-	assert.ElementsMatch(t, []SupportedController{Deployments}, config.ControllersToScan)
 }
diff --git a/pkg/config/supportedcontrollers_test.go b/pkg/config/supportedcontrollers_test.go
deleted file mode 100644
index 694f4ccf..00000000
--- a/pkg/config/supportedcontrollers_test.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2019 FairwindsOps Inc
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package config
-
-import (
-	"encoding/json"
-	"fmt"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-type checkMarshal struct {
-	Controllers []SupportedController `json:"controllers"`
-}
-
-func TestUnmarshalSupportedControllers(t *testing.T) {
-	for idx, controllerString := range ControllerStrings {
-		// Check taking all strings and convert them into enums
-		object := checkMarshal{}
-		jsonBytes := []byte(fmt.Sprintf(`{"controllers":["%v"]}`, controllerString))
-		err := json.Unmarshal(jsonBytes, &object)
-		if idx == 0 {
-			if err == nil {
-				// Assure the first element always should NOT unmarshal
-				t.Errorf("Expected the first element (%s) to fail json unmarshal. First element in this array should always be 'Unsupported'", controllerString)
-			}
-		} else if err != nil {
-			t.Errorf("Could not unmarshal json (%s) to a Supported controller; Received (%v)", jsonBytes, err)
-		}
-	}
-
-	badJSON := []byte(`{"controllers":[{"not":"valid_structure"}]}`)
-	err := json.Unmarshal(badJSON, &checkMarshal{})
-	if err == nil {
-		t.Error("expected invalid schema json to fail unmarshal")
-	}
-}
-
-func TestMarshalSupportedControllers(t *testing.T) {
-	for idx, controllerString := range ControllerStrings {
-		controllerType := GetSupportedControllerFromString(controllerString)
-		if idx == 0 {
-			assert.Equal(t, SupportedController(0), controllerType)
-		} else {
-			assert.NotEqual(t, SupportedController(0), controllerType)
-		}
-
-		object := checkMarshal{
-			Controllers: []SupportedController{controllerType},
-		}
-		_, err := json.Marshal(object)
-		if idx == 0 {
-			if err == nil {
-				t.Errorf("Expected (%s) to throw an error. Reserving the first element in the enum to be an invalid config", controllerString)
-			}
-		} else if err != nil {
-			t.Errorf("Could not write json output for element (%s); Received Error: (%s)", controllerString, err)
-		}
-	}
-}
-
-func TestCheckIfControllerKindIsConfiguredForValidation(t *testing.T) {
-	config := Configuration{}
-	for _, controllerString := range ControllerStrings[1:] {
-		controllerEnum := GetSupportedControllerFromString(controllerString)
-		assert.NotEqual(t, SupportedController(0), controllerEnum)
-		config.ControllersToScan = append(config.ControllersToScan, controllerEnum)
-	}
-
-	validControllerKinds := []string{
-		"deployment",
-		"statefulset",
-	}
-
-	invalidControllerKinds := []string{
-		"nonExistent",
-	}
-
-	for _, kind := range validControllerKinds {
-		if ok := config.CheckIfKindIsConfiguredForValidation(kind); !ok {
-			t.Errorf("Kind (%s) expected to be valid for configuration.", kind)
-		}
-	}
-
-	for _, kind := range invalidControllerKinds {
-		if ok := config.CheckIfKindIsConfiguredForValidation(kind); ok {
-			t.Errorf("Kind (%s) should not be a valid controller to check", kind)
-		}
-	}
-}
-
-func TestGetSupportedControllerFromString(t *testing.T) {
-	fixture := map[string]SupportedController{
-		"":            Unsupported,
-		"asdfasdf":    Unsupported,
-		"\000":        Unsupported,
-		"deployMENTS": Deployments,
-		"JOB":         Jobs,
-	}
-
-	for inputString, expectedType := range fixture {
-		resolvedType := GetSupportedControllerFromString(inputString)
-		assert.Equal(t, expectedType, resolvedType, fmt.Sprintf("Expected (%s) to return (%s) controller type.", inputString, expectedType))
-	}
-}
diff --git a/pkg/kube/resources_test.go b/pkg/kube/resources_test.go
index 742cc407..28517d40 100644
--- a/pkg/kube/resources_test.go
+++ b/pkg/kube/resources_test.go
@@ -26,7 +26,7 @@ func TestGetResourcesFromPath(t *testing.T) {
 	assert.Equal(t, 8, len(resources.Controllers), "Should have eight controllers")
 	namespaceCount := map[string]int{}
 	for _, controller := range resources.Controllers {
-		namespaceCount[controller.GetNamespace()]++
+		namespaceCount[controller.ObjectMeta.GetNamespace()]++
 	}
 	assert.Equal(t, 7, namespaceCount[""], "Should have seven controller in default namespace")
 	assert.Equal(t, 1, namespaceCount["two"], "Should have one controller in namespace 'two'")
@@ -72,5 +72,5 @@ func TestGetResourceFromAPI(t *testing.T) {
 	assert.Equal(t, 0, len(resources.Nodes), "Should not have any nodes")
 	assert.Equal(t, 1, len(resources.Controllers), "Should have 1 controller")
 
-	assert.Equal(t, "", resources.Controllers[0].ObjectMeta.Name)
+	assert.Equal(t, "", resources.Controllers[0].ObjectMeta.GetName())
 }
diff --git a/pkg/validator/container_test.go b/pkg/validator/container_test.go
index f3f4d822..65720909 100644
--- a/pkg/validator/container_test.go
+++ b/pkg/validator/container_test.go
@@ -19,10 +19,9 @@ import (
 	"testing"
 
 	conf "github.com/fairwindsops/polaris/pkg/config"
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
+	"github.com/fairwindsops/polaris/pkg/kube"
 
 	"github.com/stretchr/testify/assert"
-	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
@@ -51,26 +50,24 @@ exemptions:
     - foo
 `
 
-func getEmptyController(name string) controllers.GenericController {
-	return controllers.NewDeploymentController(appsv1.Deployment{
+func getEmptyWorkload(name string) kube.GenericWorkload {
+	workload := kube.NewGenericWorkload(corev1.Pod{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: name,
 		},
-		Spec: appsv1.DeploymentSpec{
-			Template: corev1.PodTemplateSpec{},
-		},
-	})
+	}, nil, nil)
+	return workload
 }
 
 func testValidate(t *testing.T, container *corev1.Container, resourceConf *string, controllerName string, expectedErrors []ResultMessage, expectedWarnings []ResultMessage, expectedSuccesses []ResultMessage) {
-	testValidateWithController(t, container, resourceConf, getEmptyController(controllerName), expectedErrors, expectedWarnings, expectedSuccesses)
+	testValidateWithWorkload(t, container, resourceConf, getEmptyWorkload(controllerName), expectedErrors, expectedWarnings, expectedSuccesses)
 }
 
-func testValidateWithController(t *testing.T, container *corev1.Container, resourceConf *string, controller controllers.GenericController, expectedErrors []ResultMessage, expectedWarnings []ResultMessage, expectedSuccesses []ResultMessage) {
+func testValidateWithWorkload(t *testing.T, container *corev1.Container, resourceConf *string, workload kube.GenericWorkload, expectedErrors []ResultMessage, expectedWarnings []ResultMessage, expectedSuccesses []ResultMessage) {
 	parsedConf, err := conf.Parse([]byte(*resourceConf))
 	assert.NoError(t, err, "Expected no error when parsing config")
 
-	results, err := applyContainerSchemaChecks(&parsedConf, controller, container, false)
+	results, err := applyContainerSchemaChecks(&parsedConf, workload, container, false)
 	if err != nil {
 		panic(err)
 	}
@@ -91,7 +88,7 @@ func TestValidateResourcesEmptyConfig(t *testing.T) {
 		Name: "Empty",
 	}
 
-	results, err := applyContainerSchemaChecks(&conf.Configuration{}, getEmptyController(""), container, false)
+	results, err := applyContainerSchemaChecks(&conf.Configuration{}, getEmptyWorkload(""), container, false)
 	if err != nil {
 		panic(err)
 	}
@@ -187,7 +184,7 @@ func TestValidateHealthChecks(t *testing.T) {
 
 	for idx, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			controller := getEmptyController("")
+			controller := getEmptyWorkload("")
 			results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.probes}, controller, tt.container, tt.isInit)
 			if err != nil {
 				panic(err)
@@ -301,7 +298,7 @@ func TestValidateImage(t *testing.T) {
 
 	for _, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			controller := getEmptyController("")
+			controller := getEmptyWorkload("")
 			results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.image}, controller, tt.container, false)
 			if err != nil {
 				panic(err)
@@ -418,7 +415,7 @@ func TestValidateNetworking(t *testing.T) {
 
 	for _, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			controller := getEmptyController("")
+			controller := getEmptyWorkload("")
 			results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.networkConf}, controller, tt.container, false)
 			if err != nil {
 				panic(err)
@@ -442,7 +439,7 @@ func TestValidateSecurity(t *testing.T) {
 	standardConf := map[string]conf.Severity{
 		"runAsRootAllowed":           conf.SeverityWarning,
 		"runAsPrivileged":            conf.SeverityError,
-		"notReadOnlyRootFileSystem":  conf.SeverityWarning,
+		"notReadOnlyRootFilesystem":  conf.SeverityWarning,
 		"privilegeEscalationAllowed": conf.SeverityError,
 		"dangerousCapabilities":      conf.SeverityError,
 		"insecureCapabilities":       conf.SeverityWarning,
@@ -450,7 +447,7 @@ func TestValidateSecurity(t *testing.T) {
 	strongConf := map[string]conf.Severity{
 		"runAsRootAllowed":           conf.SeverityError,
 		"runAsPrivileged":            conf.SeverityError,
-		"notReadOnlyRootFileSystem":  conf.SeverityError,
+		"notReadOnlyRootFilesystem":  conf.SeverityError,
 		"privilegeEscalationAllowed": conf.SeverityError,
 		"dangerousCapabilities":      conf.SeverityError,
 		"insecureCapabilities":       conf.SeverityError,
@@ -543,7 +540,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "warning",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem should be read only",
 				Success:  false,
 				Severity: "warning",
@@ -610,7 +607,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "warning",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem should be read only",
 				Success:  false,
 				Severity: "warning",
@@ -653,7 +650,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "warning",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem should be read only",
 				Success:  false,
 				Severity: "warning",
@@ -696,7 +693,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "warning",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem should be read only",
 				Success:  false,
 				Severity: "warning",
@@ -715,7 +712,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "warning",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem is read only",
 				Success:  true,
 				Severity: "warning",
@@ -770,7 +767,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "error",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem is read only",
 				Success:  true,
 				Severity: "error",
@@ -801,7 +798,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "error",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem is read only",
 				Success:  true,
 				Severity: "error",
@@ -844,7 +841,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "error",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem is read only",
 				Success:  true,
 				Severity: "error",
@@ -887,7 +884,7 @@ func TestValidateSecurity(t *testing.T) {
 				Severity: "error",
 				Category: "Security",
 			}, {
-				ID:       "notReadOnlyRootFileSystem",
+				ID:       "notReadOnlyRootFilesystem",
 				Message:  "Filesystem is read only",
 				Success:  true,
 				Severity: "error",
@@ -922,17 +919,8 @@ func TestValidateSecurity(t *testing.T) {
 
 	for _, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			controller := controllers.NewDeploymentController(appsv1.Deployment{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: "",
-				},
-				Spec: appsv1.DeploymentSpec{
-					Template: corev1.PodTemplateSpec{
-						Spec: *tt.pod,
-					},
-				},
-			})
-			results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.securityConf}, controller, tt.container, false)
+			workload := kube.NewGenericWorkload(corev1.Pod{Spec: *tt.pod}, nil, nil)
+			results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.securityConf}, workload, tt.container, false)
 			if err != nil {
 				panic(err)
 			}
@@ -1075,17 +1063,8 @@ func TestValidateRunAsRoot(t *testing.T) {
 	}
 	for idx, tt := range testCases {
 		t.Run(tt.name, func(t *testing.T) {
-			controller := controllers.NewDeploymentController(appsv1.Deployment{
-				ObjectMeta: metav1.ObjectMeta{
-					Name: "",
-				},
-				Spec: appsv1.DeploymentSpec{
-					Template: corev1.PodTemplateSpec{
-						Spec: *tt.pod,
-					},
-				},
-			})
-			results, err := applyContainerSchemaChecks(&config, controller, tt.container, false)
+			workload := kube.NewGenericWorkload(corev1.Pod{Spec: *tt.pod}, nil, nil)
+			results, err := applyContainerSchemaChecks(&config, workload, tt.container, false)
 			if err != nil {
 				panic(err)
 			}
@@ -1185,7 +1164,7 @@ func TestValidateResourcesEmptyContainerCPURequestsExempt(t *testing.T) {
 
 	expectedSuccesses := []ResultMessage{}
 
-	controller := controllers.NewDeploymentController(appsv1.Deployment{
+	workload := kube.NewGenericWorkload(corev1.Pod{
 		ObjectMeta: metav1.ObjectMeta{
 			Name: "foo",
 			Annotations: map[string]string{
@@ -1193,9 +1172,6 @@ func TestValidateResourcesEmptyContainerCPURequestsExempt(t *testing.T) {
 				"polaris.fairwinds.com/memoryRequestsMissing-exempt": "truthy", // Don't actually exempt this controller from memoryRequestsMissing
 			},
 		},
-		Spec: appsv1.DeploymentSpec{
-			Template: corev1.PodTemplateSpec{},
-		},
-	})
-	testValidateWithController(t, &container, &resourceConfMinimal, controller, expectedErrors, expectedWarnings, expectedSuccesses)
+	}, nil, nil)
+	testValidateWithWorkload(t, &container, &resourceConfMinimal, workload, expectedErrors, expectedWarnings, expectedSuccesses)
 }
diff --git a/pkg/validator/controller_test.go b/pkg/validator/controller_test.go
index a3335309..9d722ba9 100644
--- a/pkg/validator/controller_test.go
+++ b/pkg/validator/controller_test.go
@@ -22,7 +22,6 @@ import (
 
 	conf "github.com/fairwindsops/polaris/pkg/config"
 	"github.com/fairwindsops/polaris/pkg/kube"
-	controller "github.com/fairwindsops/polaris/pkg/validator/controllers"
 	"github.com/fairwindsops/polaris/test"
 )
 
@@ -33,7 +32,8 @@ func TestValidateController(t *testing.T) {
 			"hostPIDSet": conf.SeverityError,
 		},
 	}
-	deployment := controller.NewDeploymentController(test.MockDeploy())
+	deployment := kube.NewGenericWorkload(test.MockPod(), nil, nil)
+	deployment.Kind = "Deployment"
 	expectedSum := CountSummary{
 		Successes: uint(2),
 		Warnings:  uint(0),
@@ -62,18 +62,11 @@ func TestSkipHealthChecks(t *testing.T) {
 			"readinessProbeMissing": conf.SeverityError,
 			"livenessProbeMissing":  conf.SeverityWarning,
 		},
-		ControllersToScan: []conf.SupportedController{
-			conf.Deployments,
-			conf.StatefulSets,
-			conf.DaemonSets,
-			conf.Jobs,
-			conf.CronJobs,
-			conf.ReplicationControllers,
-		},
 	}
-	deploymentBase := test.MockDeploy()
-	deploymentBase.Spec.Template.Spec.InitContainers = []corev1.Container{test.MockContainer("test")}
-	deployment := controller.NewDeploymentController(deploymentBase)
+	pod := test.MockPod()
+	pod.Spec.InitContainers = []corev1.Container{test.MockContainer("test")}
+	deployment := kube.NewGenericWorkload(pod, nil, nil)
+	deployment.Kind = "Deployment"
 	expectedSum := CountSummary{
 		Successes: uint(0),
 		Warnings:  uint(1),
@@ -93,7 +86,8 @@ func TestSkipHealthChecks(t *testing.T) {
 	assert.EqualValues(t, ResultSet{}, actualResult.PodResult.ContainerResults[0].Results)
 	assert.EqualValues(t, expectedResults, actualResult.PodResult.ContainerResults[1].Results)
 
-	job := controller.NewJobController(test.MockJob())
+	job := kube.NewGenericWorkload(test.MockPod(), nil, nil)
+	job.Kind = "Job"
 	expectedSum = CountSummary{
 		Successes: uint(0),
 		Warnings:  uint(0),
@@ -109,7 +103,8 @@ func TestSkipHealthChecks(t *testing.T) {
 	assert.EqualValues(t, expectedSum, actualResult.GetSummary())
 	assert.EqualValues(t, expectedResults, actualResult.PodResult.ContainerResults[0].Results)
 
-	cronjob := controller.NewCronJobController(test.MockCronJob())
+	cronjob := kube.NewGenericWorkload(test.MockPod(), nil, nil)
+	cronjob.Kind = "CronJob"
 	expectedSum = CountSummary{
 		Successes: uint(0),
 		Warnings:  uint(0),
@@ -132,14 +127,12 @@ func TestControllerExemptions(t *testing.T) {
 			"readinessProbeMissing": conf.SeverityError,
 			"livenessProbeMissing":  conf.SeverityWarning,
 		},
-		ControllersToScan: []conf.SupportedController{
-			conf.Deployments,
-		},
 	}
-	newController := test.MockGenericController()
-	newController.Kind = "Deployment"
+	pod := test.MockPod()
+	workload := kube.NewGenericWorkload(pod, nil, nil)
+	workload.Kind = "Deployment"
 	resources := &kube.ResourceProvider{
-		Controllers: []controller.GenericController{newController},
+		Controllers: []kube.GenericWorkload{workload},
 	}
 
 	expectedSum := CountSummary{
@@ -155,9 +148,9 @@ func TestControllerExemptions(t *testing.T) {
 	assert.Equal(t, "Deployment", actualResults[0].Kind)
 	assert.EqualValues(t, expectedSum, actualResults[0].GetSummary())
 
-	resources.Controllers[0].ObjectMeta.Annotations = map[string]string{
+	resources.Controllers[0].ObjectMeta.SetAnnotations(map[string]string{
 		exemptionAnnotationKey: "true",
-	}
+	})
 	actualResults, err = ValidateControllers(&c, resources)
 	if err != nil {
 		panic(err)
diff --git a/pkg/validator/fullaudit_test.go b/pkg/validator/fullaudit_test.go
index 0135ed30..e1771af3 100644
--- a/pkg/validator/fullaudit_test.go
+++ b/pkg/validator/fullaudit_test.go
@@ -23,14 +23,6 @@ func TestGetTemplateData(t *testing.T) {
 			"readinessProbeMissing": conf.SeverityError,
 			"livenessProbeMissing":  conf.SeverityWarning,
 		},
-		ControllersToScan: []conf.SupportedController{
-			conf.Deployments,
-			conf.StatefulSets,
-			conf.DaemonSets,
-			conf.Jobs,
-			conf.CronJobs,
-			conf.ReplicationControllers,
-		},
 	}
 
 	sum := CountSummary{
diff --git a/pkg/validator/pod_test.go b/pkg/validator/pod_test.go
index 1c2139ec..5b103590 100644
--- a/pkg/validator/pod_test.go
+++ b/pkg/validator/pod_test.go
@@ -17,13 +17,12 @@ package validator
 import (
 	"testing"
 
-	conf "github.com/fairwindsops/polaris/pkg/config"
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
-	"github.com/fairwindsops/polaris/test"
-
 	"github.com/stretchr/testify/assert"
-	appsv1 "k8s.io/api/apps/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+
+	conf "github.com/fairwindsops/polaris/pkg/config"
+	"github.com/fairwindsops/polaris/pkg/kube"
+	"github.com/fairwindsops/polaris/test"
 )
 
 func TestValidatePod(t *testing.T) {
@@ -39,7 +38,7 @@ func TestValidatePod(t *testing.T) {
 	k8s, _ := test.SetupTestAPI()
 	k8s = test.SetupAddControllers(k8s, "test")
 	p := test.MockPod()
-	deployment := controllers.NewDeploymentController(appsv1.Deployment{Spec: appsv1.DeploymentSpec{Template: p}})
+	deployment := kube.NewGenericWorkload(p, nil, nil)
 
 	expectedSum := CountSummary{
 		Successes: uint(4),
@@ -77,7 +76,7 @@ func TestInvalidIPCPod(t *testing.T) {
 	k8s = test.SetupAddControllers(k8s, "test")
 	p := test.MockPod()
 	p.Spec.HostIPC = true
-	deployment := controllers.NewDeploymentController(appsv1.Deployment{Spec: appsv1.DeploymentSpec{Template: p}})
+	workload := kube.NewGenericWorkload(p, nil, nil)
 
 	expectedSum := CountSummary{
 		Successes: uint(3),
@@ -90,7 +89,7 @@ func TestInvalidIPCPod(t *testing.T) {
 		"hostPIDSet":     {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "error", Category: "Security"},
 	}
 
-	actualPodResult, err := ValidatePod(&c, deployment)
+	actualPodResult, err := ValidatePod(&c, workload)
 	if err != nil {
 		panic(err)
 	}
@@ -114,7 +113,7 @@ func TestInvalidNeworkPod(t *testing.T) {
 	k8s = test.SetupAddControllers(k8s, "test")
 	p := test.MockPod()
 	p.Spec.HostNetwork = true
-	deployment := controllers.NewDeploymentController(appsv1.Deployment{Spec: appsv1.DeploymentSpec{Template: p}})
+	workload := kube.NewGenericWorkload(p, nil, nil)
 
 	expectedSum := CountSummary{
 		Successes: uint(3),
@@ -128,7 +127,7 @@ func TestInvalidNeworkPod(t *testing.T) {
 		"hostPIDSet":     {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "error", Category: "Security"},
 	}
 
-	actualPodResult, err := ValidatePod(&c, deployment)
+	actualPodResult, err := ValidatePod(&c, workload)
 	if err != nil {
 		panic(err)
 	}
@@ -152,7 +151,7 @@ func TestInvalidPIDPod(t *testing.T) {
 	k8s = test.SetupAddControllers(k8s, "test")
 	p := test.MockPod()
 	p.Spec.HostPID = true
-	deployment := controllers.NewDeploymentController(appsv1.Deployment{Spec: appsv1.DeploymentSpec{Template: p}})
+	workload := kube.NewGenericWorkload(p, nil, nil)
 
 	expectedSum := CountSummary{
 		Successes: uint(3),
@@ -166,7 +165,7 @@ func TestInvalidPIDPod(t *testing.T) {
 		"hostNetworkSet": {ID: "hostNetworkSet", Message: "Host network is not configured", Success: true, Severity: "warning", Category: "Networking"},
 	}
 
-	actualPodResult, err := ValidatePod(&c, deployment)
+	actualPodResult, err := ValidatePod(&c, workload)
 	if err != nil {
 		panic(err)
 	}
@@ -196,13 +195,10 @@ func TestExemption(t *testing.T) {
 	k8s = test.SetupAddControllers(k8s, "test")
 	p := test.MockPod()
 	p.Spec.HostIPC = true
-	meta := metav1.ObjectMeta{
+	p.ObjectMeta = metav1.ObjectMeta{
 		Name: "foo",
 	}
-	deploySpec := appsv1.DeploymentSpec{
-		Template: p,
-	}
-	deployment := controllers.NewDeploymentController(appsv1.Deployment{ObjectMeta: meta, Spec: deploySpec})
+	workload := kube.NewGenericWorkload(p, nil, nil)
 
 	expectedSum := CountSummary{
 		Successes: uint(3),
@@ -214,7 +210,7 @@ func TestExemption(t *testing.T) {
 		"hostPIDSet":     {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "error", Category: "Security"},
 	}
 
-	actualPodResult, err := ValidatePod(&c, deployment)
+	actualPodResult, err := ValidatePod(&c, workload)
 	if err != nil {
 		panic(err)
 	}
diff --git a/pkg/validator/schema_test.go b/pkg/validator/schema_test.go
index 3005558e..a4dc1137 100644
--- a/pkg/validator/schema_test.go
+++ b/pkg/validator/schema_test.go
@@ -138,7 +138,7 @@ func TestValidateResourcesPartiallyValid(t *testing.T) {
 
 func TestValidateResourcesInit(t *testing.T) {
 	emptyContainer := &corev1.Container{}
-	controller := getEmptyController("")
+	controller := getEmptyWorkload("")
 
 	parsedConf, err := conf.Parse([]byte(resourceConfRanges))
 	assert.NoError(t, err, "Expected no error when parsing config")
@@ -259,4 +259,4 @@ func TestValidateCustomCheckExemptions(t *testing.T) {
 		},
 	}
 	testValidate(t, &container, &customCheckExemptions, "notexempt", expectedErrors, expectedWarnings, expectedSuccesses)
-}
\ No newline at end of file
+}
diff --git a/test/fixtures.go b/test/fixtures.go
index 7a5ad47c..b0178664 100644
--- a/test/fixtures.go
+++ b/test/fixtures.go
@@ -1,7 +1,6 @@
 package test
 
 import (
-	"github.com/fairwindsops/polaris/pkg/validator/controllers"
 	appsv1 "k8s.io/api/apps/v1"
 	appsv1beta1 "k8s.io/api/apps/v1beta1"
 	appsv1beta2 "k8s.io/api/apps/v1beta2"
@@ -24,9 +23,9 @@ func MockContainer(name string) corev1.Container {
 }
 
 // MockPod creates a pod object.
-func MockPod() corev1.PodTemplateSpec {
+func MockPod() corev1.Pod {
 	c1 := MockContainer("test")
-	p := corev1.PodTemplateSpec{
+	p := corev1.Pod{
 		Spec: corev1.PodSpec{
 			Containers: []corev1.Container{
 				c1,
@@ -36,13 +35,6 @@ func MockPod() corev1.PodTemplateSpec {
 	return p
 }
 
-// MockGenericController creates a generic controller object for testing.
-func MockGenericController() controllers.GenericController {
-	return controllers.GenericController{
-		PodSpec: MockPod().Spec,
-	}
-}
-
 // MockNakedPod creates a pod object.
 func MockNakedPod() corev1.Pod {
 	return corev1.Pod{
@@ -55,7 +47,7 @@ func MockDeploy() appsv1.Deployment {
 	p := MockPod()
 	d := appsv1.Deployment{
 		Spec: appsv1.DeploymentSpec{
-			Template: p,
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 	return d
@@ -66,7 +58,7 @@ func MockStatefulSet() appsv1.StatefulSet {
 	p := MockPod()
 	s := appsv1.StatefulSet{
 		Spec: appsv1.StatefulSetSpec{
-			Template: p,
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 	return s
@@ -74,29 +66,32 @@ func MockStatefulSet() appsv1.StatefulSet {
 
 // MockDaemonSet creates a DaemonSet object.
 func MockDaemonSet() appsv1.DaemonSet {
+	p := MockPod()
 	return appsv1.DaemonSet{
 		Spec: appsv1.DaemonSetSpec{
-			Template: MockPod(),
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 }
 
 // MockJob creates a Job object.
 func MockJob() batchv1.Job {
+	p := MockPod()
 	return batchv1.Job{
 		Spec: batchv1.JobSpec{
-			Template: MockPod(),
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 }
 
 // MockCronJob creates a CronJob object.
 func MockCronJob() batchv1beta1.CronJob {
+	p := MockPod()
 	return batchv1beta1.CronJob{
 		Spec: batchv1beta1.CronJobSpec{
 			JobTemplate: batchv1beta1.JobTemplateSpec{
 				Spec: batchv1.JobSpec{
-					Template: MockPod(),
+					Template: corev1.PodTemplateSpec{Spec: p.Spec},
 				},
 			},
 		},
@@ -108,7 +103,7 @@ func MockReplicationController() corev1.ReplicationController {
 	p := MockPod()
 	return corev1.ReplicationController{
 		Spec: corev1.ReplicationControllerSpec{
-			Template: &p,
+			Template: &corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 }
@@ -166,7 +161,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
 
 	dv1b1 := appsv1beta1.Deployment{
 		Spec: appsv1beta1.DeploymentSpec{
-			Template: p,
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 	if _, err := k.AppsV1beta1().Deployments(namespace).Create(&dv1b1); err != nil {
@@ -175,7 +170,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
 
 	dv1b2 := appsv1beta2.Deployment{
 		Spec: appsv1beta2.DeploymentSpec{
-			Template: p,
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 	if _, err := k.AppsV1beta2().Deployments(namespace).Create(&dv1b2); err != nil {
@@ -184,7 +179,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
 
 	ssv1b1 := appsv1beta1.StatefulSet{
 		Spec: appsv1beta1.StatefulSetSpec{
-			Template: p,
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 	if _, err := k.AppsV1beta1().StatefulSets(namespace).Create(&ssv1b1); err != nil {
@@ -193,7 +188,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
 
 	ssv1b2 := appsv1beta2.StatefulSet{
 		Spec: appsv1beta2.StatefulSetSpec{
-			Template: p,
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 	if _, err := k.AppsV1beta2().StatefulSets(namespace).Create(&ssv1b2); err != nil {
@@ -202,7 +197,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
 
 	dsv1b2 := appsv1beta2.DaemonSet{
 		Spec: appsv1beta2.DaemonSetSpec{
-			Template: p,
+			Template: corev1.PodTemplateSpec{Spec: p.Spec},
 		},
 	}
 	if _, err := k.AppsV1beta2().DaemonSets(namespace).Create(&dsv1b2); err != nil {