# You could update instead of creategcloud container node-pools create <nodepoolname> --cluster=<cluser_name> --workload-metadata=GKE_METADATA --region=us-central1
K8sからGCP権限を持つGCPサービスアカウントを偽装するために作成します:
# Create SA called "gsa2ksa"gcloudiamservice-accountscreategsa2ksa--project=<project-id># Give "roles/iam.securityReviewer" role to the SAgcloudprojectsadd-iam-policy-binding<project-id> \--member "serviceAccount:gsa2ksa@<project-id>.iam.gserviceaccount.com" \--role "roles/iam.securityReviewer"
クラスタに接続し、使用するサービスアカウントを作成します
# Get k8s credsgcloudcontainerclustersget-credentials<cluster_name>--region=us-central1# Generate our testing namespacekubectlcreatenamespacetesting# Create the KSAkubectlcreateserviceaccountksa2gcp-ntesting
GSAとKSAをバインドする
# Allow the KSA to access the GSA in GCP IAMgcloudiamservice-accountsadd-iam-policy-bindinggsa2ksa@<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 GSAkubectlannotateserviceaccountksa2gcp \--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: v1kind: Podmetadata:name: workload-identity-testnamespace: <namespace>spec:containers:- image: google/cloud-sdk:slimname: workload-identity-testcommand: ['sleep','infinity']serviceAccountName: ksa2gcpnodeSelector:iam.gke.io/gke-metadata-server-enabled: 'true'"|kubectlapply-f-# Get inside the podkubectlexec-itworkload-identity-test \--namespace testing \-- /bin/bash# Check you can access the GSA from insie the pod withcurl-H"Metadata-Flavor: Google"http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/emailgcloudauthlist
K8s内の攻撃者としては、SA(Service Account)にiam.gke.io/gcp-service-accountアノテーションがあるかどうかを検索すべきです。これは、SAがGCP内の何かにアクセスできることを示しています。別のオプションとしては、クラスタ内の各KSA(Kubernetes Service Account)を悪用し、そのアクセス権限を確認することが考えられます。
GCPからは、常にバインディングを列挙し、Kubernetes内のSAにどのようなアクセス権限を与えているかを把握することが興味深いです。
これは、すべてのポッド定義を簡単に繰り返し処理し、そのアノテーションを探すスクリプトです:
for ns in`kubectlgetnamespaces-ocustom-columns=NAME:.metadata.name|grep-vNAME`; dofor pod in`kubectlgetpods-n "$ns" -ocustom-columns=NAME:.metadata.name|grep-vNAME`; doecho"Pod: $ns/$pod"kubectlgetpod"$pod"-n"$ns"-oyaml|grep"gcp-service-account"echo""echo""donedone|grep-B1"gcp-service-account"
# Create a service account with a rolecat>my-service-account.yaml<<EOFapiVersion: v1kind: ServiceAccountmetadata:name: my-service-accountnamespace: defaultannotations:eks.amazonaws.com/role-arn: arn:aws:iam::318142138553:role/EKSOIDCTestingEOFkubectlapply-fmy-service-account.yaml# Add a role to an existent service accountkubectl annotate serviceaccount -n $namespace $service_account eks.amazonaws.com/role-arn=arn:aws:iam::$account_id:role/my-role
for ns in`kubectlgetnamespaces-ocustom-columns=NAME:.metadata.name|grep-vNAME`; dofor pod in`kubectlgetpods-n "$ns" -ocustom-columns=NAME:.metadata.name|grep-vNAME`; doecho"Pod: $ns/$pod"kubectlgetpod"$pod"-n"$ns"-oyaml|grep"amazonaws.com"echo""echo""donefor sa in`kubectlgetserviceaccounts-n "$ns" -ocustom-columns=NAME:.metadata.name|grep-vNAME`; doecho"SA: $ns/$sa"kubectlgetserviceaccount"$sa"-n"$ns"-oyaml|grep"amazonaws.com"echo""echo""donedone|grep-B1"amazonaws.com"
ノード IAM ロール
前のセクションでは、ポッドで IAM ロールを盗む方法について説明しましたが、K8s クラスターのノードはクラウド内のインスタンスになります。つまり、ノードは非常に高い確率で盗むことができる新しい IAM ロールを持つ可能性があります(通常、K8s クラスターのすべてのノードが同じ IAM ロールを持つため、各ノードをチェックしようとする価値がないかもしれません)。