Skip to content

Commit

Permalink
Set full object ObjectMeta on new workload from Pod (#471)
Browse files Browse the repository at this point in the history
* Unmarshal OriginalObjectJSON into ObjectMeta

* Unmarshal to unst before converting too v1 Object

* Add passing annotated deployment webhook test case

* fix meta accessor

* fix tests

* remove logs

* fix tests

Co-authored-by: Robert Brennan <contact@rbren.io>
  • Loading branch information
jordandoig and rbren committed Feb 26, 2021
1 parent 714b7bf commit 4c3d0e0
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 30 deletions.
39 changes: 38 additions & 1 deletion go.sum

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions pkg/kube/workload.go
Expand Up @@ -76,6 +76,19 @@ func NewGenericWorkloadFromPod(podResource kubeAPICoreV1.Pod, originalObject int
return workload, err
}
workload.OriginalObjectJSON = bytes

var unst unstructured.Unstructured
err = json.Unmarshal(bytes, &unst.Object)
if err != nil {
logrus.Error("Couldn't marshal JSON for pod ", err)
return workload, err
}
objMeta, err := meta.Accessor(&unst)
if err != nil {
logrus.Error("Couldn't create meta accessor for unstructred ", err)
return workload, err
}
workload.ObjectMeta = objMeta
}
return workload, nil
}
Expand Down
13 changes: 0 additions & 13 deletions pkg/validator/controller.go
Expand Up @@ -15,16 +15,12 @@
package validator

import (
"strings"

"github.com/sirupsen/logrus"

conf "github.com/fairwindsops/polaris/pkg/config"
"github.com/fairwindsops/polaris/pkg/kube"
)

const exemptionAnnotationKey = "polaris.fairwinds.com/exempt"

