Bootstrapping Krustlet

Krustlet supports automatic bootstrapping of its authorization and serving certificates. This document describes how the functionality works.

Initialization

Krustlet follows the same initialization flow as Kubelet (with the exception of automatic renewal of certs that are close to expiry).

Instructions

In order to join a cluster with the proper permissions, Krustlet requires a valid bootstrap config with a valid bootstrap token. This token can be generated with kubeadm or may already exist depending on your provider. However, in this case, we will be using an easier method for creating a join token. Either way, the examples here should be useful for figuring out how to do it differently depending on your setup.

Prerequisites

You will need kubectl installed and a kubeconfig that has access to create Secrets in the kube-system namespace and can approve CertificateSigningRequests.

Generating a token and kubeconfig

We have a useful bootstrapping bash script or Powershell script that can be used for generating a token and creating a bootstrap kubeconfig file. If you have cloned the repo, you can run:

$ ./scripts/bootstrap.sh

OR

$ .\scripts\bootstrap.ps1

If you are the trusting sort, you can pipe it in from the internet:

$ bash <(curl https://raw.githubusercontent.com/krustlet/krustlet/main/scripts/bootstrap.sh)

OR

(Invoke-WebRequest -UseBasicParsing https://raw.githubusercontent.com/krustlet/krustlet/main/scripts/bootstrap.ps1).Content | Invoke-Expression

This will output a ready-to-use bootstrap config to $HOME/.krustlet/config/bootstrap.conf

Script configuration

The script also exposes a few configuration options by means of environment variables. These are detailed in the table below:

Name Description Default
CONFIG_DIR The location of your configuration directory for Krustlet. Should be the same as $KRUSTLET_DATA_DIR/config where the KRUSTLET_DATA_DIR setting is the same one you use for configuring Krustlet $HOME/.krustlet/config
FILE_NAME The name of the file the bootstrap config should be saved to bootstrap.conf

Nitty-gritty details

This section contains an overview of the nitty-gritty details for those who may be constructing their own bootstrapping setup. Feel free to skip this section if it doesn’t pertain to you.

Bootstrap tokens

A bootstrap token has the format of [a-z0-9]{6}.[a-z0-9]{16} where the first part is a randomly generated token id and the second part after the . needs to be a cryptographically secure random string. The token will look something like this: ke3uxh.vhxb3ttj1nquno5t. That means you can generate a token with a simple bash command like so:

$ echo "$(< /dev/urandom tr -dc a-z0-9 | head -c${1:-6};echo;).$(< /dev/urandom tr -dc a-z0-9 | head -c${1:-16};echo;)"
Creating the secret

To actually “create” the bootstrap token, it needs to be placed in a Secret in the kube-system namespace. The name of the secret should be bootstrap-token-<token_id>. Specifically, the secret should look something like this when you send it to the API:

apiVersion: v1
kind: Secret
metadata:
  name: bootstrap-token-<token_id>
  namespace: kube-system
type: bootstrap.kubernetes.io/token
stringData:
  auth-extra-groups: system:bootstrappers:kubeadm:default-node-token
  expiration: 2020-06-04T20:07:24Z
  token-id: <token_id>
  token-secret: <token_secret>
  usage-bootstrap-authentication: "true"
  usage-bootstrap-signing: "true"

The main fields you need to set are token-id, token-secret, and expiration.

Generating the Kubeconfig

Once you have a Secret created, you then have to generate the Kubeconfig. To do so, you’ll need several pieces of information:

  • The CA cert for your Kubernetes API. This should be available from the kubeconfig you are currently using
  • The server hostname or IP address
  • The generated bootstrap token

You can either assemble a kubeconfig by hand or use similar steps to what is found in the bootstrap script

An example bootstrap config

This is an example of a bootstrap config file for reference if creating your own workflow

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwdGFXNXAKYTNWaVpVTkJNQjRYRFRFNE1EUXlOREF3TVRVME9Wb1hEVEk0TURReU1UQXdNVFUwT1Zvd0ZURVRNQkVHQTFVRQpBeE1LYldsdWFXdDFZbVZEUVRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS1lxCnhzMllBNzRETlFQTVZkbFJ3aXZFWnIwd0lTUHlQZjkzR3ZsUVNKMDQrbFgxSEF3Yi9GM3dqcDVEckVOSDAraTUKbjhZUy9QK3JlNUpqVU9tV1VmMXNtMmVLNHNRNHpNS01kMHc5by9ERlozTHc3K1h6RzMveTdvMkF4SWVlYjBPdgpzbzhwWUVOMklzRUcrRFhpa0l0MjhPZ1RtZGRhTVg1OWJQTXhGL0l6T1FPVmFEYmtnMk5ScWtjYW9CR0FTT2JkCkVId2hrVGdMYXZCNzVnVmRTVVlWUFU1M2dXc3hDQWVBYzNCaW9NekNLNmFFUXIrMDB4V3dEWkR4amxLYU02V3gKTWFQN0JmY0Y5K2U3OUt0Tkc3TXZMWG9xdFJ3cCtPdWREaTlKWHRLS1NNbVo3TFNubEY4UDdHUlhKL2IzNS9NVQpvQklkK1ZKNHpoak5zT2xKM3g4Q0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUIwR0ExVWRKUVFXCk1CUUdDQ3NHQVFVRkJ3TUNCZ2dyQmdFRkJRY0RBVEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFDWmM0SVpST3pnNS91eDdNa0Y3NmVja3dZekY4OUJiejRhRENVS3ByWUMxTDFvZVBVawpXdFc3VENWditDMDJRc2tGRnpTbGhlQUpYeXp5Q2xKMVE5VmUyUmR2bGtiZHVPTXpJeXZTS0xaZHVDT2pvVWNZCjkrMTN1UEFpaXJjNUpRZlBOTGdJcUdhbTB2ZXpqZEtROHNUK0o0WmRyNHdFOUZKQnhOeUhob0xQdjBLRENBbkcKWFlPZW5lTHdjcnJCcTVDTERRN2dIelZGbEFKVU1nSWF3ZzdtcG1HVi9KRlVlYnRpam1Cd1p1WDBNMTFpVHBqYQpNaUhDRkJOREd5a2locDBoSHdDV1ZId0ZXNHVLUWxUZjRBK2hieC9OTUkzbHhBYXozMFZKN3U1Mm1GR3pCQ0dvCmt3VjdKS2RJMEd1MGJQQmlUSDRMTmE4bWxqYmZkRnhsc2k4cAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    server: https://192.168.64.19:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    namespace: kube-system
    user: tls-bootstrap-token-user
  name: tls-bootstrap-token-user@kubernetes
current-context: tls-bootstrap-token-user@kubernetes
kind: Config
preferences: {}
users:
- name: tls-bootstrap-token-user
  user:
    token: ke3uxh.vhxb3ttj1nquno5t

Running Krustlet

Once you have the bootstrap config in place, you can run Krustlet:

$ KUBECONFIG=~/.krustlet/config/kubeconfig krustlet-wasi --port 3000 --bootstrap-file /path/to/your/bootstrap.conf

Krustlet will begin the bootstrapping process, and then await manual certificate approval (described below) before launching.

A couple important notes here. KUBECONFIG should almost always be set, especially in developer/local machine situations. During the bootstrap process, Krustlet will generate a kubeconfig with the credentials it obtains during the bootstrapping process and write it out to the specified location in KUBECONFIG. If a kubeconfig already exists there, it will be loaded and skip the bootstrapping process. A similar process occurs during the bootstrapping of the serving certificates, they will be written out to the paths specified by --cert-file (default $KRUSTLET_DATA_DIR/config/krustlet.crt) and --private-key-file (default $KRUSTLET_DATA_DIR/config/krustlet.key). If they already exist, then they will be loaded and bootstrapping skipped.

Approving the serving CSR

Once you have started Krustlet, there is one more manual step (though this could be automated depending on your setup). The client certs Krustlet needs are generally approved automatically by the API. However, the serving certs require manual approval. To do this, you’ll need the hostname you specified for the --hostname flag or the output of hostname if you didn’t specify anything. Then run:

$ kubectl certificate approve <hostname>-tls

Once you do this, Krustlet will automatically grab the new certs and start running.