apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: tls-rollout spec: mutateExistingOnPolicyUpdate: false rules: - name: deployments match: &secretMatch any: - resources: kinds: - Secret operations: - CREATE - UPDATE context: &certData - name: certs variable: jmesPath: >- sort_by(items(request.object.data || `{}`, 'key', 'value')[?value != '' && ( contains(`["tls.crt", "ca.crt", "ssl.cert"]`, key) || contains(base64_decode(value), '-----BEGIN CERTIFICATE-----'))], &key) - name: oldCerts variable: jmesPath: >- sort_by(items(request.oldObject.data || `{}`, 'key', 'value')[?value != '' && ( contains(`["tls.crt", "ca.crt", "ssl.cert"]`, key) || contains(base64_decode(value), '-----BEGIN CERTIFICATE-----'))], &key) preconditions: &changedCert all: - key: "{{ length(certs) }}" operator: GreaterThan value: 0 - key: "{{ to_string(certs) }}" operator: NotEquals value: "{{ to_string(oldCerts) }}" mutate: targets: - apiVersion: apps/v1 kind: Deployment namespace: "{{ request.object.metadata.namespace }}" context: &consumerData - name: tlsVolumes variable: jmesPath: >- target.spec.template.spec.volumes[? secret.secretName == '{{ request.object.metadata.name }}' || contains(projected.sources[].secret.name || `[]`, '{{ request.object.metadata.name }}')].name default: [] - name: clients variable: jmesPath: >- target.spec.template.spec.[containers, initContainers][] | [? length(volumeMounts[?contains(`{{ tlsVolumes }}`, name)] || `[]`) > `0` || contains(env[].valueFrom.secretKeyRef.name || `[]`, '{{ request.object.metadata.name }}') || contains(envFrom[].secretRef.name || `[]`, '{{ request.object.metadata.name }}')].name - name: handlers variable: jmesPath: >- items(parse_json(target.spec.template.metadata.annotations."certificates.quorate.internal/activation" || '{}'), 'name', 'mode')[? contains(`["native", "controller"]`, mode)].name preconditions: &rolloutTarget all: - key: "{{ target.metadata.namespace }}" operator: Equals value: "{{ request.object.metadata.namespace }}" - key: "{{ target.spec.paused || `false` }}" operator: Equals value: false - key: "{{ target.spec.updateStrategy.type || 'RollingUpdate' }}" operator: Equals value: RollingUpdate - key: "{{ target.spec.updateStrategy.rollingUpdate.partition || `0` }}" operator: Equals value: 0 - key: "{{ clients }}" operator: AnyNotIn value: "{{ handlers }}" patchStrategicMerge: &rolloutPatch spec: template: metadata: annotations: "certificates.quorate.internal/{{ truncate(sha256(request.object.metadata.name), `32`) }}": "{{ sha256(to_string(certs)) }}" - name: daemonsets match: *secretMatch context: *certData preconditions: *changedCert mutate: targets: - apiVersion: apps/v1 kind: DaemonSet namespace: "{{ request.object.metadata.namespace }}" context: *consumerData preconditions: *rolloutTarget patchStrategicMerge: *rolloutPatch - name: statefulsets match: *secretMatch context: *certData preconditions: *changedCert mutate: targets: - apiVersion: apps/v1 kind: StatefulSet namespace: "{{ request.object.metadata.namespace }}" context: *consumerData preconditions: *rolloutTarget patchStrategicMerge: *rolloutPatch