[Infrastructure as Code (IaC) Pulumi] Use Pulumi kubernetes (K8S) Helm Chart to deploy x509-certificate-exporter

x509-certificate-exporter

x509-certificate-exporter is a Prometheus exporter for certificates focusing on expiration monitoring, written in Go with cloud deployments in mind.

This article is about how to use Pulumi, kubernetes (K8S) provider, Helm Chart and TypeScript SDK to deploy x509-certificate-exporter within Kubernetes (K8S).

Get notified before certificates expire:

  • TLS Secrets from a Kubernetes cluster

  • PEM encoded files, by path or scanning directories

  • Kubeconfigs with embedded certificates or file references

The following metrics are available:

  • x509_cert_not_before

  • x509_cert_not_after

  • x509_cert_expired

  • x509_cert_error (optional)

  • x509_read_errors

Best when used with the Grafana DashboardCertificates Expiration (X509 Certificate Exporter) dashboard for Grafana | Grafana Labs - https://grafana.com/grafana/dashboards/13922 ID 13922:

enix-x509-certificate-exporter-grafana-dashboard.jpg

Prerequisites

Usage

Pulumi New

Create the workspace directory.

1
2
3
$ mkdir -p col-example-pulumi-typescript-x509-certificate-exporter

$ cd col-example-pulumi-typescript-x509-certificate-exporter

Pulumi login into local file system.

