# GCP - Containers & GKE Enum {{#include ../../../banners/hacktricks-training.md}} ## Containers In GCP containers you can find most of the containers based services GCP offers, here you can see how to enumerate the most common ones: ```bash gcloud container images list gcloud container images list --repository us.gcr.io/ #Search in other subdomains repositories gcloud container images describe gcloud container subnets list-usable gcloud container clusters list gcloud container clusters describe gcloud container clusters get-credentials [NAME] # Run a container locally docker run --rm -ti gcr.io//secret:v1 sh # Login & Download sudo docker login -u oauth2accesstoken -p $(gcloud auth print-access-token) https://HOSTNAME ## where HOSTNAME is gcr.io, us.gcr.io, eu.gcr.io, or asia.gcr.io. sudo docker pull HOSTNAME// ``` ### Privesc In the following page you can check how to **abuse container permissions to escalate privileges**: {{#ref}} ../gcp-privilege-escalation/gcp-container-privesc.md {{#endref}} ## Node Pools These are the pool of machines (nodes) that form the kubernetes clusters. ```bash # Pool of machines used by the cluster gcloud container node-pools list --zone --cluster gcloud container node-pools describe --cluster --zone ``` ## Kubernetes For information about what is Kubernetes check this page: {{#ref}} ../../kubernetes-security/ {{#endref}} First, you can check to see if any Kubernetes clusters exist in your project. ``` gcloud container clusters list ``` If you do have a cluster, you can have `gcloud` automatically configure your `~/.kube/config` file. This file is used to authenticate you when you use [kubectl](https://kubernetes.io/docs/reference/kubectl/overview/), the native CLI for interacting with K8s clusters. Try this command. ``` gcloud container clusters get-credentials [CLUSTER NAME] --region [REGION] ``` Then, take a look at the `~/.kube/config` file to see the generated credentials. This file will be used to automatically refresh access tokens based on the same identity that your active `gcloud` session is using. This of course requires the correct permissions in place. Once this is set up, you can try the following command to get the cluster configuration. ``` kubectl cluster-info ``` You can read more about `gcloud` for containers [here](https://cloud.google.com/sdk/gcloud/reference/container/). This is a simple script to enumerate kubernetes in GCP: [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 When reviewing modern GKE clusters, separate Google Cloud IAM permissions, Kubernetes RBAC, pod workload identity, and node credentials. A Google principal can often retrieve cluster endpoint data with `container.clusters.get`, but the resulting Kubernetes requests still need to pass GKE/Kubernetes authorization and any network restrictions such as private endpoints or authorized networks. Workload Identity Federation for GKE is the preferred way for pods to access Google Cloud APIs. Check whether the cluster has a workload pool and whether Kubernetes service accounts are mapped directly as IAM principals or are allowed to impersonate IAM service accounts: ```bash gcloud container clusters describe --region \ --format='value(workloadIdentityConfig.workloadPool)' 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' ``` If a service account has the annotation `iam.gke.io/gcp-service-account`, review the IAM service account policy for `roles/iam.workloadIdentityUser` grants to Kubernetes service account principals. Also check IAM allow policies for direct workload identity principals or broad `principalSet://` grants, such as namespace-wide or cluster-wide workload access. The annotation `iam.gke.io/credential-quota-project` only moves IAM Service Account Credentials API quota to another project; the workload principal still needs `serviceusage.services.use` on that quota project and separate IAM access to the target resource. Metadata access depends on cluster mode, node pool configuration, and workload settings. Do not assume every pod can steal the node service account. In Workload Identity-enabled environments, ordinary pods should use the GKE metadata server to obtain the workload identity intended for their Kubernetes service account. Node compromise, `hostNetwork` pods in some Standard configurations, and legacy node metadata exposure can still change the blast radius, so verify the actual node pool metadata mode, node service account, OAuth scopes, and pod placement. If a Workload Identity-enabled pod cannot get a token, also check NetworkPolicy egress before assuming the IAM binding is wrong. GKE Standard clusters using NetworkPolicy must allow the metadata-server path required by the cluster version and dataplane, and Dataplane V2 uses the `169.254.169.254` path for metadata-server access. ### Autopilot privileged workload allowlists GKE Autopilot blocks most privileged workloads by default, but approved exceptions can exist. Review privileged admission settings, `AllowlistSynchronizer` objects, and installed `WorkloadAllowlist` objects before assuming a privileged pod is impossible: ```bash gcloud container clusters describe --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 Initially this privilege escalation technique allowed to **privesc inside the GKE cluster** effectively allowing an attacker to **fully compromise it**. 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**. 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/) Ans this tool was created to automate the process: [https://github.com/4ARMED/kubeletmein](https://github.com/4ARMED/kubeletmein) 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 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 ``` Even if the API **doesn't allow to modify resources**, it could be possible to find **sensitive information** in the response. The endpoint /pods was found using [**Kiterunner**](https://github.com/assetnote/kiterunner). {{#include ../../../banners/hacktricks-training.md}}