Дано: кластер собранный по kubernetes-hard-way 1.
Надо: присоединить ноду kubernetes с помощью bootstrap token.
- Включаем в kube-apiserver аутентификацию по токенам
--enable-bootstrap-token-auth
- Создаем clusterrolebinding для того, чтобы пришедший kubelet с токеном смог создать CSR.
cat << EOF | kubectl apply -f -
kind: ClusterRoleBinding
metadata:
name: kubelet-bootstrap
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:node-bootstrapper
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:bootstrappers:default-node-token
EOF
- Генерируем секрет и кладем его в ns kube-system
TOKEN_ID=$(openssl rand -hex 3)
TOKEN_SECRET=$(openssl rand -hex 8)
cat << EOF | kubectl apply -n kube-system -f -
apiVersion: v1
kind: Secret
type: bootstrap.kubernetes.io/token
metadata:
name: bootstrap-token-$TOKEN_ID
namespace: kube-system
stringData:
description: "Token for node-1"
token-id: "$TOKEN_ID"
token-secret: "$TOKEN_SECRET"
auth-extra-groups: "system:bootstrappers:default-node-token"
usage-bootstrap-authentication: "true"
EOF
Обратите внимание на auth-extra-groups: "system:bootstrappers:default-node-token"
- именно так мы указываем какую дополнительную группу накинуть юзеру пришедшему с этим токеном. И именно эту группу мы привязали в clusterrolebinding.
- Создаем kubeconfig-bootstrap файл
# Вытаскиваем CA из конфигмапы, но это можно сделать и любым другим удобным вам способом.
CA="$(kubectl get cm kube-root-ca.crt -n kube-system -o jsonpath='{.data.ca\.crt}' | base64 | tr -d '\n')"
# Так же сервер можно вытащить через kubectl config view -o jsonpath='{.clusters[0].cluster.server}'
SERVER="https://server.kubernetes.local:6443"
cat << EOF > kubelet-bootstrap.yaml
apiVersion: v1
kind: Config
clusters:
- name: local
cluster:
certificate-authority-data: "$CA"
server: "$SERVER"
users:
- name: kubelet
user:
token: "$TOKEN_ID.$TOKEN_SECRET"
contexts:
- context:
cluster: local
user: kubelet
EOF
- Кладем его на ноду, которую хотим подключить и правим конфиг kubelet.
# --bootstrap-kubeconfig
ExecStart=/usr/local/bin/kubelet \
--config=/var/lib/kubelet/kubelet-config.yaml \
--bootstrap-kubeconfig=/var/lib/kubelet/bootstrap-kubeconfig.yaml \
--kubeconfig=/var/lib/kubelet/kubeconfig \
--register-node=true \
--v=2
- Стартуем кубелет и смотрим за CSR
kubectl get csr -w
NAMESPACE NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M 10s kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:26c725 <none> Pending
- Можно посмотреть CSR
echo 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlIdU1JR1dBZ0VBTURReEZUQVRCZ05WQkFvVERITjVjM1JsYlRwdWIyUmxjekViTUJrR0ExVUVBeE1TYzNsegpkR1Z0T201dlpHVTZibTlrWlMweE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTdrWFFEMWxzCnZtalE3cndyYjJGN1Q4UmxjRHJhdEtmTmJMT3poWVh1Q3VlQkZKM2g0U3p1VzhlSk55NEIzTTkwRStRTGJXdHkKTFF1dmJMRFFGSjYwM0tBQU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lDV3lrWEp6Ty9DdEVXck5kQXZycStyawpxZFlUM0ozVW5rRUNqNXhoalFlK0FpQmswQ2ZkRW05RDBPVC81NDZSVVcxN2FRKy9KdGx3L1Y0UE5zeXpKT082CmZBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==' | base64 -d | openssl req -text
Certificate Request:
Data:
Version: 1 (0x0)
Subject: O = system:nodes, CN = system:node:node-1
...
- Апрувим CSR
kubectl certificate approve node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M
certificatesigningrequest.certificates.k8s.io/node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M approved
- Сертификат для этой ноды выпущен
kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M 48m kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:26c725 <none> Approved,Issued
- kubelet на ноде после старта создал CSR, который мы видели выше и ожидал аппрува
Nov 24 19:28:50 node-1 kubelet[6868]: I1124 19:28:50.060860 6868 bootstrap.go:120] "Using bootstrap kubeconfig to generate TLS client cert, key and kubeconfig file"
Nov 24 19:28:50 node-1 kubelet[6868]: I1124 19:28:50.061317 6868 bootstrap.go:151] "No valid private key and/or certificate found, reusing existing private key or creating a new one"
Nov 24 19:28:50 node-1 kubelet[6868]: I1124 19:28:50.075410 6868 bootstrap.go:358] "Waiting for client certificate to be issued"
Nov 24 19:30:39 node-1 kubelet[6868]: I1124 19:30:39.539281 6868 csr.go:261] certificate signing request node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M is approved, waiting to be issued
Nov 24 19:30:39 node-1 kubelet[6868]: I1124 19:30:39.548262 6868 csr.go:257] certificate signing request node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M is issued
- Сертификат выпустился и нода вошла в кластер.
kubectl get node
NAME STATUS ROLES AGE VERSION
node-0 Ready <none> 138m v1.28.3
node-1 Ready <none> 49m v1.28.3
Понятное дело, что апрувить каждый сертификат не дело, поэтому можно включить автоапрувер в kube-controller-manager.
Токену можно сделать TTL и через TTL он перестанет приниматься kube-apiserver, что улучшает безопасность нод.
Примерно так и работает kubeadm token.
Об этом и многом другом я пишу в своем канале, присоединяйтесь!
Footnotes
-
У меня есть улучшенный kubernetes-hard-way с поддержкой поднятия виртуалок для практики через Vagrant. ↩