diff --git a/pkg/api/kyverno/v1/policy_types.go b/pkg/api/kyverno/v1/policy_types.go index 7ce0885031..9992b030f4 100755 --- a/pkg/api/kyverno/v1/policy_types.go +++ b/pkg/api/kyverno/v1/policy_types.go @@ -21,7 +21,7 @@ type PolicyList struct { // +kubebuilder:object:root=true // +kubebuilder:subresource:status // +kubebuilder:printcolumn:name="Background",type="string",JSONPath=".spec.background" -// +kubebuilder:printcolumn:name="Validatoin Failure Action",type="string",JSONPath=".spec.validationFailureAction" +// +kubebuilder:printcolumn:name="Validation Failure Action",type="string",JSONPath=".spec.validationFailureAction" // +kubebuilder:resource:shortName=pol type Policy struct { metav1.TypeMeta `json:",inline,omitempty" yaml:",inline,omitempty"` diff --git a/samples/AddDefaultLabels.md b/samples/AddDefaultLabels.md new file mode 100644 index 0000000000..9dc9e23a03 --- /dev/null +++ b/samples/AddDefaultLabels.md @@ -0,0 +1,29 @@ +# Add default labels to objects + +Labels are important pieces of metadata that can be attached to just about anything in Kubernetes. They are often used to tag various resources as being associated in some way. Kubernetes has no ability to assign a series of "default" labels to incoming objects. This sample policy shows you how to assign one or multiple labels by default to any object you wish. Here it shows adding a label called `custom-foo-label` with value `my-bar-default` to resources of type `Pod`, `Service`, and `Namespace` but others can be added or removed as desired. + +## Policy YAML + +[add_default_labels.yaml](more/add_default_labels.yaml) + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: add-default-labels +spec: + background: false + rules: + - name: add-default-labels + match: + resources: + kinds: + - Pod + - Service + - Namespace + mutate: + patchStrategicMerge: + metadata: + labels: + custom-foo-label: my-bar-default +``` diff --git a/samples/DisallowSecretsFromEnvVars.md b/samples/DisallowSecretsFromEnvVars.md new file mode 100644 index 0000000000..cd3afb3a4e --- /dev/null +++ b/samples/DisallowSecretsFromEnvVars.md @@ -0,0 +1,38 @@ +# Disallow Secrets from environment variables + +Secrets in Kubernetes are often sensitive pieces of information whose content should be protected. Although they can be used in many ways, when mounting them as environment variables, some applications can write their values to STDOUT revealing this sensitive information in log files and potentially other exposure. As a best practice, Kubernetes Secrets should be mounted instead as volumes. + +This sample policy checks any incoming Pod manifests and ensures that Secrets are not mounted as environment variables. + +## More Information + +* [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) + +## Policy YAML + +[disallow_secrets_from_env_vars.yaml](more/disallow_secrets_from_env_vars.yaml) + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: secrets-not-from-env-vars +spec: + background: false + validationFailureAction: audit + rules: + - name: secrets-not-from-env-vars + match: + resources: + kinds: + - Pod + validate: + message: "Secrets must be mounted as volumes, not as environment variables." + pattern: + spec: + containers: + - name: "*" + =(env): + - =(valueFrom): + X(secretKeyRef): "null" +``` diff --git a/samples/EnsurePodProbesDifferent.md b/samples/EnsurePodProbesDifferent.md new file mode 100644 index 0000000000..f6e8c5d366 --- /dev/null +++ b/samples/EnsurePodProbesDifferent.md @@ -0,0 +1,88 @@ +# Require `livenessProbe` and `readinessProbe` are different + +Pod liveness and readiness probes are often used as a check to ensure either the health of an already running Pod or when one is ready to receive traffic. For a sample policy with more information and which contains a validation rule that both are present, see [require_probes.yaml](RequirePodProbes.md). + +This sample checks to ensure that `livenessProbe` and `readinessProbe` are configured differently. When these two probes are configured but are set up the same way, race conditions can result as Kubernetes continues to kill and recreate a Pod never letting it enter a running state. This sample satisfies a common best practice in which these probes, if extant, not overlap and potentially cause this condition. + +In this sample policy, a series of `deny` rules exist, one per container, to compare the `livenessProbe` map to the `readinessProbe`. If any container in a Pod potentially having multiple is found to have identical probes, its creation will be blocked. Note that in this sample policy the `validationFailureAction` is set to `enforce` due to the use of a `deny` rule rather than a `validate` rule. By using the annotation `pod-policies.kyverno.io/autogen-controllers`, it modifies the default behavior and ensures that only Pods originating from DaemonSet, Deployment, and StatefulSet objects are validated. + +If you may potentially have more than four containers in a Pod against which this policy should operate, duplicate one of the rules found within and change the array member of the `containers` key in fields `key` and `value`. For example, to match against a potential fifth container, duplicate a rule and change `containers[3]` to `containers[4]`. + +## More Information + +* [Kyverno Deny Rules](https://kyverno.io/docs/writing-policies/validate/#deny-rules) +* [Kyverno Auto-Gen Rules for Pod Controllers](https://kyverno.io/docs/writing-policies/autogen/) +* [Configure Liveness, Readiness and Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) + +## Policy YAML + +[ensure_probes_different.yaml](more/ensure_probes_different.yaml) + +```yaml +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: validate-probes + annotations: + # Only applies to pods originating from DaemonSet, Deployment, or StatefulSet. + pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,StatefulSet +spec: + validationFailureAction: enforce + background: false + rules: + # Checks the first container in a Pod. + - name: validate-probes-c0 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + # A `deny` rule is different in structure than a `validate` rule and inverts the check. It uses `conditions` written in JMESPath notation upon which to base its decisions. + deny: + conditions: + # In this condition, it checks the entire map structure of the `readinessProbe` against that of the `livenessProbe`. If both are found to be equal, the Pod creation + # request will be denied. + - key: "{{ request.object.spec.containers[0].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[0].livenessProbe }}" + # Checks the second container in a Pod. + - name: validate-probes-c1 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + deny: + conditions: + - key: "{{ request.object.spec.containers[1].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[1].livenessProbe }}" + # Checks the third container in a Pod. + - name: validate-probes-c2 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + deny: + conditions: + - key: "{{ request.object.spec.containers[2].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[2].livenessProbe }}" + # Checks the fourth container in a Pod. + - name: validate-probes-c3 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + deny: + conditions: + - key: "{{ request.object.spec.containers[3].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[3].livenessProbe }}" +``` diff --git a/samples/README.md b/samples/README.md index 183f7b4cae..7192a47e55 100644 --- a/samples/README.md +++ b/samples/README.md @@ -41,6 +41,9 @@ These policies provide additional best practices and are worthy of close conside 1. [Require Deployments have multiple replicas](RequireDeploymentsHaveReplicas.md) 1. [Spread Pods across topology](SpreadPodsAcrossTopology.md) 1. [Create Pod Anti-Affinity](CreatePodAntiAffinity.md) +1. [Ensure Pod `livenessProbe` and `readinessProbe` are different](EnsurePodProbesDifferent.md) +1. [Disallow mounting Secrets as environment variables](DisallowSecretsFromEnvVars.md) +1. [Add default labels](AddDefaultLabels.md) ## Applying the sample policies diff --git a/samples/more/add_default_labels.yaml b/samples/more/add_default_labels.yaml new file mode 100644 index 0000000000..15225d2484 --- /dev/null +++ b/samples/more/add_default_labels.yaml @@ -0,0 +1,19 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: add-default-labels +spec: + background: false + rules: + - name: add-default-labels + match: + resources: + kinds: + - Pod + - Service + - Namespace + mutate: + patchStrategicMerge: + metadata: + labels: + custom-foo-label: my-bar-default \ No newline at end of file diff --git a/samples/more/disallow_secrets_from_env_vars.yaml b/samples/more/disallow_secrets_from_env_vars.yaml new file mode 100644 index 0000000000..6bb3ab37c9 --- /dev/null +++ b/samples/more/disallow_secrets_from_env_vars.yaml @@ -0,0 +1,22 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: secrets-not-from-env-vars +spec: + background: false + validationFailureAction: audit + rules: + - name: secrets-not-from-env-vars + match: + resources: + kinds: + - Pod + validate: + message: "Secrets must be mounted as volumes, not as environment variables." + pattern: + spec: + containers: + - name: "*" + =(env): + - =(valueFrom): + X(secretKeyRef): "null" \ No newline at end of file diff --git a/samples/more/ensure_probes_different.yaml b/samples/more/ensure_probes_different.yaml new file mode 100644 index 0000000000..e91576b414 --- /dev/null +++ b/samples/more/ensure_probes_different.yaml @@ -0,0 +1,66 @@ +apiVersion: kyverno.io/v1 +kind: ClusterPolicy +metadata: + name: validate-probes + annotations: + # Only applies to pods originating from DaemonSet, Deployment, or StatefulSet. + pod-policies.kyverno.io/autogen-controllers: DaemonSet,Deployment,StatefulSet +spec: + validationFailureAction: enforce + background: false + rules: + # Checks the first container in a Pod. + - name: validate-probes-c0 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + # A `deny` rule is different in structure than a `validate` rule and inverts the check. It uses `conditions` written in JMESPath notation upon which to base its decisions. + deny: + conditions: + # In this condition, it checks the entire map structure of the `readinessProbe` against that of the `livenessProbe`. If both are found to be equal, the Pod creation + # request will be denied. + - key: "{{ request.object.spec.containers[0].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[0].livenessProbe }}" + # Checks the second container in a Pod. + - name: validate-probes-c1 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + deny: + conditions: + - key: "{{ request.object.spec.containers[1].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[1].livenessProbe }}" + # Checks the third container in a Pod. + - name: validate-probes-c2 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + deny: + conditions: + - key: "{{ request.object.spec.containers[2].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[2].livenessProbe }}" + # Checks the fourth container in a Pod. + - name: validate-probes-c3 + match: + resources: + kinds: + - Pod + validate: + message: "Liveness and readiness probes cannot be the same." + deny: + conditions: + - key: "{{ request.object.spec.containers[3].readinessProbe }}" + operator: Equals + value: "{{ request.object.spec.containers[3].livenessProbe }}" \ No newline at end of file