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

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

#目次
[こちらをご覧ください](https://qiita.com/theFirstPenguin/items/1f702af92f4eee83f398#%E7%9B%AE%E6%AC%A1)

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

##まえおき

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

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

が必要ですが、workerノードの数は条件によって常に増減するので、前回のworker-1ノードのときのように、上記全てを全てのworkerノードに対して行うのは手間となります。
そこで、[こちらに記載されているとおり](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#initialization-process)、**TLS証明書の作成の部分を自動化する設定**を行います。
> Creating a key and certificate for each kubelet; strongly recommended to have a unique one, with a unique CN, for each kubelet

![スクリーンショット 2021-01-16 11.52.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/572098/b3d142c8-779f-ea93-d0ea-241d0502a920.png)


##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
[参考](https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/)

```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`
[参照](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#authorize-kubelet-to-create-csr)

```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`
[参考](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#approval)

```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`
[参考](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#approval)

```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.crt`と`ca.key`をmasterノードの`/var/lib/kubernetes/ca.cert`と`/var/lib/kubernetes/ca-key`に配置します。(すでに設定済です)
[参考](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#certificate-authority)

確認のため、認証局の証明書を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ファイルを作成して適用します。
[参考](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubelet-configuration)

```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コマンドから行うことができます。
[参考](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubectl-approval)

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