Kubernetes the hard way を初学者目線で解説する ~ #8 WorkerノードのTLS証明書作成自動化


はじめに

30代未経験からエンジニアを目指して勉強中のYNと申します。
インフラ初学者の私ですが、Kubernetes the hard wayを進めるにあたって、インフラに関する基本的な知識を体系的に学ぶことができました。
そこで、初学者目線での学びなどを本記事にまとめておきたいと思います。

目次

こちらをご覧ください

TLS証明書の作成の部分を自動化する

まえおき

workerノードの追加のためには

  • kubeletkube-proxyのTLS証明書の作成
  • kube-proxyの設定とデプロイ
  • kubeletの設定とデプロイ

が必要ですが、workerノードの数は条件によって常に増減するので、前回のworker-1ノードのときのように、上記全てを全てのworkerノードに対して行うのは手間となります。
そこで、こちらに記載されているとおりTLS証明書の作成の部分を自動化する設定を行います。

Creating a key and certificate for each kubelet; strongly recommended to have a unique one, with a unique CN, for each kubelet

API-serverの設定

API-serverは、kubeletを(1)system:bootstrappersグループとして認証し、(2)CSRを提出する権限を与えます。

(1)system:bootstrappersグループとして認証

kubeletにBootstrap Tokenを付与し、system:bootstrappersグループとして認証します。このためにAPI-serverの設定が--enable-bootstrap-token-auth=trueとなっていることを確認します。(これは既に、systemdのserviceの設定時にkube-apiserver.serviceに指定済です)そして、下記のようにTokenについてのsecretを発行します。

Create a Kubernetes secret with the token ID, secret and scope(s).
Issue the token to the kubelet
参考

master-1.node
cat > bootstrap-token-07401b.yaml <<EOF
apiVersion: v1
kind: Secret
metadata:
  # Name MUST be of form "bootstrap-token-<token id>"
  name: bootstrap-token-07401b
  namespace: kube-system

# Type MUST be 'bootstrap.kubernetes.io/token'
type: bootstrap.kubernetes.io/token
stringData:
  # Human readable description. Optional.
  description: "The default bootstrap token generated by 'kubeadm init'."

  # Token ID and secret. Required.
  token-id: 07401b
  token-secret: f395accd246ae52d

  # Expiration. Optional.
  expiration: 2021-03-10T03:22:11Z

  # Allowed usages.
  usage-bootstrap-authentication: "true"
  usage-bootstrap-signing: "true"

  # Extra groups to authenticate the token as. Must start with "system:bootstrappers:"
  auth-extra-groups: system:bootstrappers:worker
EOF
master-1.node
kubectl create -f bootstrap-token-07401b.yaml

(2) system:bootstrappersグループにCSRを提出する権限を与える

To do this, you just need to create a ClusterRoleBinding that binds the system:bootstrappers group to the cluster role system:node-bootstrapper
参照

master-1.node
cat > csrs-for-bootstrapping.yaml <<EOF
# enable bootstrapping nodes to create CSR
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: create-csrs-for-bootstrapping
subjects:
- kind: Group
  name: system:bootstrappers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: system:node-bootstrapper
  apiGroup: rbac.authorization.k8s.io
EOF
master-1.node
kubectl create -f csrs-for-bootstrapping.yaml

controller-managerの設定

上記によってkubeletが得られたCSRに対して、controller-managerがkubeletのTLS証明書を発行します。
このために、controller-managerの設定において、--cluster-signing-cert-file--cluster-signing-key-fileを指定する必要があります。(これは既に、systemdのserviceの設定時にkube-controller-manager.serviceに指定済です)
また、下記のようにTLS証明書の発行ができることを示すClusterRoleBindingの設定が必要です。

To enable the kubelet to request and receive a new certificate, create a ClusterRoleBinding that binds the group in which the bootstrapping node is a member system:bootstrappers to the ClusterRole that grants it permission, system:certificates.k8s.io:certificatesigningrequests:nodeclient
参考

master-1.node
cat > auto-approve-csrs-for-group.yaml <<EOF
# Approve all CSRs for the group "system:bootstrappers"
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: auto-approve-csrs-for-group
subjects:
- kind: Group
  name: system:bootstrappers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: system:certificates.k8s.io:certificatesigningrequests:nodeclient
  apiGroup: rbac.authorization.k8s.io
EOF
master-1.node
kubectl create -f auto-approve-csrs-for-group.yaml

TLS証明書の更新

