0 of 15 done
Bring It Online

Generate kubeconfig files

Where you are

A kubeconfig file bundles two things: an identity and the address of the API server to reach. You make one kubeconfig per component now so that each component can prove who it is when the runtimes start. Nothing runs yet. You are still assembling credentials, this time by packaging the certificates you signed in the last step into files each component can read.

Generate the kubeconfig files

A kubeconfig file is a Kubernetes client configuration file. It tells a client how to connect to a Kubernetes API server and how to authenticate to it. In this step you generate one for the kubelet on each worker node, one for each control plane service, and one for the admin user.

The kubelet kubeconfig file

The kubelet runs on each worker node and manages the containers there. When you generate a kubeconfig for a kubelet, you must use the client certificate that matches the kubelet’s node name. This lets the Node Authorizer, the part of the API server that decides what each node is allowed to do, recognize the node and grant the correct permissions.

Run the following commands in the same directory you used to generate the certificates in the previous step.

Generate a kubeconfig file for the node-0 and node-1 worker nodes:

for host in node-0 node-1; do
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.crt \
    --embed-certs=true \
    --server=https://server.kubernetes.local:6443 \
    --kubeconfig=${host}.kubeconfig

  kubectl config set-credentials system:node:${host} \
    --client-certificate=${host}.crt \
    --client-key=${host}.key \
    --embed-certs=true \
    --kubeconfig=${host}.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:node:${host} \
    --kubeconfig=${host}.kubeconfig

  kubectl config use-context default \
    --kubeconfig=${host}.kubeconfig
done

Each pass runs four commands. The first names the cluster and records the API server address and CA certificate. The second records the identity, the node’s client certificate and key. The third joins that cluster and that identity into a context. The fourth makes that context the active one. The --embed-certs=true flag copies the certificate contents into the file, so the kubeconfig is self contained and does not point at separate certificate files.

Results:

node-0.kubeconfig
node-1.kubeconfig

The kube-proxy kubeconfig file

The kube-proxy service runs on each worker node and keeps network rules in sync. Generate a kubeconfig file for the kube-proxy service:

{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.crt \
    --embed-certs=true \
    --server=https://server.kubernetes.local:6443 \
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config set-credentials system:kube-proxy \
    --client-certificate=kube-proxy.crt \
    --client-key=kube-proxy.key \
    --embed-certs=true \
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-proxy \
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config use-context default \
    --kubeconfig=kube-proxy.kubeconfig
}

Results:

kube-proxy.kubeconfig

The kube-controller-manager kubeconfig file

The kube-controller-manager runs on the control plane and drives the cluster toward its desired state. Generate a kubeconfig file for the kube-controller-manager service:

{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.crt \
    --embed-certs=true \
    --server=https://server.kubernetes.local:6443 \
    --kubeconfig=kube-controller-manager.kubeconfig

  kubectl config set-credentials system:kube-controller-manager \
    --client-certificate=kube-controller-manager.crt \
    --client-key=kube-controller-manager.key \
    --embed-certs=true \
    --kubeconfig=kube-controller-manager.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-controller-manager \
    --kubeconfig=kube-controller-manager.kubeconfig

  kubectl config use-context default \
    --kubeconfig=kube-controller-manager.kubeconfig
}

Results:

kube-controller-manager.kubeconfig

The kube-scheduler kubeconfig file

The kube-scheduler runs on the control plane and assigns pods to nodes. Generate a kubeconfig file for the kube-scheduler service:

{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.crt \
    --embed-certs=true \
    --server=https://server.kubernetes.local:6443 \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config set-credentials system:kube-scheduler \
    --client-certificate=kube-scheduler.crt \
    --client-key=kube-scheduler.key \
    --embed-certs=true \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-scheduler \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config use-context default \
    --kubeconfig=kube-scheduler.kubeconfig
}

Results:

kube-scheduler.kubeconfig

The admin kubeconfig file

The admin user is the identity you use to run commands against the cluster yourself. Its kubeconfig points at https://127.0.0.1:6443 because you will run these commands on the server machine itself, so the API server is reachable on the local loopback address. Generate a kubeconfig file for the admin user:

{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.crt \
    --embed-certs=true \
    --server=https://127.0.0.1:6443 \
    --kubeconfig=admin.kubeconfig

  kubectl config set-credentials admin \
    --client-certificate=admin.crt \
    --client-key=admin.key \
    --embed-certs=true \
    --kubeconfig=admin.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=admin \
    --kubeconfig=admin.kubeconfig

  kubectl config use-context default \
    --kubeconfig=admin.kubeconfig
}

Results:

admin.kubeconfig

Distribute the kubeconfig files

Each kubeconfig has to live on the machine that will read it. Copy the kubelet and kube-proxy kubeconfig files to the node-0 and node-1 machines:

for host in node-0 node-1; do
  ssh root@${host} "mkdir -p /var/lib/{kube-proxy,kubelet}"

  scp kube-proxy.kubeconfig \
    root@${host}:/var/lib/kube-proxy/kubeconfig \

  scp ${host}.kubeconfig \
    root@${host}:/var/lib/kubelet/kubeconfig
done

Copy the kube-controller-manager and kube-scheduler kubeconfig files to the server machine:

scp admin.kubeconfig \
  kube-controller-manager.kubeconfig \
  kube-scheduler.kubeconfig \
  root@server:~/

Each component now holds a file that proves its identity and tells it where to find the API server. When the runtimes start in a later step, they read these files to authenticate.

Key terms

kubeconfig: A file that tells a Kubernetes client how to reach an API server and how to authenticate to it. It holds three kinds of entries: clusters, users, and contexts.

cluster (in a kubeconfig): An entry that records an API server address and the CA certificate used to verify that server. In these files it is named kubernetes-the-hard-way.

user (in a kubeconfig): An entry that records an identity, made up of a client certificate and key. Examples here include system:node:node-0, system:kube-proxy, and admin.

context: An entry that pairs one cluster with one user. The active context decides which cluster the client talks to and which identity it presents. Each file here defines a single context named default and makes it active.

Reflect

Each kubeconfig embeds both an identity and the API server address. If you later move the API server to a new address, what would you have to do to every kubeconfig you generated here, and why does embedding the certificate contents not save you from that work?

Next: Generate the data encryption key