CVE-2018-1002105: proxy request handling in kube-apiserver can leave vulnerable TCP connections




[ Enable API Aggregation ]


## kube-apiserver 에 옵션에 다음과 같이 설정

--requestheader-client-ca-file=/etc/kubernetes/ssl/front-proxy-ca.crt
--requestheader-allowed-names=front-proxy-client
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--proxy-client-cert-file=/etc/kubernetes/ssl/front-proxy-client.crt
--proxy-client-key-file=/etc/kubernetes/ssl/front-proxy-client.key



[ Metrics API 서버 설치 ]

$ mkdir -p ~/ahnsk/metric-server && cd ~/ahnsk
$ cd metrics-server

$ kubectl create -f deploy/1.8+/

$ kubectl -n kube-system get pods -l k8s-app=metrics-server


## metric-server 로그 보기
kubectl -n kube-system logs $(kubectl get pods --namespace=kube-system -l k8s-app=metrics-server -o name)


## metric-server 가 hostname 을 알지 못한다는 로그가 나오면 metric-server 를 변경

$ kubectl edit deployment metrics-server -n kube-system
image: k8s.gcr.io/metrics-server-amd64:v0.3.0
command:
- /metrics-server
- --kubelet-insecure-tls
- --kubelet-preferred-address-types=InternalIP



[ 취약점 확인 ]

## 1.12.2 버전에서는 metric-server 가 node 의 stats 을 가져오고 있음
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.2", GitCommit:"17c77c7898218073f14c8d573582e8d2313dc740", GitTreeState:"clean", BuildDate:"2018-10-24T06:43:59Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.2", GitCommit:"17c77c7898218073f14c8d573582e8d2313dc740", GitTreeState:"clean", BuildDate:"2018-10-24T06:43:59Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}

$ kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/metrics.k8s.io/v1beta1/nodes"},"items":[{"metadata":{"name":"k1-master01","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-master01","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:09Z","window":"30s","usage":{"cpu":"425054529n","memory":"13992336Ki"}},{"metadata":{"name":"k1-master02","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-master02","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:17Z","window":"30s","usage":{"cpu":"174426537n","memory":"10275528Ki"}},{"metadata":{"name":"k1-master03","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-master03","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:15Z","window":"30s","usage":{"cpu":"322881470n","memory":"10741952Ki"}},{"metadata":{"name":"k1-node01","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-node01","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:14Z","window":"30s","usage":{"cpu":"309956501n","memory":"14327216Ki"}},{"metadata":{"name":"k1-node02","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-node02","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:12Z","window":"30s","usage":{"cpu":"363826460n","memory":"17359508Ki"}},{"metadata":{"name":"k1-node03","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-node03","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:07Z","window":"30s","usage":{"cpu":"256312214n","memory":"15248572Ki"}},{"metadata":{"name":"k1-node04","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-node04","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:13Z","window":"30s","usage":{"cpu":"124689837n","memory":"11814000Ki"}},{"metadata":{"name":"k1-node05","selfLink":"/apis/metrics.k8s.io/v1beta1/nodes/k1-node05","creationTimestamp":"2018-12-05T08:38:13Z"},"timestamp":"2018-12-05T08:37:15Z","window":"30s","usage":{"cpu":"114905912n","memory":"8340284Ki"}}]}



## 1.11.5 패치 적용된 버전에서는 metric-server 가 system:anonymous 계정으로 node 의 stats 을 가져오지 못함
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T18:02:47Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.5", GitCommit:"753b2dbc622f5cc417845f0ff8a77f539a4213ea", GitTreeState:"clean", BuildDate:"2018-11-26T14:31:35Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"}

$ kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
{"kind":"NodeMetricsList","apiVersion":"metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/metrics.k8s.io/v1beta1/nodes"},"items":[]}

$ kubectl logs metrics-server-695bdf6996-sg429 -n kube-system
E1205 08:14:30.157105       1 manager.go:102] unable to fully collect metrics: unable to fully scrape metrics from source kubelet_summary:node1: unable to fetch metrics from Kubelet node1 (192.168.0.93): request failed - "403 Forbidden", response:"Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=stats)"
E1205 08:15:30.148565       1 manager.go:102] unable to fully collect metrics: unable to fully scrape metrics from source kubelet_summary:node1: unable to fetch metrics from Kubelet node1 (192.168.0.93): request failed - "403 Forbidden", response:"Forbidden (user=system:anonymous, verb=get, resource=nodes, subresource=stats)"



[ work around 로 해결하는 방법 ]


1. kube-apiserver 옵션에 --anonymous-auth=false 를 넣는 방법 (default 는 true 임)

2. 아래 clusterrolebinding 의 system:basic-user 와 system:discovery 에 들어있는 system:unauthenticated Group 을 삭제

$ kubectl get clusterrolebindings system:basic-user -o yaml
kubectl get clusterrolebindings system:basic-user -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: 2018-11-21T08:44:59Z
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:basic-user
  resourceVersion: "113"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/system%3Abasic-user
  uid: bae78dd9-ed69-11e8-b322-3ca82a1c0c40
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:basic-user
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:authenticated
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: system:unauthenticated


그리고 clusterrole 의 system:basic-user 와 system:discovery 에 세팅된 auto repaired 를 false 로 변경


$ kubectl get clusterroles system:basic-user -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: 2018-11-21T08:44:59Z
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:basic-user
  resourceVersion: "58"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterroles/system%3Abasic-user
  uid: baae6ff5-ed69-11e8-b322-3ca82a1c0c40
rules:
- apiGroups:
  - authorization.k8s.io
  resources:
  - selfsubjectaccessreviews
  - selfsubjectrulesreviews
  verbs:
  - create







Posted by Kubernetes Korea co-leader seungkyua@gmail.com