Skip to content

Instantly share code, notes, and snippets.

@azalio
Last active April 3, 2025 09:09
Show Gist options
  • Save azalio/59eafa5305e98631e4b2f02abc2c2e7d to your computer and use it in GitHub Desktop.
Save azalio/59eafa5305e98631e4b2f02abc2c2e7d to your computer and use it in GitHub Desktop.

flow

Дано: кластер собранный по kubernetes-hard-way 1.
Надо: присоединить ноду kubernetes с помощью bootstrap token.

  1. Включаем в kube-apiserver аутентификацию по токенам
--enable-bootstrap-token-auth
  1. Создаем 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
  1. Генерируем секрет и кладем его в 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.

  1. Создаем 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
  1. Кладем его на ноду, которую хотим подключить и правим конфиг 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
  1. Стартуем кубелет и смотрим за 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
  1. Можно посмотреть CSR
echo 'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlIdU1JR1dBZ0VBTURReEZUQVRCZ05WQkFvVERITjVjM1JsYlRwdWIyUmxjekViTUJrR0ExVUVBeE1TYzNsegpkR1Z0T201dlpHVTZibTlrWlMweE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTdrWFFEMWxzCnZtalE3cndyYjJGN1Q4UmxjRHJhdEtmTmJMT3poWVh1Q3VlQkZKM2g0U3p1VzhlSk55NEIzTTkwRStRTGJXdHkKTFF1dmJMRFFGSjYwM0tBQU1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lDV3lrWEp6Ty9DdEVXck5kQXZycStyawpxZFlUM0ozVW5rRUNqNXhoalFlK0FpQmswQ2ZkRW05RDBPVC81NDZSVVcxN2FRKy9KdGx3L1Y0UE5zeXpKT082CmZBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==' | base64 -d | openssl req -text
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: O = system:nodes, CN = system:node:node-1
        ...
  1. Апрувим CSR
kubectl certificate approve node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M
certificatesigningrequest.certificates.k8s.io/node-csr-espx2a2QPpOa5CokcGvAP6vR01p3NUFqUsBYNYxVQ5M approved
  1. Сертификат для этой ноды выпущен
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
  1. 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
  1. Сертификат выпустился и нода вошла в кластер.
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

  1. У меня есть улучшенный kubernetes-hard-way с поддержкой поднятия виртуалок для практики через Vagrant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment