Intro

A while back we had a request for a “kubernetes events input” for the data streaming tool Bento - at the time an etcd input connector was being worked on and because kubernetes uses etcd as the default datastore, the etcd input component should enable streaming kubernetes events.

This blog post walks through the steps to connect a minikube based local kubernetes cluster’s etcd with Bento.

⚠️ WARNING ⚠️

THIS FOR DEV/TESTING ONLY - EXPOSING ETCD LIKE THIS IS A SECURITY RISK


Boot up minikube

minikube start

When you run minikube start - your kube config should be updated automatically, meaning that subsequent kubectl commands should connect to this minikube cluster.

Let’s have a look at what pods we are running:

kubectl get pods -A
NAMESPACE     NAME                               READY   STATUS    RESTARTS   AGE
kube-system   coredns-668d6bf9bc-d5zv4           1/1     Running   0          15s
kube-system   etcd-minikube                      1/1     Running   0          21s
kube-system   kube-apiserver-minikube            1/1     Running   0          21s
kube-system   kube-controller-manager-minikube   1/1     Running   0          21s
kube-system   kube-proxy-8qlpl                   1/1     Running   0          15s
kube-system   kube-scheduler-minikube            1/1     Running   0          21s
kube-system   storage-provisioner                1/1     Running   0          19s

When minikube boots up it starts a number of containers in the namespace: kube-system, we can see that we have an etcd-minikube pod, this is the etcd instance used by Kubernetes, that keeps track of changes made to the cluster!

Minikube deploys etcd with mTLS authentication and a self-signed certificate - the next part outlines steps to connect to etcd.

Grab some certificates from the cluster

In this guide we are going to connect to this from outside of the cluster, to do this we need to grab some tls certs and expose the endpoint to our host machine. When minikube boots up it generates a certificate and key used for health checks - we are going to reuse them for the purpose of this guide. This really isn’t what you should be doing in production but this is just a bit of local fun.

Run the following on your local machine (not the cluster) to grab the ca.crt, client.crt and client.key files and save them to your file system:

minikube ssh -- sudo cat /var/lib/minikube/certs/etcd/ca.crt > ca.crt
minikube ssh -- sudo cat /var/lib/minikube/certs/etcd/healthcheck-client.crt > client.crt
minikube ssh -- sudo cat /var/lib/minikube/certs/etcd/healthcheck-client.key > client.key

Expose etcd’s endpoint

We are going to create a kubernetes service to expose etcd’s endpoint.

kubectl describe pod etcd-minikube -n kube-system

You should see something like:

Name:                 etcd-minikube
Namespace:            kube-system
Priority:             2000001000
Priority Class Name:  system-node-critical
Node:                 minikube/192.168.49.2
Start Time:           Thu, 08 May 2025 16:35:31 +0100
Labels:               component=etcd
                      tier=control-plane
    ...

We are going to use the Labels to map our service to this pod, in the selector field:

apiVersion: v1
kind: Service
metadata:
  name: etcd-minikube-service
  namespace: kube-system
spec:
  selector:
    component: etcd
    tier: control-plane
  ports:
    - protocol: TCP
      port: 2379
      targetPort: 2379
  type: NodePort

Apply the service to the cluster:

kubectl apply -f etcd-service.yaml

Use minikube service to expose it:

minikube service etcd-minikube-service -n kube-system

you should see:

|-------------|-----------------------|-------------|---------------------------|
|  NAMESPACE  |         NAME          | TARGET PORT |            URL            |
|-------------|-----------------------|-------------|---------------------------|
| kube-system | etcd-minikube-service |        2379 | http://192.168.49.2:31670 |
|-------------|-----------------------|-------------|---------------------------|
🏃  Starting tunnel for service etcd-minikube-service.
|-------------|-----------------------|-------------|---------------------------|
|  NAMESPACE  |         NAME          | TARGET PORT |          URL              |
|-------------|-----------------------|-------------|---------------------------|
| kube-system | etcd-minikube-service |             | http://127.0.0.1:54516    |
|-------------|-----------------------|-------------|---------------------------|
🎉  Opening service kube-system/etcd-minikube-service in default browser...
❗  Because you are using a Docker driver on darwin, the terminal needs to be open to run it.

Now we should be able to connect to the etcd on the address: http://127.0.0.1:54516 (your port will be different, probably)

Running a bento stream to consume kubernetes events:

input: 
  etcd:
    endpoints:
      - 127.0.0.1:54516 # From the output of minikube service 
    key: "" # setting the key to blank with options.with_prefix set to true will get all the keys
    options:
      with_prefix: true
    tls:
      enabled: true 
      root_cas_file: ./ca.crt # filepath to your certificate authority cert.
      client_certs:
        - key_file: ./client.key # filepath to your key
          cert_file: ./client.crt # filepath to your cert 

output: 
  stdout: {}

You should see events being printed to the console:

[
    {
        "create_revision": 383,
        "key": "/registry/services/endpoints/kube-system/k8s.io-minikube-hostpath",
        "lease": 0,
        "mod_revision": 1103,
        "type": "PUT",
        "value": "azhzAAoPCgJ2MRIJRW5kcG9pbnRzEuQDCuEDChhrOHMuaW8tbWluaWt1YmUtaG9zdHBhdGgSABoLa3ViZS1zeXN0ZW0iACokMGNmZmM1YzktMTAxZi00Zjg1LWIzMjAtY2YyZDEzMzBlOTgyMgA4AEIICOie88AGEABi5wEKKGNvbnRyb2wtcGxhbmUuYWxwaGEua3ViZXJuZXRlcy5pby9sZWFkZXISugF7ImhvbGRlcklkZW50aXR5IjoibWluaWt1YmVfYTZlNGRiMTgtNjM5Ny00ZTY1LTg1NGEtMDk4YjI1MTkxZWEyIiwibGVhc2VEdXJhdGlvblNlY29uZHMiOjE1LCJhY3F1aXJlVGltZSI6IjIwMjUtMDUtMDhUMTU6MzY6MDhaIiwicmVuZXdUaW1lIjoiMjAyNS0wNS0wOFQxNTo1MDo1M1oiLCJsZWFkZXJUcmFuc2l0aW9ucyI6MH2KAZQBChNzdG9yYWdlLXByb3Zpc2lvbmVyEgZVcGRhdGUaAnYxIggI3aXzwAYQADIIRmllbGRzVjE6WwpZeyJmOm1ldGFkYXRhIjp7ImY6YW5ub3RhdGlvbnMiOnsiLiI6e30sImY6Y29udHJvbC1wbGFuZS5hbHBoYS5rdWJlcm5ldGVzLmlvL2xlYWRlciI6e319fX1CABoAIgA=",
        "version": 441
    }
]

So it is possible to get kubernetes events directly from etcd using Bento BUT - you see that the value is protobuf encoded and I am not sure where the schema files are to decode this. It’s probably better to create some new Bento components to read from the kubernetes api anyway… 😅