Skip to content

Commit fdd3d95

Browse files
committed
Add local cloud Kubernetes updates
1 parent 42c3a88 commit fdd3d95

10 files changed

Lines changed: 357 additions & 55 deletions

File tree

src/pentesting-cloud/gcp-security/gcp-services/gcp-containers-gke-and-composer-enum.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,24 @@ You can read more about `gcloud` for containers [here](https://cloud.google.com/
7474

7575
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)
7676

77+
### Current GKE identity and metadata checks
78+
79+
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.
80+
81+
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:
82+
83+
```bash
84+
gcloud container clusters describe <cluster> --region <region> \
85+
--format='value(workloadIdentityConfig.workloadPool)'
86+
87+
kubectl get serviceaccounts -A -o yaml | grep -n 'iam.gke.io' -B 5 -A 8
88+
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName'
89+
```
90+
91+
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 principal sets.
92+
93+
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.
94+
7795
### TLS Boostrap Privilege Escalation
7896

7997
Initially this privilege escalation technique allowed to **privesc inside the GKE cluster** effectively allowing an attacker to **fully compromise it**.
@@ -104,4 +122,3 @@ Even if the API **doesn't allow to modify resources**, it could be possible to f
104122
{{#include ../../../banners/hacktricks-training.md}}
105123

106124

107-

src/pentesting-cloud/kubernetes-security/abusing-roles-clusterroles-in-kubernetes/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ curl -v -H "Authorization: Bearer <jwt_token>" https://<master_ip>:<port>/api/v1
357357

358358
### Creating and Reading Secrets
359359

360-
There is a special kind of a Kubernetes secret of type **kubernetes.io/service-account-token** which stores serviceaccount tokens.
360+
There is a special kind of Kubernetes Secret of type **kubernetes.io/service-account-token** which stores service account tokens. Modern Kubernetes versions do **not** automatically create one long-lived Secret for every ServiceAccount; projected, bound TokenRequest tokens are the normal workload path. However, manually created service account token Secrets are still supported, and upgraded or legacy clusters may still contain long-lived token Secrets. Current clusters can also mark unused auto-generated legacy token Secrets invalid and eventually clean them up, leaving labels such as `kubernetes.io/legacy-token-invalid-since` and `kubernetes.io/legacy-token-last-used`.
361+
361362
If you have permissions to create and read secrets, and you also know the serviceaccount's name, you can create a secret as follows and then steal the victim serviceaccount's token from it:
362363

363364
```yaml
@@ -870,4 +871,3 @@ https://github.com/aquasecurity/kube-bench
870871
{{#include ../../../banners/hacktricks-training.md}}
871872

872873

873-

src/pentesting-cloud/kubernetes-security/exposing-services-in-kubernetes.md

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ kubectl get services --all-namespaces -o=custom-columns='NAMESPACE:.metadata.nam
116116

117117
Traffic that ingresses into the cluster with the **external IP** (as **destination IP**), on the Service port, will be **routed to one of the Service endpoints**. `externalIPs` are not managed by Kubernetes and are the responsibility of the cluster administrator.
118118

119+
`externalIPs` is a sensitive route-control field because a user who can set it might claim traffic for an IP address the Service owner should not control if the surrounding network routes that IP to the cluster. Kubernetes announced the deprecation and planned removal of Service `externalIPs` in v1.36, so prefer controller-owned exposure mechanisms such as LoadBalancer integrations or Gateway API where possible, and restrict/admit this field carefully while it still exists.
120+
119121
In the Service spec, `externalIPs` can be specified along with any of the `ServiceTypes`. In the example below, "`my-service`" can be accessed by clients on "`80.11.12.10:80`" (`externalIP:port`)
120122

121123
```yaml
@@ -160,6 +162,21 @@ List all ExternalNames:
160162
kubectl get services --all-namespaces | grep ExternalName
161163
```
162164

165+
### EndpointSlices
166+
167+
EndpointSlices show the concrete backend addresses and ports that a Service currently routes to. They are especially useful when a Service has no selector, when labels do not explain the traffic path, or when only some backends are ready.
168+
169+
List EndpointSlices associated with Services:
170+
171+
```bash
172+
kubectl get endpointslices --all-namespaces
173+
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> -o yaml
174+
kubectl get endpointslice -n <namespace> -l kubernetes.io/service-name=<service-name> \
175+
-o custom-columns='NAME:.metadata.name,ADDR:.endpoints[*].addresses,READY:.endpoints[*].conditions.ready,PORTS:.ports[*].port'
176+
```
177+
178+
When reviewing exposure, compare the Service selector with the EndpointSlice `targetRef`, endpoint addresses, readiness conditions, and ports. A selectorless Service can be paired with manually managed EndpointSlices and route traffic to non-Pod or unexpected destinations.
179+
163180
### Ingress
164181

165182
Unlike all the above examples, **Ingress is NOT a type of service**. Instead, it sits **in front of multiple services and act as a “smart router”** or entrypoint into your cluster.
@@ -171,28 +188,37 @@ The default GKE ingress controller will spin up a [HTTP(S) Load Balancer](https:
171188
The YAML for a Ingress object on GKE with a [L7 HTTP Load Balancer](https://cloud.google.com/compute/docs/load-balancing/http/) might look like this:
172189

173190
```yaml
174-
apiVersion: extensions/v1beta1
191+
apiVersion: networking.k8s.io/v1
175192
kind: Ingress
176193
metadata:
177194
name: my-ingress
178195
spec:
179-
backend:
180-
serviceName: other
181-
servicePort: 8080
196+
defaultBackend:
197+
service:
198+
name: other
199+
port:
200+
number: 8080
182201
rules:
183202
- host: foo.mydomain.com
184203
http:
185204
paths:
186-
- backend:
187-
serviceName: foo
188-
servicePort: 8080
205+
- path: /
206+
pathType: Prefix
207+
backend:
208+
service:
209+
name: foo
210+
port:
211+
number: 8080
189212
- host: mydomain.com
190213
http:
191214
paths:
192-
- path: /bar/*
215+
- path: /bar
216+
pathType: Prefix
193217
backend:
194-
serviceName: bar
195-
servicePort: 8080
218+
service:
219+
name: bar
220+
port:
221+
number: 8080
196222
```
197223

198224
List all the ingresses:
@@ -207,12 +233,29 @@ Although in this case it's better to get the info of each one by one to read it
207233
kubectl get ingresses --all-namespaces -o=yaml
208234
```
209235

236+
### Gateway API
237+
238+
Gateway API is the newer Kubernetes API for exposing Services. It separates infrastructure-owned Gateway objects from application-owned Route objects such as HTTPRoute. This is useful for delegation, but it also means exposure can be split across namespaces.
239+
240+
List Gateway API exposure objects:
241+
242+
```bash
243+
kubectl get gatewayclasses
244+
kubectl get gateways --all-namespaces
245+
kubectl get httproutes --all-namespaces
246+
kubectl get gateway -n <namespace> <gateway-name> -o yaml
247+
kubectl get httproute -n <namespace> <route-name> -o yaml
248+
```
249+
250+
Check Gateway listeners, allowed route namespaces, Route `parentRefs`, hostnames, filters, backend references, and status conditions such as whether the route was accepted. A Route that is accepted by a shared Gateway can expose a backend even when no legacy Ingress object exists.
251+
210252
### References
211253

212254
- [https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0](https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0)
213255
- [https://kubernetes.io/docs/concepts/services-networking/service/](https://kubernetes.io/docs/concepts/services-networking/service/)
256+
- [https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/](https://kubernetes.io/blog/2026/05/14/kubernetes-v1-36-deprecation-and-removal-of-service-externalips/)
257+
- [https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)
258+
- [https://gateway-api.sigs.k8s.io/](https://gateway-api.sigs.k8s.io/)
214259

215260
{{#include ../../banners/hacktricks-training.md}}
216261

217-
218-

src/pentesting-cloud/kubernetes-security/kubernetes-enumeration.md

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,23 @@ k api-resources --namespaced=false #Resources NOT specific to a namespace
192192
{{#endtab }}
193193
{{#endtabs }}
194194

195+
### Object metadata worth checking
196+
197+
When you can read an object, export the full YAML or JSON instead of relying only on table output or `describe`. The most useful security context is often in generic object fields that exist across many resource types:
198+
199+
```bash
200+
kubectl get pod <pod> -n <ns> -o yaml
201+
kubectl get deploy <deploy> -n <ns> -o json | jq '.metadata, .spec, .status'
202+
kubectl get pods -A -o custom-columns='NS:.metadata.namespace,NAME:.metadata.name,SA:.spec.serviceAccountName,NODE:.spec.nodeName,PHASE:.status.phase'
203+
```
204+
205+
- `metadata.uid`, `name`, `namespace`, `apiVersion` and `kind` identify the exact object and avoid confusion between objects with the same name in different namespaces or API groups.
206+
- `metadata.labels` and selectors connect Services, Deployments, ReplicaSets, Pods, NetworkPolicies and automation. Following selectors is often the fastest way to identify the real backend pods for a Service.
207+
- `metadata.annotations` can leak operational context such as ingress behavior, cloud load balancer settings, GitOps or Helm metadata, policy exemptions, and service mesh configuration. They should not contain secrets, but real clusters often expose useful clues there.
208+
- `metadata.ownerReferences` shows controller lineage. If a Pod is owned by a ReplicaSet owned by a Deployment, changing or deleting only the Pod usually does not fix the source.
209+
- `metadata.finalizers` and `metadata.deletionTimestamp` explain resources stuck in deletion and can reveal cleanup controllers or persistence/disruption tricks.
210+
- `status`, Events, and conditions can reveal node placement, pod IPs, image IDs, failure messages, scheduling issues, admission denials, and controller progress. They are useful clues, but audit logs are still required to prove who performed an action.
211+
195212
### Get Current Privileges
196213

197214
{{#tabs }}
@@ -330,7 +347,7 @@ kurl -k -v https://$APISERVER/api/v1/namespaces/{namespace}/serviceaccounts
330347

331348
### Get Deployments
332349

333-
The deployments specify the **components** that need to be **run**.
350+
Deployments specify the desired state for stateless application workloads. They create ReplicaSets, and those ReplicaSets create Pods.
334351

335352
{{#tabs }}
336353
{{#tab name="kubectl" }}
@@ -345,7 +362,30 @@ k get deployments -n custnamespace
345362
{{#tab name="API" }}
346363

347364
```bash
348-
kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/deployments/
365+
kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/deployments/
366+
```
367+
368+
{{#endtab }}
369+
{{#endtabs }}
370+
371+
### Get StatefulSets
372+
373+
StatefulSets manage Pods that need stable names, ordered rollout behavior, and often per-replica persistent volumes.
374+
375+
{{#tabs }}
376+
{{#tab name="kubectl" }}
377+
378+
```bash
379+
k get statefulsets
380+
k get statefulsets -n custnamespace
381+
```
382+
383+
{{#endtab }}
384+
385+
{{#tab name="API" }}
386+
387+
```bash
388+
kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/statefulsets/
349389
```
350390

351391
{{#endtab }}
@@ -391,7 +431,7 @@ k get services -n custnamespace
391431
{{#tab name="API" }}
392432

393433
```bash
394-
kurl -v https://$APISERVER/api/v1/namespaces/default/services/
434+
kurl -v https://$APISERVER/api/v1/namespaces/<namespace>/services/
395435
```
396436

397437
{{#endtab }}
@@ -421,7 +461,7 @@ kurl -v https://$APISERVER/api/v1/nodes/
421461

422462
### Get DaemonSets
423463

424-
**DaeamonSets** allows to ensure that a **specific pod is running in all the nodes** of the cluster (or in the ones selected). If you delete the DaemonSet the pods managed by it will be also removed.
464+
**DaemonSets** ensure that a **specific Pod is running on all selected nodes** of the cluster. If you delete the DaemonSet, the Pods managed by it will also be removed.
425465

426466
{{#tabs }}
427467
{{#tab name="kubectl" }}
@@ -435,29 +475,53 @@ k get daemonsets
435475
{{#tab name="API" }}
436476

437477
```bash
438-
kurl -v https://$APISERVER/apis/extensions/v1beta1/namespaces/default/daemonsets
478+
kurl -v https://$APISERVER/apis/apps/v1/namespaces/<namespace>/daemonsets
479+
```
480+
481+
{{#endtab }}
482+
{{#endtabs }}
483+
484+
### Get Jobs
485+
486+
Jobs create Pods that run until completion. They are commonly used for migrations, backups, batch work, and one-off administrative tasks.
487+
488+
{{#tabs }}
489+
{{#tab name="kubectl" }}
490+
491+
```bash
492+
k get jobs
493+
k get jobs -n custnamespace
494+
```
495+
496+
{{#endtab }}
497+
498+
{{#tab name="API" }}
499+
500+
```bash
501+
kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/jobs
439502
```
440503

441504
{{#endtab }}
442505
{{#endtabs }}
443506

444-
### Get cronjob
507+
### Get CronJobs
445508

446-
Cron jobs allows to schedule using crontab like syntax the launch of a pod that will perform some action.
509+
CronJobs use a crontab-like schedule to create Jobs that launch Pods for task-style execution.
447510

448511
{{#tabs }}
449512
{{#tab name="kubectl" }}
450513

451514
```bash
452515
k get cronjobs
516+
k get cronjobs -n custnamespace
453517
```
454518

455519
{{#endtab }}
456520

457521
{{#tab name="API" }}
458522

459523
```bash
460-
kurl -v https://$APISERVER/apis/batch/v1beta1/namespaces/<namespace>/cronjobs
524+
kurl -v https://$APISERVER/apis/batch/v1/namespaces/<namespace>/cronjobs
461525
```
462526

463527
{{#endtab }}
@@ -849,6 +913,3 @@ https://www.cyberark.com/resources/threat-research-blog/kubernetes-pentest-metho
849913
{{#endref}}
850914

851915
{{#include ../../banners/hacktricks-training.md}}
852-
853-
854-

src/pentesting-cloud/kubernetes-security/kubernetes-hardening/kubernetes-securitycontext-s.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,32 @@ Note that the attributes set in **both SecurityContext and PodSecurityContext**,
5555
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>seccompProfile</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#seccompprofile-v1-core"><em>SeccompProfile</em></a></p> | The **seccomp options** to use by this container. |
5656
| <p><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core"><strong>windowsOptions</strong></a><br><a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#windowssecuritycontextoptions-v1-core"><em>WindowsSecurityContextOptions</em></a></p> | The **Windows specific settings** applied to all containers. |
5757

58+
## Practical workload review checklist
59+
60+
When reviewing a Pod or workload template, inspect both `spec.securityContext` and every container-level `securityContext` under `containers`, `initContainers`, and `ephemeralContainers`. Container-level fields can override the pod-level defaults, so a safe-looking pod default does not guarantee that every container is safe.
61+
62+
High-risk combinations to prioritize:
63+
64+
- `privileged: true`, especially with `hostPID`, `hostIPC`, `hostNetwork`, `hostPath`, host ports, or runtime socket mounts.
65+
- Added capabilities such as `SYS_ADMIN`, `NET_ADMIN`, `SYS_PTRACE`, `SYS_MODULE`, `DAC_READ_SEARCH`, or `DAC_OVERRIDE`.
66+
- `allowPrivilegeEscalation: true` or unset in containers that can execute attacker-controlled code.
67+
- `seccompProfile: Unconfined`, `procMount: Unmasked`, or missing runtime profiles on sensitive workloads.
68+
- Writable root filesystems or broad writable volume mounts in workloads that process untrusted input.
69+
- Missing CPU, memory, or ephemeral-storage requests and limits in multi-tenant namespaces.
70+
71+
For most application workloads, a good baseline is to run as a non-root UID, set `runAsNonRoot: true`, set `allowPrivilegeEscalation: false`, drop all capabilities and add back only the minimum required ones, use `seccompProfile: RuntimeDefault`, prefer a read-only root filesystem, and avoid host namespaces, hostPath mounts, and privileged mode.
72+
73+
At cluster level, use [Pod Security Admission](https://kubernetes.io/docs/concepts/security/pod-security-admission/) namespace labels to enforce the Kubernetes [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) where possible. Use `restricted` for namespaces that can support it, at least `baseline` for ordinary application namespaces, and keep privileged exceptions narrow, documented, and isolated to trusted platform namespaces or node pools.
74+
5875
## References
5976

6077
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#podsecuritycontext-v1-core)
6178
- [https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core)
79+
- [https://kubernetes.io/docs/tasks/configure-pod-container/security-context/](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)
80+
- [https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/](https://kubernetes.io/docs/concepts/security/linux-kernel-security-constraints/)
81+
- [https://kubernetes.io/docs/concepts/security/pod-security-standards/](https://kubernetes.io/docs/concepts/security/pod-security-standards/)
82+
- [https://kubernetes.io/docs/concepts/security/pod-security-admission/](https://kubernetes.io/docs/concepts/security/pod-security-admission/)
6283

6384
{{#include ../../../banners/hacktricks-training.md}}
6485

6586

66-

0 commit comments

Comments
 (0)