It is common to have two separate Namespaces such as staging and production in order to test and promote app deployments in a controlled manner. In order to ensure that level of control, certain guardrails must be present so as to minimize regressions or unintended behavior. This policy has a set of three rules to try and provide some sane defaults for app promotion across these two environments (Namespaces) called staging and production. First, it makes sure that every Deployment in production has a corresponding Deployment in staging. Second, that a production Deployment uses same image name as its staging counterpart. Third, that a production Deployment uses an older or equal image version as its staging counterpart.
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata:name: ensure-production-matches-stagingannotations:policies.kyverno.io/title: Ensure Production Matches stagingpolicies.kyverno.io/category: Otherpolicies.kyverno.io/minversion: 1.6.0kyverno.io/kyverno-version: 1.7.0kyverno.io/kubernetes-version: "1.23"policies.kyverno.io/subject: Deploymentpolicies.kyverno.io/description: It is common to have two separate Namespaces such as staging and production in order to test and promote app deployments in a controlled manner. In order to ensure that level of control, certain guardrails must be present so as to minimize regressions or unintended behavior. This policy has a set of three rules to try and provide some sane defaults for app promotion across these two environments (Namespaces) called staging and production. First, it makes sure that every Deployment in production has a corresponding Deployment in staging. Second, that a production Deployment uses same image name as its staging counterpart. Third, that a production Deployment uses an older or equal image version as its staging counterpart.spec:validationFailureAction: Enforcebackground: truerules:- name: require-staging-deploymentmatch:any:- resources:namespaces:- productionkinds:- Deploymentpreconditions:any:- key: "{{request.operation || 'BACKGROUND'}}"operator: AnyInvalue:- CREATE- UPDATEcontext:- name: deployment_countapiCall:urlPath: /apis/apps/v1/namespaces/staging/deploymentsjmesPath: items[?metadata.name=='{{ request.object.metadata.name }}'] || `[]` | length(@)validate:message: Every Deployment in production requires a corresponding Deployment in staging.deny:conditions:any:- key: "{{deployment_count}}"operator: Equalsvalue: 0- name: require-same-imagematch:any:- resources:namespaces:- productionkinds:- Deploymentpreconditions:all:- key: "{{request.operation || 'BACKGROUND'}}"operator: AnyInvalue:- CREATE- UPDATE- key: "{{ deployment_count }}"operator: GreaterThanvalue: 0context:- name: deployment_countapiCall:urlPath: /apis/apps/v1/namespaces/staging/deploymentsjmesPath: items[?metadata.name=='{{ request.object.metadata.name}}'] || `[]` | length(@)- name: deployment_imagesapiCall:urlPath: /apis/apps/v1/namespaces/staging/deployments/{{ request.object.metadata.name }}jmesPath: spec.template.spec.containers[].image.split(@, ':')[0]validate:message: Every Deployment in production is required to use the same image(s) as in staging.deny:conditions:any:- key: "{{ request.object.spec.template.spec.containers[].image.split(@, ':')[0] }}"operator: AnyNotInvalue: "{{ deployment_images }}"- name: require-same-or-older-imageversionmatch:any:- resources:namespaces:- productionkinds:- Deploymentpreconditions:all:- key: "{{request.operation || 'BACKGROUND'}}"operator: AnyInvalue:- CREATE- UPDATE- key: "{{ deployment_count }}"operator: GreaterThanvalue: 0context:- name: deployment_countapiCall:urlPath: /apis/apps/v1/namespaces/staging/deploymentsjmesPath: items[? metadata.name == '{{ request.object.metadata.name }}' ] | length(@)- name: deployment_containersapiCall:urlPath: /apis/apps/v1/namespaces/staging/deployments/{{ request.object.metadata.name }}jmesPath: spec.template.spec.containers[]validate:message: Every Deployment in production is required to use an image version less than or equal to the one in staging.foreach:- list: request.object.spec.template.spec.containers[]deny:conditions:any:- key: "{{ element.image.split(@,':')[1] }}"operator: GreaterThanvalue: "{{ deployment_containers[?name == '{{element.name}}'].image.split(@,':')[1] | [0] }}"
This policy prevents the use of the default project in an Application.
Services of type LoadBalancer when deployed inside AWS have support for transport encryption if it is enabled via an annotation. This policy requires that Services of type LoadBalancer contain the annotation service.beta.kubernetes.io/aws-load-balancer-ssl-cert with some value.
This policy prevents updates to the project field after an Application is created.