5.3.2. Authentication
This section describes authentication options for kubelet on worker nodes when connecting to a Kubernetes cluster. The strategy depends on security requirements and the installation method.
- Bootstrap Token (Hard Way)
- Kubeadm
Manual creation of
bootstrap-kubelet.confusing a bootstrap token. After starting, kubelet will automatically perform TLS Bootstrap: obtain a client certificate and createkubelet.conf.
This example uses a static bootstrap token for all worker nodes. In production environments, it is recommended to generate a unique token for each node with a limited TTL.
Creating a bootstrap token
A bootstrap token is a Secret in the
kube-systemnamespace that allows a new node to join the cluster. Two methods for creating the token are shown below.
- Manual
- kubeadm token create
The commands below must be executed on a master node or on a host with a kubeconfig that has permissions to create Secrets in the kube-system namespace.
Environment variables
export AUTH_EXTRA_GROUPS="system:bootstrappers:kubeadm:default-node-token"
export DESCRIPTION="kubeadm bootstrap token"
export EXPIRATION=$(date -d '24 hours' "+%Y-%m-%dT%H:%M:%SZ")
export TOKEN_ID="fjt9ex"
export TOKEN_SECRET="lwzqgdlvoxtqk4yw"
export USAGE_BOOTSTRAP_AUTHENTIFICATION="true"
export USAGE_BOOTSTRAP_SIGNING="true"
Create Secret
kubectl \
--kubeconfig=/etc/kubernetes/super-admin.conf \
apply -f - <<EOF
---
apiVersion: v1
kind: Secret
metadata:
name: bootstrap-token-${TOKEN_ID}
namespace: kube-system
data:
auth-extra-groups: $(echo -n "$AUTH_EXTRA_GROUPS" | base64)
description: $(echo -n "$DESCRIPTION" | base64)
expiration: $(echo -n "$EXPIRATION" | base64)
token-id: $(echo -n "$TOKEN_ID" | base64)
token-secret: $(echo -n "$TOKEN_SECRET" | base64)
usage-bootstrap-authentication: $(echo -n "$USAGE_BOOTSTRAP_AUTHENTIFICATION" | base64)
usage-bootstrap-signing: $(echo -n "$USAGE_BOOTSTRAP_SIGNING" | base64)
type: bootstrap.kubernetes.io/token
EOF
This command must be executed on a master node or on a host with a kubeconfig that has permissions to manage bootstrap tokens.
kubeadm token create \
--kubeconfig=/etc/kubernetes/super-admin.conf \
--print-join-command \
--ttl 24h
kubeadm join api.my-first-cluster.example.com:6443 \
--token <generated-token> \
--discovery-token-ca-cert-hash sha256:<hash>
The obtained token can be used when creating
bootstrap-kubelet.confor passed to thekubeadm joinconfiguration.
Creating bootstrap-kubelet.conf
All commands in this section are executed on the worker node.
The ca.crt file is not yet present on the worker node. CA data is fetched from the public cluster-info ConfigMap
in the kube-public namespace, accessible anonymously via kube-apiserver.
Environment variables
export BOOTSTRAP_TOKEN=fjt9ex.lwzqgdlvoxtqk4yw
export API_SERVER="https://api.my-first-cluster.example.com:6443"
Working directory
mkdir -p /etc/kubernetes
Fetch CA from cluster-info
export CA_DATA=$(curl -sk "${API_SERVER}/api/v1/namespaces/kube-public/configmaps/cluster-info" | \
jq -r '.data.kubeconfig' | \
grep 'certificate-authority-data' | \
awk '{print $2}')
Save CA certificate
mkdir -p /etc/kubernetes/pki
echo "${CA_DATA}" | base64 -d > /etc/kubernetes/pki/ca.crt
Generate kubeconfig
cat <<EOF > /etc/kubernetes/bootstrap-kubelet.conf
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ${CA_DATA}
server: ${API_SERVER}
name: my-first-cluster
contexts:
- context:
cluster: my-first-cluster
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: ${BOOTSTRAP_TOKEN}
EOF
Kubernetes CSR (TLS Bootstrap simulation)
This approach simulates kubelet's TLS Bootstrap behavior: private keys are generated on the worker node, CSRs are submitted through the Kubernetes API using
bootstrap-kubelet.conf, and approval is performed by an administrator on the master node. The CA private key is not required on the worker node.
Kubelet Client Certificate (CSR)
● Required
Kubelet Client Certificate (CSR)
● Required
Purpose: Kubelet client certificate for connecting to kube-apiserver.
1. Generate key and CSR
All commands in this step are executed on the worker node.
export HOST_NAME=worker-1
export CLUSTER_NAME="my-first-cluster"
export BASE_DOMAIN="example.com"
export FULL_HOST_NAME="${HOST_NAME}.${CLUSTER_NAME}.${BASE_DOMAIN}"
mkdir -p /var/lib/kubelet/pki
mkdir -p /etc/kubernetes/openssl/csr
cat <<EOF > /etc/kubernetes/openssl/kubelet-client.conf
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
[ dn ]
CN = system:node:${FULL_HOST_NAME}
O = system:nodes
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=clientAuth
EOF
openssl genrsa \
-out /var/lib/kubelet/pki/kubelet-client-key.pem 2048
openssl req -new \
-key /var/lib/kubelet/pki/kubelet-client-key.pem \
-out /etc/kubernetes/openssl/csr/kubelet-client.csr \
-config /etc/kubernetes/openssl/kubelet-client.conf
2. Submit CSR to Kubernetes API
Worker node authenticates with the bootstrap token via bootstrap-kubelet.conf.
export HOST_NAME=worker-1
export CSR_NAME="${HOST_NAME}-kubelet-client"
export CSR_CONTENT=$(cat /etc/kubernetes/openssl/csr/kubelet-client.csr | base64 | tr -d '\n')
kubectl \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
apply -f - <<EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: ${CSR_NAME}
spec:
request: ${CSR_CONTENT}
signerName: kubernetes.io/kube-apiserver-client-kubelet
usages:
- digital signature
- key encipherment
- client auth
EOF
3. Approve CSR
CSR approval is performed on the master node. Specify the name of the worker node for which the CSR is being approved.
export HOST_NAME=worker-1
export CSR_NAME="${HOST_NAME}-kubelet-client"
kubectl \
--kubeconfig=/etc/kubernetes/super-admin.conf \
certificate approve ${CSR_NAME}
4. Retrieve signed certificate
Certificate is retrieved on the worker node using bootstrap-kubelet.conf.
export HOST_NAME=worker-1
export CSR_NAME="${HOST_NAME}-kubelet-client"
kubectl \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
get csr ${CSR_NAME} \
-o jsonpath='{.status.certificate}' | base64 -d > /var/lib/kubelet/pki/kubelet-client.pem
cat /var/lib/kubelet/pki/kubelet-client.pem /var/lib/kubelet/pki/kubelet-client-key.pem > /var/lib/kubelet/pki/kubelet-client-$(date '+%Y-%m-%d-%H-%M-%S').pem
ln -sf /var/lib/kubelet/pki/kubelet-client-$(date '+%Y-%m-%d-%H-%M-%S').pem /var/lib/kubelet/pki/kubelet-client-current.pem
Kubelet Server Certificate (CSR)
● Required
Kubelet Server Certificate (CSR)
● Required
Purpose: Kubelet server certificate for TLS on port 10250.
1. Generate key and CSR
All commands in this step are executed on the worker node.
export HOST_NAME=worker-1
export CLUSTER_NAME="my-first-cluster"
export BASE_DOMAIN="example.com"
export FULL_HOST_NAME="${HOST_NAME}.${CLUSTER_NAME}.${BASE_DOMAIN}"
export MACHINE_LOCAL_ADDRESS="$(ip -4 addr show scope global | awk '/inet/ {print $2; exit}' | cut -d/ -f1)"
mkdir -p /var/lib/kubelet/pki
mkdir -p /etc/kubernetes/openssl/csr
cat <<EOF > /etc/kubernetes/openssl/kubelet-server.conf
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = localhost
DNS.2 = ${HOST_NAME}
DNS.3 = ${FULL_HOST_NAME}
IP.1 = 127.0.0.1
IP.2 = 0:0:0:0:0:0:0:1
IP.3 = ${MACHINE_LOCAL_ADDRESS}
[ dn ]
CN = system:node:${FULL_HOST_NAME}
O = system:nodes
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth
subjectAltName=@alt_names
EOF
openssl genrsa \
-out /var/lib/kubelet/pki/kubelet-server-key.pem 2048
openssl req -new \
-key /var/lib/kubelet/pki/kubelet-server-key.pem \
-out /etc/kubernetes/openssl/csr/kubelet-server.csr \
-config /etc/kubernetes/openssl/kubelet-server.conf
2. Submit CSR to Kubernetes API
Worker node authenticates with the bootstrap token via bootstrap-kubelet.conf.
export HOST_NAME=worker-1
export CSR_NAME="${HOST_NAME}-kubelet-server"
export CSR_CONTENT=$(cat /etc/kubernetes/openssl/csr/kubelet-server.csr | base64 | tr -d '\n')
kubectl \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
apply -f - <<EOF
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: ${CSR_NAME}
spec:
request: ${CSR_CONTENT}
signerName: kubernetes.io/kubelet-serving
usages:
- digital signature
- key encipherment
- server auth
EOF
3. Approve CSR
CSR approval is performed on the master node. Specify the name of the worker node for which the CSR is being approved.
export HOST_NAME=worker-1
export CSR_NAME="${HOST_NAME}-kubelet-server"
kubectl \
--kubeconfig=/etc/kubernetes/super-admin.conf \
certificate approve ${CSR_NAME}
4. Retrieve signed certificate
Certificate is retrieved on the worker node using bootstrap-kubelet.conf.
export HOST_NAME=worker-1
export CSR_NAME="${HOST_NAME}-kubelet-server"
kubectl \
--kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf \
get csr ${CSR_NAME} \
-o jsonpath='{.status.certificate}' | base64 -d > /var/lib/kubelet/pki/kubelet-server.pem
cat /var/lib/kubelet/pki/kubelet-server.pem /var/lib/kubelet/pki/kubelet-server-key.pem > /var/lib/kubelet/pki/kubelet-server-$(date '+%Y-%m-%d-%H-%M-%S').pem
ln -sf /var/lib/kubelet/pki/kubelet-server-$(date '+%Y-%m-%d-%H-%M-%S').pem /var/lib/kubelet/pki/kubelet-server-current.pem
When using kubeadm, worker node authentication happens automatically during
kubeadm join. Kubeadm uses the bootstrap token from the configuration to obtain cluster-info, start kubelet, and perform TLS Bootstrap.
Generating a token
If the token was not created in advance or has expired, generate a new one.
This command must be executed on a master node or on a host with a kubeconfig that has permissions to manage bootstrap tokens.
kubeadm token create \
--kubeconfig=/etc/kubernetes/super-admin.conf \
--print-join-command \
--ttl 24h
kubeadm join api.my-first-cluster.example.com:6443 \
--token <generated-token> \
--discovery-token-ca-cert-hash sha256:<hash>
Kubeadm configuration
Use the obtained token in the kubeadm configuration file or pass it via command-line arguments.
This section depends on the following documents:
- Software Config (DP) — kubeadm configuration for the worker node.
Using a static config
kubeadm join \
--config=/var/run/kubeadm/kubeadm.yaml
Using a token from command line
kubeadm join \
api.my-first-cluster.example.com:6443 \
--token <generated-token> \
--discovery-token-ca-cert-hash sha256:<hash>