Compare commits

..
Author SHA1 Message Date
Bader Boland 567e16d056 Fix compile errors 2020-10-23 08:30:00 -04:00
Bader Boland f6e6f7ce2f Start work on using controller-utils 2020-10-23 08:24:48 -04:00
dependabot-preview[bot]andlnx01 9cce9fcec7 Bump github.com/sirupsen/logrus from 1.6.0 to 1.7.0 (#420)
Bumps [github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) from 1.6.0 to 1.7.0.
- [Release notes](https://github.com/sirupsen/logrus/releases)
- [Changelog](https://github.com/sirupsen/logrus/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sirupsen/logrus/compare/v1.6.0...v1.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-10-05 15:05:22 -04:00
Robert Brennan f05d3caa0b Update images.md (#423) 2020-10-05 13:07:34 -04:00
dependabot-preview[bot]andlnx01 3c1533790f Bump sigs.k8s.io/controller-runtime from 0.6.2 to 0.6.3 (#419)
Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.6.2 to 0.6.3.
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.6.2...v0.6.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-21 10:33:07 -04:00
boostrack 20746518bc "install" option as docker container (#410)
* Update usage.md

option for running as docker container locally

* Update usage.md
2020-09-21 10:09:09 -04:00
dependabot-preview[bot]andlnx01 75808b1dc1 Bump sigs.k8s.io/controller-runtime from 0.6.1 to 0.6.2 (#411)
Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.6.1 to 0.6.2.
- [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases)
- [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.6.1...v0.6.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-18 08:32:24 -04:00
baderbuddy 7c9f01639b Update dependencies (#400)
* Start working on updating dependencies:

* Fix webhook

* Rollback jsonschema update

* Checkin new config

* Fix run as root

* Update versions of kind

* Fix typo in kind URL

* Fix kind config

* Add csr permissions

* Fix weird image thing

* Fixed certificates

* Add to logging

* Approve cert manually

* Fix approval

* Add cert script

* Fix deployment

* Add requests/limits

* Wait if certificate doesn't exist yet

* Add check for file size

* Add variable

* Try a different imagE

* Fix command

* Update certificate logic

* Add healthz

* Don't check cert size

* Remove stat

* Fix vet

* Put in change that makes no sense

* Fix cert names

* Roll back

* Try changing config

* Add logging for each request

* Cleanup code some

* Remove bad deployments

* Fix client injection

* Update timeout

* Add logging

* Fixed e2e webhook tests

* Add permissions for approval

* Fix permissions for CSR

* Remove logging code

* Remove refresh certs file

* Fix merge issues

* Update deployments

* Try beta of admission controller config

* Target 1.15 for testing

* Add beta versions of resourceS

* Lower webhook timeout

* Refactor out a method

* Fix up PR issues

* Fix more tabs

* Remove unnecessary messageS

* Fix go.sum

* Fix go.sum
2020-09-11 08:53:14 -04:00
dependabot-preview[bot]andlnx01 6cb9999864 Bump go.uber.org/zap from 1.15.0 to 1.16.0 (#406)
Bumps [go.uber.org/zap](https://github.com/uber-go/zap) from 1.15.0 to 1.16.0.
- [Release notes](https://github.com/uber-go/zap/releases)
- [Changelog](https://github.com/uber-go/zap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/uber-go/zap/compare/v1.15.0...v1.16.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-11 08:28:56 -04:00
dependabot-preview[bot]andlnx01 a621249787 Bump github.com/rogpeppe/go-internal from 1.6.1 to 1.6.2 (#405)
Bumps [github.com/rogpeppe/go-internal](https://github.com/rogpeppe/go-internal) from 1.6.1 to 1.6.2.
- [Release notes](https://github.com/rogpeppe/go-internal/releases)
- [Commits](https://github.com/rogpeppe/go-internal/compare/v1.6.1...v1.6.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-11 08:28:25 -04:00
dependabot-preview[bot]andlnx01 679f135b62 Bump cloud.google.com/go from 0.63.0 to 0.65.0 (#402)
Bumps [cloud.google.com/go](https://github.com/googleapis/google-cloud-go) from 0.63.0 to 0.65.0.
- [Release notes](https://github.com/googleapis/google-cloud-go/releases)
- [Changelog](https://github.com/googleapis/google-cloud-go/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-cloud-go/compare/v0.63.0...v0.65.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-11 08:27:54 -04:00
dependabot-preview[bot]andlnx01 5c456ddb86 Bump github.com/evanphx/json-patch (#399)
Bumps [github.com/evanphx/json-patch](https://github.com/evanphx/json-patch) from 4.5.0+incompatible to 4.9.0+incompatible.
- [Release notes](https://github.com/evanphx/json-patch/releases)
- [Commits](https://github.com/evanphx/json-patch/compare/v4.5.0...v4.9.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-01 11:47:41 -04:00
dependabot-preview[bot]andlnx01 c1c07bcea2 Bump google.golang.org/grpc from 1.31.0 to 1.31.1 (#401)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.31.0 to 1.31.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.31.0...v1.31.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-01 11:47:12 -04:00
dependabot-preview[bot]andlnx01 c703aa4039 Bump github.com/prometheus/common from 0.12.0 to 0.13.0 (#398)
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.12.0 to 0.13.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Commits](https://github.com/prometheus/common/compare/v0.12.0...v0.13.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-01 11:46:59 -04:00
dependabot-preview[bot]andlnx01 1051bc5922 Bump github.com/gorilla/mux from 1.7.4 to 1.8.0 (#396)
Bumps [github.com/gorilla/mux](https://github.com/gorilla/mux) from 1.7.4 to 1.8.0.
- [Release notes](https://github.com/gorilla/mux/releases)
- [Commits](https://github.com/gorilla/mux/compare/v1.7.4...v1.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-09-01 11:46:38 -04:00
dependabot-preview[bot]andlnx01 155299a8d5 Bump github.com/karrick/godirwalk from 1.15.6 to 1.16.1 (#393)
Bumps [github.com/karrick/godirwalk](https://github.com/karrick/godirwalk) from 1.15.6 to 1.16.1.
- [Release notes](https://github.com/karrick/godirwalk/releases)
- [Changelog](https://github.com/karrick/godirwalk/blob/master/debug_release.go)
- [Commits](https://github.com/karrick/godirwalk/compare/v1.15.6...v1.16.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-19 14:01:21 -04:00
dependabot-preview[bot]andlnx01 f0b63e3cb6 Bump github.com/imdario/mergo from 0.3.10 to 0.3.11 (#392)
Bumps [github.com/imdario/mergo](https://github.com/imdario/mergo) from 0.3.10 to 0.3.11.
- [Release notes](https://github.com/imdario/mergo/releases)
- [Commits](https://github.com/imdario/mergo/compare/v0.3.10...v0.3.11)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-19 14:01:09 -04:00
dependabot-preview[bot]andlnx01 479ab1dae6 Bump github.com/prometheus/common from 0.11.1 to 0.12.0 (#394)
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.11.1 to 0.12.0.
- [Release notes](https://github.com/prometheus/common/releases)
- [Commits](https://github.com/prometheus/common/compare/v0.11.1...v0.12.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-19 14:00:56 -04:00
dependabot-preview[bot]andlnx01 b5058cd906 Bump github.com/grpc-ecosystem/grpc-gateway from 1.14.6 to 1.14.7 (#395)
Bumps [github.com/grpc-ecosystem/grpc-gateway](https://github.com/grpc-ecosystem/grpc-gateway) from 1.14.6 to 1.14.7.
- [Release notes](https://github.com/grpc-ecosystem/grpc-gateway/releases)
- [Changelog](https://github.com/grpc-ecosystem/grpc-gateway/blob/master/CHANGELOG.md)
- [Commits](https://github.com/grpc-ecosystem/grpc-gateway/compare/v1.14.6...v1.14.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-19 14:00:42 -04:00
dependabot-preview[bot]andlnx01 c1115e556b Bump github.com/pborman/uuid from 1.2.0 to 1.2.1 (#391)
Bumps [github.com/pborman/uuid](https://github.com/pborman/uuid) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/pborman/uuid/releases)
- [Commits](https://github.com/pborman/uuid/compare/v1.2...v1.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-19 14:00:28 -04:00
dependabot-preview[bot]andlnx01 617d3d28b5 Bump cloud.google.com/go from 0.61.0 to 0.63.0 (#389)
Bumps [cloud.google.com/go](https://github.com/googleapis/google-cloud-go) from 0.61.0 to 0.63.0.
- [Release notes](https://github.com/googleapis/google-cloud-go/releases)
- [Changelog](https://github.com/googleapis/google-cloud-go/blob/master/CHANGES.md)
- [Commits](https://github.com/googleapis/google-cloud-go/compare/v0.61.0...v0.63.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-13 15:35:35 -04:00
dependabot-preview[bot]andlnx01 582a631014 Bump github.com/prometheus/common from 0.10.0 to 0.11.1 (#387)
Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.10.0 to 0.11.1.
- [Release notes](https://github.com/prometheus/common/releases)
- [Commits](https://github.com/prometheus/common/compare/v0.10.0...v0.11.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-11 14:02:17 -04:00
dependabot-preview[bot]andlnx01 f4c2ae451f Bump github.com/google/gofuzz from 1.1.0 to 1.2.0 (#388)
Bumps [github.com/google/gofuzz](https://github.com/google/gofuzz) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/google/gofuzz/releases)
- [Commits](https://github.com/google/gofuzz/compare/v1.1.0...v1.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-11 14:01:45 -04:00
dependabot-preview[bot]andlnx01 b76b2c3df4 Bump github.com/rogpeppe/go-internal from 1.6.0 to 1.6.1 (#384)
Bumps [github.com/rogpeppe/go-internal](https://github.com/rogpeppe/go-internal) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/rogpeppe/go-internal/releases)
- [Commits](https://github.com/rogpeppe/go-internal/compare/v1.6.0...v1.6.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-11 14:01:35 -04:00
dependabot-preview[bot]andlnx01 0bbf43146c Bump google.golang.org/grpc from 1.30.0 to 1.31.0 (#383)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.30.0 to 1.31.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.30.0...v1.31.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-11 14:01:23 -04:00
28 changed files with 832 additions and 815 deletions
+3 -5
View File
@@ -27,24 +27,22 @@ references:
sudo apt-get install -yqq jq git
echo "Installing KIND"
curl -sLO https://github.com/kubernetes-sigs/kind/releases/download/0.2.1/kind-linux-amd64
curl -sLO https://github.com/kubernetes-sigs/kind/releases/download/v0.8.1/kind-linux-amd64
chmod 0755 kind-linux-amd64
sudo mv kind-linux-amd64 /usr/local/bin/kind
kind version
echo "Installing Kubectl"
curl -sLO https://storage.googleapis.com/kubernetes-release/release/v1.12.7/bin/linux/amd64/kubectl
curl -sLO https://storage.googleapis.com/kubernetes-release/release/v1.18.6/bin/linux/amd64/kubectl
chmod 0755 kubectl
sudo mv kubectl /usr/local/bin/
kubectl version --client
echo "Creating Kubernetes Cluster with Kind"
kind create cluster --wait=90s
kind create cluster --wait=90s --image kindest/node:v1.15.11
docker ps -a
echo "Setting up kubecfg"
cp $(kind get kubeconfig-path --name=kind) ~/.kube/config
kubectl version
# Test scripts
+3 -1
View File
@@ -21,4 +21,6 @@ main
*-packr.go
dist
.vscode
.vscode
*-test.yaml
+5 -4
View File
@@ -16,6 +16,7 @@ package cmd
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
@@ -58,7 +59,7 @@ var auditCmd = &cobra.Command{
config.DisplayName = displayName
}
auditData := runAndReportAudit(config, auditPath, resourceToAudit, auditOutputFile, auditOutputURL, auditOutputFormat)
auditData := runAndReportAudit(cmd.Context(), config, auditPath, resourceToAudit, auditOutputFile, auditOutputURL, auditOutputFormat)
summary := auditData.GetSummary()
score := summary.GetScore()
@@ -72,14 +73,14 @@ var auditCmd = &cobra.Command{
},
}
func runAndReportAudit(c conf.Configuration, auditPath, workload, outputFile, outputURL, outputFormat string) validator.AuditData {
func runAndReportAudit(ctx context.Context, c conf.Configuration, auditPath, workload, outputFile, outputURL, outputFormat string) validator.AuditData {
// Create a kubernetes client resource provider
k, err := kube.CreateResourceProvider(auditPath, workload)
k, err := kube.CreateResourceProvider(ctx, auditPath, workload)
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
os.Exit(1)
}
auditData, err := validator.RunAudit(c, k)
auditData, err := validator.RunAudit(ctx, c, k)
if err != nil {
logrus.Errorf("Error while running audit on resources: %v", err)
+17 -100
View File
@@ -15,50 +15,18 @@
package cmd
import (
"io/ioutil"
"os"
"strings"
"time"
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"
fwebhook "github.com/fairwindsops/polaris/pkg/webhook"
k8sConfig "sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/runtime/signals"
"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
@@ -74,81 +42,30 @@ var webhookCmd = &cobra.Command{
Long: `Runs the webhook webserver.`,
Run: func(cmd *cobra.Command, args []string) {
logrus.Debug("Setting up controller manager")
mgr, err := manager.New(k8sConfig.GetConfigOrDie(), manager.Options{})
mgr, err := manager.New(k8sConfig.GetConfigOrDie(), manager.Options{
CertDir: "/opt/cert",
Port: webhookPort,
})
if err != nil {
logrus.Errorf("Unable to set up overall controller manager: %v", err)
os.Exit(1)
}
polarisAppName := "polaris"
polarisResourceName := "polaris-webhook"
polarisNamespaceBytes, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
if err != nil {
// Not exiting here as we have fallback options
logrus.Debugf("Error reading namespace information: %v", err)
_, err = os.Stat("/opt/cert/tls.crt")
if os.IsNotExist(err) {
time.Sleep(time.Second * 10)
panic("Cert does not exist")
}
polarisNamespace := string(polarisNamespaceBytes)
if polarisNamespace == "" {
polarisNamespace = polarisResourceName
logrus.Debugf("Could not determine current namespace, creating resources in %s namespace", polarisNamespace)
}
logrus.Info("Setting up webhook server")
as, err := webhook.NewServer(polarisResourceName, mgr, webhook.ServerOptions{
Port: int32(webhookPort),
CertDir: "/opt/cert",
DisableWebhookConfigInstaller: &disableWebhookConfigInstaller,
BootstrapOptions: &webhook.BootstrapOptions{
ValidatingWebhookConfigName: polarisResourceName,
Secret: &apitypes.NamespacedName{
Namespace: polarisNamespace,
Name: polarisResourceName,
},
Service: &webhook.Service{
Namespace: polarisNamespace,
Name: polarisResourceName,
// Selectors should select the pods that runs this webhook server.
Selectors: map[string]string{
"app": polarisAppName,
"component": "webhook",
},
},
},
})
if err != nil {
logrus.Errorf("Error setting up webhook server: %v", err)
os.Exit(1)
}
logrus.Infof("Polaris webhook server listening on port %d", webhookPort)
server := mgr.GetWebhookServer()
server.CertName = "tls.crt"
server.KeyName = "tls.key"
// Iterate all the configurations supported controllers to scan and register them for webhooks
// Should only register controllers that are configured to be scanned
logrus.Debug("Registering webhooks to the webhook server")
var webhooks []webhook.Webhook
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)
}
fwebhook.NewWebhook(mgr, fwebhook.Validator{Config: config, Client: mgr.GetClient()})
if err = as.Register(webhooks...); err != nil {
logrus.Debugf("Unable to register webhooks in the admission server: %v", err)
os.Exit(1)
}
logrus.Debug("Starting webhook manager")
logrus.Infof("Polaris webhook server listening on port %d", webhookPort)
if err := mgr.Start(signals.SetupSignalHandler()); err != nil {
logrus.Errorf("Error starting manager: %v", err)
os.Exit(1)
+157 -7
View File
@@ -14,6 +14,15 @@ metadata:
labels:
app: polaris
---
# Source: polaris/templates/webhook.rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: polaris-certificates
namespace: polaris
labels:
app: polaris
---
# Source: polaris/templates/webhook.secret.yaml
# The name of this secret is static as it is populated by the webhook pod.
apiVersion: v1
@@ -23,9 +32,10 @@ metadata:
namespace: polaris
labels:
app: polaris
type: Opaque
stringData:
cert.pem: ''
type: kubernetes.io/tls
data:
tls.crt: ''
tls.key: ''
---
# Source: polaris/templates/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
@@ -53,8 +63,6 @@ metadata:
labels:
app: polaris
rules:
# required by controller-runtime code doing a cluster wide lookup
# when it seems namespace would suffice
- apiGroups:
- ''
resources:
@@ -64,6 +72,24 @@ rules:
- 'get'
- 'list'
- 'watch'
- apiGroups:
- 'certificates.k8s.io'
resources:
- 'certificatesigningrequests'
- 'certificatesigningrequests/approval'
verbs:
- 'get'
- 'update'
- 'create'
- 'delete'
- apiGroups:
- 'certificates.k8s.io'
resources:
- 'signers'
resourceNames:
- 'kubernetes.io/legacy-unknown'
verbs:
- 'approve'
- apiGroups:
- 'admissionregistration.k8s.io'
resources:
@@ -116,7 +142,7 @@ roleRef:
name: polaris-webhook
subjects:
- kind: ServiceAccount
name: polaris
name: polaris-certificates
namespace: polaris
---
# Source: polaris/templates/webhook.rbac.yaml
@@ -151,7 +177,7 @@ roleRef:
name: polaris-webhook
subjects:
- kind: ServiceAccount
name: polaris
name: polaris-certificates
namespace: polaris
---
# Source: polaris/templates/webhook.service.yaml
@@ -253,3 +279,127 @@ spec:
secretName: polaris-webhook
- name: cr-logs
emptyDir: {}
---
# Source: polaris/templates/webhook.job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: polaris-certificate-updater
namespace: polaris
labels:
app: polaris
component: certificate-updater
spec:
template:
metadata:
labels:
app: polaris
component: certificate-updater
spec:
containers:
- name: webhook-certificate-generator
image: 'newrelic/k8s-webhook-cert-manager:1.3.0'
imagePullPolicy: Always
command:
- ./generate_certificate.sh
- --service
- polaris-webhook
- --namespace
- polaris
- --secret
- polaris-webhook
- --webhook
- polaris-webhook
- --webhook-kind
- ValidatingWebhookConfiguration
resources:
limits:
cpu: 150m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
volumeMounts:
- name: tmp
mountPath: /tmp/
readOnly: false
securityContext:
allowPrivilegeEscalation: false
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
serviceAccountName: polaris-certificates
restartPolicy: Never
volumes:
- name: tmp
emptyDir: {}
---
# Source: polaris/templates/webhook.configuration.yaml
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: polaris-webhook
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
caBundle: ""
service:
name: polaris-webhook
namespace: polaris
path: /validate
port: 443
failurePolicy: Ignore
matchPolicy: Exact
name: polaris.fairwinds.com
namespaceSelector:
matchExpressions:
- key: control-plane
operator: DoesNotExist
objectSelector: {}
rules:
- apiGroups:
- apps
apiVersions:
- v1
- v1beta1
- v1beta2
operations:
- CREATE
- UPDATE
resources:
- daemonsets
- deployments
- statefulsets
scope: Namespaced
- apiGroups:
- batch
apiVersions:
- v1
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- jobs
- cronjobs
scope: Namespaced
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- pods
- replicationcontrollers
scope: Namespaced
sideEffects: None
timeoutSeconds: 30
+1 -1
View File
@@ -5,7 +5,7 @@ Polaris supports a number of checks related to the image specified by pods.
key | default | description
----|---------|------------
`images.tagNotSpecified` | `danger` | Fails when an image tag is either not specified or `latest`.
`images.pullPolicyNotAlways` | `ignore` | Fails when an image pull policy is not `always`.
`images.pullPolicyNotAlways` | `warning` | Fails when an image pull policy is not `always`.
## Background
+6
View File
@@ -120,6 +120,12 @@ You can also point the dashboard to the local filesystem, instead of a live clus
polaris dashboard --port 8080 --audit-path=./deploy/
```
### Local Docker container
```
docker run -d -p8080:8080 -v ~/.kube/config:/opt/app/config:ro quay.io/fairwinds/polaris:1.2 polaris dashboard --kubeconfig /opt/app/config
```
## Webhook
### kubectl
```bash
+29 -85
View File
@@ -3,95 +3,39 @@ module github.com/fairwindsops/polaris
go 1.13
require (
cloud.google.com/go v0.61.0
contrib.go.opencensus.io/exporter/ocagent v0.7.0
git.apache.org/thrift.git v0.12.0 // indirect
github.com/Azure/go-autorest v12.4.3+incompatible
github.com/Azure/go-autorest/autorest v0.10.0 // indirect
github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30
github.com/beorn7/perks v1.0.1
github.com/census-instrumentation/opencensus-proto v0.3.0
github.com/davecgh/go-spew v1.1.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/evanphx/json-patch v4.5.0+incompatible
github.com/go-logr/logr v0.1.0
github.com/go-logr/zapr v0.1.1
github.com/gobuffalo/depgen v0.1.0 // indirect
github.com/gobuffalo/envy v1.9.0
github.com/gobuffalo/genny v0.6.0
github.com/gobuffalo/gogen v0.2.0
github.com/gobuffalo/logger v1.0.3
github.com/gobuffalo/mapi v1.2.1
github.com/gobuffalo/packd v1.0.0
cloud.google.com/go v0.65.0 // indirect
github.com/Azure/go-autorest/autorest v0.11.4 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.2 // indirect
github.com/fairwindsops/controller-utils v0.1.0
github.com/gobuffalo/packr/v2 v2.8.0
github.com/gobuffalo/syncx v0.1.0
github.com/gogo/protobuf v1.3.1
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 // indirect
github.com/golang/protobuf v1.4.2
github.com/google/btree v1.0.0
github.com/google/gofuzz v1.1.0
github.com/google/uuid v1.1.1
github.com/googleapis/gnostic v0.3.1
github.com/gophercloud/gophercloud v0.0.0-20190516165734-b3a23cc94cc5
github.com/gorilla/mux v1.7.4
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc
github.com/grpc-ecosystem/grpc-gateway v1.14.6
github.com/hashicorp/golang-lru v0.5.4
github.com/imdario/mergo v0.3.10
github.com/joho/godotenv v1.3.0
github.com/json-iterator/go v1.1.10
github.com/karrick/godirwalk v1.15.6
github.com/konsorten/go-windows-terminal-sequences v1.0.3
github.com/markbates/oncer v1.0.0
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 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 v1.7.1
github.com/prometheus/client_model v0.2.0
github.com/prometheus/common v0.10.0
github.com/prometheus/procfs v0.1.3
github.com/google/go-cmp v0.5.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/gophercloud/gophercloud v0.12.0 // indirect
github.com/gorilla/mux v1.8.0
github.com/imdario/mergo v0.3.11 // indirect
github.com/jessevdk/go-flags v1.4.0 // indirect
github.com/karrick/godirwalk v1.16.1 // indirect
github.com/kr/pretty v0.2.0 // indirect
github.com/prometheus/common v0.13.0 // indirect
github.com/qri-io/jsonpointer v0.1.1 // indirect
github.com/qri-io/jsonschema v0.1.1
github.com/rogpeppe/go-internal v1.6.0
github.com/sirupsen/logrus v1.6.0
github.com/rogpeppe/go-internal v1.6.2 // indirect
github.com/sirupsen/logrus v1.7.0
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.6.1
gitlab.com/golang-commonmark/html v0.0.0-20180917080848-cfaf75183c4a
gitlab.com/golang-commonmark/linkify v0.0.0-20180917065525-c22b7bdb1179
gitlab.com/golang-commonmark/markdown v0.0.0-20181102083822-772775880e1f
gitlab.com/golang-commonmark/mdurl v0.0.0-20180912090424-e5bce34c34f2
gitlab.com/golang-commonmark/puny v0.0.0-20180912090636-2cd490539afe
go.opencensus.io v0.22.4
go.uber.org/atomic v1.6.0
go.uber.org/multierr v1.5.0
go.uber.org/zap v1.15.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1
golang.org/x/text v0.3.3
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed
google.golang.org/api v0.29.0
google.golang.org/appengine v1.6.6
google.golang.org/genproto v0.0.0-20200711021454-869866162049
google.golang.org/grpc v1.30.0
gopkg.in/inf.v0 v0.9.1
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
k8s.io/api v0.0.0-20181213150558-05914d821849
k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93
k8s.io/client-go v0.0.0-20181213151034-8d9ed539ba31
k8s.io/klog v0.4.0
k8s.io/kube-openapi v0.0.0-20190510232812-a01b7d5d6c22
sigs.k8s.io/controller-runtime v0.1.10
gitlab.com/golang-commonmark/linkify v0.0.0-20200225224916-64bca66f6ad3 // indirect
gitlab.com/golang-commonmark/markdown v0.0.0-20191127184510-91b5b3c99c19
go.uber.org/zap v1.16.0 // indirect
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 // indirect
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
gomodules.xyz/jsonpatch/v2 v2.1.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
k8s.io/api v0.18.9
k8s.io/apimachinery v0.18.9
k8s.io/client-go v0.18.9
k8s.io/klog/v2 v2.1.0 // indirect
sigs.k8s.io/controller-runtime v0.6.3
sigs.k8s.io/yaml v1.2.0
)
+415 -379
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -184,14 +184,14 @@ func GetRouter(c config.Configuration, auditPath string, port int, basePath stri
router.HandleFunc("/results.json", func(w http.ResponseWriter, r *http.Request) {
adjustedConf := getConfigForQuery(c, r.URL.Query())
if auditData == nil {
k, err := kube.CreateResourceProvider(auditPath, "")
k, err := kube.CreateResourceProvider(r.Context(), auditPath, "")
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
http.Error(w, "Error fetching Kubernetes resources", http.StatusInternalServerError)
return
}
auditDataObj, err := validator.RunAudit(adjustedConf, k)
auditDataObj, err := validator.RunAudit(r.Context(), adjustedConf, k)
if err != nil {
http.Error(w, "Error Fetching Deployments", http.StatusInternalServerError)
return
@@ -217,14 +217,14 @@ func GetRouter(c config.Configuration, auditPath string, port int, basePath stri
adjustedConf := getConfigForQuery(c, r.URL.Query())
if auditData == nil {
k, err := kube.CreateResourceProvider(auditPath, "")
k, err := kube.CreateResourceProvider(r.Context(), auditPath, "")
if err != nil {
logrus.Errorf("Error fetching Kubernetes resources %v", err)
http.Error(w, "Error fetching Kubernetes resources", http.StatusInternalServerError)
return
}
auditData, err := validator.RunAudit(adjustedConf, k)
auditData, err := validator.RunAudit(r.Context(), adjustedConf, k)
if err != nil {
logrus.Errorf("Error getting audit data: %v", err)
http.Error(w, "Error running audit", 500)
+15 -14
View File
@@ -2,6 +2,7 @@ package kube
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
@@ -42,18 +43,18 @@ type k8sResource struct {
var podSpecFields = []string{"jobTemplate", "spec", "template"}
// CreateResourceProvider returns a new ResourceProvider object to interact with k8s resources
func CreateResourceProvider(directory, workload string) (*ResourceProvider, error) {
func CreateResourceProvider(ctx context.Context, directory, workload string) (*ResourceProvider, error) {
if workload != "" {
return CreateResourceProviderFromWorkload(workload)
return CreateResourceProviderFromWorkload(ctx, workload)
}
if directory != "" {
return CreateResourceProviderFromPath(directory)
}
return CreateResourceProviderFromCluster()
return CreateResourceProviderFromCluster(ctx)
}
// CreateResourceProviderFromWorkload creates a new ResourceProvider that just contains one workload
func CreateResourceProviderFromWorkload(workload string) (*ResourceProvider, error) {
func CreateResourceProviderFromWorkload(ctx context.Context, workload string) (*ResourceProvider, error) {
kubeConf, configError := config.GetConfig()
if configError != nil {
logrus.Errorf("Error fetching KubeConfig: %v", configError)
@@ -98,7 +99,7 @@ func CreateResourceProviderFromWorkload(workload string) (*ResourceProvider, err
return nil, err
}
restMapper := restmapper.NewDiscoveryRESTMapper(groupResources)
obj, err := getObject(namespace, kind, version, name, &dynamicInterface, &restMapper)
obj, err := getObject(ctx, namespace, kind, version, name, &dynamicInterface, &restMapper)
if err != nil {
logrus.Errorf("Could not find workload %s: %v", workload, err)
return nil, err
@@ -154,7 +155,7 @@ func CreateResourceProviderFromPath(directory string) (*ResourceProvider, error)
}
// CreateResourceProviderFromCluster creates a new ResourceProvider using live data from a cluster
func CreateResourceProviderFromCluster() (*ResourceProvider, error) {
func CreateResourceProviderFromCluster(ctx context.Context) (*ResourceProvider, error) {
kubeConf, configError := config.GetConfig()
if configError != nil {
logrus.Errorf("Error fetching KubeConfig: %v", configError)
@@ -170,11 +171,11 @@ func CreateResourceProviderFromCluster() (*ResourceProvider, error) {
logrus.Errorf("Error connecting to dynamic interface: %v", err)
return nil, err
}
return CreateResourceProviderFromAPI(api, kubeConf.Host, &dynamicInterface)
return CreateResourceProviderFromAPI(ctx, api, kubeConf.Host, &dynamicInterface)
}
// CreateResourceProviderFromAPI creates a new ResourceProvider from an existing k8s interface
func CreateResourceProviderFromAPI(kube kubernetes.Interface, clusterName string, dynamic *dynamic.Interface) (*ResourceProvider, error) {
func CreateResourceProviderFromAPI(ctx context.Context, kube kubernetes.Interface, clusterName string, dynamic *dynamic.Interface) (*ResourceProvider, error) {
listOpts := metav1.ListOptions{}
serverVersion, err := kube.Discovery().ServerVersion()
if err != nil {
@@ -182,17 +183,17 @@ func CreateResourceProviderFromAPI(kube kubernetes.Interface, clusterName string
return nil, err
}
nodes, err := kube.CoreV1().Nodes().List(listOpts)
nodes, err := kube.CoreV1().Nodes().List(ctx, listOpts)
if err != nil {
logrus.Errorf("Error fetching Nodes: %v", err)
return nil, err
}
namespaces, err := kube.CoreV1().Namespaces().List(listOpts)
namespaces, err := kube.CoreV1().Namespaces().List(ctx, listOpts)
if err != nil {
logrus.Errorf("Error fetching Namespaces: %v", err)
return nil, err
}
pods, err := kube.CoreV1().Pods("").List(listOpts)
pods, err := kube.CoreV1().Pods("").List(ctx, listOpts)
if err != nil {
logrus.Errorf("Error fetching Pods: %v", err)
return nil, err
@@ -207,7 +208,7 @@ func CreateResourceProviderFromAPI(kube kubernetes.Interface, clusterName string
objectCache := map[string]unstructured.Unstructured{}
controllers, err := LoadControllers(pods.Items, dynamic, &restMapper, objectCache)
controllers, err := LoadControllers(ctx, pods.Items, dynamic, &restMapper, objectCache)
if err != nil {
logrus.Errorf("Error loading controllers from pods: %v", err)
return nil, err
@@ -226,7 +227,7 @@ 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, objectCache map[string]unstructured.Unstructured) ([]GenericWorkload, error) {
func LoadControllers(ctx context.Context, pods []corev1.Pod, dynamicClientPointer *dynamic.Interface, restMapperPointer *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) ([]GenericWorkload, error) {
interfaces := []GenericWorkload{}
deduped := map[string]corev1.Pod{}
for _, pod := range pods {
@@ -238,7 +239,7 @@ func LoadControllers(pods []corev1.Pod, dynamicClientPointer *dynamic.Interface,
deduped[pod.ObjectMeta.Namespace+"/"+owners[0].Kind+"/"+owners[0].Name] = pod
}
for _, pod := range deduped {
workload, err := NewGenericWorkload(pod, dynamicClientPointer, restMapperPointer, objectCache)
workload, err := NewGenericWorkload(ctx, pod, dynamicClientPointer, restMapperPointer, objectCache)
if err != nil {
return nil, err
}
+3 -2
View File
@@ -2,6 +2,7 @@ package kube
import (
"bytes"
"context"
"io/ioutil"
"testing"
"time"
@@ -87,10 +88,10 @@ func TestAddResourcesFromReader(t *testing.T) {
func TestGetResourceFromAPI(t *testing.T) {
k8s, dynamicInterface := test.SetupTestAPI()
k8s = test.SetupAddControllers(k8s, "test")
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
// TODO find a way to mock out the dynamic client
// and create fake pods in order to find all of the controllers.
resources, err := CreateResourceProviderFromAPI(k8s, "test", &dynamicInterface)
resources, err := CreateResourceProviderFromAPI(context.Background(), k8s, "test", &dynamicInterface)
assert.Equal(t, nil, err, "Error should be nil")
assert.Equal(t, "Cluster", resources.SourceType, "Should have type Path")
+27 -75
View File
@@ -2,9 +2,11 @@ package kube
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/fairwindsops/controller-utils/pkg/controller"
"github.com/sirupsen/logrus"
"gopkg.in/yaml.v3"
kubeAPICoreV1 "k8s.io/api/core/v1"
@@ -47,17 +49,17 @@ func NewGenericWorkloadFromUnstructured(kind string, unst *unstructured.Unstruct
if err != nil {
return workload, err
}
podSpecMap := GetPodSpec(m)
podSpecMap := controller.GetPodSpec(m)
b, err = json.Marshal(podSpecMap)
if err != nil {
return workload, err
}
podSpec := kubeAPICoreV1.PodSpec{}
err = json.Unmarshal(b, &podSpec)
podSpecObject := kubeAPICoreV1.PodSpec{}
err = json.Unmarshal(b, &podSpecObject)
if err != nil {
return workload, err
}
workload.PodSpec = podSpec
workload.PodSpec = podSpecObject
return workload, nil
}
@@ -80,8 +82,8 @@ func NewGenericWorkloadFromPod(podResource kubeAPICoreV1.Pod, originalObject int
}
// NewGenericWorkload builds a new workload for a given Pod
func NewGenericWorkload(podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericWorkload, error) {
workload, err := newGenericWorkload(podResource, dynamicClient, restMapper, objectCache)
func NewGenericWorkload(ctx context.Context, podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericWorkload, error) {
workload, err := newGenericWorkload(ctx, podResource, dynamicClient, restMapper, objectCache)
if err != nil {
return workload, err
}
@@ -91,66 +93,29 @@ func NewGenericWorkload(podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.In
return workload, err
}
func newGenericWorkload(podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericWorkload, error) {
func newGenericWorkload(ctx context.Context, podResource kubeAPICoreV1.Pod, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) (GenericWorkload, error) {
workload, err := NewGenericWorkloadFromPod(podResource, nil)
if err != nil {
return workload, err
}
// 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()
lastKey := ""
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
key := fmt.Sprintf("%s/%s/%s", firstOwner.Kind, workload.ObjectMeta.GetNamespace(), firstOwner.Name)
lastKey = key
abstractObject, ok := objectCache[key]
if !ok {
err = cacheAllObjectsOfKind(firstOwner.APIVersion, firstOwner.Kind, dynamicClient, restMapper, objectCache)
if err != nil {
logrus.Warnf("Error caching objects of Kind %s %v", firstOwner.Kind, err)
break
}
abstractObject, ok = objectCache[key]
if !ok {
logrus.Errorf("Cache missed %s again", key)
break
}
}
objMeta, err := meta.Accessor(&abstractObject)
if err != nil {
logrus.Warnf("Error retrieving parent metadata %s of API %s and Kind %s because of error: %v ", firstOwner.Name, firstOwner.APIVersion, firstOwner.Kind, err)
return workload, err
}
workload.ObjectMeta = objMeta
owners = abstractObject.GetOwnerReferences()
objMeta, err := meta.Accessor(&podResource)
if err != nil {
return workload, err
}
controllerObject, err := controller.GetTopController(ctx, *dynamicClient, *restMapper, objMeta)
if err != nil {
return workload, err
}
if lastKey != "" {
bytes, err := json.Marshal(objectCache[lastKey])
if err != nil {
return workload, err
}
workload.OriginalObjectJSON = bytes
} else {
bytes, err := json.Marshal(podResource)
if err != nil {
return workload, err
}
workload.OriginalObjectJSON = bytes
bytes, err := json.Marshal(controllerObject)
if err != nil {
return workload, err
}
workload.OriginalObjectJSON = bytes
return workload, nil
}
func cacheAllObjectsOfKind(apiVersion, kind string, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) error {
func cacheAllObjectsOfKind(ctx context.Context, apiVersion, kind string, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper, objectCache map[string]unstructured.Unstructured) error {
fqKind := schema.FromAPIVersionAndKind(apiVersion, kind)
mapping, err := (*restMapper).RESTMapping(fqKind.GroupKind(), fqKind.Version)
if err != nil {
@@ -158,7 +123,7 @@ func cacheAllObjectsOfKind(apiVersion, kind string, dynamicClient *dynamic.Inter
return err
}
objects, err := (*dynamicClient).Resource(mapping.Resource).Namespace("").List(kubeAPIMetaV1.ListOptions{})
objects, err := (*dynamicClient).Resource(mapping.Resource).Namespace("").List(ctx, kubeAPIMetaV1.ListOptions{})
if err != nil {
logrus.Warnf("Error retrieving parent object API %s and Kind %s because of error: %v ", mapping.Resource.Version, mapping.Resource.Resource, err)
return err
@@ -170,29 +135,16 @@ func cacheAllObjectsOfKind(apiVersion, kind string, dynamicClient *dynamic.Inter
return nil
}
func getObject(namespace, kind, version, name string, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper) (*unstructured.Unstructured, error) {
func getObject(ctx context.Context, namespace, kind, version, name string, dynamicClient *dynamic.Interface, restMapper *meta.RESTMapper) (*unstructured.Unstructured, error) {
fqKind := schema.ParseGroupKind(kind)
mapping, err := (*restMapper).RESTMapping(fqKind, version)
if err != nil {
return nil, err
}
object, err := (*dynamicClient).Resource(mapping.Resource).Namespace(namespace).Get(name, kubeAPIMetaV1.GetOptions{})
object, err := (*dynamicClient).Resource(mapping.Resource).Namespace(namespace).Get(ctx, name, kubeAPIMetaV1.GetOptions{})
return object, err
}
// 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{}))
}
}
if _, ok := yaml["containers"]; ok {
return yaml
}
return nil
}
// GetWorkloadFromBytes parses a GenericWorkload
func GetWorkloadFromBytes(contentBytes []byte) (*GenericWorkload, error) {
yamlNode := make(map[string]interface{})
@@ -205,11 +157,11 @@ func GetWorkloadFromBytes(contentBytes []byte) (*GenericWorkload, error) {
finalDoc["metadata"] = yamlNode["metadata"]
finalDoc["apiVersion"] = "v1"
finalDoc["kind"] = "Pod"
podSpec := GetPodSpec(yamlNode)
if podSpec == nil {
podSpecObject := podspec.GetPodSpec(yamlNode)
if podSpecObject == nil {
return nil, nil
}
finalDoc["spec"] = podSpec
finalDoc["spec"] = podSpecObject
marshaledYaml, err := yaml.Marshal(finalDoc)
if err != nil {
logrus.Errorf("Could not marshal yaml: %v", err)
+7 -5
View File
@@ -15,6 +15,8 @@
package validator
import (
"context"
"github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
@@ -22,8 +24,8 @@ import (
)
// ValidateContainer validates a single container from a given controller
func ValidateContainer(conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ContainerResult, error) {
results, err := applyContainerSchemaChecks(conf, controller, container, isInit)
func ValidateContainer(ctx context.Context, conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ContainerResult, error) {
results, err := applyContainerSchemaChecks(ctx, conf, controller, container, isInit)
if err != nil {
return ContainerResult{}, err
}
@@ -37,18 +39,18 @@ func ValidateContainer(conf *config.Configuration, controller kube.GenericWorklo
}
// ValidateAllContainers validates both init and regular containers
func ValidateAllContainers(conf *config.Configuration, controller kube.GenericWorkload) ([]ContainerResult, error) {
func ValidateAllContainers(ctx context.Context, conf *config.Configuration, controller kube.GenericWorkload) ([]ContainerResult, error) {
results := []ContainerResult{}
pod := controller.PodSpec
for _, container := range pod.InitContainers {
result, err := ValidateContainer(conf, controller, &container, true)
result, err := ValidateContainer(ctx, conf, controller, &container, true)
if err != nil {
return nil, err
}
results = append(results, result)
}
for _, container := range pod.Containers {
result, err := ValidateContainer(conf, controller, &container, false)
result, err := ValidateContainer(ctx, conf, controller, &container, false)
if err != nil {
return nil, err
}
+8 -7
View File
@@ -15,6 +15,7 @@
package validator
import (
"context"
"fmt"
"testing"
@@ -68,7 +69,7 @@ func testValidateWithWorkload(t *testing.T, container *corev1.Container, resourc
parsedConf, err := conf.Parse([]byte(*resourceConf))
assert.NoError(t, err, "Expected no error when parsing config")
results, err := applyContainerSchemaChecks(&parsedConf, workload, container, false)
results, err := applyContainerSchemaChecks(context.Background(), &parsedConf, workload, container, false)
if err != nil {
panic(err)
}
@@ -89,7 +90,7 @@ func TestValidateResourcesEmptyConfig(t *testing.T) {
Name: "Empty",
}
results, err := applyContainerSchemaChecks(&conf.Configuration{}, getEmptyWorkload(t, ""), container, false)
results, err := applyContainerSchemaChecks(context.Background(), &conf.Configuration{}, getEmptyWorkload(t, ""), container, false)
if err != nil {
panic(err)
}
@@ -186,7 +187,7 @@ func TestValidateHealthChecks(t *testing.T) {
for idx, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
controller := getEmptyWorkload(t, "")
results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.probes}, controller, tt.container, tt.isInit)
results, err := applyContainerSchemaChecks(context.Background(), &conf.Configuration{Checks: tt.probes}, controller, tt.container, tt.isInit)
if err != nil {
panic(err)
}
@@ -300,7 +301,7 @@ func TestValidateImage(t *testing.T) {
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
controller := getEmptyWorkload(t, "")
results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.image}, controller, tt.container, false)
results, err := applyContainerSchemaChecks(context.Background(), &conf.Configuration{Checks: tt.image}, controller, tt.container, false)
if err != nil {
panic(err)
}
@@ -417,7 +418,7 @@ func TestValidateNetworking(t *testing.T) {
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
controller := getEmptyWorkload(t, "")
results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.networkConf}, controller, tt.container, false)
results, err := applyContainerSchemaChecks(context.Background(), &conf.Configuration{Checks: tt.networkConf}, controller, tt.container, false)
if err != nil {
panic(err)
}
@@ -922,7 +923,7 @@ func TestValidateSecurity(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
workload, err := kube.NewGenericWorkloadFromPod(corev1.Pod{Spec: *tt.pod}, nil)
assert.NoError(t, err)
results, err := applyContainerSchemaChecks(&conf.Configuration{Checks: tt.securityConf}, workload, tt.container, false)
results, err := applyContainerSchemaChecks(context.Background(), &conf.Configuration{Checks: tt.securityConf}, workload, tt.container, false)
if err != nil {
panic(err)
}
@@ -1067,7 +1068,7 @@ func TestValidateRunAsRoot(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
workload, err := kube.NewGenericWorkloadFromPod(corev1.Pod{Spec: *tt.pod}, nil)
assert.NoError(t, err)
results, err := applyContainerSchemaChecks(&config, workload, tt.container, false)
results, err := applyContainerSchemaChecks(context.Background(), &config, workload, tt.container, false)
if err != nil {
panic(err)
}
+6 -5
View File
@@ -15,6 +15,7 @@
package validator
import (
"context"
"strings"
"github.com/sirupsen/logrus"
@@ -26,13 +27,13 @@ import (
const exemptionAnnotationKey = "polaris.fairwinds.com/exempt"
// ValidateController validates a single controller, returns a ControllerResult.
func ValidateController(conf *conf.Configuration, controller kube.GenericWorkload) (ControllerResult, error) {
podResult, err := ValidatePod(conf, controller)
func ValidateController(ctx context.Context, conf *conf.Configuration, controller kube.GenericWorkload) (ControllerResult, error) {
podResult, err := ValidatePod(ctx, conf, controller)
if err != nil {
return ControllerResult{}, err
}
controllerResult, err := applyControllerSchemaChecks(conf, controller)
controllerResult, err := applyControllerSchemaChecks(ctx, conf, controller)
if err != nil {
return ControllerResult{}, err
}
@@ -50,7 +51,7 @@ func ValidateController(conf *conf.Configuration, controller kube.GenericWorkloa
// ValidateControllers validates that each deployment conforms to the Polaris config,
// builds a list of ResourceResults organized by namespace.
func ValidateControllers(config *conf.Configuration, kubeResources *kube.ResourceProvider) ([]ControllerResult, error) {
func ValidateControllers(ctx context.Context, config *conf.Configuration, kubeResources *kube.ResourceProvider) ([]ControllerResult, error) {
controllersToAudit := kubeResources.Controllers
results := []ControllerResult{}
@@ -58,7 +59,7 @@ func ValidateControllers(config *conf.Configuration, kubeResources *kube.Resourc
if !config.DisallowExemptions && hasExemptionAnnotation(controller) {
continue
}
result, err := ValidateController(config, controller)
result, err := ValidateController(ctx, config, controller)
if err != nil {
logrus.Warn("An error occured validating controller:", err)
return nil, err
+14 -13
View File
@@ -15,6 +15,7 @@
package validator
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -38,7 +39,7 @@ func TestValidateController(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(2),
Warnings: uint(0),
Dangers: uint(0),
Dangers: uint(0),
}
expectedResults := ResultSet{
@@ -46,7 +47,7 @@ func TestValidateController(t *testing.T) {
"hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"},
}
actualResult, err := ValidateController(&c, deployment)
actualResult, err := ValidateController(context.Background(), &c, deployment)
if err != nil {
panic(err)
}
@@ -72,7 +73,7 @@ func TestControllerLevelChecks(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(0),
Warnings: uint(0),
Dangers: uint(1),
Dangers: uint(1),
}
expectedResults := ResultSet{
@@ -81,7 +82,7 @@ func TestControllerLevelChecks(t *testing.T) {
for _, controller := range resources.Controllers {
if controller.Kind == "Deployment" && controller.ObjectMeta.GetName() == "test-deployment" {
actualResult, err := ValidateController(&c, controller)
actualResult, err := ValidateController(context.Background(), &c, controller)
if err != nil {
panic(err)
}
@@ -110,13 +111,13 @@ func TestSkipHealthChecks(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(0),
Warnings: uint(1),
Dangers: uint(1),
Dangers: uint(1),
}
expectedResults := ResultSet{
"readinessProbeMissing": {ID: "readinessProbeMissing", Message: "Readiness probe should be configured", Success: false, Severity: "danger", Category: "Health Checks"},
"livenessProbeMissing": {ID: "livenessProbeMissing", Message: "Liveness probe should be configured", Success: false, Severity: "warning", Category: "Health Checks"},
}
actualResult, err := ValidateController(&c, deployment)
actualResult, err := ValidateController(context.Background(), &c, deployment)
if err != nil {
panic(err)
}
@@ -132,10 +133,10 @@ func TestSkipHealthChecks(t *testing.T) {
expectedSum = CountSummary{
Successes: uint(0),
Warnings: uint(0),
Dangers: uint(0),
Dangers: uint(0),
}
expectedResults = ResultSet{}
actualResult, err = ValidateController(&c, job)
actualResult, err = ValidateController(context.Background(), &c, job)
if err != nil {
panic(err)
}
@@ -150,10 +151,10 @@ func TestSkipHealthChecks(t *testing.T) {
expectedSum = CountSummary{
Successes: uint(0),
Warnings: uint(0),
Dangers: uint(0),
Dangers: uint(0),
}
expectedResults = ResultSet{}
actualResult, err = ValidateController(&c, cronjob)
actualResult, err = ValidateController(context.Background(), &c, cronjob)
if err != nil {
panic(err)
}
@@ -181,9 +182,9 @@ func TestControllerExemptions(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(0),
Warnings: uint(1),
Dangers: uint(1),
Dangers: uint(1),
}
actualResults, err := ValidateControllers(&c, resources)
actualResults, err := ValidateControllers(context.Background(), &c, resources)
if err != nil {
panic(err)
}
@@ -194,7 +195,7 @@ func TestControllerExemptions(t *testing.T) {
resources.Controllers[0].ObjectMeta.SetAnnotations(map[string]string{
exemptionAnnotationKey: "true",
})
actualResults, err = ValidateControllers(&c, resources)
actualResults, err = ValidateControllers(context.Background(), &c, resources)
if err != nil {
panic(err)
}
+3 -2
View File
@@ -2,6 +2,7 @@ package validator
import (
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
@@ -16,13 +17,13 @@ import (
)
// RunAudit runs a full Polaris audit and returns an AuditData object
func RunAudit(config conf.Configuration, kubeResources *kube.ResourceProvider) (AuditData, error) {
func RunAudit(ctx context.Context, config conf.Configuration, kubeResources *kube.ResourceProvider) (AuditData, error) {
displayName := config.DisplayName
if displayName == "" {
displayName = kubeResources.SourceName
}
results, err := ValidateControllers(&config, kubeResources)
results, err := ValidateControllers(ctx, &config, kubeResources)
if err != nil {
return AuditData{}, err
}
+7 -5
View File
@@ -1,6 +1,7 @@
package validator
import (
"context"
"testing"
conf "github.com/fairwindsops/polaris/pkg/config"
@@ -11,11 +12,11 @@ import (
func TestGetTemplateData(t *testing.T) {
k8s, dynamicClient := test.SetupTestAPI()
k8s = test.SetupAddControllers(k8s, "test")
k8s = test.SetupAddExtraControllerVersions(k8s, "test-extra")
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
k8s = test.SetupAddExtraControllerVersions(context.Background(), k8s, "test-extra")
// TODO figure out how to mock out dynamic client.
// and add in pods for all controllers to fill out tests.
resources, err := kube.CreateResourceProviderFromAPI(k8s, "test", &dynamicClient)
resources, err := kube.CreateResourceProviderFromAPI(context.Background(), k8s, "test", &dynamicClient)
assert.Equal(t, err, nil, "error should be nil")
c := conf.Configuration{
@@ -28,10 +29,11 @@ func TestGetTemplateData(t *testing.T) {
sum := CountSummary{
Successes: uint(0),
Warnings: uint(1),
Dangers: uint(1),
Dangers: uint(1),
}
actualAudit, err := RunAudit(c, resources)
actualAudit, err := RunAudit(context.Background(), c, resources)
assert.Equal(t, err, nil, "error should be nil")
assert.EqualValues(t, sum, actualAudit.GetSummary())
+5 -3
View File
@@ -15,13 +15,15 @@
package validator
import (
"context"
"github.com/fairwindsops/polaris/pkg/config"
"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 kube.GenericWorkload) (PodResult, error) {
podResults, err := applyPodSchemaChecks(conf, controller)
func ValidatePod(ctx context.Context, conf *config.Configuration, controller kube.GenericWorkload) (PodResult, error) {
podResults, err := applyPodSchemaChecks(ctx, conf, controller)
if err != nil {
return PodResult{}, err
}
@@ -30,7 +32,7 @@ func ValidatePod(conf *config.Configuration, controller kube.GenericWorkload) (P
ContainerResults: []ContainerResult{},
}
pRes.ContainerResults, err = ValidateAllContainers(conf, controller)
pRes.ContainerResults, err = ValidateAllContainers(ctx, conf, controller)
if err != nil {
return pRes, err
}
+16 -15
View File
@@ -15,6 +15,7 @@
package validator
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -36,14 +37,14 @@ func TestValidatePod(t *testing.T) {
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(k8s, "test")
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
deployment, err := kube.NewGenericWorkloadFromPod(p, nil)
assert.NoError(t, err)
expectedSum := CountSummary{
Successes: uint(4),
Warnings: uint(0),
Dangers: uint(0),
Dangers: uint(0),
}
expectedResults := ResultSet{
@@ -52,7 +53,7 @@ func TestValidatePod(t *testing.T) {
"hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"},
}
actualPodResult, err := ValidatePod(&c, deployment)
actualPodResult, err := ValidatePod(context.Background(), &c, deployment)
if err != nil {
panic(err)
}
@@ -73,7 +74,7 @@ func TestInvalidIPCPod(t *testing.T) {
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(k8s, "test")
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostIPC = true
workload, err := kube.NewGenericWorkloadFromPod(p, nil)
@@ -81,7 +82,7 @@ func TestInvalidIPCPod(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(3),
Warnings: uint(0),
Dangers: uint(1),
Dangers: uint(1),
}
expectedResults := ResultSet{
"hostIPCSet": {ID: "hostIPCSet", Message: "Host IPC should not be configured", Success: false, Severity: "danger", Category: "Security"},
@@ -89,7 +90,7 @@ func TestInvalidIPCPod(t *testing.T) {
"hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"},
}
actualPodResult, err := ValidatePod(&c, workload)
actualPodResult, err := ValidatePod(context.Background(), &c, workload)
if err != nil {
panic(err)
}
@@ -110,7 +111,7 @@ func TestInvalidNeworkPod(t *testing.T) {
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(k8s, "test")
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostNetwork = true
workload, err := kube.NewGenericWorkloadFromPod(p, nil)
@@ -118,7 +119,7 @@ func TestInvalidNeworkPod(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(3),
Warnings: uint(1),
Dangers: uint(0),
Dangers: uint(0),
}
expectedResults := ResultSet{
@@ -127,7 +128,7 @@ func TestInvalidNeworkPod(t *testing.T) {
"hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"},
}
actualPodResult, err := ValidatePod(&c, workload)
actualPodResult, err := ValidatePod(context.Background(), &c, workload)
if err != nil {
panic(err)
}
@@ -148,7 +149,7 @@ func TestInvalidPIDPod(t *testing.T) {
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(k8s, "test")
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostPID = true
workload, err := kube.NewGenericWorkloadFromPod(p, nil)
@@ -156,7 +157,7 @@ func TestInvalidPIDPod(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(3),
Warnings: uint(0),
Dangers: uint(1),
Dangers: uint(1),
}
expectedResults := ResultSet{
@@ -165,7 +166,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, workload)
actualPodResult, err := ValidatePod(context.Background(), &c, workload)
if err != nil {
panic(err)
}
@@ -192,7 +193,7 @@ func TestExemption(t *testing.T) {
}
k8s, _ := test.SetupTestAPI()
k8s = test.SetupAddControllers(k8s, "test")
k8s = test.SetupAddControllers(context.Background(), k8s, "test")
p := test.MockPod()
p.Spec.HostIPC = true
p.ObjectMeta = metav1.ObjectMeta{
@@ -203,14 +204,14 @@ func TestExemption(t *testing.T) {
expectedSum := CountSummary{
Successes: uint(3),
Warnings: uint(0),
Dangers: uint(0),
Dangers: uint(0),
}
expectedResults := ResultSet{
"hostNetworkSet": {ID: "hostNetworkSet", Message: "Host network is not configured", Success: true, Severity: "warning", Category: "Networking"},
"hostPIDSet": {ID: "hostPIDSet", Message: "Host PID is not configured", Success: true, Severity: "danger", Category: "Security"},
}
actualPodResult, err := ValidatePod(&c, workload)
actualPodResult, err := ValidatePod(context.Background(), &c, workload)
if err != nil {
panic(err)
}
+4 -3
View File
@@ -2,6 +2,7 @@ package validator
import (
"bytes"
"context"
"fmt"
"io"
"sort"
@@ -113,7 +114,7 @@ func getExemptKey(checkID string) string {
return fmt.Sprintf("polaris.fairwinds.com/%s-exempt", checkID)
}
func applyPodSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
func applyPodSchemaChecks(ctx context.Context, conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.ObjectMeta.GetAnnotations()
@@ -138,7 +139,7 @@ func applyPodSchemaChecks(conf *config.Configuration, controller kube.GenericWor
return results, nil
}
func applyControllerSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
func applyControllerSchemaChecks(ctx context.Context, conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.ObjectMeta.GetAnnotations()
@@ -163,7 +164,7 @@ func applyControllerSchemaChecks(conf *config.Configuration, controller kube.Gen
return results, nil
}
func applyContainerSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ResultSet, error) {
func applyContainerSchemaChecks(ctx context.Context, conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.ObjectMeta.GetAnnotations()
+3 -2
View File
@@ -1,6 +1,7 @@
package validator
import (
"context"
"testing"
conf "github.com/fairwindsops/polaris/pkg/config"
@@ -143,14 +144,14 @@ func TestValidateResourcesInit(t *testing.T) {
parsedConf, err := conf.Parse([]byte(resourceConfRanges))
assert.NoError(t, err, "Expected no error when parsing config")
results, err := applyContainerSchemaChecks(&parsedConf, controller, emptyContainer, false)
results, err := applyContainerSchemaChecks(context.Background(), &parsedConf, controller, emptyContainer, false)
if err != nil {
panic(err)
}
assert.Equal(t, uint(1), results.GetSummary().Dangers)
assert.Equal(t, uint(1), results.GetSummary().Warnings)
results, err = applyContainerSchemaChecks(&parsedConf, controller, emptyContainer, true)
results, err = applyContainerSchemaChecks(context.Background(), &parsedConf, controller, emptyContainer, true)
if err != nil {
panic(err)
}
+42 -56
View File
@@ -25,37 +25,25 @@ import (
"github.com/fairwindsops/polaris/pkg/kube"
validator "github.com/fairwindsops/polaris/pkg/validator"
"github.com/fairwindsops/controller-utils/pkg/podspec"
"github.com/sirupsen/logrus"
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/builder"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission/types"
)
// Validator validates k8s resources.
type Validator struct {
client client.Client
decoder types.Decoder
Client client.Client
decoder *admission.Decoder
Config config.Configuration
}
var _ inject.Client = &Validator{}
// InjectClient injects the client.
func (v *Validator) InjectClient(c client.Client) error {
v.client = c
return nil
}
var _ inject.Decoder = &Validator{}
// InjectDecoder injects the decoder.
func (v *Validator) InjectDecoder(d types.Decoder) error {
func (v *Validator) InjectDecoder(d *admission.Decoder) error {
logrus.Info("Injecting decoder")
v.decoder = d
return nil
}
@@ -63,28 +51,42 @@ 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, error) {
name = fmt.Sprintf("%s.k8s.io", name)
path := fmt.Sprintf("/validating-%s", name)
func NewWebhook(mgr manager.Manager, validator Validator) {
path := "/validate"
webhook, err := builder.NewWebhookBuilder().
Name(name).
Validating().
Path(path).
Operations(admissionregistrationv1beta1.Create, admissionregistrationv1beta1.Update).
WithManager(mgr).
ForType(apiType).
Handlers(&validator).
Build()
if err != nil {
return nil, err
}
return webhook, nil
mgr.GetWebhookServer().Register(path, &webhook.Admission{Handler: &validator})
}
func (v *Validator) handleInternal(ctx context.Context, req types.Request) (*validator.PodResult, error) {
// GetObjectFromRawRequest returns the pod object and the controller's object from the raw json bytes.
func GetObjectFromRawRequest(raw []byte) (corev1.Pod, interface{}, error) {
pod := corev1.Pod{}
var originalObject interface{}
decoded := map[string]interface{}{}
err := json.Unmarshal(raw, &decoded)
if err != nil {
return pod, originalObject, err
}
podMap := podspec.GetPodSpec(decoded)
if podMap == nil {
return pod, originalObject, errors.New("Object does not contain pods")
}
encoded, err := json.Marshal(podMap)
if err != nil {
return pod, originalObject, err
}
err = json.Unmarshal(encoded, &pod.Spec)
if err != nil {
return pod, originalObject, err
}
originalObject = decoded
return pod, originalObject, err
}
func (v *Validator) handleInternal(ctx context.Context, req admission.Request) (*validator.PodResult, error) {
pod := corev1.Pod{}
var originalObject interface{}
var err error
if req.AdmissionRequest.Kind.Kind == "Pod" {
err := v.decoder.Decode(req, &pod)
if err != nil {
@@ -96,31 +98,14 @@ func (v *Validator) handleInternal(ctx context.Context, req types.Request) (*val
}
originalObject = pod
} else {
decoded := map[string]interface{}{}
err := json.Unmarshal(req.AdmissionRequest.Object.Raw, &decoded)
if err != nil {
return nil, err
}
podMap := kube.GetPodSpec(decoded)
if podMap == nil {
return nil, errors.New("Object does not contain pods")
}
encoded, err := json.Marshal(podMap)
if err != nil {
return nil, err
}
err = json.Unmarshal(encoded, &pod.Spec)
if err != nil {
return nil, err
}
originalObject = decoded
pod, originalObject, err = GetObjectFromRawRequest(req.Object.Raw)
}
controller, err := kube.NewGenericWorkloadFromPod(pod, originalObject)
if err != nil {
return nil, err
}
controller.Kind = req.AdmissionRequest.Kind.Kind
controllerResult, err := validator.ValidateController(&v.Config, controller)
controllerResult, err := validator.ValidateController(ctx, &v.Config, controller)
if err != nil {
return nil, err
}
@@ -128,11 +113,12 @@ func (v *Validator) handleInternal(ctx context.Context, req types.Request) (*val
}
// Handle for Validator to run validation checks.
func (v *Validator) Handle(ctx context.Context, req types.Request) types.Response {
func (v *Validator) Handle(ctx context.Context, req admission.Request) admission.Response {
logrus.Info("Starting request")
podResult, err := v.handleInternal(ctx, req)
if err != nil {
logrus.Errorf("Error validating request: %v", err)
return admission.ErrorResponse(http.StatusBadRequest, err)
return admission.Errored(http.StatusBadRequest, err)
}
allowed := true
reason := ""
+1 -1
View File
@@ -1,6 +1,6 @@
# /bin/bash
set -eo pipefail
set -e
helm template polaris $CHARTS_DIR/stable/polaris/ \
--namespace polaris \
+2 -1
View File
@@ -1,6 +1,7 @@
package test
import (
"context"
"io/ioutil"
"path/filepath"
"runtime"
@@ -56,7 +57,7 @@ func TestChecks(t *testing.T) {
assert.NoError(t, err)
c, err := config.Parse([]byte("checks:\n " + tc.check + ": danger"))
assert.NoError(t, err)
result, err := validator.ValidateController(&c, *workload)
result, err := validator.ValidateController(context.Background(), &c, *workload)
assert.NoError(t, err)
summary := result.GetSummary()
if tc.failure {
+17 -14
View File
@@ -1,12 +1,15 @@
package test
import (
"context"
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"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
dynamicFake "k8s.io/client-go/dynamic/fake"
@@ -116,39 +119,39 @@ func SetupTestAPI() (kubernetes.Interface, dynamic.Interface) {
}
// SetupAddControllers creates mock controllers and adds them to the test clientset.
func SetupAddControllers(k kubernetes.Interface, namespace string) kubernetes.Interface {
func SetupAddControllers(ctx context.Context, k kubernetes.Interface, namespace string) kubernetes.Interface {
d1 := MockDeploy()
if _, err := k.AppsV1().Deployments(namespace).Create(&d1); err != nil {
if _, err := k.AppsV1().Deployments(namespace).Create(ctx, &d1, metav1.CreateOptions{}); err != nil {
panic(err)
}
s1 := MockStatefulSet()
if _, err := k.AppsV1().StatefulSets(namespace).Create(&s1); err != nil {
if _, err := k.AppsV1().StatefulSets(namespace).Create(ctx, &s1, metav1.CreateOptions{}); err != nil {
panic(err)
}
ds1 := MockDaemonSet()
if _, err := k.AppsV1().DaemonSets(namespace).Create(&ds1); err != nil {
if _, err := k.AppsV1().DaemonSets(namespace).Create(ctx, &ds1, metav1.CreateOptions{}); err != nil {
panic(err)
}
j1 := MockJob()
if _, err := k.BatchV1().Jobs(namespace).Create(&j1); err != nil {
if _, err := k.BatchV1().Jobs(namespace).Create(ctx, &j1, metav1.CreateOptions{}); err != nil {
panic(err)
}
cj1 := MockCronJob()
if _, err := k.BatchV1beta1().CronJobs(namespace).Create(&cj1); err != nil {
if _, err := k.BatchV1beta1().CronJobs(namespace).Create(ctx, &cj1, metav1.CreateOptions{}); err != nil {
panic(err)
}
rc1 := MockReplicationController()
if _, err := k.CoreV1().ReplicationControllers(namespace).Create(&rc1); err != nil {
if _, err := k.CoreV1().ReplicationControllers(namespace).Create(ctx, &rc1, metav1.CreateOptions{}); err != nil {
panic(err)
}
p1 := MockNakedPod()
if _, err := k.CoreV1().Pods(namespace).Create(&p1); err != nil {
if _, err := k.CoreV1().Pods(namespace).Create(ctx, &p1, metav1.CreateOptions{}); err != nil {
panic(err)
}
@@ -156,7 +159,7 @@ func SetupAddControllers(k kubernetes.Interface, namespace string) kubernetes.In
}
// SetupAddExtraControllerVersions creates mock controllers and adds them to the test clientset.
func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) kubernetes.Interface {
func SetupAddExtraControllerVersions(ctx context.Context, k kubernetes.Interface, namespace string) kubernetes.Interface {
p := MockPod()
dv1b1 := appsv1beta1.Deployment{
@@ -164,7 +167,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta1().Deployments(namespace).Create(&dv1b1); err != nil {
if _, err := k.AppsV1beta1().Deployments(namespace).Create(ctx, &dv1b1, metav1.CreateOptions{}); err != nil {
panic(err)
}
@@ -173,7 +176,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta2().Deployments(namespace).Create(&dv1b2); err != nil {
if _, err := k.AppsV1beta2().Deployments(namespace).Create(ctx, &dv1b2, metav1.CreateOptions{}); err != nil {
panic(err)
}
@@ -182,7 +185,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta1().StatefulSets(namespace).Create(&ssv1b1); err != nil {
if _, err := k.AppsV1beta1().StatefulSets(namespace).Create(ctx, &ssv1b1, metav1.CreateOptions{}); err != nil {
panic(err)
}
@@ -191,7 +194,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta2().StatefulSets(namespace).Create(&ssv1b2); err != nil {
if _, err := k.AppsV1beta2().StatefulSets(namespace).Create(ctx, &ssv1b2, metav1.CreateOptions{}); err != nil {
panic(err)
}
@@ -200,7 +203,7 @@ func SetupAddExtraControllerVersions(k kubernetes.Interface, namespace string) k
Template: corev1.PodTemplateSpec{Spec: p.Spec},
},
}
if _, err := k.AppsV1beta2().DaemonSets(namespace).Create(&dsv1b2); err != nil {
if _, err := k.AppsV1beta2().DaemonSets(namespace).Create(ctx, &dsv1b2, metav1.CreateOptions{}); err != nil {
panic(err)
}
return k
+12 -6
View File
@@ -2,9 +2,7 @@
set -e
#sed is replacing the polaris version with this commit sha so we are testing exactly this verison.
sed -ri "s|'(quay.io/fairwinds/polaris:).+'|'\1${CIRCLE_SHA1}'|" ./deploy/webhook.yaml
# TODO: remove this after 1.0 is released
sed -i "s/--webhook/webhook/" ./deploy/webhook.yaml
sed -r "s|'(quay.io/fairwinds/polaris:).+'|'\1${CIRCLE_SHA1}'|" ./deploy/webhook.yaml > ./deploy/webhook-test.yaml
# Testing to ensure that the webhook starts up, allows a correct deployment to pass,
# and prevents a incorrectly formatted deployment.
@@ -12,8 +10,13 @@ function check_webhook_is_ready() {
# Get the epoch time in one minute from now
local timeout_epoch
# Reset another 2 minutes to wait for webhook
timeout_epoch=$(date -d "+2 minutes" +%s)
# Reset another 4 minutes to wait for webhook
timeout_epoch=$(date -d "+4 minutes" +%s)
while ! kubectl get csr | grep -E "polaris-webhook.polaris"; do
check_timeout "${timeout_epoch}"
echo -n "."
done
# loop until this fails (desired condition is we cannot apply this yaml doc, which means the webhook is working
echo "Waiting for webhook to be ready"
@@ -22,6 +25,8 @@ function check_webhook_is_ready() {
echo -n "."
done
check_timeout "${timeout_epoch}"
echo "Webhook started!"
}
@@ -52,6 +57,7 @@ function clean_up() {
function grab_logs() {
kubectl -n polaris get pods -oyaml -l app=polaris
kubectl -n polaris describe pods -l app=polaris
kubectl -n polaris logs -l app=polaris -c webhook-certificate-generator
kubectl -n polaris logs -l app=polaris
}
@@ -60,7 +66,7 @@ kubectl create ns scale-test
kubectl apply -n scale-test -f ./test/webhook_cases/failing_test.deployment.yaml
# Install the webhook
kubectl apply -f ./deploy/webhook.yaml &> /dev/null
kubectl apply -f ./deploy/webhook-test.yaml &> /dev/null
# wait for the webhook to come online