// ValidateController validates a single controller, returns a Result.
func ValidateController(conf *conf.Configuration, controller kube.GenericWorkload) (Result, error) {
podResult, err := ValidatePod(conf, controller)
Expand Down Expand Up @@ -56,9 +52,6 @@ func ValidateControllers(config *conf.Configuration, kubeResources *kube.Resourc

results := []Result{}
for _, controller := range controllersToAudit {
if !config.DisallowExemptions && hasExemptionAnnotation(controller) {
continue
}
result, err := ValidateController(config, controller)
if err != nil {
logrus.Warn("An error occurred validating controller:", err)
Expand All @@ -69,9 +62,3 @@ func ValidateControllers(config *conf.Configuration, kubeResources *kube.Resourc

return results, nil
}

func hasExemptionAnnotation(ctrl kube.GenericWorkload) bool {
annot := ctrl.ObjectMeta.GetAnnotations()
val := annot[exemptionAnnotationKey]
return strings.ToLower(val) == "true"
}
18 changes: 17 additions & 1 deletion pkg/validator/controller_test.go
Expand Up @@ -222,5 +222,21 @@ func TestControllerExemptions(t *testing.T) {
if err != nil {
panic(err)
}
assert.Equal(t, 0, len(actualResults))
expectedExemptSum := CountSummary{
Successes: uint(0),
Warnings: uint(0),
Dangers: uint(0),
}
assert.Equal(t, 1, len(actualResults))
assert.Equal(t, "Deployment", actualResults[0].Kind)
assert.EqualValues(t, expectedExemptSum, actualResults[0].GetSummary())

c.DisallowExemptions = true
actualResults, err = ValidateControllers(&c, resources)
if err != nil {
panic(err)
}
assert.Equal(t, 1, len(actualResults))
assert.Equal(t, "Deployment", actualResults[0].Kind)
assert.EqualValues(t, expectedSum, actualResults[0].GetSummary())
}
30 changes: 19 additions & 11 deletions pkg/validator/schema.go
Expand Up @@ -116,17 +116,28 @@ func makeResult(conf *config.Configuration, check *config.SchemaCheck, passes bo
return result
}

func getExemptKey(checkID string) string {
return fmt.Sprintf("polaris.fairwinds.com/%s-exempt", checkID)
const exemptionAnnotationKey = "polaris.fairwinds.com/exempt"
const exemptionAnnotationPattern = "polaris.fairwinds.com/%s-exempt"

func hasExemptionAnnotation(ctrl kube.GenericWorkload, checkID string) bool {
annot := ctrl.ObjectMeta.GetAnnotations()
val := annot[exemptionAnnotationKey]
if strings.ToLower(val) == "true" {
return true
}
checkKey := fmt.Sprintf(exemptionAnnotationPattern, checkID)
val = annot[checkKey]
if strings.ToLower(val) == "true" {
return true
}
return false
}

func applyPodSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.ObjectMeta.GetAnnotations()
for _, checkID := range checkIDs {
exemptValue := objectAnnotations[getExemptKey(checkID)]
if strings.ToLower(exemptValue) == "true" {
if !conf.DisallowExemptions && hasExemptionAnnotation(controller, checkID) {
continue
}
check, err := resolveCheck(conf, checkID, controller.Kind, config.TargetPod, controller.ObjectMeta, "", false)
Expand All @@ -148,10 +159,8 @@ func applyPodSchemaChecks(conf *config.Configuration, controller kube.GenericWor
func applyControllerSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.ObjectMeta.GetAnnotations()
for _, checkID := range checkIDs {
exemptValue := objectAnnotations[getExemptKey(checkID)]
if strings.ToLower(exemptValue) == "true" {
if !conf.DisallowExemptions && hasExemptionAnnotation(controller, checkID) {
continue
}
check, err := resolveCheck(conf, checkID, controller.Kind, config.TargetController, controller.ObjectMeta, "", false)
Expand All @@ -173,13 +182,12 @@ func applyControllerSchemaChecks(conf *config.Configuration, controller kube.Gen
func applyContainerSchemaChecks(conf *config.Configuration, controller kube.GenericWorkload, container *corev1.Container, isInit bool) (ResultSet, error) {
results := ResultSet{}
checkIDs := getSortedKeys(conf.Checks)
objectAnnotations := controller.ObjectMeta.GetAnnotations()
for _, checkID := range checkIDs {
exemptValue := objectAnnotations[getExemptKey(checkID)]
if strings.ToLower(exemptValue) == "true" {
if !conf.DisallowExemptions && hasExemptionAnnotation(controller, checkID) {
continue
}
check, err := resolveCheck(conf, checkID, controller.Kind, config.TargetContainer, controller.ObjectMeta, container.Name, isInit)

if err != nil {
return nil, err
} else if check == nil {
Expand Down
31 changes: 31 additions & 0 deletions test/webhook_cases/passing_test.deployment.annotations.yaml
@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
annotations:
polaris.fairwinds.com/exempt: "true"
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
securityContext:
allowPrivilegeEscalation: true
privileged: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
16 changes: 12 additions & 4 deletions test/webhook_test.sh
Expand Up @@ -3,6 +3,10 @@ set -e

# Testing to ensure that the webhook starts up, allows a correct deployment to pass,
# and prevents a incorrectly formatted deployment.
BLUE='\033[0;34m'
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color

function get_timeout() {
if [[ "$OSTYPE" == "darwin"* ]]; then
Expand Down Expand Up @@ -98,22 +102,26 @@ ALL_TESTS_PASSED=1
# Run tests against correctly configured objects
for filename in test/webhook_cases/passing_test.*.yaml; do
echo -e "\n\n"
echo $filename
echo -e "${BLUE}TEST CASE: $filename${NC}"
if ! kubectl apply -n tests -f $filename; then
ALL_TESTS_PASSED=0
echo -e "****Test Failed: Polaris prevented a deployment with no configuration issues****"
echo -e "${RED}****Test Failed: Polaris prevented a resource with no configuration issues****${NC}"
else
echo -e "${GREEN}****Test Passed: Polaris correctly allowed this resource****${NC}"
fi
kubectl delete -n tests -f $filename || true
done

# Run tests against incorrectly configured objects
for filename in test/webhook_cases/failing_test.*.yaml; do
echo -e "\n\n"
echo $filename
echo -e "${BLUE}TEST CASE: $filename${NC}"
if kubectl apply -n tests -f $filename; then
ALL_TESTS_PASSED=0
echo -e "****Test Failed: Polaris should have prevented this deployment due to configuration issues.****"
echo -e "${RED}****Test Failed: Polaris should have prevented this resource due to configuration issues.****${NC}"
kubectl logs -n polaris $(kubectl get po -oname -n polaris | grep webhook)
else
echo -e "${GREEN}****Test Passed: Polaris correctly prevented this resource****${NC}"
fi
kubectl delete -n tests -f $filename || true
done
Expand Down

0 comments on commit 4c3d0e0

Please sign in to comment.