1
2
3
$ pulumi login file://.
Logged in to cloudolife as cloudolife (file://.)
or visit https://pulumi.com/docs/reference/install/ for manual instructions and release notes.

Pulumi new a project with kubernetes-typescript SDK.

1
$ pulumi new kubernetes-typescript

The above command will create some files within the current directory.

1
2
3
4
5
6
7
8
tree . -L 1
.
├── node_modules/
├── package.json
├── package.json.lock
├── Pulumi.dev.yaml
├── Pulumi.yaml
└── main.ts

Install js-yaml package to load and parse yaml file.

1
$ npm i js-yaml

Pulumi Configuration

Configure Kubernetes

By default, Pulumi will look for a kubeconfig file in the following locations, just like kubectl:

  • The environment variable: $KUBECONFIG,

  • Or in current user’s default kubeconfig directory: ~/.kube/config

If the kubeconfig file is not in either of these locations, Pulumi will not find it, and it will fail to authenticate against the cluster. Set one of these locations to a valid kubeconfig file, if you have not done so already.

Configure Values.yaml

Edit values.yaml and replace content within {{ }}.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# values.yaml

# helm-charts/values.yaml at master · enix/helm-charts
# https://github.com/enix/helm-charts/blob/master/charts/x509-certificate-exporter/values.yaml

# Without Prometheus CRDs(For example Loki Statck)
secretsExporter:
podAnnotations:
prometheus.io/port: "9793"
prometheus.io/scrape: "true"
service:
create: false
prometheusServiceMonitor:
create: false
prometheusRules:
create: false

# Monitor hostpath Certificates.
hostPathsExporter:
podAnnotations:
prometheus.io/port: "9793"
prometheus.io/scrape: "true"

# Example 1: Kubernetes and etcd
daemonSets:
cp:
nodeSelector:
node-role.kubernetes.io/master: ""
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
operator: Exists
watchFiles:
- /etc/kubernetes/pki/apiserver.crt
- /etc/kubernetes/pki/apiserver-etcd-client.crt
- /etc/kubernetes/pki/apiserver-kubelet-client.crt
- /etc/kubernetes/pki/ca.crt
- /etc/kubernetes/pki/front-proxy-ca.crt
- /etc/kubernetes/pki/front-proxy-client.crt

- /etc/kubernetes/pki/etcd/ca.crt
- /etc/kubernetes/pki/etcd/healthcheck-client.crt
- /etc/kubernetes/pki/etcd/peer.crt
- /etc/kubernetes/pki/etcd/server.crt
watchKubeconfFiles:
- /etc/kubernetes/admin.conf
- /etc/kubernetes/controller-manager.conf
- /etc/kubernetes/scheduler.conf

nodes:
tolerations:
- effect: NoSchedule
key: node-role.kubernetes.io/master
operator: Exists
watchFiles:
- /var/lib/kubelet/pki/kubelet-client-current.pem
- /etc/kubernetes/pki/ca.crt

# # Example 1: etcd is independent of Kubernetes
# daemonSets:
# cp:
# nodeSelector:
# node-role.kubernetes.io/master: ""
# tolerations:
# - effect: NoSchedule
# key: node-role.kubernetes.io/master
# operator: Exists
# watchFiles:
# - /var/lib/kubelet/pki/kubelet-client-current.pem

# - /etc/kubernetes/pki/apiserver.crt
# - /etc/kubernetes/pki/apiserver-kubelet-client.crt
# - /etc/kubernetes/pki/ca.crt
# - /etc/kubernetes/pki/front-proxy-ca.crt
# - /etc/kubernetes/pki/front-proxy-client.crt

# # etcd SSL
# - /etc/ssl/etcd/ssl/admin-s1.pem
# - /etc/ssl/etcd/ssl/admin-s2.pem
# - /etc/ssl/etcd/ssl/admin-s3.pem
# - /etc/ssl/etcd/ssl/ca.pem
# - /etc/ssl/etcd/ssl/member-s1.pem
# - /etc/ssl/etcd/ssl/member-s2.pem
# - /etc/ssl/etcd/ssl/member-s3.pem
# - /etc/ssl/etcd/ssl/node-s1.pem
# - /etc/ssl/etcd/ssl/node-s2.pem
# - /etc/ssl/etcd/ssl/node-s3.pem

# watchKubeconfFiles:
# - /etc/kubernetes/admin.conf
# - /etc/kubernetes/controller-manager.conf
# - /etc/kubernetes/scheduler.conf

# nodes:
# tolerations:
# - effect: NoSchedule
# key: node-role.kubernetes.io/master
# operator: Exists
# watchFiles:
# - /var/lib/kubelet/pki/kubelet-client-current.pem
# - /etc/kubernetes/pki/ca.crt

main.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// main.ts

import * as pulumi from "@pulumi/pulumi";

import * as k8s from "@pulumi/kubernetes";

const yaml = require('js-yaml');
const fs = require('fs');

const nameX509CertificateExporter = "x509-certificate-exporter"

// kubernetes.core/v1.Namespace | Pulumi
// https://www.pulumi.com/docs/reference/pkg/kubernetes/core/v1/namespace/
const namespaceX509CertificateExporter = new k8s.core.v1.Namespace(nameX509CertificateExporter, {
metadata: {
name: nameX509CertificateExporter,
},
})

const values = yaml.safeLoad(fs.readFileSync("./values.yaml", 'utf8'))

const charNameX509CertificateExporter = "x509-certificate-exporter"

// helm-charts/charts/x509-certificate-exporter at master · enix/helm-charts
// https://github.com/enix/helm-charts/tree/master/charts/x509-certificate-exporter
const charX509CertificateExporter = new k8s.helm.v3.Chart(charNameX509CertificateExporter, {
chart: charNamex509-certificate-exporter,
version: "1.20.0",
fetchOpts:{
repo: "https://charts.enix.io",
},
values: values,
namespace: namespaceX509CertificateExporter.metadata.name,
})

Pulumi Up

Run pulumi up to create the namespace and pods.

1
$ pulumi up

See pods about x509-certificate-exporter.

1
2
3
4
5
6
$ kubectl get pods -n x509-certificate-exporter
NAME READY STATUS RESTARTS AGE
x509-certificate-exporter-5b56cb7cb-tj8rh 1/1 Running 0 16h
x509-certificate-exporter-cp-6std8 1/1 Running 0 15h
x509-certificate-exporter-cp-fc2xf 1/1 Running 0 15h
x509-certificate-exporter-cp-s6bgj 1/1 Running 0 15h

Import X509 Certificate Exporter Grafana Dashboard

See Certificates Expiration (X509 Certificate Exporter) dashboard for Grafana | Grafana Labs - https://grafana.com/grafana/dashboards/13922 to learn more.

Pulumi Destroy

Destroy all resources created by Pulumi.

1
$ pulumi destroy

FAQs

Panel plugin not found: grafana-piechart-panel

First, enter into the Pod.

1
$ exec kubectl exec -i -t <grafana> -c grafana -- sh -c "clear; (bash || ash || sh)"

Use the new grafana-cli tool to install grafana-piechart-panel from the Pod commandline:

1
$ grafana-cli plugins install grafana-piechart-panel

Remember to restart Pod to make that plugin available.

See Pie Chart plugin for Grafana | Grafana Labs - https://grafana.com/grafana/plugins/grafana-piechart-panel/ to learn more.

References

[1] helm-charts/charts/x509-certificate-exporter at master · enix/helm-charts - https://github.com/enix/helm-charts/tree/master/charts/x509-certificate-exporter

[2] enix/x509-certificate-exporter: A Prometheus exporter to monitor x509 certificates expiration in Kubernetes clusters or standalone - https://github.com/enix/x509-certificate-exporter

[3] Certificates Expiration (X509 Certificate Exporter) dashboard for Grafana | Grafana Labs - https://grafana.com/grafana/dashboards/13922

[4] helm-charts/values.yaml at master · enix/helm-charts - https://github.com/enix/helm-charts/blob/master/charts/x509-certificate-exporter/values.yaml

[5] Helm | Grafana Labs - https://grafana.com/docs/loki/latest/installation/helm/

[6] helm-charts/charts/kube-prometheus-stack at main · prometheus-community/helm-charts - https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack

[7] Kubernetes Getting Started | Pulumi - https://www.pulumi.com/docs/get-started/kubernetes/

[8] Pulumi - Modern Infrastructure as Code - https://www.pulumi.com/

[9] Kubernetes - https://kubernetes.io/

[10] TypeScript: Typed JavaScript at Any Scale. - https://www.typescriptlang.org/

[11] Helm - https://helm.sh/