فهرست منبع

Merge branch 'nafees/hotfixes' into dev

Mohammed Nafees 3 سال پیش
والد
کامیت
7bbd552441

+ 21 - 0
api/server/handlers/infra/forms.go

@@ -639,6 +639,27 @@ tabs:
       label: Add an additional prometheus node group to ensure monitoring stability.
       settings:
         default: false
+  - name: prometheus_machine_settings
+    show_if: additional_prometheus_node_group
+    contents:
+    - type: select
+      label: ⚙️ AWS Prometheus Machine Type
+      variable: additional_prometheus_machine_type
+      settings:
+        default: t2.medium
+        options:
+        - label: t2.medium
+          value: t2.medium
+        - label: t2.large
+          value: t2.large
+        - label: t2.xlarge
+          value: t2.xlarge
+        - label: t3.medium
+          value: t3.medium
+        - label: t3.large
+          value: t3.large
+        - label: t3.xlarge
+          value: t3.xlarge
 `
 
 const gcrForm = `name: GCR

+ 5 - 5
api/types/namespace.go

@@ -135,8 +135,8 @@ type GetEnvGroupRequest struct {
 
 type CloneEnvGroupRequest struct {
 	Namespace string `json:"namespace" form:"required"`
-	Name      string `json:"name" form:"required"`
-	CloneName string `json:"clone_name"`
+	Name      string `json:"name" form:"required,dns1123"`
+	CloneName string `json:"clone_name,dns1123"`
 	Version   uint   `json:"version"`
 }
 
@@ -149,7 +149,7 @@ type DeleteEnvGroupRequest struct {
 }
 
 type AddEnvGroupApplicationRequest struct {
-	Name            string `json:"name" form:"required"`
+	Name            string `json:"name" form:"required,dns1123"`
 	ApplicationName string `json:"app_name" form:"required"`
 }
 
@@ -161,7 +161,7 @@ type ListEnvGroupsResponse []*EnvGroupMeta
 type CreateEnvGroupRequest struct {
 	// the name of the env group to create or update
 	// example: prod-env-group
-	Name string `json:"name" form:"required"`
+	Name string `json:"name" form:"required,dns1123"`
 
 	// the variables to include in the env group
 	Variables map[string]string `json:"variables" form:"required"`
@@ -231,7 +231,7 @@ type GetEnvGroupResponse struct {
 //
 // swagger:model
 type V1EnvGroupReleaseRequest struct {
-	ReleaseName string `json:"release_name" form:"required"`
+	ReleaseName string `json:"release_name" form:"required,dns1123"`
 }
 
 // V1EnvGroupResponse defines an env group

+ 1 - 1
api/types/release.go

@@ -68,7 +68,7 @@ type CreateReleaseBaseRequest struct {
 
 	// The name of this release
 	// required: true
-	Name string `json:"name" form:"required"`
+	Name string `json:"name" form:"required,dns1123"`
 }
 
 // swagger:model

+ 4 - 4
api/types/stacks.go

@@ -56,7 +56,7 @@ type CreateStackAppResourceRequest struct {
 
 	// The name of the resource.
 	// required: true
-	Name string `json:"name" form:"required"`
+	Name string `json:"name" form:"required,dns1123"`
 
 	// The name of the source config (must exist inside `source_configs`).
 	// required: true
@@ -235,15 +235,15 @@ type StackSourceConfig struct {
 type CreateStackEnvGroupRequest struct {
 	// The name of the env group
 	// required: true
-	Name string `json:"name" form:"required"`
+	Name string `json:"name" form:"required,dns1123"`
 
 	// The non-secret variables to set in the env group
 	// required: true
-	Variables map[string]string `json:"variables,required" form:"required"`
+	Variables map[string]string `json:"variables" form:"required"`
 
 	// The secret variables to set in the env group
 	// required: true
-	SecretVariables map[string]string `json:"secret_variables,required" form:"required"`
+	SecretVariables map[string]string `json:"secret_variables" form:"required"`
 
 	// The list of applications that this env group should be synced to. These applications **must** be present
 	// in the stack - if an env group is created from a stack, syncing to applications which are not in the stack

+ 31 - 2
internal/opa/config.yaml

@@ -56,7 +56,7 @@ prometheus:
     name: "prometheus.version"
 nginx_pod:
   kind: "pod"
-  override_severity: "critical"
+  overrideSeverity: "critical"
   match:
     namespace: ingress-nginx
     labels:
@@ -119,4 +119,33 @@ certificates:
   - path: "./policies/certificates/expiry_two_weeks.rego"
     name: "certificates.expiry_two_weeks"
   - path: "./policies/certificates/expired.rego"
-    name: "certificates.expired"
+    name: "certificates.expired"
+node:
+  kind: "crd_list"
+  match:
+    group: core
+    version: v1
+    resource: nodes
+  policies:
+  - path: "./policies/node/k8s_version.rego"
+    name: "node.k8s_version"
+  - path: "./policies/node/porter_run_taints.rego"
+    name: "node.porter_run_taints"
+  - path: "./policies/node/porter_run_labels.rego"
+    name: "node.porter_run_labels"
+  - path: "./policies/node/healthy.rego"
+    name: "node.healthy"
+descheduler:
+  kind: "helm_release"
+  match:
+    name: descheduler
+    namespace: kube-system
+  mustExist: true
+  policies: []
+vpa:
+  kind: "helm_release"
+  match:
+    name: vpa
+    namespace: kube-system
+  mustExist: true
+  policies: []

+ 10 - 9
internal/opa/loader.go

@@ -13,11 +13,11 @@ import (
 type ConfigFile map[string]ConfigFilePolicyCollection
 
 type ConfigFilePolicyCollection struct {
-	Kind             string             `yaml:"kind"`
-	Match            MatchParameters    `yaml:"match"`
-	MustExist        bool               `yaml:"mustExist"`
-	OverrideSeverity string             `yaml:"override_severity"`
-	Policies         []ConfigFilePolicy `yaml:"policies"`
+	Kind             string             `json:"kind"`
+	Match            MatchParameters    `json:"match"`
+	MustExist        bool               `json:"mustExist"`
+	OverrideSeverity string             `json:"overrideSeverity"`
+	Policies         []ConfigFilePolicy `json:"policies"`
 }
 
 type ConfigFilePolicy struct {
@@ -68,10 +68,11 @@ func LoadPolicies(configFilePathDir string) (*KubernetesPolicies, error) {
 		}
 
 		policies[name] = KubernetesOPAQueryCollection{
-			Kind:      KubernetesBuiltInKind(cfPolicyCollection.Kind),
-			Queries:   queries,
-			Match:     cfPolicyCollection.Match,
-			MustExist: cfPolicyCollection.MustExist,
+			Kind:             KubernetesBuiltInKind(cfPolicyCollection.Kind),
+			Queries:          queries,
+			Match:            cfPolicyCollection.Match,
+			OverrideSeverity: cfPolicyCollection.OverrideSeverity,
+			MustExist:        cfPolicyCollection.MustExist,
 		}
 	}
 

+ 9 - 2
internal/opa/opa.go

@@ -211,8 +211,10 @@ func (runner *KubernetesOPARunner) runHelmReleaseQueries(name string, collection
 			results, err := query.Eval(
 				context.Background(),
 				rego.EvalInput(map[string]interface{}{
-					"version": helmRelease.Chart.Metadata.Version,
-					"values":  helmRelease.Config,
+					"version":   helmRelease.Chart.Metadata.Version,
+					"values":    helmRelease.Config,
+					"name":      helmRelease.Name,
+					"namespace": helmRelease.Namespace,
 				}),
 			)
 
@@ -315,6 +317,11 @@ func (runner *KubernetesOPARunner) runCRDListQueries(name string, collection Kub
 		Resource: collection.Match.Resource,
 	}
 
+	// just case on the "core" group and unset it
+	if collection.Match.Group == "core" {
+		objRes.Group = ""
+	}
+
 	crdList, err := runner.dynamicClient.Resource(objRes).Namespace(collection.Match.Namespace).List(context.Background(), v1.ListOptions{})
 
 	if err != nil {

+ 25 - 0
internal/opa/policies/node/healthy.rego

@@ -0,0 +1,25 @@
+package node.healthy
+
+import future.keywords
+
+POLICY_ID := sprintf("healthy_%s", [input.metadata.name])
+
+POLICY_VERSION := "v0.0.1"
+
+POLICY_SEVERITY := "critical"
+
+POLICY_TITLE := sprintf("The node %s should be healthy", [input.metadata.name])
+
+POLICY_SUCCESS_MESSAGE := sprintf("Success: this node is healthy", [])
+
+# check if one of the node's conditions states that the kubelet is ready
+allow if {
+	some condition in input.status.conditions
+	condition.reason == "KubeletReady"
+	condition.status = "True"
+}
+
+FAILURE_MESSAGE contains msg if {
+	not allow
+	msg := sprintf("Failed: the node %s is not healthy", [input.metadata.name])
+}

+ 25 - 0
internal/opa/policies/node/k8s_version.rego

@@ -0,0 +1,25 @@
+package node.k8s_version
+
+import future.keywords
+
+POLICY_ID := sprintf("k8s_version_%s", [input.metadata.name])
+
+POLICY_VERSION := "v0.0.1"
+
+POLICY_SEVERITY := "high"
+
+latest_stable_version := "1.21.0"
+
+POLICY_TITLE := sprintf("The Kubernetes version for node %s should be at least v%s", [input.metadata.name, latest_stable_version])
+
+POLICY_SUCCESS_MESSAGE := sprintf("Success: Kubernetes version is up-to-date", [])
+
+trimmedVersion := trim_left(input.status.nodeInfo.kubeletVersion, "v")
+
+# semver.compare returns -1 if latest_stable_version < trimmedVersion
+allow if semver.compare(latest_stable_version, trimmedVersion) <= 0
+
+FAILURE_MESSAGE contains msg if {
+	not allow
+	msg := sprintf("Failed: latest stable version is %s, but node %s is on %s", [latest_stable_version, input.metadata.name, trimmedVersion])
+}

+ 23 - 0
internal/opa/policies/node/porter_run_labels.rego

@@ -0,0 +1,23 @@
+package node.porter_run_labels
+
+import future.keywords
+
+POLICY_ID := sprintf("porter_run_labels_%s", [input.metadata.name])
+
+POLICY_VERSION := "v0.0.1"
+
+POLICY_SEVERITY := "high"
+
+POLICY_TITLE := sprintf("The node %s should have the label porter.run/workload-kind", [input.metadata.name])
+
+POLICY_SUCCESS_MESSAGE := sprintf("Success: this node has the label porter.run/workload-kind", [])
+
+# determine if the label porter.run/workload-kind exists
+allow if {
+	input.metadata.labels["porter.run/workload-kind"]
+}
+
+FAILURE_MESSAGE contains msg if {
+	not allow
+	msg := sprintf("Failed: the node %s does not have the label porter.run/workload-kind", [input.metadata.name])
+}

+ 41 - 0
internal/opa/policies/node/porter_run_taints.rego

@@ -0,0 +1,41 @@
+package node.porter_run_taints
+
+import future.keywords
+
+POLICY_ID := sprintf("porter_run_taints_%s", [input.metadata.name])
+
+POLICY_VERSION := "v0.0.1"
+
+POLICY_SEVERITY := "high"
+
+POLICY_TITLE := sprintf("The only taints on node %s should be porter.run/workload-kind=system", [input.metadata.name])
+
+POLICY_SUCCESS_MESSAGE := sprintf("Success: this node either has no taints, or has a taint with key porter.run/workload-kind", [])
+
+# if there are no taints, allow the condition
+allow if {
+	not input.spec.taints[0]
+}
+
+# if there is a taint with the key porter.run/workload-kind, allow the condition
+allow if {
+	input.spec.taints[0].key == "porter.run/workload-kind"
+	input.spec.taints[0].effect == "NoSchedule"
+}
+
+FAILURE_MESSAGE contains msg1 if {
+	not allow
+	msg1 := sprintf("Failed: the only permitted taints must contain the key porter.run/workload-kind", [])
+}
+
+FAILURE_MESSAGE contains msg2 if {
+	not allow
+	not input.spec.taints[0].key == "porter.run/workload-kind"
+	msg2 := sprintf("Taint has key %s", [input.spec.taints[0].key])
+}
+
+FAILURE_MESSAGE contains msg3 if {
+	not allow
+	not input.spec.taints[0].effect == "NoSchedule"
+	msg3 := sprintf("Taint has effect %s", [input.spec.taints[0].effect])
+}

+ 4 - 0
internal/validator/validator.go

@@ -2,6 +2,7 @@ package validator
 
 import (
 	"github.com/go-playground/validator/v10"
+	"k8s.io/apimachinery/pkg/util/validation"
 )
 
 // New creates a new instance of validator and sets the tag name
@@ -9,5 +10,8 @@ import (
 func New() *validator.Validate {
 	validate := validator.New()
 	validate.SetTagName("form")
+	validate.RegisterValidation("dns1123", func(fl validator.FieldLevel) bool {
+		return len(validation.IsDNS1123Label(fl.Field().String())) == 0
+	})
 	return validate
 }