kubeletのTLS証明書の有効期限が切れた場合の更新も自動化できます。

To enable the kubelet to renew its own client certificate, create a ClusterRoleBinding that binds the group in which the fully functioning node is a member system:nodes to the ClusterRole that grants it permission, system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
参考

master-1.node
cat > auto-approve-renewals-for-nodes.yaml <<EOF
# Approve renewal CSRs for the group "system:nodes"
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: auto-approve-renewals-for-nodes
subjects:
- kind: Group
  name: system:nodes
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: system:certificates.k8s.io:certificatesigningrequests:selfnodeclient
  apiGroup: rbac.authorization.k8s.io
EOF
master-1.node
kubectl create -f auto-approve-renewals-for-nodes.yaml

worker-2ノードの設定

事前準備

ルート証明書の準備

ルート認証局証明書であるca.crtca.keyをmasterノードの/var/lib/kubernetes/ca.cert/var/lib/kubernetes/ca-keyに配置します。(すでに設定済です)
参考

確認のため、認証局の証明書をworker-2ノードにコピーします。

master-1.node
scp ca.crt worker-2:~/

kubectl, kube-proxy, kubeletのインストール

worker-2ノードにkubectl, kube-proxy, kubeletをインストールします。

worker-2.node
wget -q --show-progress --https-only --timestamping \
  https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl \
  https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kube-proxy \
  https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubelet

適切なディレクトリに移動して実行権限を付与します。

worker-2.node
sudo mkdir -p \
  /etc/cni/net.d \
  /opt/cni/bin \
  /var/lib/kubelet \
  /var/lib/kube-proxy \
  /var/lib/kubernetes \
  /var/run/kubernetes
worker-2.node
{
  chmod +x kubectl kube-proxy kubelet
  sudo mv kubectl kube-proxy kubelet /usr/local/bin/
}

worker-2ノードにTLS証明書作成の自動化設定を適用する

kubeletのconfigファイルを作成して適用します。
参考

worker-2.node
cat <<EOF | sudo tee /var/lib/kubelet/bootstrap-kubeconfig
apiVersion: v1
clusters:
- cluster:
    certificate-authority: /var/lib/kubernetes/ca.crt
    server: https://192.168.5.30:6443
  name: bootstrap
contexts:
- context:
    cluster: bootstrap
    user: kubelet-bootstrap
  name: bootstrap
current-context: bootstrap
kind: Config
preferences: {}
users:
- name: kubelet-bootstrap
  user:
    token: 07401b.f395accd246ae52d
EOF

kubelet-config.yamlファイルをつくる

これは前回のworke-1ノードのときと同じ手順です。

worker-2.node
cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: "/var/lib/kubernetes/ca.crt"
authorization:
  mode: Webhook
clusterDomain: "cluster.local"
clusterDNS:
  - "10.96.0.10"
resolvConf: "/run/systemd/resolve/resolv.conf"
runtimeRequestTimeout: "15m"
EOF

kubelet.serviceファイルを設定する

これも前回のworke-1ノードのときと同じ手順です。

worker-2.node
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=docker.service
Requires=docker.service

[Service]
ExecStart=/usr/local/bin/kubelet \\
  --bootstrap-kubeconfig="/var/lib/kubelet/bootstrap-kubeconfig" \\
  --config=/var/lib/kubelet/kubelet-config.yaml \\
  --image-pull-progress-deadline=2m \\
  --kubeconfig=/var/lib/kubelet/kubeconfig \\
  --cert-dir=/var/lib/kubelet/pki/ \\
  --rotate-certificates=true \\
  --rotate-server-certificates=true \\
  --network-plugin=cni \\
  --register-node=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

kube-proxyの設定

これも前回のworke-1ノードのときと同じ手順です。

worker-2.node
sudo mv kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig
worker-2.node
cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: "/var/lib/kube-proxy/kubeconfig"
mode: "iptables"
clusterCIDR: "192.168.5.0/24"
EOF
worker-2.node
cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-proxy \\
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

kubeletとkube-proxyを起動する

これも前回のworke-1ノードのときと同じ手順です。

worker-2.node
{
  sudo systemctl daemon-reload
  sudo systemctl enable kubelet kube-proxy
  sudo systemctl start kubelet kube-proxy
}

CSRを承認してkubeletのTLS証明書を有効化する

CSRの承認は外部ツールもしくはkubectlコマンドから行うことができます。
参考

master-1.node
kubectl get csr
kubectl certificate approve <name>
# or kubectl certificate deny <name>