1 minute read

Imagine I’ve been working with Kubernetes for years, but kubeconfig was always somehow delivered to me and I didn’t really look on it. Until now!

Cluster CA

Kubernetes API Server provides a HTTP REST API with TLS enabled. There are multiple authentication methods, but from the client perspective, we are making regular HTTP call:

$ curl https://192.168.0.229:6443
[ fails with invalid certificate authority ]

CA for the cluster isn’t installed on our system - it’s not a well-known public CA (like Let’s encrypt). Instead, every cluster has own CA certificate and deals with TLS termination. That’s different from the “normal” scenario of exposing HTTPS servers - certificates are sorted out on ingress / reverse proxy level.

CA can be found in our Kubeconfig:

$ cat $KUBECONFIG | yq '.clusters[0].cluster.certificate-authority-data' | base64 -d > ca.crt
$ curl --cacert ca.crt https://192.168.0.229:6443
{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}

User credential

User credentials can be provided to the HTTP request in two ways:

Certificates

Client certificates are pretty common, Kubeconfig generated from my simple K3S installation contains client certificates.

$ cat $KUBECONFIG | yq '.users[0].user.client-certificate-data' | base64 -d  > client.crt
$ cat $KUBECONFIG | yq '.users[0].user.client-key-data' | base64 -d  > client.key

We can check certificate contents by:

$ openssl x509 -in client.crt -text -noout  | egrep 'Issuer:|Subject:'
        Issuer: CN = k3s-client-ca@1670179571
        Subject: O = system:masters, CN = system:admin

O and CN correspond to group and username for Kubernetes RBAC. We can now use client certificates to issue the request:

$ curl --cacert ca.crt --cert client.crt --key client.key https://192.168.0.229:6443/api/v1/namespaces
[ displays namespaces ]

Token

Tokens are passed in HTTPS request’s header. For example in GKE clusters, piece of Kubeconfig that represents token looks the following:

    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args: null
      command: gke-gcloud-auth-plugin
      env: null
      installHint: Install gke-gcloud-auth-plugin for use with kubectl by following
        https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
      interactiveMode: IfAvailable
      provideClusterInfo: true

If we just call gke-gcloud-auth-plugin, we are receiving JSON file with status.token entry:

$ export TOKEN=$(gke-gcloud-auth-plugin | yq .status.token)

We can use this token to call API directly:

$ curl --cacert ca.crt -H "Authorization: $TOKEN" https://gke-cluster-address/api/v1/namespaces
[ displays namespaces ]

What to check next

Updated: